FORM v5.0.0-35-g6318119
spectator.c
Go to the documentation of this file.
1
6/* #[ License : */
7/*
8 * Copyright (C) 1984-2026 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 ( AM.SpectatorFiles[i].name != 0 ) {
256 if ( StrCmp((UBYTE *)(AM.SpectatorFiles[i].name),(UBYTE *)(inp)) == 0 ) {
257 break;
258 }
259 }
260 }
261 if ( i >= AM.SizeForSpectatorFiles ) {
262 MesPrint("&Spectator %s not found.",inp);
263 return(1);
264 }
265 sp = AM.SpectatorFiles+i;
266 Expressions[numexpr].status = DROPSPECTATOREXPRESSION;
267 if ( sp->fh->handle != -1 ) {
268 CloseFile(sp->fh->handle);
269 sp->fh->handle = -1;
270 remove(sp->fh->name);
271 }
272 M_free(sp->fh,"Temporary FileHandle");
273 M_free(sp->name,"Spectator expression name");
274
275 PUTZERO(sp->position);
276 PUTZERO(sp->readpos);
277 sp->fh = 0;
278 sp->name = 0;
279 sp->exprnumber = -1;
280 sp->flags = 0;
281 AM.NumSpectatorFiles--;
282 return(0);
283Syntax:
284 MesPrint("&Proper syntax is: RemoveSpectator,exprname;");
285 return(-1);
286}
287
288/*
289 #] CoRemoveSpectator :
290 #[ CoEmptySpectator :
291*/
292
293int CoEmptySpectator(UBYTE *inp)
294{
295 UBYTE *q;
296 WORD c1, numexpr;
297 int i;
298 SPECTATOR *sp;
299 while ( *inp == ',' ) inp++;
300 if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
301 MesPrint("&Illegal name for expression");
302 return(1);
303 }
304 if ( *q != 0 ) goto Syntax;
305 if ( GetVar(inp,&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
306 c1 != CEXPRESSION ) {
307 MesPrint("&%s is not a valid expression.",inp);
308 return(1);
309 }
310 if ( Expressions[numexpr].status != SPECTATOREXPRESSION ) {
311 MesPrint("&%s is not a spectator.",inp);
312 return(1);
313 }
314 for ( i = 0; i < AM.SizeForSpectatorFiles; i++ ) {
315 if ( StrCmp((UBYTE *)(AM.SpectatorFiles[i].name),(UBYTE *)(inp)) == 0 ) break;
316 }
317 if ( i >= AM.SizeForSpectatorFiles ) {
318 MesPrint("&Spectator %s not found.",inp);
319 return(1);
320 }
321 sp = AM.SpectatorFiles+i;
322 if ( sp->fh->handle != -1 ) {
323 CloseFile(sp->fh->handle);
324 sp->fh->handle = -1;
325 remove(sp->fh->name);
326 }
327 sp->fh->POfill = sp->fh->POfull = sp->fh->PObuffer;
328 PUTZERO(sp->position);
329 PUTZERO(sp->readpos);
330 return(0);
331Syntax:
332 MesPrint("&Proper syntax is: EmptySpectator,exprname;");
333 return(-1);
334}
335
336/*
337 #] CoEmptySpectator :
338 #[ PutInSpectator :
339
340 We need to use locks! There is only one file.
341 The code was copied (and modified) from PutOut.
342 Here we use no compression.
343*/
344
345int PutInSpectator(WORD *term,WORD specnum)
346{
347 GETBIDENTITY
348 WORD i, *p, ret;
349 LONG RetCode;
350 SPECTATOR *sp = &(AM.SpectatorFiles[specnum]);
351 FILEHANDLE *fi = sp->fh;
352
353 if ( ( i = *term ) <= 0 ) return(0);
354 LOCK(fi->pthreadslock);
355 ret = i;
356 p = fi->POfill;
357 do {
358 if ( p >= fi->POstop ) {
359 if ( fi->handle < 0 ) {
360 if ( ( RetCode = CreateFile(fi->name) ) >= 0 ) {
361 fi->handle = (WORD)RetCode;
362 PUTZERO(fi->filesize);
363 PUTZERO(fi->POposition);
364 }
365 else {
366 MLOCK(ErrorMessageLock);
367 MesPrint("Cannot create spectator file %s",fi->name);
368 MUNLOCK(ErrorMessageLock);
369 UNLOCK(fi->pthreadslock);
370 return(-1);
371 }
372 }
373 SeekFile(fi->handle,&(sp->position),SEEK_SET);
374 if ( ( RetCode = WriteFile(fi->handle,(UBYTE *)(fi->PObuffer),fi->POsize) ) != fi->POsize ) {
375 MLOCK(ErrorMessageLock);
376 MesPrint("Error during spectator write. Disk full?");
377 MesPrint("Attempt to write %l bytes on file %d at position %15p",
378 fi->POsize,fi->handle,&(fi->POposition));
379 MesPrint("RetCode = %l, Buffer address = %l",RetCode,(LONG)(fi->PObuffer));
380 MUNLOCK(ErrorMessageLock);
381 UNLOCK(fi->pthreadslock);
382 return(-1);
383 }
384 ADDPOS(fi->filesize,fi->POsize);
385 p = fi->PObuffer;
386 ADDPOS(sp->position,fi->POsize);
387 fi->POposition = sp->position;
388 }
389 *p++ = *term++;
390 } while ( --i > 0 );
391 fi->POfull = fi->POfill = p;
392 Expressions[AM.SpectatorFiles[specnum].exprnumber].counter++;
393 UNLOCK(fi->pthreadslock);
394 return(ret);
395}
396
397/*
398 #] PutInSpectator :
399 #[ FlushSpectators :
400*/
401
402void FlushSpectators(void)
403{
404 SPECTATOR *sp = AM.SpectatorFiles;
405 FILEHANDLE *fh;
406 LONG RetCode;
407 int i;
408 LONG size;
409 if ( AM.NumSpectatorFiles <= 0 ) return;
410 for ( i = 0; i < AM.SizeForSpectatorFiles; i++, sp++ ) {
411 if ( sp->name == 0 ) continue;
412 fh = sp->fh;
413 if ( ( sp->flags & READSPECTATORFLAG ) != 0 ) { /* reset for writing */
414 sp->flags &= ~READSPECTATORFLAG;
415 fh->POfill = fh->PObuffer;
416 if ( fh->handle >= 0 ) {
417 SeekFile(fh->handle,&(sp->position),SEEK_SET);
418 fh->POposition = sp->position;
419 }
420 continue;
421 }
422 if ( fh->POfill <= fh->PObuffer ) continue; /* is clean */
423 if ( fh->handle < 0 ) { /* File needs to be created */
424 if ( ( RetCode = CreateFile(fh->name) ) >= 0 ) {
425 PUTZERO(fh->filesize);
426 PUTZERO(fh->POposition);
427 fh->handle = (WORD)RetCode;
428 }
429 else {
430 MLOCK(ErrorMessageLock);
431 MesPrint("Cannot create spectator file %s",fh->name);
432 MUNLOCK(ErrorMessageLock);
433 Terminate(-1);
434 }
435 PUTZERO(sp->position);
436 }
437 SeekFile(fh->handle,&(sp->position),SEEK_SET);
438 size = (fh->POfill - fh->PObuffer)*sizeof(WORD);
439 if ( ( RetCode = WriteFile(fh->handle,(UBYTE *)(fh->PObuffer),size) ) != size ) {
440 MLOCK(ErrorMessageLock);
441 MesPrint("Write error synching spectator file. Disk full?");
442 MesPrint("Attempt to write %l bytes on file %s at position %15p",
443 size,fh->name,&(sp->position));
444 MUNLOCK(ErrorMessageLock);
445 Terminate(-1);
446 }
447 fh->POfill = fh->PObuffer;
448 SeekFile(fh->handle,&(sp->position),SEEK_END);
449 fh->POposition = sp->position;
450 }
451 return;
452}
453
454/*
455 #] FlushSpectators :
456 #[ CoCopySpectator :
457*/
458
459int CoCopySpectator(UBYTE *inp)
460{
461 GETIDENTITY
462 UBYTE *q, c, *exprname, *p;
463 WORD c1, c2, numexpr;
464 int specnum, error = 0;
465 SPECTATOR *sp;
466 while ( *inp == ',' ) inp++;
467 if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
468 MesPrint("&Illegal name for expression");
469 return(1);
470 }
471 if ( *q == 0 ) goto Syntax;
472 c = *q; *q = 0;
473 if ( GetVar(inp,&c1,&c2,ALLVARIABLES,NOAUTO) != NAMENOTFOUND ) {
474 MesPrint("&%s is the name of an existing variable.",inp);
475 return(1);
476 }
477 numexpr = EntVar(CEXPRESSION,inp,LOCALEXPRESSION,0,0,0);
478 p = q;
479 exprname = inp;
480 *q = c;
481 while ( *q == ' ' || *q == ',' || *q == '\t' ) q++;
482 if ( *q != '=' ) goto Syntax;
483 q++;
484 while ( *q == ' ' || *q == ',' || *q == '\t' ) q++;
485 inp = q;
486 if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
487 MesPrint("&Illegal name for spectator expression");
488 return(1);
489 }
490 if ( *q != 0 ) goto Syntax;
491 if ( AM.NumSpectatorFiles <= 0 ) {
492 MesPrint("&CopySpectator: There are no spectator expressions!");
493 return(1);
494 }
495 sp = AM.SpectatorFiles;
496 for ( specnum = 0; specnum < AM.SizeForSpectatorFiles; specnum++, sp++ ) {
497 if ( sp->name != 0 ) {
498 if ( StrCmp((UBYTE *)(sp->name),(UBYTE *)(inp)) == 0 ) break;
499 }
500 }
501 if ( specnum >= AM.SizeForSpectatorFiles ) {
502 MesPrint("&Spectator %s not found.",inp);
503 return(1);
504 }
505 sp->flags |= READSPECTATORFLAG;
506 PUTZERO(sp->fh->POposition);
507 PUTZERO(sp->readpos);
508 sp->fh->POfill = sp->fh->PObuffer;
509 if ( sp->fh->handle >= 0 ) {
510 SeekFile(sp->fh->handle,&(sp->fh->POposition),SEEK_SET);
511 }
512/*
513 Now we have:
514 1: The name of the target expression: numexpr
515 2: The spectator: sp (or specnum).
516 Time for some action. We need:
517 a: Write a prototype to create the expression
518 b: Signal to Processor that this is a spectator.
519 We do this by giving a negative compiler buffer number.
520*/
521 {
522 WORD *OldWork, *w;
523 POSITION pos;
524 OldWork = w = AT.WorkPointer;
525 *w++ = TYPEEXPRESSION;
526 *w++ = 3+SUBEXPSIZE;
527 *w++ = numexpr;
528 AC.ProtoType = w;
529 AR.CurExpr = numexpr; /* Block expression numexpr */
530 *w++ = SUBEXPRESSION;
531 *w++ = SUBEXPSIZE;
532 *w++ = numexpr;
533 *w++ = 1;
534 *w++ = -specnum-1; /* Indicates "spectator" to Processor */
535 FILLSUB(w)
536 *w++ = 1;
537 *w++ = 1;
538 *w++ = 3;
539 *w++ = 0;
540 SeekScratch(AR.outfile,&pos);
541 Expressions[numexpr].counter = 1;
542 Expressions[numexpr].onfile = pos;
543 Expressions[numexpr].whichbuffer = 0;
544#ifdef PARALLELCODE
545 Expressions[numexpr].partodo = AC.inparallelflag;
546#endif
547 OldWork[2] = w - OldWork - 3;
548 AT.WorkPointer = w;
549
550 if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0 ) {
551 c = *p; *p = 0;
552 MesPrint("&Cannot create expression %s",exprname);
553 *p = c;
554 error = -1;
555 }
556 else {
557 OldWork[2] = 4+SUBEXPSIZE;
558 OldWork[4] = SUBEXPSIZE;
559 OldWork[5] = numexpr;
560 OldWork[SUBEXPSIZE+3] = 1;
561 OldWork[SUBEXPSIZE+4] = 1;
562 OldWork[SUBEXPSIZE+5] = 3;
563 OldWork[SUBEXPSIZE+6] = 0;
564 if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0
565 || FlushOut(&pos,AR.outfile,0) ) {
566 c = *p; *p = 0;
567 MesPrint("&Cannot create expression %s",exprname);
568 *p = c;
569 error = -1;
570 }
571 AR.outfile->POfull = AR.outfile->POfill;
572 }
573 OldWork[2] = numexpr;
574/*
575 Seems unnecessary (13-feb-2018)
576
577 AddNtoL(OldWork[1],OldWork);
578*/
579 AT.WorkPointer = OldWork;
580 if ( AC.dumnumflag ) Add2Com(TYPEDETCURDUM)
581 }
582#ifdef WITHMPI
583 /*
584 * In ParFORM, substitutions of spectators has to be done on the master.
585 */
586 AC.mparallelflag |= NOPARALLEL_SPECTATOR;
587#endif
588 return(error);
589Syntax:
590 MesPrint("&Proper syntax is: CopySpectator,exprname=spectatorname;");
591 return(-1);
592}
593
594/*
595 #] CoCopySpectator :
596 #[ GetFromSpectator :
597
598 Note that if we did things right, we do not need a lock for the reading.
599*/
600
601WORD GetFromSpectator(WORD *term,WORD specnum)
602{
603 SPECTATOR *sp = &(AM.SpectatorFiles[specnum]);
604 FILEHANDLE *fh = sp->fh;
605 WORD i, size, *t = term;
606 LONG InIn;
607 if ( fh-> handle < 0 ) {
608 *term = 0;
609 return(0);
610 }
611/*
612 sp->position marks the 'end' of the file: the point where writing should
613 take place. sp->readpos marks from where to read.
614 fh->POposition marks where the file is currently positioned.
615 Note that when we read, we need to
616*/
617 if ( ISZEROPOS(sp->readpos) ) { /* we start reading. Fill buffer. */
618FillBuffer:
619 SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
620 InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
621 if ( InIn < 0 || ( InIn & 1 ) ) {
622 MLOCK(ErrorMessageLock);
623 MesPrint("Error reading information for %s spectator",sp->name);
624 MUNLOCK(ErrorMessageLock);
625 Terminate(-1);
626 }
627 InIn /= sizeof(WORD);
628 if ( InIn == 0 ) { *term = 0; return(0); }
629 SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
630 fh->POposition = sp->readpos;
631 fh->POfull = fh->PObuffer+InIn;
632 fh->POfill = fh->PObuffer;
633 }
634 if ( fh->POfill == fh->POfull ) { /* not even the size of the term! */
635 if ( ISLESSPOS(sp->readpos,sp->position) ) goto FillBuffer;
636 *term = 0;
637 return(0);
638 }
639 size = *fh->POfill++; *t++ = size;
640 for ( i = 1; i < size; i++ ) {
641 if ( fh->POfill >= fh->POfull ) {
642 SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
643 InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
644 if ( InIn < 0 || ( InIn & 1 ) ) {
645 MLOCK(ErrorMessageLock);
646 MesPrint("Error reading information for %s spectator",sp->name);
647 MUNLOCK(ErrorMessageLock);
648 Terminate(-1);
649 }
650 InIn /= sizeof(WORD);
651 if ( InIn == 0 ) {
652 MLOCK(ErrorMessageLock);
653 MesPrint("Reading incomplete information for %s spectator",sp->name);
654 MUNLOCK(ErrorMessageLock);
655 Terminate(-1);
656 }
657 SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
658 fh->POposition = sp->readpos;
659 fh->POfull = fh->PObuffer+InIn;
660 fh->POfill = fh->PObuffer;
661 }
662 *t++ = *fh->POfill++;
663 }
664 return(size);
665}
666
667/*
668 #] GetFromSpectator :
669 #[ ClearSpectators :
670
671 Removes all spectators.
672 In case of .store, the ones that are protected by .global stay.
673*/
674
675void ClearSpectators(WORD par)
676{
677 SPECTATOR *sp = AM.SpectatorFiles;
678 WORD numexpr, c1;
679 int i;
680 if ( AM.NumSpectatorFiles > 0 ) {
681 for ( i = 0; i < AM.SizeForSpectatorFiles; i++, sp++ ) {
682 if ( sp->name == 0 ) continue;
683 if ( ( sp->flags & GLOBALSPECTATORFLAG ) == 1 && par == STOREMODULE ) continue;
684
685 if ( GetVar((UBYTE *)(sp->name),&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
686 c1 != CEXPRESSION ) {
687 MesPrint("&%s is not a valid expression.",sp->name);
688 continue;
689 }
690 Expressions[numexpr].status = DROPPEDEXPRESSION;
691 if ( sp->fh->handle != -1 ) {
692 CloseFile(sp->fh->handle);
693 sp->fh->handle = -1;
694 remove(sp->fh->name);
695 }
696 M_free(sp->fh,"Temporary FileHandle");
697 M_free(sp->name,"Spectator expression name");
698 PUTZERO(sp->position);
699 sp->fh = 0;
700 sp->name = 0;
701 sp->exprnumber = -1;
702 sp->flags = 0;
703 AM.NumSpectatorFiles--;
704 }
705 }
706}
707
708/*
709 #] ClearSpectators :
710*/
UBYTE * SkipAName(UBYTE *s)
Definition compiler.c:443
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition sort.c:1171
int FlushOut(POSITION *, FILEHANDLE *, int)
Definition sort.c:1533
int handle
Definition structs.h:709