FORM  4.2
spectator.c
Go to the documentation of this file.
1 
6 /* #[ License : */
7 /*
8  * Copyright (C) 1984-2017 J.A.M. Vermaseren
9  * When using this file you are requested to refer to the publication
10  * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
11  * This is considered a matter of courtesy as the development was paid
12  * for by FOM the Dutch physics granting agency and we would like to
13  * be able to track its scientific use to convince FOM of its value
14  * for the community.
15  *
16  * This file is part of FORM.
17  *
18  * FORM is free software: you can redistribute it and/or modify it under the
19  * terms of the GNU General Public License as published by the Free Software
20  * Foundation, either version 3 of the License, or (at your option) any later
21  * version.
22  *
23  * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
24  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
25  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
26  * details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with FORM. If not, see <http://www.gnu.org/licenses/>.
30  */
31 /* #] License : */
32 /*
33  #[ includes :
34 */
35 
36 #include "form3.h"
37 
38 /*
39  #] includes :
40  #[ Commentary :
41 
42  We use an array of SPECTATOR structs in AM.SpectatorFiles.
43  When a spectator is removed this leaves a hole. This means that
44  we cannot use AM.NumSpectatorFiles but always have to scan up to
45  AM.SizeForSpectatorFiles which is the size of the array.
46  An element is in use when it has a name. This is the name of the
47  expression that is associated with it. There is also the number of
48  the expression, but because the expressions are frequently renumbered
49  at the end of a module, we always search for the spectators by name.
50  The expression number is only valid in the current module.
51  During execution we use the number of the spectator.
52 
53  The FILEHANDLE struct is borrowed from the structs for the scratch
54  files, but we do not keep copies for all workers as with the scratch
55  files. This brings some limitations (but saves much space). Basically
56  the reading can only be done by one master or worker. And because
57  we use the buffer both for writing and for reading we cannot read and
58  write in the same module.
59 
60  Processor can see that an expression is to be filled with a spectator
61  because we replace the compiler buffer number in the prototype by
62  -specnum-1. Of course, after this filling has taken place we should
63  make sure that in the next module there is a nonnegative number there.
64  The input is then obtained from GetFromSpectator instead from GetTerm.
65  This needed an extra argument in ThreadsProcessor. InParallelProcessor
66  can figure it out by itself. ParFORM still needs to be treated for this.
67 
68  The writing is to a single buffer. Hence it needs a lock. It is possible
69  to give all workers their own buffers (at great memory cost) and merge
70  the results when needed. That would be friendlier on ParFORM. We ALWAYS
71  assume that the order of the terms in the spectator file is random.
72 
73  In the first version there is no compression in the file. This could
74  change in later versions because both the writing and the reading are
75  purely sequential. Brackets are not possible.
76 
77  Currently, ParFORM allows use of spectators only in the sequential
78  mode. The parallelization is switched off in modules containing
79  ToSpectator or CopySpectator. Workers never create or access to
80  spectator files. Their file handles are always -1. We leave the
81  parallelization of modules with spectators for future work.
82 
83  #] Commentary :
84  #[ CoCreateSpectator :
85 
86  Syntax: CreateSpectator name_of_expr "filename";
87 */
88 
89 int CoCreateSpectator(UBYTE *inp)
90 {
91  UBYTE *p, *q, *filename, c, cc;
92  WORD c1, c2, numexpr = 0, specnum, HadOne = 0;
93  FILEHANDLE *fh;
94  while ( *inp == ',' ) inp++;
95  if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
96  MesPrint("&Illegal name for expression");
97  return(1);
98  }
99  c = *q; *q = 0;
100  if ( GetVar(inp,&c1,&c2,ALLVARIABLES,NOAUTO) != NAMENOTFOUND ) {
101  if ( c2 == CEXPRESSION &&
102  Expressions[c1].status == DROPSPECTATOREXPRESSION ) {
103  numexpr = c1;
104  Expressions[numexpr].status = SPECTATOREXPRESSION;
105  HadOne = 1;
106  }
107  else {
108  MesPrint("&The name %s has been used already.",inp);
109  *q = c;
110  return(1);
111  }
112  }
113  p = q+1;
114  while ( *p == ',' ) p++;
115  if ( *p != '"' ) goto Syntax;
116  p++; filename = p;
117  while ( *p && *p != '"' ) {
118  if ( *p == '\\' ) p++;
119  p++;
120  }
121  if ( *p != '"' ) goto Syntax;
122  q = p+1;
123  while ( *q && ( *q == ',' || *q == ' ' || *q == '\t' ) ) q++;
124  if ( *q ) goto Syntax;
125  cc = *p; *p = 0;
126 /*
127  Now we need to: create a struct for the spectator file.
128 */
129  if ( HadOne == 0 )
130  numexpr = EntVar(CEXPRESSION,inp,SPECTATOREXPRESSION,0,0,0);
131  fh = AllocFileHandle(1,(char *)filename);
132 /*
133  Make sure there is space in the AM.spectatorfiles array
134 */
135  if ( AM.NumSpectatorFiles >= AM.SizeForSpectatorFiles || AM.SpectatorFiles == 0 ) {
136  int newsize, i;
137  SPECTATOR *newspectators;
138  if ( AM.SizeForSpectatorFiles == 0 ) {
139  newsize = 10;
140  AM.NumSpectatorFiles = AM.SizeForSpectatorFiles = 0;
141  }
142  else newsize = AM.SizeForSpectatorFiles*2;
143  newspectators = (SPECTATOR *)Malloc1(newsize*sizeof(SPECTATOR),"Spectators");
144  for ( i = 0; i < AM.NumSpectatorFiles; i++ )
145  newspectators[i] = AM.SpectatorFiles[i];
146  for ( ; i < newsize; i++ ) {
147  newspectators[i].fh = 0;
148  newspectators[i].name = 0;
149  newspectators[i].exprnumber = -1;
150  newspectators[i].flags = 0;
151  PUTZERO(newspectators[i].position);
152  PUTZERO(newspectators[i].readpos);
153  }
154  AM.SizeForSpectatorFiles = newsize;
155  if ( AM.SpectatorFiles != 0 ) M_free(AM.SpectatorFiles,"Spectators");
156  AM.SpectatorFiles = newspectators;
157  specnum = AM.NumSpectatorFiles++;
158  }
159  else {
160  for ( specnum = 0; specnum < AM.SizeForSpectatorFiles; specnum++ ) {
161  if ( AM.SpectatorFiles[specnum].name == 0 ) break;
162  }
163  AM.NumSpectatorFiles++;
164  }
165  PUTZERO(AM.SpectatorFiles[specnum].position);
166  AM.SpectatorFiles[specnum].name = (char *)(strDup1(inp,"Spectator expression name"));
167  AM.SpectatorFiles[specnum].fh = fh;
168  AM.SpectatorFiles[specnum].exprnumber = numexpr;
169  *p = cc;
170  return(0);
171 Syntax:
172  MesPrint("&Proper syntax is: CreateSpectator,exprname,\"filename\";");
173  return(-1);
174 }
175 
176 /*
177  #] CoCreateSpectator :
178  #[ CoToSpectator :
179 */
180 
181 int CoToSpectator(UBYTE *inp)
182 {
183  UBYTE *q;
184  WORD c1, numexpr;
185  int i;
186  while ( *inp == ',' ) inp++;
187  if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
188  MesPrint("&Illegal name for expression");
189  return(1);
190  }
191  if ( *q != 0 ) goto Syntax;
192  if ( GetVar(inp,&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
193  c1 != CEXPRESSION ) {
194  MesPrint("&%s is not a valid expression.",inp);
195  return(1);
196  }
197  if ( Expressions[numexpr].status != SPECTATOREXPRESSION ) {
198  MesPrint("&%s is not an active spectator.",inp);
199  return(1);
200  }
201  for ( i = 0; i < AM.SizeForSpectatorFiles; i++ ) {
202  if ( AM.SpectatorFiles[i].name != 0 ) {
203  if ( StrCmp((UBYTE *)(AM.SpectatorFiles[i].name),(UBYTE *)(inp)) == 0 ) break;
204  }
205  }
206  if ( i >= AM.SizeForSpectatorFiles ) {
207  MesPrint("&Spectator %s not found.",inp);
208  return(1);
209  }
210  if ( ( AM.SpectatorFiles[i].flags & READSPECTATORFLAG ) != 0 ) {
211  MesPrint("&Spectator %s: It is not permitted to read from and write to the same spectator in one module.",inp);
212  return(1);
213  }
214  AM.SpectatorFiles[i].exprnumber = numexpr;
215  Add3Com(TYPETOSPECTATOR,i);
216 #ifdef WITHMPI
217  /*
218  * In ParFORM, ToSpectator has to be executed on the master.
219  */
220  AC.mparallelflag |= NOPARALLEL_SPECTATOR;
221 #endif
222  return(0);
223 Syntax:
224  MesPrint("&Proper syntax is: ToSpectator,exprname;");
225  return(-1);
226 }
227 
228 /*
229  #] CoToSpectator :
230  #[ CoRemoveSpectator :
231 */
232 
233 int CoRemoveSpectator(UBYTE *inp)
234 {
235  UBYTE *q;
236  WORD c1, numexpr;
237  int i;
238  SPECTATOR *sp;
239  while ( *inp == ',' ) inp++;
240  if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
241  MesPrint("&Illegal name for expression");
242  return(1);
243  }
244  if ( *q != 0 ) goto Syntax;
245  if ( GetVar(inp,&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
246  c1 != CEXPRESSION ) {
247  MesPrint("&%s is not a valid expression.",inp);
248  return(1);
249  }
250  if ( Expressions[numexpr].status != SPECTATOREXPRESSION ) {
251  MesPrint("&%s is not a spectator.",inp);
252  return(1);
253  }
254  for ( i = 0; i < AM.SizeForSpectatorFiles; i++ ) {
255  if ( StrCmp((UBYTE *)(AM.SpectatorFiles[i].name),(UBYTE *)(inp)) == 0 ) break;
256  }
257  if ( i >= AM.SizeForSpectatorFiles ) {
258  MesPrint("&Spectator %s not found.",inp);
259  return(1);
260  }
261  sp = AM.SpectatorFiles+i;
262  Expressions[numexpr].status = DROPSPECTATOREXPRESSION;
263  if ( sp->fh->handle != -1 ) {
264  CloseFile(sp->fh->handle);
265  sp->fh->handle = -1;
266  remove(sp->fh->name);
267  }
268  M_free(sp->fh,"Temporary FileHandle");
269  M_free(sp->name,"Spectator expression name");
270 
271  PUTZERO(sp->position);
272  PUTZERO(sp->readpos);
273  sp->fh = 0;
274  sp->name = 0;
275  sp->exprnumber = -1;
276  sp->flags = 0;
277  AM.NumSpectatorFiles--;
278  return(0);
279 Syntax:
280  MesPrint("&Proper syntax is: RemoveSpectator,exprname;");
281  return(-1);
282 }
283 
284 /*
285  #] CoRemoveSpectator :
286  #[ CoEmptySpectator :
287 */
288 
289 int CoEmptySpectator(UBYTE *inp)
290 {
291  UBYTE *q;
292  WORD c1, numexpr;
293  int i;
294  SPECTATOR *sp;
295  while ( *inp == ',' ) inp++;
296  if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
297  MesPrint("&Illegal name for expression");
298  return(1);
299  }
300  if ( *q != 0 ) goto Syntax;
301  if ( GetVar(inp,&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
302  c1 != CEXPRESSION ) {
303  MesPrint("&%s is not a valid expression.",inp);
304  return(1);
305  }
306  if ( Expressions[numexpr].status != SPECTATOREXPRESSION ) {
307  MesPrint("&%s is not a spectator.",inp);
308  return(1);
309  }
310  for ( i = 0; i < AM.SizeForSpectatorFiles; i++ ) {
311  if ( StrCmp((UBYTE *)(AM.SpectatorFiles[i].name),(UBYTE *)(inp)) == 0 ) break;
312  }
313  if ( i >= AM.SizeForSpectatorFiles ) {
314  MesPrint("&Spectator %s not found.",inp);
315  return(1);
316  }
317  sp = AM.SpectatorFiles+i;
318  if ( sp->fh->handle != -1 ) {
319  CloseFile(sp->fh->handle);
320  sp->fh->handle = -1;
321  remove(sp->fh->name);
322  }
323  sp->fh->POfill = sp->fh->POfull = sp->fh->PObuffer;
324  PUTZERO(sp->position);
325  PUTZERO(sp->readpos);
326  return(0);
327 Syntax:
328  MesPrint("&Proper syntax is: EmptySpectator,exprname;");
329  return(-1);
330 }
331 
332 /*
333  #] CoEmptySpectator :
334  #[ PutInSpectator :
335 
336  We need to use locks! There is only one file.
337  The code was copied (and modified) from PutOut.
338  Here we use no compression.
339 */
340 
341 int PutInSpectator(WORD *term,WORD specnum)
342 {
343  GETBIDENTITY
344  WORD i, *p, ret;
345  LONG RetCode;
346  SPECTATOR *sp = &(AM.SpectatorFiles[specnum]);
347  FILEHANDLE *fi = sp->fh;
348 
349  if ( ( i = *term ) <= 0 ) return(0);
350  LOCK(fi->pthreadslock);
351  ret = i;
352  p = fi->POfill;
353  do {
354  if ( p >= fi->POstop ) {
355  if ( fi->handle < 0 ) {
356  if ( ( RetCode = CreateFile(fi->name) ) >= 0 ) {
357  fi->handle = (WORD)RetCode;
358  PUTZERO(fi->filesize);
359  PUTZERO(fi->POposition);
360  }
361  else {
362  MLOCK(ErrorMessageLock);
363  MesPrint("Cannot create spectator file %s",fi->name);
364  MUNLOCK(ErrorMessageLock);
365  UNLOCK(fi->pthreadslock);
366  return(-1);
367  }
368  }
369  SeekFile(fi->handle,&(sp->position),SEEK_SET);
370  if ( ( RetCode = WriteFile(fi->handle,(UBYTE *)(fi->PObuffer),fi->POsize) ) != fi->POsize ) {
371  MLOCK(ErrorMessageLock);
372  MesPrint("Error during spectator write. Disk full?");
373  MesPrint("Attempt to write %l bytes on file %d at position %15p",
374  fi->POsize,fi->handle,&(fi->POposition));
375  MesPrint("RetCode = %l, Buffer address = %l",RetCode,(LONG)(fi->PObuffer));
376  MUNLOCK(ErrorMessageLock);
377  UNLOCK(fi->pthreadslock);
378  return(-1);
379  }
380  ADDPOS(fi->filesize,fi->POsize);
381  p = fi->PObuffer;
382  ADDPOS(sp->position,fi->POsize);
383  fi->POposition = sp->position;
384  }
385  *p++ = *term++;
386  } while ( --i > 0 );
387  fi->POfull = fi->POfill = p;
388  Expressions[AM.SpectatorFiles[specnum].exprnumber].counter++;
389  UNLOCK(fi->pthreadslock);
390  return(ret);
391 }
392 
393 /*
394  #] PutInSpectator :
395  #[ FlushSpectators :
396 */
397 
398 void FlushSpectators(VOID)
399 {
400  SPECTATOR *sp = AM.SpectatorFiles;
401  FILEHANDLE *fh;
402  LONG RetCode;
403  int i;
404  LONG size;
405  if ( AM.NumSpectatorFiles <= 0 ) return;
406  for ( i = 0; i < AM.SizeForSpectatorFiles; i++, sp++ ) {
407  if ( sp->name == 0 ) continue;
408  fh = sp->fh;
409  if ( ( sp->flags & READSPECTATORFLAG ) != 0 ) { /* reset for writing */
410  sp->flags &= ~READSPECTATORFLAG;
411  fh->POfill = fh->PObuffer;
412  if ( fh->handle >= 0 ) {
413  SeekFile(fh->handle,&(sp->position),SEEK_SET);
414  fh->POposition = sp->position;
415  }
416  continue;
417  }
418  if ( fh->POfill <= fh->PObuffer ) continue; /* is clean */
419  if ( fh->handle < 0 ) { /* File needs to be created */
420  if ( ( RetCode = CreateFile(fh->name) ) >= 0 ) {
421  PUTZERO(fh->filesize);
422  PUTZERO(fh->POposition);
423  fh->handle = (WORD)RetCode;
424  }
425  else {
426  MLOCK(ErrorMessageLock);
427  MesPrint("Cannot create spectator file %s",fh->name);
428  MUNLOCK(ErrorMessageLock);
429  Terminate(-1);
430  }
431  PUTZERO(sp->position);
432  }
433  SeekFile(fh->handle,&(sp->position),SEEK_SET);
434  size = (fh->POfill - fh->PObuffer)*sizeof(WORD);
435  if ( ( RetCode = WriteFile(fh->handle,(UBYTE *)(fh->PObuffer),size) ) != size ) {
436  MLOCK(ErrorMessageLock);
437  MesPrint("Write error synching spectator file. Disk full?");
438  MesPrint("Attempt to write %l bytes on file %s at position %15p",
439  size,fh->name,&(sp->position));
440  MUNLOCK(ErrorMessageLock);
441  Terminate(-1);
442  }
443  fh->POfill = fh->PObuffer;
444  SeekFile(fh->handle,&(sp->position),SEEK_END);
445  fh->POposition = sp->position;
446  }
447  return;
448 }
449 
450 /*
451  #] FlushSpectators :
452  #[ CoCopySpectator :
453 */
454 
455 int CoCopySpectator(UBYTE *inp)
456 {
457  GETIDENTITY
458  UBYTE *q, c, *exprname, *p;
459  WORD c1, c2, numexpr;
460  int specnum, error = 0;
461  SPECTATOR *sp;
462  while ( *inp == ',' ) inp++;
463  if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
464  MesPrint("&Illegal name for expression");
465  return(1);
466  }
467  if ( *q == 0 ) goto Syntax;
468  c = *q; *q = 0;
469  if ( GetVar(inp,&c1,&c2,ALLVARIABLES,NOAUTO) != NAMENOTFOUND ) {
470  MesPrint("&%s is the name of an existing variable.",inp);
471  return(1);
472  }
473  numexpr = EntVar(CEXPRESSION,inp,LOCALEXPRESSION,0,0,0);
474  p = q;
475  exprname = inp;
476  *q = c;
477  while ( *q == ' ' || *q == ',' || *q == '\t' ) q++;
478  if ( *q != '=' ) goto Syntax;
479  q++;
480  while ( *q == ' ' || *q == ',' || *q == '\t' ) q++;
481  inp = q;
482  if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
483  MesPrint("&Illegal name for spectator expression");
484  return(1);
485  }
486  if ( *q != 0 ) goto Syntax;
487  if ( AM.NumSpectatorFiles <= 0 ) {
488  MesPrint("&CopySpectator: There are no spectator expressions!");
489  return(1);
490  }
491  sp = AM.SpectatorFiles;
492  for ( specnum = 0; specnum < AM.SizeForSpectatorFiles; specnum++, sp++ ) {
493  if ( sp->name != 0 ) {
494  if ( StrCmp((UBYTE *)(sp->name),(UBYTE *)(inp)) == 0 ) break;
495  }
496  }
497  if ( specnum >= AM.SizeForSpectatorFiles ) {
498  MesPrint("&Spectator %s not found.",inp);
499  return(1);
500  }
501  sp->flags |= READSPECTATORFLAG;
502  PUTZERO(sp->fh->POposition);
503  PUTZERO(sp->readpos);
504  sp->fh->POfill = sp->fh->PObuffer;
505  if ( sp->fh->handle >= 0 ) {
506  SeekFile(sp->fh->handle,&(sp->fh->POposition),SEEK_SET);
507  }
508 /*
509  Now we have:
510  1: The name of the target expression: numexpr
511  2: The spectator: sp (or specnum).
512  Time for some action. We need:
513  a: Write a prototype to create the expression
514  b: Signal to Processor that this is a spectator.
515  We do this by giving a negative compiler buffer number.
516 */
517  {
518  WORD *OldWork, *w;
519  POSITION pos;
520  OldWork = w = AT.WorkPointer;
521  *w++ = TYPEEXPRESSION;
522  *w++ = 3+SUBEXPSIZE;
523  *w++ = numexpr;
524  AC.ProtoType = w;
525  AR.CurExpr = numexpr; /* Block expression numexpr */
526  *w++ = SUBEXPRESSION;
527  *w++ = SUBEXPSIZE;
528  *w++ = numexpr;
529  *w++ = 1;
530  *w++ = -specnum-1; /* Indicates "spectator" to Processor */
531  FILLSUB(w)
532  *w++ = 1;
533  *w++ = 1;
534  *w++ = 3;
535  *w++ = 0;
536  SeekScratch(AR.outfile,&pos);
537  Expressions[numexpr].counter = 1;
538  Expressions[numexpr].onfile = pos;
539  Expressions[numexpr].whichbuffer = 0;
540 #ifdef PARALLELCODE
541  Expressions[numexpr].partodo = AC.inparallelflag;
542 #endif
543  OldWork[2] = w - OldWork - 3;
544  AT.WorkPointer = w;
545 
546  if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0 ) {
547  c = *p; *p = 0;
548  MesPrint("&Cannot create expression %s",exprname);
549  *p = c;
550  error = -1;
551  }
552  else {
553  OldWork[2] = 4+SUBEXPSIZE;
554  OldWork[4] = SUBEXPSIZE;
555  OldWork[5] = numexpr;
556  OldWork[SUBEXPSIZE+3] = 1;
557  OldWork[SUBEXPSIZE+4] = 1;
558  OldWork[SUBEXPSIZE+5] = 3;
559  OldWork[SUBEXPSIZE+6] = 0;
560  if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0
561  || FlushOut(&pos,AR.outfile,0) ) {
562  c = *p; *p = 0;
563  MesPrint("&Cannot create expression %s",exprname);
564  *p = c;
565  error = -1;
566  }
567  AR.outfile->POfull = AR.outfile->POfill;
568  }
569  OldWork[2] = numexpr;
570  AddNtoL(OldWork[1],OldWork);
571  AT.WorkPointer = OldWork;
572  if ( AC.dumnumflag ) Add2Com(TYPEDETCURDUM)
573  }
574 #ifdef WITHMPI
575  /*
576  * In ParFORM, substitutions of spectators has to be done on the master.
577  */
578  AC.mparallelflag |= NOPARALLEL_SPECTATOR;
579 #endif
580  return(error);
581 Syntax:
582  MesPrint("&Proper syntax is: CopySpectator,exprname=spectatorname;");
583  return(-1);
584 }
585 
586 /*
587  #] CoCopySpectator :
588  #[ GetFromSpectator :
589 
590  Note that if we did things right, we do not need a lock for the reading.
591 */
592 
593 WORD GetFromSpectator(WORD *term,WORD specnum)
594 {
595  SPECTATOR *sp = &(AM.SpectatorFiles[specnum]);
596  FILEHANDLE *fh = sp->fh;
597  WORD i, size, *t = term;
598  LONG InIn;
599  if ( fh-> handle < 0 ) {
600  *term = 0;
601  return(0);
602  }
603 /*
604  sp->position marks the 'end' of the file: the point where writing should
605  take place. sp->readpos marks from where to read.
606  fh->POposition marks where the file is currently positioned.
607  Note that when we read, we need to
608 */
609  if ( ISZEROPOS(sp->readpos) ) { /* we start reading. Fill buffer. */
610 FillBuffer:
611  SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
612  InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
613  if ( InIn < 0 || ( InIn & 1 ) ) {
614  MLOCK(ErrorMessageLock);
615  MesPrint("Error reading information for %s spectator",sp->name);
616  MUNLOCK(ErrorMessageLock);
617  Terminate(-1);
618  }
619  InIn /= sizeof(WORD);
620  if ( InIn == 0 ) { *term = 0; return(0); }
621  SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
622  fh->POposition = sp->readpos;
623  fh->POfull = fh->PObuffer+InIn;
624  fh->POfill = fh->PObuffer;
625  }
626  if ( fh->POfill == fh->POfull ) { /* not even the size of the term! */
627  if ( ISLESSPOS(sp->readpos,sp->position) ) goto FillBuffer;
628  *term = 0;
629  return(0);
630  }
631  size = *fh->POfill++; *t++ = size;
632  for ( i = 1; i < size; i++ ) {
633  if ( fh->POfill >= fh->POfull ) {
634  SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
635  InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
636  if ( InIn < 0 || ( InIn & 1 ) ) {
637  MLOCK(ErrorMessageLock);
638  MesPrint("Error reading information for %s spectator",sp->name);
639  MUNLOCK(ErrorMessageLock);
640  Terminate(-1);
641  }
642  InIn /= sizeof(WORD);
643  if ( InIn == 0 ) {
644  MLOCK(ErrorMessageLock);
645  MesPrint("Reading incomplete information for %s spectator",sp->name);
646  MUNLOCK(ErrorMessageLock);
647  Terminate(-1);
648  }
649  SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
650  fh->POposition = sp->readpos;
651  fh->POfull = fh->PObuffer+InIn;
652  fh->POfill = fh->PObuffer;
653  }
654  *t++ = *fh->POfill++;
655  }
656  return(size);
657 }
658 
659 /*
660  #] GetFromSpectator :
661  #[ ClearSpectators :
662 
663  Removes all spectators.
664  In case of .store, the ones that are protected by .global stay.
665 */
666 
667 void ClearSpectators(WORD par)
668 {
669  SPECTATOR *sp = AM.SpectatorFiles;
670  WORD numexpr, c1;
671  int i;
672  if ( AM.NumSpectatorFiles > 0 ) {
673  for ( i = 0; i < AM.SizeForSpectatorFiles; i++, sp++ ) {
674  if ( sp->name == 0 ) continue;
675  if ( ( sp->flags & GLOBALSPECTATORFLAG ) == 1 && par == STOREMODULE ) continue;
676 
677  if ( GetVar((UBYTE *)(sp->name),&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
678  c1 != CEXPRESSION ) {
679  MesPrint("&%s is not a valid expression.",sp->name);
680  continue;
681  }
682  Expressions[numexpr].status = DROPPEDEXPRESSION;
683  if ( sp->fh->handle != -1 ) {
684  CloseFile(sp->fh->handle);
685  sp->fh->handle = -1;
686  remove(sp->fh->name);
687  }
688  M_free(sp->fh,"Temporary FileHandle");
689  M_free(sp->name,"Spectator expression name");
690  PUTZERO(sp->position);
691  sp->fh = 0;
692  sp->name = 0;
693  sp->exprnumber = -1;
694  sp->flags = 0;
695  AM.NumSpectatorFiles--;
696  }
697  }
698 }
699 
700 /*
701  #] ClearSpectators :
702 */
Definition: structs.h:620
int AddNtoL(int n, WORD *array)
Definition: comtool.c:288
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition: sort.c:1387
WORD FlushOut(POSITION *, FILEHANDLE *, int)
Definition: sort.c:1724
int handle
Definition: structs.h:648