FORM  4.2.1
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 /*
571  Seems unnecessary (13-feb-2018)
572 
573  AddNtoL(OldWork[1],OldWork);
574 */
575  AT.WorkPointer = OldWork;
576  if ( AC.dumnumflag ) Add2Com(TYPEDETCURDUM)
577  }
578 #ifdef WITHMPI
579  /*
580  * In ParFORM, substitutions of spectators has to be done on the master.
581  */
582  AC.mparallelflag |= NOPARALLEL_SPECTATOR;
583 #endif
584  return(error);
585 Syntax:
586  MesPrint("&Proper syntax is: CopySpectator,exprname=spectatorname;");
587  return(-1);
588 }
589 
590 /*
591  #] CoCopySpectator :
592  #[ GetFromSpectator :
593 
594  Note that if we did things right, we do not need a lock for the reading.
595 */
596 
597 WORD GetFromSpectator(WORD *term,WORD specnum)
598 {
599  SPECTATOR *sp = &(AM.SpectatorFiles[specnum]);
600  FILEHANDLE *fh = sp->fh;
601  WORD i, size, *t = term;
602  LONG InIn;
603  if ( fh-> handle < 0 ) {
604  *term = 0;
605  return(0);
606  }
607 /*
608  sp->position marks the 'end' of the file: the point where writing should
609  take place. sp->readpos marks from where to read.
610  fh->POposition marks where the file is currently positioned.
611  Note that when we read, we need to
612 */
613  if ( ISZEROPOS(sp->readpos) ) { /* we start reading. Fill buffer. */
614 FillBuffer:
615  SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
616  InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
617  if ( InIn < 0 || ( InIn & 1 ) ) {
618  MLOCK(ErrorMessageLock);
619  MesPrint("Error reading information for %s spectator",sp->name);
620  MUNLOCK(ErrorMessageLock);
621  Terminate(-1);
622  }
623  InIn /= sizeof(WORD);
624  if ( InIn == 0 ) { *term = 0; return(0); }
625  SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
626  fh->POposition = sp->readpos;
627  fh->POfull = fh->PObuffer+InIn;
628  fh->POfill = fh->PObuffer;
629  }
630  if ( fh->POfill == fh->POfull ) { /* not even the size of the term! */
631  if ( ISLESSPOS(sp->readpos,sp->position) ) goto FillBuffer;
632  *term = 0;
633  return(0);
634  }
635  size = *fh->POfill++; *t++ = size;
636  for ( i = 1; i < size; i++ ) {
637  if ( fh->POfill >= fh->POfull ) {
638  SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
639  InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
640  if ( InIn < 0 || ( InIn & 1 ) ) {
641  MLOCK(ErrorMessageLock);
642  MesPrint("Error reading information for %s spectator",sp->name);
643  MUNLOCK(ErrorMessageLock);
644  Terminate(-1);
645  }
646  InIn /= sizeof(WORD);
647  if ( InIn == 0 ) {
648  MLOCK(ErrorMessageLock);
649  MesPrint("Reading incomplete information for %s spectator",sp->name);
650  MUNLOCK(ErrorMessageLock);
651  Terminate(-1);
652  }
653  SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
654  fh->POposition = sp->readpos;
655  fh->POfull = fh->PObuffer+InIn;
656  fh->POfill = fh->PObuffer;
657  }
658  *t++ = *fh->POfill++;
659  }
660  return(size);
661 }
662 
663 /*
664  #] GetFromSpectator :
665  #[ ClearSpectators :
666 
667  Removes all spectators.
668  In case of .store, the ones that are protected by .global stay.
669 */
670 
671 void ClearSpectators(WORD par)
672 {
673  SPECTATOR *sp = AM.SpectatorFiles;
674  WORD numexpr, c1;
675  int i;
676  if ( AM.NumSpectatorFiles > 0 ) {
677  for ( i = 0; i < AM.SizeForSpectatorFiles; i++, sp++ ) {
678  if ( sp->name == 0 ) continue;
679  if ( ( sp->flags & GLOBALSPECTATORFLAG ) == 1 && par == STOREMODULE ) continue;
680 
681  if ( GetVar((UBYTE *)(sp->name),&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
682  c1 != CEXPRESSION ) {
683  MesPrint("&%s is not a valid expression.",sp->name);
684  continue;
685  }
686  Expressions[numexpr].status = DROPPEDEXPRESSION;
687  if ( sp->fh->handle != -1 ) {
688  CloseFile(sp->fh->handle);
689  sp->fh->handle = -1;
690  remove(sp->fh->name);
691  }
692  M_free(sp->fh,"Temporary FileHandle");
693  M_free(sp->name,"Spectator expression name");
694  PUTZERO(sp->position);
695  sp->fh = 0;
696  sp->name = 0;
697  sp->exprnumber = -1;
698  sp->flags = 0;
699  AM.NumSpectatorFiles--;
700  }
701  }
702 }
703 
704 /*
705  #] ClearSpectators :
706 */
Definition: structs.h:633
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition: sort.c:1404
WORD FlushOut(POSITION *, FILEHANDLE *, int)
Definition: sort.c:1747
int handle
Definition: structs.h:661