FORM 4.3
spectator.c
Go to the documentation of this file.
1
6/* #[ License : */
7/*
8 * Copyright (C) 1984-2022 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
89int 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);
171Syntax:
172 MesPrint("&Proper syntax is: CreateSpectator,exprname,\"filename\";");
173 return(-1);
174}
175
176/*
177 #] CoCreateSpectator :
178 #[ CoToSpectator :
179*/
180
181int 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);
223Syntax:
224 MesPrint("&Proper syntax is: ToSpectator,exprname;");
225 return(-1);
226}
227
228/*
229 #] CoToSpectator :
230 #[ CoRemoveSpectator :
231*/
232
233int 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);
279Syntax:
280 MesPrint("&Proper syntax is: RemoveSpectator,exprname;");
281 return(-1);
282}
283
284/*
285 #] CoRemoveSpectator :
286 #[ CoEmptySpectator :
287*/
288
289int 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);
327Syntax:
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
341int 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
398void 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
455int 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);
585Syntax:
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
597WORD 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. */
614FillBuffer:
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
671void 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*/
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition sort.c:1405
WORD FlushOut(POSITION *, FILEHANDLE *, int)
Definition sort.c:1748
int handle
Definition structs.h:661