FORM v5.0.1-33-gdf7fc94
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/* INTERNAL_ERROR_EXCL_START */
367 MLOCK(ErrorMessageLock);
368 MesPrint("!>Cannot create spectator file %s",fi->name);
369 MUNLOCK(ErrorMessageLock);
370 UNLOCK(fi->pthreadslock);
371 return(-1);
372/* INTERNAL_ERROR_EXCL_STOP */
373 }
374 }
375 SeekFile(fi->handle,&(sp->position),SEEK_SET);
376 if ( ( RetCode = WriteFile(fi->handle,(UBYTE *)(fi->PObuffer),fi->POsize) ) != fi->POsize ) {
377 MLOCK(ErrorMessageLock);
378 MesPrint("Error during spectator write. Disk full?");
379 MesPrint("Attempt to write %l bytes on file %d at position %15p",
380 fi->POsize,fi->handle,&(fi->POposition));
381 MesPrint("RetCode = %l, Buffer address = %l",RetCode,(LONG)(fi->PObuffer));
382 MUNLOCK(ErrorMessageLock);
383 UNLOCK(fi->pthreadslock);
384 return(-1);
385 }
386 ADDPOS(fi->filesize,fi->POsize);
387 p = fi->PObuffer;
388 ADDPOS(sp->position,fi->POsize);
389 fi->POposition = sp->position;
390 }
391 *p++ = *term++;
392 } while ( --i > 0 );
393 fi->POfull = fi->POfill = p;
394 Expressions[AM.SpectatorFiles[specnum].exprnumber].counter++;
395 UNLOCK(fi->pthreadslock);
396 return(ret);
397}
398
399/*
400 #] PutInSpectator :
401 #[ FlushSpectators :
402*/
403
404void FlushSpectators(void)
405{
406 SPECTATOR *sp = AM.SpectatorFiles;
407 FILEHANDLE *fh;
408 LONG RetCode;
409 int i;
410 LONG size;
411 if ( AM.NumSpectatorFiles <= 0 ) return;
412 for ( i = 0; i < AM.SizeForSpectatorFiles; i++, sp++ ) {
413 if ( sp->name == 0 ) continue;
414 fh = sp->fh;
415 if ( ( sp->flags & READSPECTATORFLAG ) != 0 ) { /* reset for writing */
416 sp->flags &= ~READSPECTATORFLAG;
417 fh->POfill = fh->PObuffer;
418 if ( fh->handle >= 0 ) {
419 SeekFile(fh->handle,&(sp->position),SEEK_SET);
420 fh->POposition = sp->position;
421 }
422 continue;
423 }
424 if ( fh->POfill <= fh->PObuffer ) continue; /* is clean */
425 if ( fh->handle < 0 ) { /* File needs to be created */
426 if ( ( RetCode = CreateFile(fh->name) ) >= 0 ) {
427 PUTZERO(fh->filesize);
428 PUTZERO(fh->POposition);
429 fh->handle = (WORD)RetCode;
430 }
431 else {
432/* INTERNAL_ERROR_EXCL_START */
433 MLOCK(ErrorMessageLock);
434 MesPrint("!>Cannot create spectator file %s",fh->name);
435 MUNLOCK(ErrorMessageLock);
436 Terminate(-1);
437/* INTERNAL_ERROR_EXCL_STOP */
438 }
439 PUTZERO(sp->position);
440 }
441 SeekFile(fh->handle,&(sp->position),SEEK_SET);
442 size = (fh->POfill - fh->PObuffer)*sizeof(WORD);
443 if ( ( RetCode = WriteFile(fh->handle,(UBYTE *)(fh->PObuffer),size) ) != size ) {
444 MLOCK(ErrorMessageLock);
445 MesPrint("Write error synching spectator file. Disk full?");
446 MesPrint("Attempt to write %l bytes on file %s at position %15p",
447 size,fh->name,&(sp->position));
448 MUNLOCK(ErrorMessageLock);
449 Terminate(-1);
450 }
451 fh->POfill = fh->PObuffer;
452 SeekFile(fh->handle,&(sp->position),SEEK_END);
453 fh->POposition = sp->position;
454 }
455 return;
456}
457
458/*
459 #] FlushSpectators :
460 #[ CoCopySpectator :
461*/
462
463int CoCopySpectator(UBYTE *inp)
464{
465 GETIDENTITY
466 UBYTE *q, c, *exprname, *p;
467 WORD c1, c2, numexpr;
468 int specnum, error = 0;
469 SPECTATOR *sp;
470 while ( *inp == ',' ) inp++;
471 if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
472 MesPrint("&Illegal name for expression");
473 return(1);
474 }
475 if ( *q == 0 ) goto Syntax;
476 c = *q; *q = 0;
477 if ( GetVar(inp,&c1,&c2,ALLVARIABLES,NOAUTO) != NAMENOTFOUND ) {
478 MesPrint("&%s is the name of an existing variable.",inp);
479 return(1);
480 }
481 numexpr = EntVar(CEXPRESSION,inp,LOCALEXPRESSION,0,0,0);
482 p = q;
483 exprname = inp;
484 *q = c;
485 while ( *q == ' ' || *q == ',' || *q == '\t' ) q++;
486 if ( *q != '=' ) goto Syntax;
487 q++;
488 while ( *q == ' ' || *q == ',' || *q == '\t' ) q++;
489 inp = q;
490 if ( ( q = SkipAName(inp) ) == 0 || q[-1] == '_' ) {
491 MesPrint("&Illegal name for spectator expression");
492 return(1);
493 }
494 if ( *q != 0 ) goto Syntax;
495 if ( AM.NumSpectatorFiles <= 0 ) {
496 MesPrint("&CopySpectator: There are no spectator expressions!");
497 return(1);
498 }
499 sp = AM.SpectatorFiles;
500 for ( specnum = 0; specnum < AM.SizeForSpectatorFiles; specnum++, sp++ ) {
501 if ( sp->name != 0 ) {
502 if ( StrCmp((UBYTE *)(sp->name),(UBYTE *)(inp)) == 0 ) break;
503 }
504 }
505 if ( specnum >= AM.SizeForSpectatorFiles ) {
506 MesPrint("&Spectator %s not found.",inp);
507 return(1);
508 }
509 sp->flags |= READSPECTATORFLAG;
510 PUTZERO(sp->fh->POposition);
511 PUTZERO(sp->readpos);
512 sp->fh->POfill = sp->fh->PObuffer;
513 if ( sp->fh->handle >= 0 ) {
514 SeekFile(sp->fh->handle,&(sp->fh->POposition),SEEK_SET);
515 }
516/*
517 Now we have:
518 1: The name of the target expression: numexpr
519 2: The spectator: sp (or specnum).
520 Time for some action. We need:
521 a: Write a prototype to create the expression
522 b: Signal to Processor that this is a spectator.
523 We do this by giving a negative compiler buffer number.
524*/
525 {
526 WORD *OldWork, *w;
527 POSITION pos;
528 OldWork = w = AT.WorkPointer;
529 *w++ = TYPEEXPRESSION;
530 *w++ = 3+SUBEXPSIZE;
531 *w++ = numexpr;
532 AC.ProtoType = w;
533 AR.CurExpr = numexpr; /* Block expression numexpr */
534 *w++ = SUBEXPRESSION;
535 *w++ = SUBEXPSIZE;
536 *w++ = numexpr;
537 *w++ = 1;
538 *w++ = -specnum-1; /* Indicates "spectator" to Processor */
539 FILLSUB(w)
540 *w++ = 1;
541 *w++ = 1;
542 *w++ = 3;
543 *w++ = 0;
544 SeekScratch(AR.outfile,&pos);
545 Expressions[numexpr].counter = 1;
546 Expressions[numexpr].onfile = pos;
547 Expressions[numexpr].whichbuffer = 0;
548#ifdef PARALLELCODE
549 Expressions[numexpr].partodo = AC.inparallelflag;
550#endif
551 OldWork[2] = w - OldWork - 3;
552 AT.WorkPointer = w;
553
554 if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0 ) {
555 c = *p; *p = 0;
556 MesPrint("&Cannot create expression %s",exprname);
557 *p = c;
558 error = -1;
559 }
560 else {
561 OldWork[2] = 4+SUBEXPSIZE;
562 OldWork[4] = SUBEXPSIZE;
563 OldWork[5] = numexpr;
564 OldWork[SUBEXPSIZE+3] = 1;
565 OldWork[SUBEXPSIZE+4] = 1;
566 OldWork[SUBEXPSIZE+5] = 3;
567 OldWork[SUBEXPSIZE+6] = 0;
568 if ( PutOut(BHEAD OldWork+2,&pos,AR.outfile,0) < 0
569 || FlushOut(&pos,AR.outfile,0) ) {
570 c = *p; *p = 0;
571 MesPrint("&Cannot create expression %s",exprname);
572 *p = c;
573 error = -1;
574 }
575 AR.outfile->POfull = AR.outfile->POfill;
576 }
577 OldWork[2] = numexpr;
578/*
579 Seems unnecessary (13-feb-2018)
580
581 AddNtoL(OldWork[1],OldWork);
582*/
583 AT.WorkPointer = OldWork;
584 if ( AC.dumnumflag ) Add2Com(TYPEDETCURDUM)
585 }
586#ifdef WITHMPI
587 /*
588 * In ParFORM, substitutions of spectators has to be done on the master.
589 */
590 AC.mparallelflag |= NOPARALLEL_SPECTATOR;
591#endif
592 return(error);
593Syntax:
594 MesPrint("&Proper syntax is: CopySpectator,exprname=spectatorname;");
595 return(-1);
596}
597
598/*
599 #] CoCopySpectator :
600 #[ GetFromSpectator :
601
602 Note that if we did things right, we do not need a lock for the reading.
603*/
604
605WORD GetFromSpectator(WORD *term,WORD specnum)
606{
607 SPECTATOR *sp = &(AM.SpectatorFiles[specnum]);
608 FILEHANDLE *fh = sp->fh;
609 WORD i, size, *t = term;
610 LONG InIn;
611 if ( fh-> handle < 0 ) {
612 *term = 0;
613 return(0);
614 }
615/*
616 sp->position marks the 'end' of the file: the point where writing should
617 take place. sp->readpos marks from where to read.
618 fh->POposition marks where the file is currently positioned.
619 Note that when we read, we need to
620*/
621 if ( ISZEROPOS(sp->readpos) ) { /* we start reading. Fill buffer. */
622FillBuffer:
623 SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
624 InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
625 if ( InIn < 0 || ( InIn & 1 ) ) {
626/* INTERNAL_ERROR_EXCL_START */
627 MLOCK(ErrorMessageLock);
628 MesPrint("!>Error reading information for %s spectator",sp->name);
629 MUNLOCK(ErrorMessageLock);
630 Terminate(-1);
631/* INTERNAL_ERROR_EXCL_STOP */
632 }
633 InIn /= sizeof(WORD);
634 if ( InIn == 0 ) { *term = 0; return(0); }
635 SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
636 fh->POposition = sp->readpos;
637 fh->POfull = fh->PObuffer+InIn;
638 fh->POfill = fh->PObuffer;
639 }
640 if ( fh->POfill == fh->POfull ) { /* not even the size of the term! */
641 if ( ISLESSPOS(sp->readpos,sp->position) ) goto FillBuffer;
642 *term = 0;
643 return(0);
644 }
645 size = *fh->POfill++; *t++ = size;
646 for ( i = 1; i < size; i++ ) {
647 if ( fh->POfill >= fh->POfull ) {
648 SeekFile(fh->handle,&(sp->readpos),SEEK_SET);
649 InIn = ReadFile(fh->handle,(UBYTE *)(fh->PObuffer),fh->POsize);
650 if ( InIn < 0 || ( InIn & 1 ) ) {
651/* INTERNAL_ERROR_EXCL_START */
652 MLOCK(ErrorMessageLock);
653 MesPrint("!>Error reading information for %s spectator",sp->name);
654 MUNLOCK(ErrorMessageLock);
655 Terminate(-1);
656/* INTERNAL_ERROR_EXCL_STOP */
657 }
658 InIn /= sizeof(WORD);
659 if ( InIn == 0 ) {
660/* INTERNAL_ERROR_EXCL_START */
661 MLOCK(ErrorMessageLock);
662 MesPrint("!>Reading incomplete information for %s spectator",sp->name);
663 MUNLOCK(ErrorMessageLock);
664 Terminate(-1);
665/* INTERNAL_ERROR_EXCL_STOP */
666 }
667 SeekFile(fh->handle,&(sp->readpos),SEEK_CUR);
668 fh->POposition = sp->readpos;
669 fh->POfull = fh->PObuffer+InIn;
670 fh->POfill = fh->PObuffer;
671 }
672 *t++ = *fh->POfill++;
673 }
674 return(size);
675}
676
677/*
678 #] GetFromSpectator :
679 #[ ClearSpectators :
680
681 Removes all spectators.
682 In case of .store, the ones that are protected by .global stay.
683*/
684
685void ClearSpectators(WORD par)
686{
687 SPECTATOR *sp = AM.SpectatorFiles;
688 WORD numexpr, c1;
689 int i;
690 if ( AM.NumSpectatorFiles > 0 ) {
691 for ( i = 0; i < AM.SizeForSpectatorFiles; i++, sp++ ) {
692 if ( sp->name == 0 ) continue;
693 if ( ( sp->flags & GLOBALSPECTATORFLAG ) == 1 && par == STOREMODULE ) continue;
694
695 if ( GetVar((UBYTE *)(sp->name),&c1,&numexpr,ALLVARIABLES,NOAUTO) == NAMENOTFOUND ||
696 c1 != CEXPRESSION ) {
697 MesPrint("&%s is not a valid expression.",sp->name);
698 continue;
699 }
700 Expressions[numexpr].status = DROPPEDEXPRESSION;
701 if ( sp->fh->handle != -1 ) {
702 CloseFile(sp->fh->handle);
703 sp->fh->handle = -1;
704 remove(sp->fh->name);
705 }
706 M_free(sp->fh,"Temporary FileHandle");
707 M_free(sp->name,"Spectator expression name");
708 PUTZERO(sp->position);
709 sp->fh = 0;
710 sp->name = 0;
711 sp->exprnumber = -1;
712 sp->flags = 0;
713 AM.NumSpectatorFiles--;
714 }
715 }
716}
717
718/*
719 #] ClearSpectators :
720*/
UBYTE * SkipAName(UBYTE *s)
Definition compiler.c:443
WORD PutOut(PHEAD WORD *, POSITION *, FILEHANDLE *, WORD)
Definition sort.c:1217
int FlushOut(POSITION *, FILEHANDLE *, int)
Definition sort.c:1581
int handle
Definition structs.h:709