FORM  4.2.1
tools.c
Go to the documentation of this file.
1 
11 /* #[ License : */
12 /*
13  * Copyright (C) 1984-2017 J.A.M. Vermaseren
14  * When using this file you are requested to refer to the publication
15  * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
16  * This is considered a matter of courtesy as the development was paid
17  * for by FOM the Dutch physics granting agency and we would like to
18  * be able to track its scientific use to convince FOM of its value
19  * for the community.
20  *
21  * This file is part of FORM.
22  *
23  * FORM is free software: you can redistribute it and/or modify it under the
24  * terms of the GNU General Public License as published by the Free Software
25  * Foundation, either version 3 of the License, or (at your option) any later
26  * version.
27  *
28  * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
29  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
31  * details.
32  *
33  * You should have received a copy of the GNU General Public License along
34  * with FORM. If not, see <http://www.gnu.org/licenses/>.
35  */
36 /* #] License : */
37 /*
38  #[ Includes :
39  Note: TERMMALLOCDEBUG tests part of the TermMalloc and NumberMalloc
40  system. To work properly it needs MEMORYMACROS in declare.h
41  not to be defined to make sure that all calls will be diverted
42  to the routines here.
43 #define TERMMALLOCDEBUG
44 #define FILLVALUE 126
45 #define MALLOCDEBUGOUTPUT
46 #define MALLOCDEBUG 1
47 */
48 #ifndef FILLVALUE
49  #define FILLVALUE 0
50 #endif
51 
52 /*
53  The enhanced malloc debugger, see comments in the beginning of the
54  file mallocprotect.h
55  MALLOCPROTECT == -1 -- protect left side, used block is left-aligned.
56  MALLOCPROTECT == 0 -- protect both sides, used block is left-aligned;
57  MALLOCPROTECT == 1 -- protect both sides, used block is right-aligned;
58  ATTENTION! The macro MALLOCPROTECT must be defined
59  BEFORE #include mallocprotect.h
60 #define MALLOCPROTECT 1
61 */
62 
63 #include "form3.h"
64 
65 FILES **filelist;
66 int numinfilelist = 0;
67 int filelistsize = 0;
68 #ifdef MALLOCDEBUG
69 #define BANNER (4*sizeof(LONG))
70 void *malloclist[60000];
71 LONG mallocsizes[60000];
72 char *mallocstrings[60000];
73 int nummalloclist = 0;
74 #endif
75 
76 #ifdef GPP
77 extern "C" getdtablesize();
78 #endif
79 
80 #ifdef WITHSTATS
81 LONG numwrites = 0;
82 LONG numreads = 0;
83 LONG numseeks = 0;
84 LONG nummallocs = 0;
85 LONG numfrees = 0;
86 #endif
87 
88 #ifdef MALLOCPROTECT
89 #ifdef TRAPSIGNALS
90 #error "MALLOCPROTECT": undefine "TRAPSIGNALS" in unix.h first!
91 #endif
92 #include "mallocprotect.h"
93 
94 #ifdef M_alloc
95 #undef M_alloc
96 #endif
97 
98 #define M_alloc mprotectMalloc
99 
100 #endif
101 
102 #ifdef TERMMALLOCDEBUG
103 WORD **DebugHeap1, **DebugHeap2;
104 #endif
105 
106 /*
107  #] Includes :
108  #[ Streams :
109  #[ LoadInputFile :
110 */
111 
112 UBYTE *LoadInputFile(UBYTE *filename, int type)
113 {
114  int handle;
115  LONG filesize;
116  UBYTE *buffer, *name = filename;
117  POSITION scrpos;
118  handle = LocateFile(&name,type);
119  if ( handle < 0 ) return(0);
120  PUTZERO(scrpos);
121  SeekFile(handle,&scrpos,SEEK_END);
122  TELLFILE(handle,&scrpos);
123  filesize = BASEPOSITION(scrpos);
124  PUTZERO(scrpos);
125  SeekFile(handle,&scrpos,SEEK_SET);
126  buffer = (UBYTE *)Malloc1(filesize+2,"LoadInputFile");
127  if ( ReadFile(handle,buffer,filesize) != filesize ) {
128  Error1("Read error for file ",name);
129  M_free(buffer,"LoadInputFile");
130  if ( name != filename ) M_free(name,"FromLoadInputFile");
131  CloseFile(handle);
132  return(0);
133  }
134  CloseFile(handle);
135  if ( type == PROCEDUREFILE || type == SETUPFILE ) {
136  buffer[filesize] = '\n';
137  buffer[filesize+1] = 0;
138  }
139  else {
140  buffer[filesize] = 0;
141  }
142  if ( name != filename ) M_free(name,"FromLoadInputFile");
143  return(buffer);
144 }
145 
146 /*
147  #] LoadInputFile :
148  #[ ReadFromStream :
149 */
150 
151 UBYTE ReadFromStream(STREAM *stream)
152 {
153  UBYTE c;
154  POSITION scrpos;
155 #ifdef WITHPIPE
156  if ( stream->type == PIPESTREAM ) {
157 #ifndef WITHMPI
158  FILE *f;
159  int cc;
160  RWLOCKR(AM.handlelock);
161  f = (FILE *)(filelist[stream->handle]);
162  UNRWLOCK(AM.handlelock);
163  cc = getc(f);
164  if ( cc == EOF ) return(ENDOFSTREAM);
165  c = (UBYTE)cc;
166 #else
167  if ( stream->pointer >= stream->top ) {
168  /* The master reads the pipe and broadcasts it to the slaves. */
169  LONG len;
170  if ( PF.me == MASTER ) {
171  FILE *f;
172  UBYTE *p, *end;
173  RWLOCKR(AM.handlelock);
174  f = (FILE *)filelist[stream->handle];
175  UNRWLOCK(AM.handlelock);
176  p = stream->buffer;
177  end = stream->buffer + stream->buffersize;
178  while ( p < end ) {
179  int cc = getc(f);
180  if ( cc == EOF ) {
181  break;
182  }
183  *p++ = (UBYTE)cc;
184  }
185  len = p - stream->buffer;
186  PF_BroadcastNumber(len);
187  }
188  else {
189  len = PF_BroadcastNumber(0);
190  }
191  if ( len > 0 ) {
192  PF_Bcast(stream->buffer, len);
193  }
194  stream->pointer = stream->buffer;
195  stream->inbuffer = len;
196  stream->top = stream->buffer + stream->inbuffer;
197  if ( stream->pointer == stream->top ) return ENDOFSTREAM;
198  }
199  c = (UBYTE)*stream->pointer++;
200 #endif
201  if ( stream->eqnum == 1 ) { stream->eqnum = 0; stream->linenumber++; }
202  if ( c == LINEFEED ) stream->eqnum = 1;
203  return(c);
204  }
205 #endif
206 /*[14apr2004 mt]:*/
207 #ifdef WITHEXTERNALCHANNEL
208  if ( stream->type == EXTERNALCHANNELSTREAM ) {
209  int cc;
210  cc = getcFromExtChannel();
211  /*[18may20006 mt]:*/
212  /*if ( cc == EOF ) return(ENDOFSTREAM);*/
213  if ( cc < 0 ){
214  if( cc == EOF )
215  return(ENDOFSTREAM);
216  else{
217  Error0("No current external channel");
218  Terminate(-1);
219  }
220  }/*if ( cc < 0 )*/
221  /*:[18may20006 mt]*/
222  c = (UBYTE)cc;
223  if ( stream->eqnum == 1 ) { stream->eqnum = 0; stream->linenumber++; }
224  if ( c == LINEFEED ) stream->eqnum = 1;
225  return(c);
226  }
227 #endif /*ifdef WITHEXTERNALCHANNEL*/
228 /*:[14apr2004 mt]*/
229  if ( stream->pointer >= stream->top ) {
230  if ( stream->type != FILESTREAM ) return(ENDOFSTREAM);
231  if ( stream->fileposition != stream->bufferposition+stream->inbuffer ) {
232  stream->fileposition = stream->bufferposition+stream->inbuffer;
233  SETBASEPOSITION(scrpos,stream->fileposition);
234  SeekFile(stream->handle,&scrpos,SEEK_SET);
235  }
236  stream->bufferposition = stream->fileposition;
237  stream->inbuffer = ReadFile(stream->handle,
238  stream->buffer,stream->buffersize);
239  if ( stream->inbuffer <= 0 ) return(ENDOFSTREAM);
240  stream->top = stream->buffer + stream->inbuffer;
241  stream->pointer = stream->buffer;
242  stream->fileposition = stream->bufferposition + stream->inbuffer;
243  }
244  if ( stream->eqnum == 1 ) { stream->eqnum = 0; stream->linenumber++; }
245  c = *(stream->pointer)++;
246  if ( c == LINEFEED ) stream->eqnum = 1;
247  return(c);
248 }
249 
250 /*
251  #] ReadFromStream :
252  #[ GetFromStream :
253 */
254 
255 UBYTE GetFromStream(STREAM *stream)
256 {
257  UBYTE c1, c2;
258  if ( stream->isnextchar > 0 ) {
259  return(stream->nextchar[--stream->isnextchar]);
260  }
261  c1 = ReadFromStream(stream);
262  if ( c1 == LINEFEED || c1 == CARRIAGERETURN ) {
263  c2 = ReadFromStream(stream);
264  if ( c2 == c1 || ( c2 != LINEFEED && c2 != CARRIAGERETURN ) ) {
265  stream->isnextchar = 1;
266  stream->nextchar[0] = c2;
267  }
268  return(LINEFEED);
269  }
270  else return(c1);
271 }
272 
273 /*
274  #] GetFromStream :
275  #[ LookInStream :
276 */
277 
278 UBYTE LookInStream(STREAM *stream)
279 {
280  UBYTE c = GetFromStream(stream);
281  UngetFromStream(stream,c);
282  return(c);
283 }
284 
285 /*
286  #] LookInStream :
287  #[ OpenStream :
288 */
289 
290 STREAM *OpenStream(UBYTE *name, int type, int prevarmode, int raiselow)
291 {
292  STREAM *stream;
293  UBYTE *rhsofvariable, *s, *newname, c;
294  POSITION scrpos;
295  int handle, num;
296  LONG filesize;
297  switch ( type ) {
298  case REVERSEFILESTREAM:
299  case FILESTREAM:
300 /*
301  Notice that FILESTREAM is only used for text files:
302  The #include files and the main input file (.frm)
303  Hence we do not worry about files longer than 2 Gbytes.
304 */
305  newname = name;
306  handle = LocateFile(&newname,-1);
307  if ( handle < 0 ) return(0);
308  PUTZERO(scrpos);
309  SeekFile(handle,&scrpos,SEEK_END);
310  TELLFILE(handle,&scrpos);
311  filesize = BASEPOSITION(scrpos);
312  PUTZERO(scrpos);
313  SeekFile(handle,&scrpos,SEEK_SET);
314  if ( filesize > AM.MaxStreamSize && type == FILESTREAM )
315  filesize = AM.MaxStreamSize;
316  stream = CreateStream((UBYTE *)"filestream");
317 /*
318  The extra +1 in the Malloc1 is potentially needed in ReverseStatements!
319 */
320  stream->buffer = (UBYTE *)Malloc1(filesize+1,"name of input stream");
321  stream->inbuffer = ReadFile(handle,stream->buffer,filesize);
322  if ( type == REVERSEFILESTREAM ) {
323  if ( ReverseStatements(stream) ) {
324  M_free(stream->buffer,"name of input stream");
325  return(0);
326  }
327  }
328  stream->top = stream->buffer + stream->inbuffer;
329  stream->pointer = stream->buffer;
330  stream->handle = handle;
331  stream->buffersize = filesize;
332  stream->fileposition = stream->inbuffer;
333  if ( newname != name ) stream->name = newname;
334  else if ( name ) stream->name = strDup1(name,"name of input stream");
335  else
336  stream->name = 0;
337  stream->prevline = stream->linenumber = 1;
338  stream->eqnum = 0;
339  break;
340  case PREVARSTREAM:
341  if ( ( rhsofvariable = GetPreVar(name,WITHERROR) ) == 0 ) return(0);
342  stream = CreateStream((UBYTE *)"var-stream");
343  stream->buffer = stream->pointer = s = rhsofvariable;
344  while ( *s ) s++;
345  stream->top = s;
346  stream->inbuffer = s - stream->buffer;
347  stream->name = AC.CurrentStream->name;
348  stream->linenumber = AC.CurrentStream->linenumber;
349  stream->prevline = AC.CurrentStream->prevline;
350  stream->eqnum = AC.CurrentStream->eqnum;
351  stream->pname = strDup1(name,"stream->pname");
352  stream->olddelay = AP.AllowDelay;
353  s = stream->pname; while ( *s ) s++;
354  while ( s[-1] == '+' || s[-1] == '-' ) s--;
355  *s = 0;
356  UnsetAllowDelay();
357  break;
358  case DOLLARSTREAM:
359  if ( ( num = GetDollar(name) ) < 0 ) {
360  WORD numfac = 0;
361 /*
362  Here we have to test first whether we have $x[1], $x[0]
363  or just an undefined $x.
364 */
365  s = name; while ( *s && *s != '[' ) s++;
366  if ( *s == 0 ) return(0);
367  c = *s; *s = 0;
368  if ( ( num = GetDollar(name) ) < 0 ) return(0);
369  *s = c;
370  s++;
371  if ( *s == 0 || FG.cTable[*s] != 1 || *s == ']' ) {
372  MesPrint("@Illegal factor number for dollar variable");
373  return(0);
374  }
375  while ( *s && FG.cTable[*s] == 1 ) {
376  numfac = 10*numfac+*s++-'0';
377  }
378  if ( *s != ']' || s[1] != 0 ) {
379  MesPrint("@Illegal factor number for $ variable");
380  return(0);
381  }
382  stream = CreateStream((UBYTE *)"dollar-stream");
383  stream->buffer = stream->pointer = s = WriteDollarFactorToBuffer(num,numfac,1);
384  }
385  else {
386  stream = CreateStream((UBYTE *)"dollar-stream");
387  stream->buffer = stream->pointer = s = WriteDollarToBuffer(num,1);
388  }
389  while ( *s ) s++;
390  stream->top = s;
391  stream->inbuffer = s - stream->buffer;
392  stream->name = AC.CurrentStream->name;
393  stream->linenumber = AC.CurrentStream->linenumber;
394  stream->prevline= AC.CurrentStream->prevline;
395  stream->eqnum = AC.CurrentStream->eqnum;
396  stream->pname = strDup1(name,"stream->pname");
397  s = stream->pname; while ( *s ) s++;
398  while ( s[-1] == '+' || s[-1] == '-' ) s--;
399  *s = 0;
400  /* We 'stole' the buffer. Later we can free it. */
401  AO.DollarOutSizeBuffer = 0;
402  AO.DollarOutBuffer = 0;
403  AO.DollarInOutBuffer = 0;
404  break;
405  case PREREADSTREAM:
406  case PREREADSTREAM2:
407  case PREREADSTREAM3:
408  case PRECALCSTREAM:
409  stream = CreateStream((UBYTE *)"calculator");
410  stream->buffer = stream->pointer = s = name;
411  while ( *s ) s++;
412  stream->top = s;
413  stream->inbuffer = s - stream->buffer;
414  stream->name = AC.CurrentStream->name;
415  stream->linenumber = AC.CurrentStream->linenumber;
416  stream->prevline = AC.CurrentStream->prevline;
417  stream->eqnum = 0;
418  break;
419 #ifdef WITHPIPE
420  case PIPESTREAM:
421  stream = CreateStream((UBYTE *)"pipe");
422 #ifndef WITHMPI
423  {
424  FILE *f;
425  if ( ( f = popen((char *)name,"r") ) == 0 ) {
426  Error0("@Cannot create pipe");
427  }
428  stream->handle = CreateHandle();
429  RWLOCKW(AM.handlelock);
430  filelist[stream->handle] = (FILES *)f;
431  UNRWLOCK(AM.handlelock);
432  }
433  stream->buffer = stream->top = 0;
434  stream->inbuffer = 0;
435 #else
436  {
437  /* Only the master opens the pipe. */
438  FILE *f;
439  if ( PF.me == MASTER ) {
440  f = popen((char *)name, "r");
441  PF_BroadcastNumber(f == 0);
442  if ( f == 0 ) Error0("@Cannot create pipe");
443  }
444  else {
445  if ( PF_BroadcastNumber(0) ) Error0("@Cannot create pipe");
446  f = (FILE *)123; /* dummy */
447  }
448  stream->handle = CreateHandle();
449  RWLOCKW(AM.handlelock);
450  filelist[stream->handle] = (FILES *)f;
451  UNRWLOCK(AM.handlelock);
452  }
453  /* stream->buffer as a send/receive buffer. */
454  stream->buffersize = AM.MaxStreamSize;
455  stream->buffer = (UBYTE *)Malloc1(stream->buffersize, "pipe buffer");
456  stream->inbuffer = 0;
457  stream->top = stream->buffer;
458  stream->pointer = stream->buffer;
459 #endif
460  stream->name = strDup1((UBYTE *)"pipe","pipe");
461  stream->prevline = stream->linenumber = 1;
462  stream->eqnum = 0;
463  break;
464 #endif
465 /*[14apr2004 mt]:*/
466 #ifdef WITHEXTERNALCHANNEL
467  case EXTERNALCHANNELSTREAM:
468  {/*Block*/
469  int n, *tmpn;
470  if( (n=getCurrentExternalChannel()) == 0 )
471  Error0("@No current extrenal channel");
472  stream = CreateStream((UBYTE *)"externalchannel");
473  stream->handle = CreateHandle();
474  tmpn = (int *)Malloc1(sizeof(int),"external channel handle");
475  *tmpn = n;
476  RWLOCKW(AM.handlelock);
477  filelist[stream->handle] = (FILES *)tmpn;
478  UNRWLOCK(AM.handlelock);
479  }/*Block*/
480  stream->buffer = stream->top = 0;
481  stream->inbuffer = 0;
482  stream->name = strDup1((UBYTE *)"externalchannel","externalchannel");
483  stream->prevline = stream->linenumber = 1;
484  stream->eqnum = 0;
485  break;
486 #endif /*ifdef WITHEXTERNALCHANNEL*/
487 /*:[14apr2004 mt]*/
488  default:
489  return(0);
490  }
491  stream->bufferposition = 0;
492  stream->isnextchar = 0;
493  stream->type = type;
494  stream->previousNoShowInput = AC.NoShowInput;
495  stream->afterwards = raiselow;
496  if ( AC.CurrentStream ) stream->previous = AC.CurrentStream - AC.Streams;
497  else stream->previous = -1;
498  stream->FoldName = 0;
499  if ( prevarmode == 0 ) stream->prevars = -1;
500  else if ( prevarmode > 0 ) stream->prevars = NumPre;
501  else if ( prevarmode < 0 ) stream->prevars = -prevarmode-1;
502  AC.CurrentStream = stream;
503  if ( type == PREREADSTREAM || type == PREREADSTREAM3 || type == PRECALCSTREAM
504  || type == DOLLARSTREAM ) AC.NoShowInput = 1;
505  return(stream);
506 }
507 
508 /*
509  #] OpenStream :
510  #[ LocateFile :
511 */
512 
513 int LocateFile(UBYTE **name, int type)
514 {
515  int handle, namesize, i;
516  UBYTE *s, *to, *u1, *u2, *newname, *indir;
517  handle = OpenFile((char *)(*name));
518  if ( handle >= 0 ) return(handle);
519  if ( type == SETUPFILE && AM.SetupFile ) {
520  handle = OpenFile((char *)(AM.SetupFile));
521  if ( handle >= 0 ) return(handle);
522  MesPrint("Could not open setup file %s",(char *)(AM.SetupFile));
523  }
524  namesize = 4; s = *name;
525  while ( *s ) { s++; namesize++; }
526  if ( type == SETUPFILE ) indir = AM.SetupDir;
527  else indir = AM.IncDir;
528  if ( indir ) {
529 
530  s = indir; i = 0;
531  while ( *s ) { s++; i++; }
532  newname = (UBYTE *)Malloc1(namesize+i,"LocateFile");
533  s = indir; to = newname;
534  while ( *s ) *to++ = *s++;
535  if ( to > newname && to[-1] != SEPARATOR ) *to++ = SEPARATOR;
536  s = *name;
537  while ( *s ) *to++ = *s++;
538  *to = 0;
539  handle = OpenFile((char *)newname);
540  if ( handle >= 0 ) {
541  *name = newname;
542  return(handle);
543  }
544  M_free(newname,"LocateFile, incdir/file");
545  }
546  if ( type == SETUPFILE ) {
547  handle = OpenFile(setupfilename);
548  if ( handle >= 0 ) return(handle);
549  s = (UBYTE *)getenv("FORMSETUP");
550  if ( s ) {
551  handle = OpenFile((char *)s);
552  if ( handle >= 0 ) return(handle);
553  MesPrint("Could not open setup file %s",s);
554  }
555  }
556  if ( type != SETUPFILE && AM.Path ) {
557  u1 = AM.Path;
558  while ( *u1 ) {
559  u2 = u1; i = 0;
560 #ifdef WINDOWS
561  while ( *u1 && *u1 != ';' ) {
562  u1++; i++;
563  }
564 #else
565  while ( *u1 && *u1 != ':' ) {
566  if ( *u1 == '\\' ) u1++;
567  u1++; i++;
568  }
569 #endif
570  newname = (UBYTE *)Malloc1(namesize+i,"LocateFile");
571  s = u2; to = newname;
572  while ( s < u1 ) {
573 #ifndef WINDOWS
574  if ( *s == '\\' ) s++;
575 #endif
576  *to++ = *s++;
577  }
578  if ( to > newname && to[-1] != SEPARATOR ) *to++ = SEPARATOR;
579  s = *name;
580  while ( *s ) *to++ = *s++;
581  *to = 0;
582  handle = OpenFile((char *)newname);
583  if ( handle >= 0 ) {
584  *name = newname;
585  return(handle);
586  }
587  M_free(newname,"LocateFile Path/file");
588  if ( *u1 ) u1++;
589  }
590  }
591  if ( type != SETUPFILE ) Error1("LocateFile: Cannot find file",*name);
592  return(-1);
593 }
594 
595 /*
596  #] LocateFile :
597  #[ CloseStream :
598 */
599 
600 STREAM *CloseStream(STREAM *stream)
601 {
602  int newstr = stream->previous, sgn;
603  UBYTE *t, numbuf[24];
604  LONG x;
605  if ( stream->FoldName ) {
606  M_free(stream->FoldName,"stream->FoldName");
607  stream->FoldName = 0;
608  }
609  if ( stream->type == FILESTREAM || stream->type == REVERSEFILESTREAM ) {
610  CloseFile(stream->handle);
611  if ( stream->buffer != 0 ) M_free(stream->buffer,"name of input stream");
612  stream->buffer = 0;
613  }
614 #ifdef WITHPIPE
615  else if ( stream->type == PIPESTREAM ) {
616  RWLOCKW(AM.handlelock);
617 #ifdef WITHMPI
618  if ( PF.me == MASTER )
619 #endif
620  pclose((FILE *)(filelist[stream->handle]));
621  filelist[stream->handle] = 0;
622  numinfilelist--;
623  UNRWLOCK(AM.handlelock);
624 #ifdef WITHMPI
625  if ( stream->buffer != 0 ) {
626  M_free(stream->buffer, "pipe buffer");
627  stream->buffer = 0;
628  }
629 #endif
630  }
631 #endif
632 /*[14apr2004 mt]:*/
633 #ifdef WITHEXTERNALCHANNEL
634  else if ( stream->type == EXTERNALCHANNELSTREAM ) {
635  int *tmpn;
636  RWLOCKW(AM.handlelock);
637  tmpn = (int *)(filelist[stream->handle]);
638  filelist[stream->handle] = 0;
639  numinfilelist--;
640  UNRWLOCK(AM.handlelock);
641  M_free(tmpn,"external channel handle");
642  }
643 #endif /*ifdef WITHEXTERNALCHANNEL*/
644 /*:[14apr2004 mt]*/
645  else if ( stream->type == PREVARSTREAM && (
646  stream->afterwards == PRERAISEAFTER || stream->afterwards == PRELOWERAFTER ) ) {
647  t = stream->buffer; x = 0; sgn = 1;
648  while ( *t == '-' || *t == '+' ) {
649  if ( *t == '-' ) sgn = -sgn;
650  t++;
651  }
652  if ( FG.cTable[*t] == 1 ) {
653  while ( *t && FG.cTable[*t] == 1 ) x = 10*x + *t++ - '0';
654  if ( *t == 0 ) {
655  if ( stream->afterwards == PRERAISEAFTER ) x = sgn*x + 1;
656  else x = sgn*x - 1;
657  NumToStr(numbuf,x);
658  PutPreVar(stream->pname,numbuf,0,1);
659  }
660  }
661  }
662  else if ( stream->type == DOLLARSTREAM && (
663  stream->afterwards == PRERAISEAFTER || stream->afterwards == PRELOWERAFTER ) ) {
664  if ( stream->afterwards == PRERAISEAFTER ) x = 1;
665  else x = -1;
666  DollarRaiseLow(stream->pname,x);
667  }
668  else if ( stream->type == PRECALCSTREAM || stream->type == DOLLARSTREAM ) {
669  if ( stream->buffer ) M_free(stream->buffer,"stream->buffer");
670  stream->buffer = 0;
671  }
672  if ( stream->name && stream->type != PREVARSTREAM
673  && stream->type != PREREADSTREAM && stream->type != PREREADSTREAM2 && stream->type != PREREADSTREAM3
674  && stream->type != PRECALCSTREAM && stream->type != DOLLARSTREAM ) {
675  M_free(stream->name,"stream->name");
676  }
677  stream->name = 0;
678 /* if ( stream->type != FILESTREAM ) */
679  AC.NoShowInput = stream->previousNoShowInput;
680  stream->buffer = 0; /* To make sure we will not reuse it */
681  stream->pointer = 0;
682 /*
683  Look whether we have to pop preprocessor variables.
684 */
685  if ( stream->prevars >= 0 ) {
686  while ( NumPre > stream->prevars ) {
687  NumPre--;
688  M_free(PreVar[NumPre].name,"PreVar[NumPre].name");
689  PreVar[NumPre].name = PreVar[NumPre].value = 0;
690  }
691  }
692  if ( stream->type == PREVARSTREAM ) {
693  AP.AllowDelay = stream->olddelay;
694  ClearMacro(stream->pname);
695  M_free(stream->pname,"stream->pname");
696  }
697  else if ( stream->type == DOLLARSTREAM ) {
698  M_free(stream->pname,"stream->pname");
699  }
700  AC.NumStreams--;
701  if ( newstr >= 0 ) return(AC.Streams + newstr);
702  else return(0);
703 }
704 
705 /*
706  #] CloseStream :
707  #[ CreateStream :
708 */
709 
710 STREAM *CreateStream(UBYTE *where)
711 {
712  STREAM *newstreams;
713  int numnewstreams,i;
714  int offset;
715  if ( AC.NumStreams >= AC.MaxNumStreams ) {
716  if ( AC.MaxNumStreams == 0 ) numnewstreams = 10;
717  else numnewstreams = 2*AC.MaxNumStreams;
718  newstreams = (STREAM *)Malloc1(sizeof(STREAM)*(numnewstreams+1),"CreateStream");
719  if ( AC.MaxNumStreams > 0 ) {
720  offset = AC.CurrentStream - AC.Streams;
721  for ( i = 0; i < AC.MaxNumStreams; i++ ) {
722  newstreams[i] = AC.Streams[i];
723  }
724  AC.CurrentStream = newstreams + offset;
725  }
726  else newstreams[0].previous = -1;
727  AC.MaxNumStreams = numnewstreams;
728  if ( AC.Streams ) M_free(AC.Streams,(char *)where);
729  AC.Streams = newstreams;
730  }
731  newstreams = AC.Streams+AC.NumStreams++;
732  newstreams->name = 0;
733  return(newstreams);
734 }
735 
736 /*
737  #] CreateStream :
738  #[ GetStreamPosition :
739 */
740 
741 LONG GetStreamPosition(STREAM *stream)
742 {
743  return(stream->bufferposition + ((LONG)stream->pointer-(LONG)stream->buffer));
744 }
745 
746 /*
747  #] GetStreamPosition :
748  #[ PositionStream :
749 */
750 
751 VOID PositionStream(STREAM *stream, LONG position)
752 {
753  POSITION scrpos;
754  if ( position >= stream->bufferposition
755  && position < stream->bufferposition + stream->inbuffer ) {
756  stream->pointer = stream->buffer + (position-stream->bufferposition);
757  }
758  else if ( stream->type == FILESTREAM ) {
759  SETBASEPOSITION(scrpos,position);
760  SeekFile(stream->handle,&scrpos,SEEK_SET);
761  stream->inbuffer = ReadFile(stream->handle,stream->buffer,stream->buffersize);
762  stream->pointer = stream->buffer;
763  stream->top = stream->buffer + stream->inbuffer;
764  stream->bufferposition = position;
765  stream->fileposition = position + stream->inbuffer;
766  stream->isnextchar = 0;
767  }
768  else {
769  Error0("Illegal position for stream");
770  Terminate(-1);
771  }
772 }
773 
774 /*
775  #] PositionStream :
776  #[ ReverseStatements :
777 
778  Reverses the order of the statements in the buffer.
779  We allocate an extra buffer and copy a bit to and fro.
780  Note that there are some nasties that cannot be resolved.
781 */
782 
783 int ReverseStatements(STREAM *stream)
784 {
785  UBYTE *spare = (UBYTE *)Malloc1((stream->inbuffer+1)*sizeof(UBYTE),"Reverse copy");
786  UBYTE *top = stream->buffer + stream->inbuffer, *in, *s, *ss, *out;
787  out = spare+stream->inbuffer+1;
788  in = stream->buffer;
789  while ( in < top ) {
790  s = in;
791  if ( *s == AP.ComChar ) {
792 toeol:;
793  for(;;) {
794  if ( s == top ) { *--out = '\n'; break; }
795  if ( *s == '\\' ) {
796  s++;
797  if ( s >= top ) { /* This is an error! */
798 irrend: MesPrint("@Irregular end of reverse include file.");
799  return(1);
800  }
801  }
802  else if ( *s == '\n' ) {
803  s++; ss = s;
804  while ( ss > in ) *--out = *--ss;
805  in = s;
806  if ( out[0] == AP.ComChar && ss+6 < s && out[3] == '#' ) {
807 /*
808  For folds we have to exchange begin and end
809 */
810  if ( out[4] == '[' ) out[4] = ']';
811  else if ( out[4] == ']' ) out[4] = '[';
812  }
813  break;
814  }
815  s++;
816  }
817  continue;
818  }
819  while ( s < top && ( *s == ' ' || *s == '\t' ) ) s++;
820  if ( *s == '#' ) { /* preprocessor instruction */
821  goto toeol; /* read to end of line */
822  }
823  if ( *s == '.' ) { /* end-of-module instruction */
824  goto toeol; /* read to end of line */
825  }
826 /*
827  Here we have a regular statement. In principle we scan to ; and its \n
828  but there are special cases.
829  1: ; inside a string (in print "......;";)
830  2: multiple statements on one line.
831  3: ; + commentary after some blanks.
832  4: `var' can cause problems.....
833 */
834  while ( s < top ) {
835  if ( *s == ';' ) {
836  s++;
837  while ( s < top && ( *s == ' ' || *s == '\t' ) ) s++;
838  while ( s < top && *s == '\n' ) s++;
839  if ( s >= top && s[-1] != '\n' ) *s++ = '\n';
840  ss = s;
841  while ( ss > in ) *--out = *--ss;
842  in = s;
843  break;
844  }
845  else if ( *s == '"' ) {
846  s++;
847  while ( s < top ) {
848  if ( *s == '"' ) break;
849  if ( *s == '\\' ) { s++; }
850  s++;
851  }
852  if ( s >= top ) goto irrend;
853  }
854  else if ( *s == '\\' ) {
855  s++;
856  if ( s >= top ) goto irrend;
857  }
858  s++;
859  }
860  if ( in < top ) { /* Like blank lines at the end */
861  if ( s >= top && s[-1] != '\n' ) *s++ = '\n';
862  ss = s;
863  while ( ss > in ) *--out = *--ss;
864  in = s;
865  }
866  }
867  if ( out == spare ) stream->inbuffer++;
868  if ( out > spare+1 ) {
869  MesPrint("@Internal error in #reverseinclude instruction.");
870  return(1);
871  }
872  memcpy((void *)(stream->buffer),(void *)out,(size_t)(stream->inbuffer*sizeof(UBYTE)));
873  M_free(spare,"Reverse copy");
874  return(0);
875 }
876 
877 /*
878  #] ReverseStatements :
879  #] Streams :
880  #[ Files :
881  #[ StartFiles :
882 */
883 
884 VOID StartFiles()
885 {
886  int i = CreateHandle();
887  filelist[i] = Ustdout;
888  AM.StdOut = i;
889  AC.StoreHandle = -1;
890  AC.LogHandle = -1;
891 #ifndef WITHPTHREADS
892  AR.Fscr[0].handle = -1;
893  AR.Fscr[1].handle = -1;
894  AR.Fscr[2].handle = -1;
895  AR.FoStage4[0].handle = -1;
896  AR.FoStage4[1].handle = -1;
897  AR.infile = &(AR.Fscr[0]);
898  AR.outfile = &(AR.Fscr[1]);
899  AR.hidefile = &(AR.Fscr[2]);
900  AR.StoreData.Handle = -1;
901 #endif
902  AC.Streams = 0;
903  AC.MaxNumStreams = 0;
904 }
905 
906 /*
907  #] StartFiles :
908  #[ OpenFile :
909 */
910 
911 int OpenFile(char *name)
912 {
913  FILES *f;
914  int i;
915 
916  if ( ( f = Uopen(name,"rb") ) == 0 ) return(-1);
917 /* Usetbuf(f,0); */
918  i = CreateHandle();
919  RWLOCKW(AM.handlelock);
920  filelist[i] = f;
921  UNRWLOCK(AM.handlelock);
922  return(i);
923 }
924 
925 /*
926  #] OpenFile :
927  #[ OpenAddFile :
928 */
929 
930 int OpenAddFile(char *name)
931 {
932  FILES *f;
933  int i;
934  POSITION scrpos;
935  if ( ( f = Uopen(name,"a+b") ) == 0 ) return(-1);
936 /* Usetbuf(f,0); */
937  i = CreateHandle();
938  RWLOCKW(AM.handlelock);
939  filelist[i] = f;
940  UNRWLOCK(AM.handlelock);
941  TELLFILE(i,&scrpos);
942  SeekFile(i,&scrpos,SEEK_SET);
943  return(i);
944 }
945 
946 /*
947  #] OpenAddFile :
948  #[ ReOpenFile :
949 */
950 
951 int ReOpenFile(char *name)
952 {
953  FILES *f;
954  int i;
955  POSITION scrpos;
956  if ( ( f = Uopen(name,"r+b") ) == 0 ) return(-1);
957  i = CreateHandle();
958  RWLOCKW(AM.handlelock);
959  filelist[i] = f;
960  UNRWLOCK(AM.handlelock);
961  TELLFILE(i,&scrpos);
962  SeekFile(i,&scrpos,SEEK_SET);
963  return(i);
964 }
965 
966 /*
967  #] ReOpenFile :
968  #[ CreateFile :
969 */
970 
971 int CreateFile(char *name)
972 {
973  FILES *f;
974  int i;
975  if ( ( f = Uopen(name,"w+b") ) == 0 ) return(-1);
976  i = CreateHandle();
977  RWLOCKW(AM.handlelock);
978  filelist[i] = f;
979  UNRWLOCK(AM.handlelock);
980  return(i);
981 }
982 
983 /*
984  #] CreateFile :
985  #[ CreateLogFile :
986 */
987 
988 int CreateLogFile(char *name)
989 {
990  FILES *f;
991  int i;
992  if ( ( f = Uopen(name,"w+b") ) == 0 ) return(-1);
993  Usetbuf(f,0);
994  i = CreateHandle();
995  RWLOCKW(AM.handlelock);
996  filelist[i] = f;
997  UNRWLOCK(AM.handlelock);
998  return(i);
999 }
1000 
1001 /*
1002  #] CreateLogFile :
1003  #[ CloseFile :
1004 */
1005 
1006 VOID CloseFile(int handle)
1007 {
1008  if ( handle >= 0 ) {
1009  FILES *f; /* we need this variable to be thread-safe */
1010  RWLOCKW(AM.handlelock);
1011  f = filelist[handle];
1012  filelist[handle] = 0;
1013  numinfilelist--;
1014  UNRWLOCK(AM.handlelock);
1015  Uclose(f);
1016  }
1017 }
1018 
1019 /*
1020  #] CloseFile :
1021  #[ CopyFile :
1022 */
1023 
1029 int CopyFile(char *source, char *dest)
1030 {
1031  #define COPYFILEBUFSIZE 40960L
1032  FILE *in, *out;
1033  size_t countin, countout, sumcount;
1034  char *buffer = NULL;
1035 
1036  sumcount = (AM.S0->LargeSize+AM.S0->SmallEsize)*sizeof(WORD);
1037  if ( sumcount <= COPYFILEBUFSIZE ) {
1038  sumcount = COPYFILEBUFSIZE;
1039  buffer = (char*)Malloc1(sumcount, "file copy buffer");
1040  }
1041  else {
1042  buffer = (char *)(AM.S0->lBuffer);
1043  }
1044 
1045  in = fopen(source, "rb");
1046  if ( in == NULL ) {
1047  perror("CopyFile: ");
1048  return(1);
1049  }
1050  out = fopen(dest, "wb");
1051  if ( out == NULL ) {
1052  perror("CopyFile: ");
1053  return(2);
1054  }
1055 
1056  while ( !feof(in) ) {
1057  countin = fread(buffer, 1, sumcount, in);
1058  if ( countin != sumcount ) {
1059  if ( ferror(in) ) {
1060  perror("CopyFile: ");
1061  return(3);
1062  }
1063  }
1064  countout = fwrite(buffer, 1, countin, out);
1065  if ( countin != countout ) {
1066  perror("CopyFile: ");
1067  return(4);
1068  }
1069  }
1070 
1071  fclose(in);
1072  fclose(out);
1073  if ( sumcount <= COPYFILEBUFSIZE ) {
1074  M_free(buffer, "file copy buffer");
1075  }
1076  return(0);
1077 }
1078 
1079 /*
1080  #] CopyFile :
1081  #[ CreateHandle :
1082 
1083  We need a lock here.
1084  Problem: the same lock is needed inside Malloc1 and M_free which
1085  is used in DoubleList when we use MALLOCDEBUG
1086 
1087  Conclusion: MALLOCDEBUG will have to be a bit unsafe
1088 */
1089 
1090 int CreateHandle()
1091 {
1092  int i, j;
1093 #ifndef MALLOCDEBUG
1094  RWLOCKW(AM.handlelock);
1095 #endif
1096  if ( filelistsize == 0 ) {
1097  filelistsize = 10;
1098  filelist = (FILES **)Malloc1(sizeof(FILES *)*filelistsize,"file handle");
1099  for ( j = 0; j < filelistsize; j++ ) filelist[j] = 0;
1100  numinfilelist = 1;
1101  i = 0;
1102  }
1103  else if ( numinfilelist >= filelistsize ) {
1104  VOID **fl = (VOID **)filelist;
1105  i = filelistsize;
1106  if ( DoubleList((VOID ***)(&fl),&filelistsize,(int)sizeof(FILES *),
1107  "list of open files") != 0 ) Terminate(-1);
1108  filelist = (FILES **)fl;
1109  for ( j = i; j < filelistsize; j++ ) filelist[j] = 0;
1110  numinfilelist = i + 1;
1111  }
1112  else {
1113  i = filelistsize;
1114  for ( j = 0; j < filelistsize; j++ ) {
1115  if ( filelist[j] == 0 ) { i = j; break; }
1116  }
1117  numinfilelist++;
1118  }
1119  filelist[i] = (FILES *)(filelist); /* Just for now to not get into problems */
1120 /*
1121  The next code is not needed when we use open.
1122  It may be needed when we use fopen.
1123  fopen is used in minos.c without this central administration.
1124 */
1125  if ( numinfilelist > MAX_OPEN_FILES ) {
1126 #ifndef MALLOCDEBUG
1127  UNRWLOCK(AM.handlelock);
1128 #endif
1129  MesPrint("More than %d open files",MAX_OPEN_FILES);
1130  Error0("System limit. This limit is not due to FORM!");
1131  }
1132  else {
1133 #ifndef MALLOCDEBUG
1134  UNRWLOCK(AM.handlelock);
1135 #endif
1136  }
1137  return(i);
1138 }
1139 
1140 /*
1141  #] CreateHandle :
1142  #[ ReadFile :
1143 */
1144 
1145 LONG ReadFile(int handle, UBYTE *buffer, LONG size)
1146 {
1147  LONG inbuf = 0, r;
1148  FILES *f;
1149  char *b;
1150  b = (char *)buffer;
1151  for(;;) { /* Gotta do difficult because of VMS! */
1152  RWLOCKR(AM.handlelock);
1153  f = filelist[handle];
1154  UNRWLOCK(AM.handlelock);
1155 #ifdef WITHSTATS
1156  numreads++;
1157 #endif
1158  r = Uread(b,1,size,f);
1159  if ( r < 0 ) return(r);
1160  if ( r == 0 ) return(inbuf);
1161  inbuf += r;
1162  if ( r == size ) return(inbuf);
1163  if ( r > size ) return(-1);
1164  size -= r;
1165  b += r;
1166  }
1167 }
1168 
1169 /*
1170  #] ReadFile :
1171  #[ ReadPosFile :
1172 
1173  Gets words from a file(handle).
1174  First tries to get the information from the buffers.
1175  Reads a file at a position. Updates the position.
1176  Places a lock in the case of multithreading.
1177  Exists for multiple reading from the same file.
1178  size is the number of WORDs to read!!!!
1179 
1180  We may need some strategy in the caching. This routine is used from
1181  GetOneTerm only. The problem is when it reads brackets and the
1182  brackets are read backwards. This is very uneconomical because
1183  each time it may read a large buffer.
1184  On the other hand, reading piece by piece in GetOneTerm takes
1185  much overhead as well.
1186  Two strategies come to mind:
1187  1: keep things as they are but limit the size of the buffers.
1188  2: have the position of 'pos' at about 1/3 of the buffer.
1189  this is of course guess work.
1190  Currently we have implemented the first method by creating the
1191  setup parameter threadscratchsize with the default value 100K.
1192  In the test program much bigger values gave a slower program.
1193 */
1194 
1195 LONG ReadPosFile(PHEAD FILEHANDLE *fi, UBYTE *buffer, LONG size, POSITION *pos)
1196 {
1197  GETBIDENTITY
1198  LONG i, retval = 0;
1199  WORD *b = (WORD *)buffer, *t;
1200 
1201  if ( fi->handle < 0 ) {
1202  fi->POfill = (WORD *)((UBYTE *)(fi->PObuffer) + BASEPOSITION(*pos));
1203  t = fi->POfill;
1204  while ( size > 0 && fi->POfill < fi->POfull ) { *b++ = *t++; size--; }
1205  }
1206  else {
1207  if ( ISLESSPOS(*pos,fi->POposition) || ISGEPOSINC(*pos,fi->POposition,
1208  ((UBYTE *)(fi->POfull)-(UBYTE *)(fi->PObuffer))) ) {
1209 /*
1210  The start is not inside the buffer. Fill the buffer.
1211 */
1212 
1213  fi->POposition = *pos;
1214  LOCK(AS.inputslock);
1215  SeekFile(fi->handle,pos,SEEK_SET);
1216  retval = ReadFile(fi->handle,(UBYTE *)(fi->PObuffer),fi->POsize);
1217  UNLOCK(AS.inputslock);
1218  fi->POfull = fi->PObuffer+retval/sizeof(WORD);
1219  fi->POfill = fi->PObuffer;
1220  if ( fi != AR.hidefile ) AR.InInBuf = retval/sizeof(WORD);
1221  else AR.InHiBuf = retval/sizeof(WORD);
1222  }
1223  else {
1224  fi->POfill = (WORD *)((UBYTE *)(fi->PObuffer) + DIFBASE(*pos,fi->POposition));
1225  }
1226  if ( fi->POfill + size <= fi->POfull ) {
1227  t = fi->POfill;
1228  while ( size > 0 ) { *b++ = *t++; size--; }
1229  }
1230  else {
1231  for (;;) {
1232  i = fi->POfull - fi->POfill; t = fi->POfill;
1233  if ( i > size ) i = size;
1234  size -= i;
1235  while ( --i >= 0 ) *b++ = *t++;
1236  if ( size == 0 ) break;
1237  ADDPOS(fi->POposition,(UBYTE *)(fi->POfull)-(UBYTE *)(fi->PObuffer));
1238  LOCK(AS.inputslock);
1239  SeekFile(fi->handle,&(fi->POposition),SEEK_SET);
1240  retval = ReadFile(fi->handle,(UBYTE *)(fi->PObuffer),fi->POsize);
1241  UNLOCK(AS.inputslock);
1242  fi->POfull = fi->PObuffer+retval/sizeof(WORD);
1243  fi->POfill = fi->PObuffer;
1244  if ( fi != AR.hidefile ) AR.InInBuf = retval/sizeof(WORD);
1245  else AR.InHiBuf = retval/sizeof(WORD);
1246  if ( retval == 0 ) { t = fi->POfill; break; }
1247  }
1248  }
1249  }
1250  retval = (UBYTE *)b - buffer;
1251  fi->POfill = t;
1252  ADDPOS(*pos,retval);
1253  return(retval);
1254 }
1255 
1256 /*
1257  #] ReadPosFile :
1258  #[ WriteFile :
1259 */
1260 
1261 LONG WriteFileToFile(int handle, UBYTE *buffer, LONG size)
1262 {
1263  FILES *f;
1264  LONG retval, totalwritten = 0, stilltowrite;
1265  RWLOCKR(AM.handlelock);
1266  f = filelist[handle];
1267  UNRWLOCK(AM.handlelock);
1268  while ( totalwritten < size ) {
1269  stilltowrite = size - totalwritten;
1270 #ifdef WITHSTATS
1271  numwrites++;
1272 #endif
1273  retval = Uwrite((char *)buffer+totalwritten,1,stilltowrite,f);
1274  if ( retval < 0 ) return(retval);
1275  if ( retval == 0 ) return(totalwritten);
1276  totalwritten += retval;
1277  }
1278 /*
1279 if ( handle == AC.LogHandle || handle == ERROROUT ) FlushFile(handle);
1280 */
1281  return(totalwritten);
1282 }
1283 #ifndef WITHMPI
1284 /*[17nov2005]:*/
1285 WRITEFILE WriteFile = &WriteFileToFile;
1286 /*
1287 LONG (*WriteFile)(int handle, UBYTE *buffer, LONG size) = &WriteFileToFile;
1288 */
1289 /*:[17nov2005]*/
1290 #else
1291 WRITEFILE WriteFile = &PF_WriteFileToFile;
1292 #endif
1293 
1294 /*
1295  #] WriteFile :
1296  #[ SeekFile :
1297 */
1298 
1299 VOID SeekFile(int handle, POSITION *offset, int origin)
1300 {
1301  FILES *f;
1302  RWLOCKR(AM.handlelock);
1303  f = filelist[handle];
1304  UNRWLOCK(AM.handlelock);
1305 #ifdef WITHSTATS
1306  numseeks++;
1307 #endif
1308  if ( origin == SEEK_SET ) {
1309  Useek(f,BASEPOSITION(*offset),origin);
1310  SETBASEPOSITION(*offset,(Utell(f)));
1311  return;
1312  }
1313  else if ( origin == SEEK_END ) {
1314  Useek(f,0,origin);
1315  }
1316  SETBASEPOSITION(*offset,(Utell(f)));
1317 }
1318 
1319 /*
1320  #] SeekFile :
1321  #[ TellFile :
1322 */
1323 
1324 LONG TellFile(int handle)
1325 {
1326  POSITION pos;
1327  TELLFILE(handle,&pos);
1328 #ifdef WITHSTATS
1329  numseeks++;
1330 #endif
1331  return(BASEPOSITION(pos));
1332 }
1333 
1334 VOID TELLFILE(int handle, POSITION *position)
1335 {
1336  FILES *f;
1337  RWLOCKR(AM.handlelock);
1338  f = filelist[handle];
1339  UNRWLOCK(AM.handlelock);
1340  SETBASEPOSITION(*position,(Utell(f)));
1341 }
1342 
1343 /*
1344  #] TellFile :
1345  #[ FlushFile :
1346 */
1347 
1348 void FlushFile(int handle)
1349 {
1350  FILES *f;
1351  RWLOCKR(AM.handlelock);
1352  f = filelist[handle];
1353  UNRWLOCK(AM.handlelock);
1354  Uflush(f);
1355 }
1356 
1357 /*
1358  #] FlushFile :
1359  #[ GetPosFile :
1360 */
1361 
1362 int GetPosFile(int handle, fpos_t *pospointer)
1363 {
1364  FILES *f;
1365  RWLOCKR(AM.handlelock);
1366  f = filelist[handle];
1367  UNRWLOCK(AM.handlelock);
1368  return(Ugetpos(f,pospointer));
1369 }
1370 
1371 /*
1372  #] GetPosFile :
1373  #[ SetPosFile :
1374 */
1375 
1376 int SetPosFile(int handle, fpos_t *pospointer)
1377 {
1378  FILES *f;
1379  RWLOCKR(AM.handlelock);
1380  f = filelist[handle];
1381  UNRWLOCK(AM.handlelock);
1382  return(Usetpos(f,(fpos_t *)pospointer));
1383 }
1384 
1385 /*
1386  #] SetPosFile :
1387  #[ SynchFile :
1388 
1389  It may be that when we use many sort files at the same time there
1390  is a big traffic jam in the cache. This routine is experimental,
1391  just to see whether this improves the situation.
1392  It could also be that the internal disk of the Quad opteron norma
1393  is very slow.
1394 */
1395 
1396 VOID SynchFile(int handle)
1397 {
1398  FILES *f;
1399  if ( handle >= 0 ) {
1400  RWLOCKR(AM.handlelock);
1401  f = filelist[handle];
1402  UNRWLOCK(AM.handlelock);
1403  Usync(f);
1404  }
1405 }
1406 
1407 /*
1408  #] SynchFile :
1409  #[ TruncateFile :
1410 
1411  It may be that when we use many sort files at the same time there
1412  is a big traffic jam in the cache. This routine is experimental,
1413  just to see whether this improves the situation.
1414  It could also be that the internal disk of the Quad opteron norma
1415  is very slow.
1416 */
1417 
1418 VOID TruncateFile(int handle)
1419 {
1420  FILES *f;
1421  if ( handle >= 0 ) {
1422  RWLOCKR(AM.handlelock);
1423  f = filelist[handle];
1424  UNRWLOCK(AM.handlelock);
1425  Utruncate(f);
1426  }
1427 }
1428 
1429 /*
1430  #] TruncateFile :
1431  #[ GetChannel :
1432 
1433  Checks whether we have this file already. If so, we return its
1434  handle. If not and mode == 0, we open the file first and add it
1435  to the buffers.
1436 */
1437 
1438 int GetChannel(char *name,int mode)
1439 {
1440  CHANNEL *ch;
1441  int i;
1442  FILES *f;
1443  for ( i = 0; i < NumOutputChannels; i++ ) {
1444  if ( channels[i].name == 0 ) continue;
1445  if ( StrCmp((UBYTE *)name,(UBYTE *)(channels[i].name)) == 0 ) return(channels[i].handle);
1446  }
1447  if ( mode == 1 ) {
1448  MesPrint("&File %s in print statement is not open",name);
1449  MesPrint(" You should open it first with a #write or #append instruction");
1450  return(-1);
1451  }
1452  for ( i = 0; i < NumOutputChannels; i++ ) {
1453  if ( channels[i].name == 0 ) break;
1454  }
1455  if ( i < NumOutputChannels ) { ch = &(channels[i]); }
1456  else { ch = (CHANNEL *)FromList(&AC.ChannelList); }
1457  ch->name = (char *)strDup1((UBYTE *)name,"name of channel");
1458  ch->handle = CreateFile(name);
1459  RWLOCKR(AM.handlelock);
1460  f = filelist[ch->handle];
1461  UNRWLOCK(AM.handlelock);
1462  Usetbuf(f,0); /* We turn the buffer off!!!!!!*/
1463  return(ch->handle);
1464 }
1465 
1466 /*
1467  #] GetChannel :
1468  #[ GetAppendChannel :
1469 
1470  Checks whether we have this file already. If so, we return its
1471  handle. If not, we open the file first and add it to the buffers.
1472 */
1473 
1474 int GetAppendChannel(char *name)
1475 {
1476  CHANNEL *ch;
1477  int i;
1478  FILES *f;
1479  for ( i = 0; i < NumOutputChannels; i++ ) {
1480  if ( channels[i].name == 0 ) continue;
1481  if ( StrCmp((UBYTE *)name,(UBYTE *)(channels[i].name)) == 0 ) return(channels[i].handle);
1482  }
1483  for ( i = 0; i < NumOutputChannels; i++ ) {
1484  if ( channels[i].name == 0 ) break;
1485  }
1486  if ( i < NumOutputChannels ) { ch = &(channels[i]); }
1487  else { ch = (CHANNEL *)FromList(&AC.ChannelList); }
1488  ch->name = (char *)strDup1((UBYTE *)name,"name of channel");
1489  ch->handle = OpenAddFile(name);
1490  RWLOCKR(AM.handlelock);
1491  f = filelist[ch->handle];
1492  UNRWLOCK(AM.handlelock);
1493  Usetbuf(f,0); /* We turn the buffer off!!!!!!*/
1494  return(ch->handle);
1495 }
1496 
1497 /*
1498  #] GetAppendChannel :
1499  #[ CloseChannel :
1500 
1501  Checks whether we have this file already. If so, we close it.
1502 */
1503 
1504 int CloseChannel(char *name)
1505 {
1506  int i;
1507  for ( i = 0; i < NumOutputChannels; i++ ) {
1508  if ( channels[i].name == 0 ) continue;
1509  if ( channels[i].name[0] == 0 ) continue;
1510  if ( StrCmp((UBYTE *)name,(UBYTE *)(channels[i].name)) == 0 ) {
1511  CloseFile(channels[i].handle);
1512  M_free(channels[i].name,"CloseChannel");
1513  channels[i].name = 0;
1514  return(0);
1515  }
1516  }
1517  return(0);
1518 }
1519 
1520 /*
1521  #] CloseChannel :
1522  #[ UpdateMaxSize :
1523 
1524  Updates the maximum size of the combined input/output/hide scratch
1525  files, the sort files and the .str file.
1526  The result becomes only visible with either
1527  ON totalsize;
1528  #: totalsize ON;
1529  or the -T in the command tail.
1530 
1531  To be called, whenever a file is closed/removed or truncated to zero.
1532 
1533  We have no provisions yet for expressions that remain inside the
1534  small or large buffer during the sort. The space they use there is
1535  currently ignored.
1536 */
1537 
1538 void UpdateMaxSize()
1539 {
1540  POSITION position, sumsize;
1541  int i;
1542  FILEHANDLE *scr;
1543 #ifdef WITHMPI
1544  /* Currently, it works only on the master. The sort files on the slaves
1545  * are ignored. (TU 11 Oct 2011) */
1546  if ( PF.me != MASTER ) return;
1547 #endif
1548  PUTZERO(sumsize);
1549  if ( AM.PrintTotalSize ) {
1550 /*
1551  First the three scratch files
1552 */
1553 #ifdef WITHPTHREADS
1554  scr = AB[0]->R.Fscr;
1555 #else
1556  scr = AR.Fscr;
1557 #endif
1558  for ( i = 0; i <=2; i++ ) {
1559  if ( scr[i].handle < 0 ) {
1560  SETBASEPOSITION(position,(scr[i].POfull-scr[i].PObuffer)*sizeof(WORD));
1561  }
1562  else {
1563  position = scr[i].filesize;
1564  }
1565  ADD2POS(sumsize,position);
1566  }
1567 /*
1568  Now the sort file(s)
1569 */
1570 #ifdef WITHPTHREADS
1571  {
1572  int j;
1573  ALLPRIVATES *B;
1574  for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
1575  B = AB[j];
1576  if ( AT.SS && AT.SS->file.handle >= 0 ) {
1577  position = AT.SS->file.filesize;
1578 /*
1579 MLOCK(ErrorMessageLock);
1580 MesPrint("%d: %10p",j,&(AT.SS->file.filesize));
1581 MUNLOCK(ErrorMessageLock);
1582 */
1583  ADD2POS(sumsize,position);
1584  }
1585  if ( AR.FoStage4[0].handle >= 0 ) {
1586  position = AR.FoStage4[0].filesize;
1587  ADD2POS(sumsize,position);
1588  }
1589  }
1590  }
1591 #else
1592  if ( AT.SS && AT.SS->file.handle >= 0 ) {
1593  position = AT.SS->file.filesize;
1594  ADD2POS(sumsize,position);
1595  }
1596  if ( AR.FoStage4[0].handle >= 0 ) {
1597  position = AR.FoStage4[0].filesize;
1598  ADD2POS(sumsize,position);
1599  }
1600 #endif
1601 /*
1602  And of course the str file.
1603 */
1604  ADD2POS(sumsize,AC.StoreFileSize);
1605 /*
1606  Finally the test whether it is bigger
1607 */
1608  if ( ISLESSPOS(AS.MaxExprSize,sumsize) ) {
1609 #ifdef WITHPTHREADS
1610  LOCK(AS.MaxExprSizeLock);
1611  if ( ISLESSPOS(AS.MaxExprSize,sumsize) ) AS.MaxExprSize = sumsize;
1612  UNLOCK(AS.MaxExprSizeLock);
1613 #else
1614  AS.MaxExprSize = sumsize;
1615 #endif
1616  }
1617  }
1618  return;
1619 }
1620 
1621 /*
1622  #] UpdateMaxSize :
1623  #] Files :
1624  #[ Strings :
1625  #[ StrCmp :
1626 */
1627 
1628 int StrCmp(UBYTE *s1, UBYTE *s2)
1629 {
1630  while ( *s1 && *s1 == *s2 ) { s1++; s2++; }
1631  return((int)*s1-(int)*s2);
1632 }
1633 
1634 /*
1635  #] StrCmp :
1636  #[ StrICmp :
1637 */
1638 
1639 int StrICmp(UBYTE *s1, UBYTE *s2)
1640 {
1641  while ( *s1 && tolower(*s1) == tolower(*s2) ) { s1++; s2++; }
1642  return((int)tolower(*s1)-(int)tolower(*s2));
1643 }
1644 
1645 /*
1646  #] StrICmp :
1647  #[ StrHICmp :
1648 */
1649 
1650 int StrHICmp(UBYTE *s1, UBYTE *s2)
1651 {
1652  while ( *s1 && tolower(*s1) == *s2 ) { s1++; s2++; }
1653  return((int)tolower(*s1)-(int)(*s2));
1654 }
1655 
1656 /*
1657  #] StrHICmp :
1658  #[ StrICont :
1659 */
1660 
1661 int StrICont(UBYTE *s1, UBYTE *s2)
1662 {
1663  while ( *s1 && tolower(*s1) == tolower(*s2) ) { s1++; s2++; }
1664  if ( *s1 == 0 ) return(0);
1665  return((int)tolower(*s1)-(int)tolower(*s2));
1666 }
1667 
1668 /*
1669  #] StrICont :
1670  #[ CmpArray :
1671 */
1672 
1673 int CmpArray(WORD *t1, WORD *t2, WORD n)
1674 {
1675  int i,x;
1676  for ( i = 0; i < n; i++ ) {
1677  if ( ( x = (int)(t1[i]-t2[i]) ) != 0 ) return(x);
1678  }
1679  return(0);
1680 }
1681 
1682 /*
1683  #] CmpArray :
1684  #[ ConWord :
1685 */
1686 
1687 int ConWord(UBYTE *s1, UBYTE *s2)
1688 {
1689  while ( *s1 && ( tolower(*s1) == tolower(*s2) ) ) { s1++; s2++; }
1690  if ( *s1 == 0 ) return(1);
1691  return(0);
1692 }
1693 
1694 /*
1695  #] ConWord :
1696  #[ StrLen :
1697 */
1698 
1699 int StrLen(UBYTE *s)
1700 {
1701  int i = 0;
1702  while ( *s ) { s++; i++; }
1703  return(i);
1704 }
1705 
1706 /*
1707  #] StrLen :
1708  #[ NumToStr :
1709 */
1710 
1711 VOID NumToStr(UBYTE *s, LONG x)
1712 {
1713  UBYTE *t, str[24];
1714  ULONG xx;
1715  t = str;
1716  if ( x < 0 ) { *s++ = '-'; xx = -x; }
1717  else xx = x;
1718  do {
1719  *t++ = xx % 10 + '0';
1720  xx /= 10;
1721  } while ( xx );
1722  while ( t > str ) *s++ = *--t;
1723  *s = 0;
1724 }
1725 
1726 /*
1727  #] NumToStr :
1728  #[ WriteString :
1729 
1730  Writes a characterstring to the various outputs.
1731  The action may depend on the flags involved.
1732  The type of output is given by type, the string by str and the
1733  number of characters in it by num
1734 */
1735 VOID WriteString(int type, UBYTE *str, int num)
1736 {
1737  int error = 0;
1738 
1739  if ( num > 0 && str[num-1] == 0 ) { num--; }
1740  else if ( num <= 0 || str[num-1] != LINEFEED ) {
1741  AddLineFeed(str,num);
1742  }
1743  /*[15apr2004 mt]:*/
1744  if(type == EXTERNALCHANNELOUT){
1745  if(WriteFile(0,str,num) != num) error = 1;
1746  }else
1747  /*:[15apr2004 mt]*/
1748  if ( AM.silent == 0 || type == ERROROUT ) {
1749  if ( type == INPUTOUT ) {
1750  if ( !AM.FileOnlyFlag && WriteFile(AM.StdOut,(UBYTE *)" ",4) != 4 ) error = 1;
1751  if ( AC.LogHandle >= 0 && WriteFile(AC.LogHandle,(UBYTE *)" ",4) != 4 ) error = 1;
1752  }
1753  if ( !AM.FileOnlyFlag && WriteFile(AM.StdOut,str,num) != num ) error = 1;
1754  if ( AC.LogHandle >= 0 && WriteFile(AC.LogHandle,str,num) != num ) error = 1;
1755  }
1756  if ( error ) Terminate(-1);
1757 }
1758 
1759 /*
1760  #] WriteString :
1761  #[ WriteUnfinString :
1762 
1763  Writes a characterstring to the various outputs.
1764  The action may depend on the flags involved.
1765  The type of output is given by type, the string by str and the
1766  number of characters in it by num
1767 */
1768 
1769 VOID WriteUnfinString(int type, UBYTE *str, int num)
1770 {
1771  int error = 0;
1772 
1773  /*[15apr2004 mt]:*/
1774  if(type == EXTERNALCHANNELOUT){
1775  if(WriteFile(0,str,num) != num) error = 1;
1776  }else
1777  /*:[15apr2004 mt]*/
1778  if ( AM.silent == 0 || type == ERROROUT ) {
1779  if ( type == INPUTOUT ) {
1780  if ( !AM.FileOnlyFlag && WriteFile(AM.StdOut,(UBYTE *)" ",4) != 4 ) error = 1;
1781  if ( AC.LogHandle >= 0 && WriteFile(AC.LogHandle,(UBYTE *)" ",4) != 4 ) error = 1;
1782  }
1783  if ( !AM.FileOnlyFlag && WriteFile(AM.StdOut,str,num) != num ) error = 1;
1784  if ( AC.LogHandle >= 0 && WriteFile(AC.LogHandle,str,num) != num ) error = 1;
1785  }
1786  if ( error ) Terminate(-1);
1787 }
1788 
1789 /*
1790  #] WriteUnfinString :
1791  #[ AddToString :
1792 */
1793 
1794 UBYTE *AddToString(UBYTE *outstring, UBYTE *extrastring, int par)
1795 {
1796  UBYTE *s = extrastring, *t, *newstring;
1797  int n, nn;
1798  while ( *s ) { s++; }
1799  n = s-extrastring;
1800  if ( outstring == 0 ) {
1801  s = extrastring;
1802  t = outstring = (UBYTE *)Malloc1(n+1,"AddToString");
1803  NCOPY(t,s,n)
1804  *t++ = 0;
1805  return(outstring);
1806  }
1807  else {
1808  t = outstring;
1809  while ( *t ) t++;
1810  nn = t - outstring;
1811  t = newstring = (UBYTE *)Malloc1(n+nn+2,"AddToString");
1812  s = outstring;
1813  NCOPY(t,s,nn)
1814  if ( par == 1 ) *t++ = ',';
1815  s = extrastring;
1816  NCOPY(t,s,n)
1817  *t = 0;
1818  M_free(outstring,"AddToString");
1819  return(newstring);
1820  }
1821 }
1822 
1823 /*
1824  #] AddToString :
1825  #[ strDup1 :
1826 
1827  string duplication with message passing for Malloc1, allowing
1828  this routine to give a more detailed error message if there
1829  is not enough memory.
1830 */
1831 
1832 UBYTE *strDup1(UBYTE *instring, char *ifwrong)
1833 {
1834  UBYTE *s = instring, *to;
1835  while ( *s ) s++;
1836  to = s = (UBYTE *)Malloc1((s-instring)+1,ifwrong);
1837  while ( *instring ) *to++ = *instring++;
1838  *to = 0;
1839  return(s);
1840 }
1841 
1842 /*
1843  #] strDup1 :
1844  #[ EndOfToken :
1845 */
1846 
1847 UBYTE *EndOfToken(UBYTE *s)
1848 {
1849  UBYTE c;
1850  while ( ( c = (UBYTE)(FG.cTable[*s]) ) == 0 || c == 1 ) s++;
1851  return(s);
1852 }
1853 
1854 /*
1855  #] EndOfToken :
1856  #[ ToToken :
1857 */
1858 
1859 UBYTE *ToToken(UBYTE *s)
1860 {
1861  UBYTE c;
1862  while ( *s && ( c = (UBYTE)(FG.cTable[*s]) ) != 0 && c != 1 ) s++;
1863  return(s);
1864 }
1865 
1866 /*
1867  #] ToToken :
1868  #[ SkipField :
1869 
1870  Skips from s to the end of a declaration field.
1871  par is the number of parentheses that still has to be closed.
1872 */
1873 
1874 UBYTE *SkipField(UBYTE *s, int level)
1875 {
1876  while ( *s ) {
1877  if ( *s == ',' && level == 0 ) return(s);
1878  if ( *s == '(' ) level++;
1879  else if ( *s == ')' ) { level--; if ( level < 0 ) level = 0; }
1880  else if ( *s == '[' ) {
1881  SKIPBRA1(s)
1882  }
1883  else if ( *s == '{' ) {
1884  SKIPBRA2(s)
1885  }
1886  s++;
1887  }
1888  return(s);
1889 }
1890 
1891 /*
1892  #] SkipField :
1893  #[ ReadSnum : WORD ReadSnum(p)
1894 
1895  Reads a number that should fit in a word.
1896  The number should be unsigned and a negative return value
1897  indicates an irregularity.
1898 
1899 */
1900 
1901 WORD ReadSnum(UBYTE **p)
1902 {
1903  LONG x = 0;
1904  UBYTE *s;
1905  s = *p;
1906  if ( FG.cTable[*s] == 1 ) {
1907  do {
1908  x = ( x << 3 ) + ( x << 1 ) + ( *s++ - '0' );
1909  if ( x > MAXPOSITIVE ) return(-1);
1910  } while ( FG.cTable[*s] == 1 );
1911  *p = s;
1912  return((WORD)x);
1913  }
1914  else return(-1);
1915 }
1916 
1917 /*
1918  #] ReadSnum :
1919  #[ NumCopy :
1920 
1921  Adds the decimal representation of a number to a string.
1922 
1923 */
1924 
1925 UBYTE *NumCopy(WORD y, UBYTE *to)
1926 {
1927  UBYTE *s;
1928  WORD i = 0, j;
1929  UWORD x;
1930  if ( y < 0 ) {
1931  *to++ = '-';
1932  }
1933  x = WordAbs(y);
1934  s = to;
1935  do { *s++ = (UBYTE)((x % 10)+'0'); i++; } while ( ( x /= 10 ) != 0 );
1936  *s-- = '\0';
1937  j = ( i - 1 ) >> 1;
1938  while ( j >= 0 ) {
1939  i = to[j]; to[j] = s[-j]; s[-j] = (UBYTE)i; j--;
1940  }
1941  return(s+1);
1942 }
1943 
1944 /*
1945  #] NumCopy :
1946  #[ LongCopy :
1947 
1948  Adds the decimal representation of a number to a string.
1949 
1950 */
1951 
1952 char *LongCopy(LONG y, char *to)
1953 {
1954  char *s;
1955  WORD i = 0, j;
1956  ULONG x;
1957  if ( y < 0 ) {
1958  *to++ = '-';
1959  }
1960  x = LongAbs(y);
1961  s = to;
1962  do { *s++ = (x % 10)+'0'; i++; } while ( ( x /= 10 ) != 0 );
1963  *s-- = '\0';
1964  j = ( i - 1 ) >> 1;
1965  while ( j >= 0 ) {
1966  i = to[j]; to[j] = s[-j]; s[-j] = (char)i; j--;
1967  }
1968  return(s+1);
1969 }
1970 
1971 /*
1972  #] LongCopy :
1973  #[ LongLongCopy :
1974 
1975  Adds the decimal representation of a number to a string.
1976  Bugfix feb 2003. y was not pointer!
1977 */
1978 
1979 char *LongLongCopy(off_t *y, char *to)
1980 {
1981  /*
1982  * This code fails to print the maximum negative value on systems with two's
1983  * complement. To fix this, we need the unsigned version of off_t with the
1984  * same size, but unfortunately it is undefined. On the other hand, if a
1985  * system is configured with a 64-bit off_t, in practice one never reaches
1986  * 2^63 ~ 10^18 as of 2016. If one really reach such a big number, then it
1987  * would be the time to move on a 128-bit off_t.
1988  */
1989  off_t x = *y;
1990  char *s;
1991  WORD i = 0, j;
1992  if ( x < 0 ) { x = -x; *to++ = '-'; }
1993  s = to;
1994  do { *s++ = (x % 10)+'0'; i++; } while ( ( x /= 10 ) != 0 );
1995  *s-- = '\0';
1996  j = ( i - 1 ) >> 1;
1997  while ( j >= 0 ) {
1998  i = to[j]; to[j] = s[-j]; s[-j] = (char)i; j--;
1999  }
2000  return(s+1);
2001 }
2002 
2003 /*
2004  #] LongLongCopy :
2005  #[ MakeDate :
2006 
2007  Routine produces a string with the date and time of the run
2008 */
2009 
2010 #ifdef ANSI
2011 #else
2012 #ifdef mBSD
2013 #else
2014 static char notime[] = "";
2015 #endif
2016 #endif
2017 
2018 UBYTE *MakeDate()
2019 {
2020 #ifdef ANSI
2021  time_t tp;
2022  time(&tp);
2023  return((UBYTE *)ctime(&tp));
2024 #else
2025 #ifdef mBSD
2026  time_t tp;
2027  time(&tp);
2028  return((UBYTE *)ctime(&tp));
2029 #else
2030  return((UBYTE *)notime);
2031 #endif
2032 #endif
2033 }
2034 
2035 /*
2036  #] MakeDate :
2037  #[ set_in :
2038  Returns 1 if ch is in set ; 0 if ch is not in set:
2039 */
2040 int set_in(UBYTE ch, set_of_char set)
2041 {
2042  set += ch/8;
2043  switch (ch % 8){
2044  case 0: return(set->bit_0);
2045  case 1: return(set->bit_1);
2046  case 2: return(set->bit_2);
2047  case 3: return(set->bit_3);
2048  case 4: return(set->bit_4);
2049  case 5: return(set->bit_5);
2050  case 6: return(set->bit_6);
2051  case 7: return(set->bit_7);
2052  }/*switch (ch % 8)*/
2053  return(-1);
2054 }/*set_in*/
2055 /*
2056  #] set_in :
2057  #[ set_set :
2058  sets ch into set; returns *set:
2059 */
2060 one_byte set_set(UBYTE ch, set_of_char set)
2061 {
2062  one_byte tmp=(one_byte)set;
2063  set += ch/8;
2064  switch (ch % 8){
2065  case 0: set->bit_0=1;break;
2066  case 1: set->bit_1=1;break;
2067  case 2: set->bit_2=1;break;
2068  case 3: set->bit_3=1;break;
2069  case 4: set->bit_4=1;break;
2070  case 5: set->bit_5=1;break;
2071  case 6: set->bit_6=1;break;
2072  case 7: set->bit_7=1;break;
2073  }
2074  return(tmp);
2075 }/*set_set*/
2076 /*
2077  #] set_set :
2078  #[ set_del :
2079  deletes ch from set; returns *set:
2080 */
2081 one_byte set_del(UBYTE ch, set_of_char set)
2082 {
2083  one_byte tmp=(one_byte)set;
2084  set += ch/8;
2085  switch (ch % 8){
2086  case 0: set->bit_0=0;break;
2087  case 1: set->bit_1=0;break;
2088  case 2: set->bit_2=0;break;
2089  case 3: set->bit_3=0;break;
2090  case 4: set->bit_4=0;break;
2091  case 5: set->bit_5=0;break;
2092  case 6: set->bit_6=0;break;
2093  case 7: set->bit_7=0;break;
2094  }
2095  return(tmp);
2096 }/*set_del*/
2097 /*
2098  #] set_del :
2099  #[ set_sub :
2100  returns *set = set1\set2. This function may be usd for initialising,
2101  set_sub(a,a,a) => now a is empty set :
2102 */
2103 one_byte set_sub(set_of_char set, set_of_char set1, set_of_char set2)
2104 {
2105  one_byte tmp=(one_byte)set;
2106  int i=0,j=0;
2107  while(j=0,i++<32)
2108  while(j<9)
2109  switch (j++){
2110  case 0: set->bit_0=(set1->bit_0&&(!set2->bit_0));break;
2111  case 1: set->bit_1=(set1->bit_1&&(!set2->bit_1));break;
2112  case 2: set->bit_2=(set1->bit_2&&(!set2->bit_2));break;
2113  case 3: set->bit_3=(set1->bit_3&&(!set2->bit_3));break;
2114  case 4: set->bit_4=(set1->bit_4&&(!set2->bit_4));break;
2115  case 5: set->bit_5=(set1->bit_5&&(!set2->bit_5));break;
2116  case 6: set->bit_6=(set1->bit_6&&(!set2->bit_6));break;
2117  case 7: set->bit_7=(set1->bit_7&&(!set2->bit_7));break;
2118  case 8: set++;set1++;set2++;
2119  };
2120  return(tmp);
2121 }/*set_sub*/
2122 /*
2123  #] set_sub :
2124  #] Strings :
2125  #[ Mixed :
2126  #[ iniTools :
2127 */
2128 
2129 VOID iniTools(VOID)
2130 {
2131 #ifdef MALLOCPROTECT
2132  if ( mprotectInit() ) exit(0);
2133 #endif
2134  return;
2135 }
2136 
2137 /*
2138  #] iniTools :
2139  #[ Malloc :
2140 
2141  Malloc routine with built in error checking.
2142  This saves lots of messages.
2143 */
2144 #ifdef MALLOCDEBUG
2145 char *dummymessage = "Malloc";
2146 INILOCK(MallocLock)
2147 #endif
2148 
2149 VOID *Malloc(LONG size)
2150 {
2151  VOID *mem;
2152 #ifdef MALLOCDEBUG
2153  char *t, *u;
2154  int i;
2155  LOCK(MallocLock);
2156 /* MLOCK(ErrorMessageLock); */
2157  if ( size == 0 ) {
2158  MesPrint("Asking for 0 bytes in Malloc");
2159  }
2160 #endif
2161  if ( ( size & 7 ) != 0 ) { size = size - ( size&7 ) + 8; }
2162 #ifdef MALLOCDEBUG
2163  size += 2*BANNER;
2164 #endif
2165  mem = (VOID *)M_alloc(size);
2166  if ( mem == 0 ) {
2167 #ifndef MALLOCDEBUG
2168  MLOCK(ErrorMessageLock);
2169 #endif
2170  Error0("No memory!");
2171 #ifndef MALLOCDEBUG
2172  MUNLOCK(ErrorMessageLock);
2173 #else
2174 /* MUNLOCK(ErrorMessageLock); */
2175 #endif
2176 #ifdef MALLOCDEBUG
2177  UNLOCK(MallocLock);
2178 #endif
2179  Terminate(-1);
2180  }
2181 #ifdef MALLOCDEBUG
2182  mallocsizes[nummalloclist] = size;
2183  mallocstrings[nummalloclist] = dummymessage;
2184  malloclist[nummalloclist++] = mem;
2185  if ( filelist ) MesPrint("Mem0 at 0x%x, %l bytes",mem,size);
2186  {
2187  int i = nummalloclist-1;
2188  while ( --i >= 0 ) {
2189  if ( (char *)mem < (((char *)malloclist[i]) + mallocsizes[i])
2190  && (char *)(malloclist[i]) < ((char *)mem + size) ) {
2191  if ( filelist ) MesPrint("This memory overlaps with the block at 0x%x"
2192  ,malloclist[i]);
2193  }
2194  }
2195  }
2196  t = (char *)mem;
2197  u = t + size;
2198  for ( i = 0; i < (int)BANNER; i++ ) { *t++ = FILLVALUE; *--u = FILLVALUE; }
2199  mem = (void *)t;
2200  {
2201  int j = nummalloclist-1, i;
2202  while ( --j >= 0 ) {
2203  t = (char *)(malloclist[j]);
2204  u = t + mallocsizes[j];
2205  for ( i = 0; i < (int)BANNER; i++ ) {
2206  u--;
2207  if ( *t != FILLVALUE || *u != FILLVALUE ) {
2208  MesPrint("Writing outside memory for %s",malloclist[i]);
2209 /* MUNLOCK(ErrorMessageLock); */
2210  UNLOCK(MallocLock);
2211  Terminate(-1);
2212  }
2213  t--;
2214  }
2215  }
2216  }
2217 /* MUNLOCK(ErrorMessageLock); */
2218  UNLOCK(MallocLock);
2219 #endif
2220  return(mem);
2221 }
2222 
2223 /*
2224  #] Malloc :
2225  #[ Malloc1 :
2226 
2227  Malloc with more detailed error message.
2228  Gives the user some idea of what is happening.
2229 */
2230 
2231 VOID *Malloc1(LONG size, const char *messageifwrong)
2232 {
2233  VOID *mem;
2234 #ifdef MALLOCDEBUG
2235  char *t, *u;
2236  int i;
2237  LOCK(MallocLock);
2238 /* MLOCK(ErrorMessageLock); */
2239  if ( size == 0 ) {
2240  MesPrint("%wAsking for 0 bytes in Malloc1");
2241  }
2242 #endif
2243 #ifdef WITHSTATS
2244  nummallocs++;
2245 #endif
2246  if ( ( size & 7 ) != 0 ) { size = size - ( size&7 ) + 8; }
2247 #ifdef MALLOCDEBUG
2248  size += 2*BANNER;
2249 #endif
2250  mem = (VOID *)M_alloc(size);
2251  if ( mem == 0 ) {
2252 #ifndef MALLOCDEBUG
2253  MLOCK(ErrorMessageLock);
2254 #endif
2255  Error1("No memory while allocating ",(UBYTE *)messageifwrong);
2256 #ifndef MALLOCDEBUG
2257  MUNLOCK(ErrorMessageLock);
2258 #else
2259 /* MUNLOCK(ErrorMessageLock); */
2260 #endif
2261 #ifdef MALLOCDEBUG
2262  UNLOCK(MallocLock);
2263 #endif
2264  Terminate(-1);
2265  }
2266 #ifdef MALLOCDEBUG
2267  mallocsizes[nummalloclist] = size;
2268  mallocstrings[nummalloclist] = (char *)messageifwrong;
2269  malloclist[nummalloclist++] = mem;
2270  if ( AC.MemDebugFlag && filelist ) MesPrint("%wMem1 at 0x%x: %l bytes. %s",mem,size,messageifwrong);
2271  {
2272  int i = nummalloclist-1;
2273  while ( --i >= 0 ) {
2274  if ( (char *)mem < (((char *)malloclist[i]) + mallocsizes[i])
2275  && (char *)(malloclist[i]) < ((char *)mem + size) ) {
2276  if ( filelist ) MesPrint("This memory overlaps with the block at 0x%x"
2277  ,malloclist[i]);
2278  }
2279  }
2280  }
2281 
2282 #ifdef MALLOCDEBUGOUTPUT
2283  printf ("Malloc1: %s, allocated %li bytes at %.8lx\n",messageifwrong,size,(unsigned long)mem);
2284  fflush (stdout);
2285 #endif
2286 
2287  t = (char *)mem;
2288  u = t + size;
2289  for ( i = 0; i < (int)BANNER; i++ ) { *t++ = FILLVALUE; *--u = FILLVALUE; }
2290  mem = (void *)t;
2291  M_check();
2292 /* MUNLOCK(ErrorMessageLock); */
2293  UNLOCK(MallocLock);
2294 #endif
2295 /*
2296  if ( size > 500000000L ) {
2297  MLOCK(ErrorMessageLock);
2298  MesPrint("Malloc1: %s, allocated %l bytes\n",messageifwrong,size);
2299  MUNLOCK(ErrorMessageLock);
2300  }
2301 */
2302  return(mem);
2303 }
2304 
2305 /*
2306  #] Malloc1 :
2307  #[ M_free :
2308 */
2309 
2310 void M_free(VOID *x, const char *where)
2311 {
2312 #ifdef MALLOCDEBUG
2313  char *t = (char *)x;
2314  int i, j, k;
2315  LONG size = 0;
2316  x = (void *)(((char *)x)-BANNER);
2317 /* MLOCK(ErrorMessageLock); */
2318  if ( AC.MemDebugFlag ) MesPrint("%wFreeing 0x%x: %s",x,where);
2319  LOCK(MallocLock);
2320  for ( i = nummalloclist-1; i >= 0; i-- ) {
2321  if ( x == malloclist[i] ) {
2322  size = mallocsizes[i];
2323  for ( j = i+1; j < nummalloclist; j++ ) {
2324  malloclist[j-1] = malloclist[j];
2325  mallocsizes[j-1] = mallocsizes[j];
2326  mallocstrings[j-1] = mallocstrings[j];
2327  }
2328  nummalloclist--;
2329  break;
2330  }
2331  }
2332  if ( i < 0 ) {
2333  unsigned int xx = ((ULONG)x);
2334  printf("Error returning non-allocated address: 0x%x from %s\n"
2335  ,xx,where);
2336 /* MUNLOCK(ErrorMessageLock); */
2337  UNLOCK(MallocLock);
2338  exit(-1);
2339  }
2340  else {
2341  for ( k = 0, j = 0; k < (int)BANNER; k++ ) {
2342  if ( *--t != FILLVALUE ) j++;
2343  }
2344  if ( j ) {
2345  LONG *tt = (LONG *)x;
2346  MesPrint("%w!!!!! Banner has been written in !!!!!: %x %x %x %x",
2347  tt[0],tt[1],tt[2],tt[3]);
2348  }
2349  t += size;
2350  for ( k = 0, j = 0; k < (int)BANNER; k++ ) {
2351  if ( *--t != FILLVALUE ) j++;
2352  }
2353  if ( j ) {
2354  LONG *tt = (LONG *)x;
2355  MesPrint("%w!!!!! Tail has been written in !!!!!: %x %x %x %x",
2356  tt[0],tt[1],tt[2],tt[3]);
2357  }
2358  M_check();
2359 /* MUNLOCK(ErrorMessageLock); */
2360  UNLOCK(MallocLock);
2361  }
2362 #else
2363  DUMMYUSE(where);
2364 #endif
2365 #ifdef WITHSTATS
2366  numfrees++;
2367 #endif
2368  if ( x ) {
2369 #ifdef MALLOCDEBUGOUTPUT
2370  printf ("M_free: %s, memory freed at %.8lx\n",where,(unsigned long)x);
2371  fflush(stdout);
2372 #endif
2373 
2374 #ifdef MALLOCPROTECT
2375  mprotectFree((void *)x);
2376 #else
2377  free(x);
2378 #endif
2379  }
2380 }
2381 
2382 /*
2383  #] M_free :
2384  #[ M_check :
2385 */
2386 
2387 #ifdef MALLOCDEBUG
2388 
2389 void M_check1() { MesPrint("Checking Malloc"); M_check(); }
2390 
2391 void M_check()
2392 {
2393  int i,j,k,error = 0;
2394  char *t;
2395  LONG *tt;
2396  for ( i = 0; i < nummalloclist; i++ ) {
2397  t = (char *)(malloclist[i]);
2398  for ( k = 0, j = 0; k < (int)BANNER; k++ ) {
2399  if ( *t++ != FILLVALUE ) j++;
2400  }
2401  if ( j ) {
2402  tt = (LONG *)(malloclist[i]);
2403  MesPrint("%w!!!!! Banner %d (%s) has been written in !!!!!: %x %x %x %x",
2404  i,mallocstrings[i],tt[0],tt[1],tt[2],tt[3]);
2405  tt[0] = tt[1] = tt[2] = tt[3] = 0;
2406  error = 1;
2407  }
2408  t = (char *)(malloclist[i]) + mallocsizes[i];
2409  for ( k = 0, j = 0; k < (int)BANNER; k++ ) {
2410  if ( *--t != FILLVALUE ) j++;
2411  }
2412  if ( j ) {
2413  tt = (LONG *)t;
2414  MesPrint("%w!!!!! Tail %d (%s) has been written in !!!!!: %x %x %x %x",
2415  i,mallocstrings[i],tt[0],tt[1],tt[2],tt[3]);
2416  tt[0] = tt[1] = tt[2] = tt[3] = 0;
2417  error = 1;
2418  }
2419  if ( ( mallocstrings[i][0] == ' ' ) || ( mallocstrings[i][0] == '#' ) ) {
2420  MesPrint("%w!!!!! Funny mallocstring");
2421  error = 1;
2422  }
2423  }
2424  if ( error ) {
2425  M_print();
2426 /* MUNLOCK(ErrorMessageLock); */
2427  UNLOCK(MallocLock);
2428  Terminate(-1);
2429  }
2430 }
2431 
2432 void M_print()
2433 {
2434  int i;
2435  MesPrint("We have the following memory allocations left:");
2436  for ( i = 0; i < nummalloclist; i++ ) {
2437  MesPrint("0x%x: %l bytes. number %d: '%s'",malloclist[i],mallocsizes[i],i,mallocstrings[i]);
2438  }
2439 }
2440 
2441 #else
2442 
2443 void M_check1() {}
2444 void M_print() {}
2445 
2446 #endif
2447 
2448 /*
2449  #] M_check :
2450  #[ TermMalloc :
2451 */
2474 #define TERMMEMSTARTNUM 16
2475 #define TERMEXTRAWORDS 10
2476 
2477 VOID TermMallocAddMemory(PHEAD0)
2478 {
2479  WORD *newbufs;
2480  int i, extra;
2481  if ( AT.TermMemMax == 0 ) extra = TERMMEMSTARTNUM;
2482  else extra = AT.TermMemMax;
2483  if ( AT.TermMemHeap ) M_free(AT.TermMemHeap,"TermMalloc");
2484  newbufs = (WORD *)Malloc1(extra*(AM.MaxTer+TERMEXTRAWORDS*sizeof(WORD)),"TermMalloc");
2485  AT.TermMemHeap = (WORD **)Malloc1((extra+AT.TermMemMax)*sizeof(WORD *),"TermMalloc");
2486  for ( i = 0; i < extra; i++ ) {
2487  AT.TermMemHeap[i] = newbufs + i*(AM.MaxTer/sizeof(WORD)+TERMEXTRAWORDS);
2488  }
2489 #ifdef TERMMALLOCDEBUG
2490  DebugHeap2 = (WORD **)Malloc1((extra+AT.TermMemMax)*sizeof(WORD *),"TermMalloc");
2491  for ( i = 0; i < AT.TermMemMax; i++ ) { DebugHeap2[i] = DebugHeap1[i]; }
2492  for ( i = 0; i < extra; i++ ) {
2493  DebugHeap2[i+AT.TermMemMax] = newbufs + i*(AM.MaxTer/sizeof(WORD)+TERMEXTRAWORDS);
2494  }
2495  if ( DebugHeap1 ) M_free(DebugHeap1,"TermMalloc");
2496  DebugHeap1 = DebugHeap2;
2497 #endif
2498  AT.TermMemTop = extra;
2499  AT.TermMemMax += extra;
2500 #ifdef TERMMALLOCDEBUG
2501  MesPrint("AT.TermMemMax is now %l",AT.TermMemMax);
2502 #endif
2503 }
2504 
2505 #ifndef MEMORYMACROS
2506 
2507 WORD *TermMalloc2(PHEAD char *text)
2508 {
2509  if ( AT.TermMemTop <= 0 ) TermMallocAddMemory(BHEAD0);
2510 
2511 #ifdef TERMMALLOCDEBUG
2512  MesPrint("TermMalloc: %s, %d",text,(AT.TermMemMax-AT.TermMemTop));
2513 #endif
2514 
2515 #ifdef MALLOCDEBUGOUTPUT
2516  MesPrint("TermMalloc: %s, %l/%l (%x)",text,AT.TermMemTop,AT.TermMemMax,AT.TermMemHeap[AT.TermMemTop-1]);
2517 #endif
2518 
2519  DUMMYUSE(text);
2520  return(AT.TermMemHeap[--AT.TermMemTop]);
2521 }
2522 
2523 VOID TermFree2(PHEAD WORD *TermMem, char *text)
2524 {
2525 #ifdef TERMMALLOCDEBUG
2526 
2527  int i;
2528 
2529  for ( i = 0; i < AT.TermMemMax; i++ ) {
2530  if ( TermMem == DebugHeap1[i] ) break;
2531  }
2532  if ( i >= AT.TermMemMax ) {
2533  MesPrint(" ERROR: TermFree called with an address not given by TermMalloc.");
2534  Terminate(-1);
2535  }
2536 #endif
2537  DUMMYUSE(text);
2538  AT.TermMemHeap[AT.TermMemTop++] = TermMem;
2539 
2540 #ifdef TERMMALLOCDEBUG
2541  MesPrint("TermFree: %s, %d",text,(AT.TermMemMax-AT.TermMemTop));
2542 #endif
2543 #ifdef MALLOCDEBUGOUTPUT
2544  MesPrint("TermFree: %s, %l/%l (%x)",text,AT.TermMemTop,AT.TermMemMax,TermMem);
2545 #endif
2546 }
2547 
2548 #endif
2549 
2550 /*
2551  #] TermMalloc :
2552  #[ NumberMalloc :
2553 */
2574 #define NUMBERMEMSTARTNUM 16
2575 #define NUMBEREXTRAWORDS 10L
2576 
2577 #ifdef TERMMALLOCDEBUG
2578 UWORD **DebugHeap3, **DebugHeap4;
2579 #endif
2580 
2581 VOID NumberMallocAddMemory(PHEAD0)
2582 {
2583  UWORD *newbufs;
2584  WORD extra;
2585  int i;
2586  if ( AT.NumberMemMax == 0 ) extra = NUMBERMEMSTARTNUM;
2587  else extra = AT.NumberMemMax;
2588  if ( AT.NumberMemHeap ) M_free(AT.NumberMemHeap,"NumberMalloc");
2589  newbufs = (UWORD *)Malloc1(extra*(AM.MaxTal+NUMBEREXTRAWORDS)*sizeof(UWORD),"NumberMalloc");
2590  AT.NumberMemHeap = (UWORD **)Malloc1((extra+AT.NumberMemMax)*sizeof(UWORD *),"NumberMalloc");
2591  for ( i = 0; i < extra; i++ ) {
2592  AT.NumberMemHeap[i] = newbufs + i*(LONG)(AM.MaxTal+NUMBEREXTRAWORDS);
2593  }
2594 #ifdef TERMMALLOCDEBUG
2595  DebugHeap4 = (UWORD **)Malloc1((extra+AT.NumberMemMax)*sizeof(WORD *),"NumberMalloc");
2596  for ( i = 0; i < AT.NumberMemMax; i++ ) { DebugHeap4[i] = DebugHeap3[i]; }
2597  for ( i = 0; i < extra; i++ ) {
2598  DebugHeap4[i+AT.NumberMemMax] = newbufs + i*(LONG)(AM.MaxTal+NUMBEREXTRAWORDS);
2599  }
2600  if ( DebugHeap3 ) M_free(DebugHeap3,"NumberMalloc");
2601  DebugHeap3 = DebugHeap4;
2602 #endif
2603  AT.NumberMemTop = extra;
2604  AT.NumberMemMax += extra;
2605 /*
2606 MesPrint("AT.NumberMemMax is now %l",AT.NumberMemMax);
2607 */
2608 }
2609 
2610 #ifndef MEMORYMACROS
2611 
2612 UWORD *NumberMalloc2(PHEAD char *text)
2613 {
2614  if ( AT.NumberMemTop <= 0 ) NumberMallocAddMemory(BHEAD text);
2615 
2616 #ifdef MALLOCDEBUGOUTPUT
2617  if ( (AT.NumberMemMax-AT.NumberMemTop) > 10 )
2618  MesPrint("NumberMalloc: %s, %l/%l (%x)",text,AT.NumberMemTop,AT.NumberMemMax,AT.NumberMemHeap[AT.NumberMemTop-1]);
2619 #endif
2620 
2621  DUMMYUSE(text);
2622  return(AT.NumberMemHeap[--AT.NumberMemTop]);
2623 }
2624 
2625 VOID NumberFree2(PHEAD UWORD *NumberMem, char *text)
2626 {
2627 #ifdef TERMMALLOCDEBUG
2628  int i;
2629  for ( i = 0; i < AT.NumberMemMax; i++ ) {
2630  if ( NumberMem == DebugHeap3[i] ) break;
2631  }
2632  if ( i >= AT.NumberMemMax ) {
2633  MesPrint(" ERROR: NumberFree called with an address not given by NumberMalloc.");
2634  Terminate(-1);
2635  }
2636 #endif
2637  DUMMYUSE(text);
2638  AT.NumberMemHeap[AT.NumberMemTop++] = NumberMem;
2639 
2640 #ifdef MALLOCDEBUGOUTPUT
2641  if ( (AT.NumberMemMax-AT.NumberMemTop) > 10 )
2642  MesPrint("NumberFree: %s, %l/%l (%x)",text,AT.NumberMemTop,AT.NumberMemMax,NumberMem);
2643 #endif
2644 }
2645 
2646 #endif
2647 
2648 /*
2649  #] NumberMalloc :
2650  #[ CacheNumberMalloc :
2651 
2652  Similar to NumberMalloc
2653  */
2654 
2655 VOID CacheNumberMallocAddMemory(PHEAD0)
2656 {
2657  UWORD *newbufs;
2658  WORD extra;
2659  int i;
2660  if ( AT.CacheNumberMemMax == 0 ) extra = NUMBERMEMSTARTNUM;
2661  else extra = AT.CacheNumberMemMax;
2662  if ( AT.CacheNumberMemHeap ) M_free(AT.CacheNumberMemHeap,"NumberMalloc");
2663  newbufs = (UWORD *)Malloc1(extra*(AM.MaxTal+NUMBEREXTRAWORDS)*sizeof(UWORD),"CacheNumberMalloc");
2664  AT.CacheNumberMemHeap = (UWORD **)Malloc1((extra+AT.NumberMemMax)*sizeof(UWORD *),"CacheNumberMalloc");
2665  for ( i = 0; i < extra; i++ ) {
2666  AT.CacheNumberMemHeap[i] = newbufs + i*(LONG)(AM.MaxTal+NUMBEREXTRAWORDS);
2667  }
2668  AT.CacheNumberMemTop = extra;
2669  AT.CacheNumberMemMax += extra;
2670 }
2671 
2672 #ifndef MEMORYMACROS
2673 
2674 UWORD *CacheNumberMalloc2(PHEAD char *text)
2675 {
2676  if ( AT.CacheNumberMemTop <= 0 ) CacheNumberMallocAddMemory(BHEAD0);
2677 
2678 #ifdef MALLOCDEBUGOUTPUT
2679  MesPrint("NumberMalloc: %s, %l/%l (%x)",text,AT.NumberMemTop,AT.NumberMemMax,AT.NumberMemHeap[AT.NumberMemTop-1]);
2680 #endif
2681 
2682  DUMMYUSE(text);
2683  return(AT.CacheNumberMemHeap[--AT.CacheNumberMemTop]);
2684 }
2685 
2686 VOID CacheNumberFree2(PHEAD UWORD *NumberMem, char *text)
2687 {
2688  DUMMYUSE(text);
2689  AT.CacheNumberMemHeap[AT.CacheNumberMemTop++] = NumberMem;
2690 
2691 #ifdef MALLOCDEBUGOUTPUT
2692  MesPrint("NumberFree: %s, %l/%l (%x)",text,AT.NumberMemTop,AT.NumberMemMax,NumberMem);
2693 #endif
2694 }
2695 
2696 #endif
2697 
2698 /*
2699  #] CacheNumberMalloc :
2700  #[ FromList :
2701 
2702  Returns the next object in a list.
2703  If the list has been exhausted we double it (like a realloc)
2704  If the list has not been initialized yet we start with 10 elements.
2705 */
2706 
2707 VOID *FromList(LIST *L)
2708 {
2709  void *newlist;
2710  int i, *old, *newL;
2711  if ( L->num >= L->maxnum || L->lijst == 0 ) {
2712  if ( L->maxnum == 0 ) L->maxnum = 12;
2713  else if ( L->lijst ) L->maxnum *= 2;
2714  newlist = Malloc1(L->maxnum * L->size,L->message);
2715  if ( L->lijst ) {
2716  i = ( L->num * L->size ) / sizeof(int);
2717  old = (int *)L->lijst; newL = (int *)newlist;
2718  while ( --i >= 0 ) *newL++ = *old++;
2719  if ( L->lijst ) M_free(L->lijst,"L->lijst FromList");
2720  }
2721  L->lijst = newlist;
2722  }
2723  return( ((char *)(L->lijst)) + L->size * (L->num)++ );
2724 }
2725 
2726 /*
2727  #] FromList :
2728  #[ From0List :
2729 
2730  Same as FromList, but we zero excess variables.
2731 */
2732 
2733 VOID *From0List(LIST *L)
2734 {
2735  void *newlist;
2736  int i, *old, *newL;
2737  if ( L->num >= L->maxnum || L->lijst == 0 ) {
2738  if ( L->maxnum == 0 ) L->maxnum = 12;
2739  else if ( L->lijst ) L->maxnum *= 2;
2740  newlist = Malloc1(L->maxnum * L->size,L->message);
2741  i = ( L->num * L->size ) / sizeof(int);
2742  old = (int *)(L->lijst); newL = (int *)newlist;
2743  while ( --i >= 0 ) *newL++ = *old++;
2744  i = ( L->maxnum - L->num ) / sizeof(int);
2745  while ( --i >= 0 ) *newL++ = 0;
2746  if ( L->lijst ) M_free(L->lijst,"L->lijst From0List");
2747  L->lijst = newlist;
2748  }
2749  return( ((char *)(L->lijst)) + L->size * (L->num)++ );
2750 }
2751 
2752 /*
2753  #] From0List :
2754  #[ FromVarList :
2755 
2756  Returns the next object in a list of variables.
2757  If the list has been exhausted we double it (like a realloc)
2758  If the list has not been initialized yet we start with 10 elements.
2759  We allow at most MAXVARIABLES elements!
2760 */
2761 
2762 VOID *FromVarList(LIST *L)
2763 {
2764  void *newlist;
2765  int i, *old, *newL;
2766  if ( L->num >= L->maxnum || L->lijst == 0 ) {
2767  if ( L->maxnum == 0 ) L->maxnum = 12;
2768  else if ( L->lijst ) {
2769  L->maxnum *= 2;
2770  if ( L == &(AP.DollarList) ) {
2771  if ( L->maxnum > MAXDOLLARVARIABLES ) L->maxnum = MAXDOLLARVARIABLES;
2772  if ( L->num >= MAXDOLLARVARIABLES ) {
2773  MesPrint("!!!More than %l objects in list of $-variables",
2774  MAXDOLLARVARIABLES);
2775  Terminate(-1);
2776  }
2777  }
2778  else {
2779  if ( L->maxnum > MAXVARIABLES ) L->maxnum = MAXVARIABLES;
2780  if ( L->num >= MAXVARIABLES ) {
2781  MesPrint("!!!More than %l objects in list of variables",
2782  MAXVARIABLES);
2783  Terminate(-1);
2784  }
2785  }
2786  }
2787  newlist = Malloc1(L->maxnum * L->size,L->message);
2788  if ( L->lijst ) {
2789  i = ( L->num * L->size ) / sizeof(int);
2790  old = (int *)(L->lijst); newL = (int *)newlist;
2791  while ( --i >= 0 ) *newL++ = *old++;
2792  if ( L->lijst ) M_free(L->lijst,"L->lijst from VarList");
2793  }
2794  L->lijst = newlist;
2795  }
2796  return( ((char *)(L->lijst)) + L->size * ((L->num)++) );
2797 }
2798 
2799 /*
2800  #] FromVarList :
2801  #[ DoubleList :
2802 */
2803 
2804 int DoubleList(VOID ***lijst, int *oldsize, int objectsize, char *nameoftype)
2805 {
2806  VOID **newlist;
2807  LONG i, newsize, fullsize;
2808  VOID **to, **from;
2809  static LONG maxlistsize = (LONG)(MAXPOSITIVE);
2810  if ( *lijst == 0 ) {
2811  if ( *oldsize > 0 ) newsize = *oldsize;
2812  else newsize = 100;
2813  }
2814  else newsize = *oldsize * 2;
2815  if ( newsize > maxlistsize ) {
2816  if ( *oldsize == maxlistsize ) {
2817  MesPrint("No memory for extra space in %s",nameoftype);
2818  return(-1);
2819  }
2820  newsize = maxlistsize;
2821  }
2822  fullsize = ( newsize * objectsize + sizeof(VOID *)-1 ) & (-sizeof(VOID *));
2823  newlist = (VOID **)Malloc1(fullsize,nameoftype);
2824  if ( *lijst ) { /* Now some punning. DANGEROUS CODE in principle */
2825  to = newlist; from = *lijst; i = (*oldsize * objectsize)/sizeof(VOID *);
2826 /*
2827 #ifdef MALLOCDEBUG
2828 if ( filelist ) MesPrint(" oldsize: %l, objectsize: %d, fullsize: %l"
2829  ,*oldsize,objectsize,fullsize);
2830 #endif
2831 */
2832  while ( --i >= 0 ) *to++ = *from++;
2833  }
2834  if ( *lijst ) M_free(*lijst,"DoubleLList");
2835  *lijst = newlist;
2836  *oldsize = newsize;
2837  return(0);
2838 /*
2839  int error;
2840  LONG lsize = *oldsize;
2841 
2842  maxlistsize = (LONG)(MAXPOSITIVE);
2843  error = DoubleLList(lijst,&lsize,objectsize,nameoftype);
2844  *oldsize = lsize;
2845  maxlistsize = (LONG)(MAXLONG);
2846 
2847  return(error);
2848 */
2849 }
2850 
2851 /*
2852  #] DoubleList :
2853  #[ DoubleLList :
2854 */
2855 
2856 int DoubleLList(VOID ***lijst, LONG *oldsize, int objectsize, char *nameoftype)
2857 {
2858  VOID **newlist;
2859  LONG i, newsize, fullsize;
2860  VOID **to, **from;
2861  static LONG maxlistsize = (LONG)(MAXLONG);
2862  if ( *lijst == 0 ) {
2863  if ( *oldsize > 0 ) newsize = *oldsize;
2864  else newsize = 100;
2865  }
2866  else newsize = *oldsize * 2;
2867  if ( newsize > maxlistsize ) {
2868  if ( *oldsize == maxlistsize ) {
2869  MesPrint("No memory for extra space in %s",nameoftype);
2870  return(-1);
2871  }
2872  newsize = maxlistsize;
2873  }
2874  fullsize = ( newsize * objectsize + sizeof(VOID *)-1 ) & (-sizeof(VOID *));
2875  newlist = (VOID **)Malloc1(fullsize,nameoftype);
2876  if ( *lijst ) { /* Now some punning. DANGEROUS CODE in principle */
2877  to = newlist; from = *lijst; i = (*oldsize * objectsize)/sizeof(VOID *);
2878 /*
2879 #ifdef MALLOCDEBUG
2880 if ( filelist ) MesPrint(" oldsize: %l, objectsize: %d, fullsize: %l"
2881  ,*oldsize,objectsize,fullsize);
2882 #endif
2883 */
2884  while ( --i >= 0 ) *to++ = *from++;
2885  }
2886  if ( *lijst ) M_free(*lijst,"DoubleLList");
2887  *lijst = newlist;
2888  *oldsize = newsize;
2889  return(0);
2890 }
2891 
2892 /*
2893  #] DoubleLList :
2894  #[ DoubleBuffer :
2895 */
2896 
2897 #define DODOUBLE(x) { x *s, *t, *u; if ( *start ) { \
2898  oldsize = *(x **)stop - *(x **)start; newsize = 2*oldsize; \
2899  t = u = (x *)Malloc1(newsize*sizeof(x),text); s = *(x **)start; \
2900  for ( i = 0; i < oldsize; i++ ) *t++ = *s++; M_free(*start,"double"); } \
2901  else { newsize = 100; u = (x *)Malloc1(newsize*sizeof(x),text); } \
2902  *start = (void *)u; *stop = (void *)(u+newsize); }
2903 
2904 void DoubleBuffer(void **start, void **stop, int size, char *text)
2905 {
2906  LONG oldsize, newsize, i;
2907  if ( size == sizeof(char) ) DODOUBLE(char)
2908  else if ( size == sizeof(short) ) DODOUBLE(short)
2909  else if ( size == sizeof(int) ) DODOUBLE(int)
2910  else if ( size == sizeof(LONG) ) DODOUBLE(LONG)
2911  else if ( size % sizeof(int) == 0 ) DODOUBLE(int)
2912  else {
2913  MesPrint("---Cannot handle doubling buffers of size %d",size);
2914  Terminate(-1);
2915  }
2916 }
2917 
2918 /*
2919  #] DoubleBuffer :
2920  #[ ExpandBuffer :
2921 */
2922 
2923 #define DOEXPAND(x) { x *newbuffer, *t, *m; \
2924  t = newbuffer = (x *)Malloc1((newsize+2)*type,"ExpandBuffer"); \
2925  if ( *buffer ) { m = (x *)*buffer; i = *oldsize; \
2926  while ( --i >= 0 ) *t++ = *m++; M_free(*buffer,"ExpandBuffer"); \
2927  } *buffer = newbuffer; *oldsize = newsize; }
2928 
2929 void ExpandBuffer(void **buffer, LONG *oldsize, int type)
2930 {
2931  LONG newsize, i;
2932  if ( *oldsize <= 0 ) { newsize = 100; }
2933  else newsize = 2*(*oldsize);
2934  if ( type == sizeof(char) ) DOEXPAND(char)
2935  else if ( type == sizeof(short) ) DOEXPAND(short)
2936  else if ( type == sizeof(int) ) DOEXPAND(int)
2937  else if ( type == sizeof(LONG) ) DOEXPAND(LONG)
2938  else if ( type == sizeof(POSITION) ) DOEXPAND(POSITION)
2939  else {
2940  MesPrint("---Cannot handle expanding buffers with objects of size %d",type);
2941  Terminate(-1);
2942  }
2943 }
2944 
2945 /*
2946  #] ExpandBuffer :
2947  #[ iexp :
2948 
2949  Raises the long integer y to the power p.
2950  Returnvalue is long, regardless of overflow.
2951 */
2952 
2953 LONG iexp(LONG x, int p)
2954 {
2955  int sign;
2956  ULONG y;
2957  ULONG ux;
2958  if ( x == 0 ) return(0);
2959  if ( p == 0 ) return(1);
2960  sign = x < 0 ? -1 : 1;
2961  if ( sign < 0 && ( p & 1 ) == 0 ) sign = 1;
2962  ux = LongAbs(x);
2963  if ( ux == 1 ) return(sign);
2964  if ( p < 0 ) return(0);
2965  y = 1;
2966  while ( p ) {
2967  if ( ( p & 1 ) != 0 ) y *= ux;
2968  p >>= 1;
2969  ux = ux*ux;
2970  }
2971  if ( sign < 0 ) y = -y;
2972  return ULongToLong(y);
2973 }
2974 
2975 /*
2976  #] iexp :
2977  #[ ToGeneral :
2978 
2979  Convert a fast argument to a general argument
2980  Input in r, output in m.
2981  If par == 0 we need the argument header also.
2982 */
2983 
2984 void ToGeneral(WORD *r, WORD *m, WORD par)
2985 {
2986  WORD *mm = m, j, k;
2987  if ( par ) m++;
2988  else { m[1] = 0; m += ARGHEAD + 1; }
2989  j = -*r++;
2990  k = 3;
2991 /* JV: Bugfix 1-feb-2016. Old code assumed FUNHEAD to be 2 */
2992  if ( j >= FUNCTION ) { *m++ = j; *m++ = FUNHEAD; FILLFUN(m) }
2993  else {
2994  switch ( j ) {
2995  case SYMBOL: *m++ = j; *m++ = 4; *m++ = *r++; *m++ = 1; break;
2996  case SNUMBER:
2997  if ( *r > 0 ) { *m++ = *r; *m++ = 1; *m++ = 3; }
2998  else if ( *r == 0 ) { m--; }
2999  else { *m++ = -*r; *m++ = 1; *m++ = -3; }
3000  goto MakeSize;
3001  case MINVECTOR:
3002  k = -k;
3003  /* fall through */
3004  case INDEX:
3005  case VECTOR:
3006  *m++ = INDEX; *m++ = 3; *m++ = *r++;
3007  break;
3008  }
3009  }
3010  *m++ = 1; *m++ = 1; *m++ = k;
3011 MakeSize:
3012  *mm = m-mm;
3013  if ( !par ) mm[ARGHEAD] = *mm-ARGHEAD;
3014 }
3015 
3016 /*
3017  #] ToGeneral :
3018  #[ ToFast :
3019 
3020  Checks whether an argument can be converted to fast notation
3021  If this can be done it does it.
3022  Important: m should be allowed to be equal to r!
3023  Return value is 1 if conversion took place.
3024  If there was conversion the answer is in m.
3025  If there was no conversion m hasn't been touched.
3026 */
3027 
3028 int ToFast(WORD *r, WORD *m)
3029 {
3030  WORD i;
3031  if ( *r == ARGHEAD ) { *m++ = -SNUMBER; *m++ = 0; return(1); }
3032  if ( *r != r[ARGHEAD]+ARGHEAD ) return(0); /* > 1 term */
3033  r += ARGHEAD;
3034  if ( *r == 4 ) {
3035  if ( r[2] != 1 || r[1] <= 0 ) return(0);
3036  *m++ = -SNUMBER; *m = ( r[3] < 0 ) ? -r[1] : r[1]; return(1);
3037  }
3038  i = *r - 1;
3039  if ( r[i-1] != 1 || r[i-2] != 1 ) return(0);
3040  if ( r[i] != 3 ) {
3041  if ( r[i] == -3 && r[2] == *r-4 && r[2] == 3 && r[1] == INDEX
3042  && r[3] < MINSPEC ) {}
3043  else return(0);
3044  }
3045  else if ( r[2] != *r - 4 ) return(0);
3046  r++;
3047  if ( *r >= FUNCTION ) {
3048  if ( r[1] <= FUNHEAD ) { *m++ = -*r; return(1); }
3049  }
3050  else if ( *r == SYMBOL ) {
3051  if ( r[1] == 4 && r[3] == 1 )
3052  { *m++ = -SYMBOL; *m++ = r[2]; return(1); }
3053  }
3054  else if ( *r == INDEX ) {
3055  if ( r[1] == 3 ) {
3056  if ( r[2] >= MINSPEC ) {
3057  if ( r[2] >= 0 && r[2] < AM.OffsetIndex ) *m++ = -SNUMBER;
3058  else *m++ = -INDEX;
3059  }
3060  else {
3061  if ( r[5] == -3 ) *m++ = -MINVECTOR;
3062  else *m++ = -VECTOR;
3063  }
3064  *m++ = r[2];
3065  return(1);
3066  }
3067  }
3068  return(0);
3069 }
3070 
3071 /*
3072  #] ToFast :
3073  #[ ToPolyFunGeneral :
3074 
3075  Routine forces a polyratfun into general notation if needed.
3076  If no action was needed, the return value is zero.
3077  A positive return value indicates how many arguments were converted.
3078  The new term overwrite the old.
3079 */
3080 
3081 WORD ToPolyFunGeneral(PHEAD WORD *term)
3082 {
3083  WORD *t = term+1, *tt, *to, *to1, *termout, *tstop, *tnext;
3084  WORD numarg, i, change = 0;
3085  tstop = term + *term; tstop -= ABS(tstop[-1]);
3086  termout = to = AT.WorkPointer;
3087  to++;
3088  while ( t < tstop ) { /* go through the subterms */
3089  if ( *t == AR.PolyFun ) {
3090  tt = t+FUNHEAD; tnext = t + t[1];
3091  numarg = 0;
3092  while ( tt < tnext ) { numarg++; NEXTARG(tt); }
3093  if ( numarg == 2 ) { /* this needs attention */
3094  tt = t + FUNHEAD;
3095  to1 = to;
3096  i = FUNHEAD; NCOPY(to,t,i);
3097  while ( tt < tnext ) { /* Do the arguments */
3098  if ( *tt > 0 ) {
3099  i = *tt; NCOPY(to,tt,i);
3100  }
3101  else if ( *tt == -SYMBOL ) {
3102  to1[1] += 6+ARGHEAD; to1[2] |= MUSTCLEANPRF; change++;
3103  *to++ = 8+ARGHEAD; *to++ = 0; FILLARG(to);
3104  *to++ = 8; *to++ = SYMBOL; *to++ = 4; *to++ = tt[1];
3105  *to++ = 1; *to++ = 1; *to++ = 1; *to++ = 3;
3106  tt += 2;
3107  }
3108  else if ( *tt == -SNUMBER ) {
3109  if ( tt[1] > 0 ) {
3110  to1[1] += 2+ARGHEAD; to1[2] |= MUSTCLEANPRF; change++;
3111  *to++ = 4+ARGHEAD; *to++ = 0; FILLARG(to);
3112  *to++ = 4; *to++ = tt[1]; *to++ = 1; *to++ = 3;
3113  tt += 2;
3114  }
3115  else if ( tt[1] < 0 ) {
3116  to1[1] += 2+ARGHEAD; to1[2] |= MUSTCLEANPRF; change++;
3117  *to++ = 4+ARGHEAD; *to++ = 0; FILLARG(to);
3118  *to++ = 4; *to++ = -tt[1]; *to++ = 1; *to++ = -3;
3119  tt += 2;
3120  }
3121  else {
3122  MLOCK(ErrorMessageLock);
3123  MesPrint("Internal error: Zero in PolyRatFun");
3124  MUNLOCK(ErrorMessageLock);
3125  Terminate(-1);
3126  }
3127  }
3128  }
3129  t = tnext;
3130  continue;
3131  }
3132  }
3133  i = t[1]; NCOPY(to,t,i)
3134  }
3135  if ( change ) {
3136  tt = term + *term;
3137  while ( t < tt ) *to++ = *t++;
3138  *termout = to - termout;
3139  t = term; i = *termout; tt = termout;
3140  NCOPY(t,tt,i)
3141  AT.WorkPointer = term + *term;
3142  }
3143  return(change);
3144 }
3145 
3146 /*
3147  #] ToPolyFunGeneral :
3148  #[ IsLikeVector :
3149 
3150  Routine determines whether a function argument is like a vector.
3151  Returnvalue: 1: is vector or index
3152  0: is not vector or index
3153  -1: may be an index
3154 */
3155 
3156 int IsLikeVector(WORD *arg)
3157 {
3158  WORD *sstop, *t, *tstop;
3159  if ( *arg < 0 ) {
3160  if ( *arg == -VECTOR || *arg == -INDEX ) return(1);
3161  if ( *arg == -SNUMBER && arg[1] >= 0 && arg[1] < AM.OffsetIndex )
3162  return(-1);
3163  return(0);
3164  }
3165  sstop = arg + *arg; arg += ARGHEAD;
3166  while ( arg < sstop ) {
3167  t = arg + *arg;
3168  tstop = t - ABS(t[-1]);
3169  arg++;
3170  while ( arg < tstop ) {
3171  if ( *arg == INDEX ) return(1);
3172  arg += arg[1];
3173  }
3174  arg = t;
3175  }
3176  return(0);
3177 }
3178 
3179 /*
3180  #] IsLikeVector :
3181  #[ AreArgsEqual :
3182 */
3183 
3184 int AreArgsEqual(WORD *arg1, WORD *arg2)
3185 {
3186  int i;
3187  if ( *arg2 != *arg1 ) return(0);
3188  if ( *arg1 > 0 ) {
3189  i = *arg1;
3190  while ( --i > 0 ) { if ( arg1[i] != arg2[i] ) return(0); }
3191  return(1);
3192  }
3193  else if ( *arg1 <= -FUNCTION ) return(1);
3194  else if ( arg1[1] == arg2[1] ) return(1);
3195  return(0);
3196 }
3197 
3198 /*
3199  #] AreArgsEqual :
3200  #[ CompareArgs :
3201 */
3202 
3203 int CompareArgs(WORD *arg1, WORD *arg2)
3204 {
3205  int i1,i2;
3206  if ( *arg1 > 0 ) {
3207  if ( *arg2 < 0 ) return(-1);
3208  i1 = *arg1-ARGHEAD; arg1 += ARGHEAD;
3209  i2 = *arg2-ARGHEAD; arg2 += ARGHEAD;
3210  while ( i1 > 0 && i2 > 0 ) {
3211  if ( *arg1 != *arg2 ) return((int)(*arg1)-(int)(*arg2));
3212  i1--; i2--; arg1++; arg2++;
3213  }
3214  return(i1-i2);
3215  }
3216  else if ( *arg2 > 0 ) return(1);
3217  else {
3218  if ( *arg1 != *arg2 ) {
3219  if ( *arg1 < *arg2 ) return(-1);
3220  else return(1);
3221  }
3222  if ( *arg1 <= -FUNCTION ) return(0);
3223  return((int)(arg1[1])-(int)(arg2[1]));
3224  }
3225 }
3226 
3227 /*
3228  #] CompareArgs :
3229  #[ CompArg :
3230 
3231  returns 1 if arg1 comes first, -1 if arg2 comes first, 0 if equal
3232 */
3233 
3234 int CompArg(WORD *s1, WORD *s2)
3235 {
3236  GETIDENTITY
3237  WORD *st1, *st2, x[7];
3238  int k;
3239  if ( *s1 < 0 ) {
3240  if ( *s2 < 0 ) {
3241  if ( *s1 <= -FUNCTION && *s2 <= -FUNCTION ) {
3242  if ( *s1 > *s2 ) return(-1);
3243  if ( *s1 < *s2 ) return(1);
3244  return(0);
3245  }
3246  if ( *s1 > *s2 ) return(1);
3247  if ( *s1 < *s2 ) return(-1);
3248  if ( *s1 <= -FUNCTION ) return(0);
3249  s1++; s2++;
3250  if ( *s1 > *s2 ) return(1);
3251  if ( *s1 < *s2 ) return(-1);
3252  return(0);
3253  }
3254  x[1] = AT.comsym[3];
3255  x[2] = AT.comnum[1];
3256  x[3] = AT.comnum[3];
3257  x[4] = AT.comind[3];
3258  x[5] = AT.comind[6];
3259  x[6] = AT.comfun[1];
3260  if ( *s1 == -SYMBOL ) {
3261  AT.comsym[3] = s1[1];
3262  st1 = AT.comsym+8; s1 = AT.comsym;
3263  }
3264  else if ( *s1 == -SNUMBER ) {
3265  if ( s1[1] < 0 ) {
3266  AT.comnum[1] = -s1[1]; AT.comnum[3] = -3;
3267  }
3268  else {
3269  AT.comnum[1] = s1[1]; AT.comnum[3] = 3;
3270  }
3271  st1 = AT.comnum+4;
3272  s1 = AT.comnum;
3273  }
3274  else if ( *s1 == -INDEX || *s1 == -VECTOR ) {
3275  AT.comind[3] = s1[1]; AT.comind[6] = 3;
3276  st1 = AT.comind+7; s1 = AT.comind;
3277  }
3278  else if ( *s1 == -MINVECTOR ) {
3279  AT.comind[3] = s1[1]; AT.comind[6] = -3;
3280  st1 = AT.comind+7; s1 = AT.comind;
3281  }
3282  else if ( *s1 <= -FUNCTION ) {
3283  AT.comfun[1] = -*s1;
3284  st1 = AT.comfun+FUNHEAD+4; s1 = AT.comfun;
3285  }
3286 /*
3287  Symmetrize during compilation of id statement when properorder
3288  needs this one. Code added 10-nov-2001
3289 */
3290  else if ( *s1 == -ARGWILD ) {
3291  return(-1);
3292  }
3293  else { goto argerror; }
3294  st2 = s2 + *s2; s2 += ARGHEAD;
3295  goto docompare;
3296  }
3297  else if ( *s2 < 0 ) {
3298  x[1] = AT.comsym[3];
3299  x[2] = AT.comnum[1];
3300  x[3] = AT.comnum[3];
3301  x[4] = AT.comind[3];
3302  x[5] = AT.comind[6];
3303  x[6] = AT.comfun[1];
3304  if ( *s2 == -SYMBOL ) {
3305  AT.comsym[3] = s2[1];
3306  st2 = AT.comsym+8; s2 = AT.comsym;
3307  }
3308  else if ( *s2 == -SNUMBER ) {
3309  if ( s2[1] < 0 ) {
3310  AT.comnum[1] = -s2[1]; AT.comnum[3] = -3;
3311  st2 = AT.comnum+4;
3312  }
3313  else if ( s2[1] == 0 ) {
3314  st2 = AT.comnum+4; s2 = st2;
3315  }
3316  else {
3317  AT.comnum[1] = s2[1]; AT.comnum[3] = 3;
3318  st2 = AT.comnum+4;
3319  }
3320  s2 = AT.comnum;
3321  }
3322  else if ( *s2 == -INDEX || *s2 == -VECTOR ) {
3323  AT.comind[3] = s2[1]; AT.comind[6] = 3;
3324  st2 = AT.comind+7; s2 = AT.comind;
3325  }
3326  else if ( *s2 == -MINVECTOR ) {
3327  AT.comind[3] = s2[1]; AT.comind[6] = -3;
3328  st2 = AT.comind+7; s2 = AT.comind;
3329  }
3330  else if ( *s2 <= -FUNCTION ) {
3331  AT.comfun[1] = -*s2;
3332  st2 = AT.comfun+FUNHEAD+4; s2 = AT.comfun;
3333  }
3334 /*
3335  Symmetrize during compilation of id statement when properorder
3336  needs this one. Code added 10-nov-2001
3337 */
3338  else if ( *s2 == -ARGWILD ) {
3339  return(1);
3340  }
3341  else { goto argerror; }
3342  st1 = s1 + *s1; s1 += ARGHEAD;
3343  goto docompare;
3344  }
3345  else {
3346  x[1] = AT.comsym[3];
3347  x[2] = AT.comnum[1];
3348  x[3] = AT.comnum[3];
3349  x[4] = AT.comind[3];
3350  x[5] = AT.comind[6];
3351  x[6] = AT.comfun[1];
3352  st1 = s1 + *s1; st2 = s2 + *s2;
3353  s1 += ARGHEAD; s2 += ARGHEAD;
3354 docompare:
3355  while ( s1 < st1 && s2 < st2 ) {
3356  if ( ( k = CompareTerms(s1,s2,(WORD)2) ) != 0 ) {
3357  AT.comsym[3] = x[1];
3358  AT.comnum[1] = x[2];
3359  AT.comnum[3] = x[3];
3360  AT.comind[3] = x[4];
3361  AT.comind[6] = x[5];
3362  AT.comfun[1] = x[6];
3363  return(-k);
3364  }
3365  s1 += *s1; s2 += *s2;
3366  }
3367  AT.comsym[3] = x[1];
3368  AT.comnum[1] = x[2];
3369  AT.comnum[3] = x[3];
3370  AT.comind[3] = x[4];
3371  AT.comind[6] = x[5];
3372  AT.comfun[1] = x[6];
3373  if ( s1 < st1 ) return(1);
3374  if ( s2 < st2 ) return(-1);
3375  }
3376  return(0);
3377 
3378 argerror:
3379  MesPrint("Illegal type of short function argument in Normalize");
3380  Terminate(-1); return(0);
3381 }
3382 
3383 /*
3384  #] CompArg :
3385  #[ TimeWallClock :
3386 */
3387 
3388 #ifdef HAVE_CLOCK_GETTIME
3389 #include <time.h> /* for clock_gettime() */
3390 #else
3391 #ifdef HAVE_GETTIMEOFDAY
3392 #include <sys/time.h> /* for gettimeofday() */
3393 #else
3394 #include <sys/timeb.h> /* for ftime() */
3395 #endif
3396 #endif
3397 
3404 LONG TimeWallClock(WORD par)
3405 {
3406  /*
3407  * NOTE: this function is not thread-safe. Operations on tp are not atomic.
3408  */
3409 
3410 #ifdef HAVE_CLOCK_GETTIME
3411  struct timespec ts;
3412  clock_gettime(CLOCK_MONOTONIC, &ts);
3413 
3414  if ( par ) {
3415  return(((LONG)(ts.tv_sec)-AM.OldSecTime)*100 +
3416  ((LONG)(ts.tv_nsec / 1000000)-AM.OldMilliTime)/10);
3417  }
3418  else {
3419  AM.OldSecTime = (LONG)(ts.tv_sec);
3420  AM.OldMilliTime = (LONG)(ts.tv_nsec / 1000000);
3421  return(0L);
3422  }
3423 #else
3424 #ifdef HAVE_GETTIMEOFDAY
3425  struct timeval t;
3426  LONG sec, msec;
3427  gettimeofday(&t, NULL);
3428  sec = (LONG)t.tv_sec;
3429  msec = (LONG)(t.tv_usec/1000);
3430  if ( par ) {
3431  return (sec-AM.OldSecTime)*100 + (msec-AM.OldMilliTime)/10;
3432  }
3433  else {
3434  AM.OldSecTime = sec;
3435  AM.OldMilliTime = msec;
3436  return(0L);
3437  }
3438 #else
3439  struct timeb tp;
3440  ftime(&tp);
3441 
3442  if ( par ) {
3443  return(((LONG)(tp.time)-AM.OldSecTime)*100 +
3444  ((LONG)(tp.millitm)-AM.OldMilliTime)/10);
3445  }
3446  else {
3447  AM.OldSecTime = (LONG)(tp.time);
3448  AM.OldMilliTime = (LONG)(tp.millitm);
3449  return(0L);
3450  }
3451 #endif
3452 #endif
3453 }
3454 
3455 /*
3456  #] TimeWallClock :
3457  #[ TimeChildren :
3458 */
3459 
3460 LONG TimeChildren(WORD par)
3461 {
3462  if ( par ) return(Timer(1)-AM.OldChildTime);
3463  AM.OldChildTime = Timer(1);
3464  return(0L);
3465 }
3466 
3467 /*
3468  #] TimeChildren :
3469  #[ TimeCPU :
3470 */
3471 
3478 LONG TimeCPU(WORD par)
3479 {
3480  GETIDENTITY
3481  if ( par ) return(Timer(0)-AR.OldTime);
3482  AR.OldTime = Timer(0);
3483  return(0L);
3484 }
3485 
3486 /*
3487  #] TimeCPU :
3488  #[ Timer :
3489 */
3490 #if defined(WINDOWS)
3491 
3492 LONG Timer(int par)
3493 {
3494 #ifndef WITHPTHREADS
3495  static int initialized = 0;
3496  static HANDLE hProcess;
3497  FILETIME ftCreate, ftExit, ftKernel, ftUser;
3498  DUMMYUSE(par);
3499 
3500  if ( !initialized ) {
3501  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
3502  }
3503  if ( GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser) ) {
3504  PFILETIME pftKernel = &ftKernel; /* to avoid strict-aliasing rule warnings */
3505  PFILETIME pftUser = &ftUser;
3506  __int64 t = *(__int64 *)pftKernel + *(__int64 *)pftUser; /* in 100 nsec. */
3507  return (LONG)(t / 10000); /* in msec. */
3508  }
3509  return 0;
3510 #else
3511  LONG lResult = 0;
3512  HANDLE hThread;
3513  FILETIME ftCreate, ftExit, ftKernel, ftUser;
3514  DUMMYUSE(par);
3515 
3516  hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, GetCurrentThreadId());
3517  if ( hThread ) {
3518  if ( GetThreadTimes(hThread, &ftCreate, &ftExit, &ftKernel, &ftUser) ) {
3519  PFILETIME pftKernel = &ftKernel; /* to avoid strict-aliasing rule warnings */
3520  PFILETIME pftUser = &ftUser;
3521  __int64 t = *(__int64 *)pftKernel + *(__int64 *)pftUser; /* in 100 nsec. */
3522  lResult = (LONG)(t / 10000); /* in msec. */
3523  }
3524  CloseHandle(hThread);
3525  }
3526  return lResult;
3527 #endif
3528 }
3529 
3530 #elif defined(UNIX)
3531 #include <sys/time.h>
3532 #include <sys/resource.h>
3533 #ifdef WITHPOSIXCLOCK
3534 #include <time.h>
3535 /*
3536  And include -lrt in the link statement (on blade02)
3537 */
3538 #endif
3539 
3540 LONG Timer(int par)
3541 {
3542 #ifdef WITHPOSIXCLOCK
3543 /*
3544  Only to be used in combination with WITHPTHREADS
3545  This clock seems to be supported by the standard.
3546  The getrusage clock returns according to the standard only the combined
3547  time of the whole process. But in older versions of Linux LinuxThreads
3548  is used which gives a separate id to each thread and individual timings.
3549  In NPTL we get, according to the standard, one combined timing.
3550  To get individual timings we need to use
3551  clock_gettime(CLOCK_THREAD_CPUTIME_ID, &timing)
3552  with timing of the time
3553  struct timespec {
3554  time_t tv_sec; Seconds.
3555  long tv_nsec; Nanoseconds.
3556  };
3557 
3558 */
3559  struct timespec t;
3560  if ( par == 0 ) {
3561  if ( clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t) ) {
3562  MesPrint("Error in getting timing information");
3563  }
3564  return (LONG)t.tv_sec * 1000 + (LONG)t.tv_nsec / 1000000;
3565  }
3566  return(0);
3567 #else
3568  struct rusage rusage;
3569  if ( par == 1 ) {
3570  getrusage(RUSAGE_CHILDREN,&rusage);
3571  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3572  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3573  }
3574  else {
3575  getrusage(RUSAGE_SELF,&rusage);
3576  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3577  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3578  }
3579 #endif
3580 }
3581 
3582 #elif defined(SUN)
3583 #define _TIME_T_
3584 #include <sys/time.h>
3585 #include <sys/resource.h>
3586 
3587 LONG Timer(int par)
3588 {
3589  struct rusage rusage;
3590  if ( par == 1 ) {
3591  getrusage(RUSAGE_CHILDREN,&rusage);
3592  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3593  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3594  }
3595  else {
3596  getrusage(RUSAGE_SELF,&rusage);
3597  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3598  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3599  }
3600 }
3601 
3602 #elif defined(RS6K)
3603 #include <sys/time.h>
3604 #include <sys/resource.h>
3605 
3606 LONG Timer(int par)
3607 {
3608  struct rusage rusage;
3609  if ( par == 1 ) {
3610  getrusage(RUSAGE_CHILDREN,&rusage);
3611  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3612  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3613  }
3614  else {
3615  getrusage(RUSAGE_SELF,&rusage);
3616  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3617  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3618  }
3619 }
3620 
3621 #elif defined(ANSI)
3622 LONG Timer(int par)
3623 {
3624 #ifdef ALPHA
3625 /* clock_t t,tikken = clock(); */
3626 /* MesPrint("ALPHA-clock = %l",(LONG)tikken); */
3627 /* t = tikken % CLOCKS_PER_SEC; */
3628 /* tikken /= CLOCKS_PER_SEC; */
3629 /* tikken *= 1000; */
3630 /* tikken += (t*1000)/CLOCKS_PER_SEC; */
3631 /* return((LONG)tikken); */
3632 /* #define _TIME_T_ */
3633 #include <sys/time.h>
3634 #include <sys/resource.h>
3635  struct rusage rusage;
3636  if ( par == 1 ) {
3637  getrusage(RUSAGE_CHILDREN,&rusage);
3638  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3639  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3640  }
3641  else {
3642  getrusage(RUSAGE_SELF,&rusage);
3643  return(((LONG)(rusage.ru_utime.tv_sec)+(LONG)(rusage.ru_stime.tv_sec))*1000
3644  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3645  }
3646 #else
3647 #ifdef DEC_STATION
3648  clock_t tikken = clock();
3649  return((LONG)tikken/1000);
3650 #else
3651  clock_t t, tikken = clock();
3652  t = tikken % CLK_TCK;
3653  tikken /= CLK_TCK;
3654  tikken *= 1000;
3655  tikken += (t*1000)/CLK_TCK;
3656  return(tikken);
3657 #endif
3658 #endif
3659 }
3660 #elif defined(VMS)
3661 
3662 #include <time.h>
3663 void times(tbuffer_t *buffer);
3664 
3665 LONG
3666 Timer(int par)
3667 {
3668  tbuffer_t buffer;
3669  if ( par == 1 ) { return(0); }
3670  else {
3671  times(&buffer);
3672  return(buffer.proc_user_time * 10);
3673  }
3674 }
3675 
3676 #elif defined(mBSD)
3677 
3678 #ifdef MICROTIME
3679 /*
3680  There is only a CP time clock in microseconds here
3681  This can cause problems with AO.wrap around
3682 */
3683 #else
3684 #ifdef mBSD2
3685 #include <sys/types.h>
3686 #include <sys/times.h>
3687 #include <time.h>
3688 LONG pretime = 0;
3689 #else
3690 #define _TIME_T_
3691 #include <sys/time.h>
3692 #include <sys/resource.h>
3693 #endif
3694 #endif
3695 
3696 LONG Timer(int par)
3697 {
3698 #ifdef MICROTIME
3699  LONG t;
3700  if ( par == 1 ) { return(0); }
3701  t = clock();
3702  if ( ( AO.wrapnum & 1 ) != 0 ) t ^= 0x80000000;
3703  if ( t < 0 ) {
3704  t ^= 0x80000000;
3705  warpnum++;
3706  AO.wrap += 2147584;
3707  }
3708  return(AO.wrap+(t/1000));
3709 #else
3710 #ifdef mBSD2
3711  struct tms buffer;
3712  LONG ret;
3713  ULONG a1, a2, a3, a4;
3714  if ( par == 1 ) { return(0); }
3715  times(&buffer);
3716  a1 = (ULONG)buffer.tms_utime;
3717  a2 = a1 >> 16;
3718  a3 = a1 & 0xFFFFL;
3719  a3 *= 1000;
3720  a2 = 1000*a2 + (a3 >> 16);
3721  a3 &= 0xFFFFL;
3722  a4 = a2/CLK_TCK;
3723  a2 %= CLK_TCK;
3724  a3 += a2 << 16;
3725  ret = (LONG)((a4 << 16) + a3 / CLK_TCK);
3726 /* ret = ((LONG)buffer.tms_utime * 1000)/CLK_TCK; */
3727  return(ret);
3728 #else
3729 #ifdef REALTIME
3730  struct timeval tp;
3731  struct timezone tzp;
3732  if ( par == 1 ) { return(0); }
3733  gettimeofday(&tp,&tzp); */
3734  return(tp.tv_sec*1000+tp.tv_usec/1000);
3735 #else
3736  struct rusage rusage;
3737  if ( par == 1 ) {
3738  getrusage(RUSAGE_CHILDREN,&rusage);
3739  return((rusage.ru_utime.tv_sec+rusage.ru_stime.tv_sec)*1000
3740  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3741  }
3742  else {
3743  getrusage(RUSAGE_SELF,&rusage);
3744  return((rusage.ru_utime.tv_sec+rusage.ru_stime.tv_sec)*1000
3745  +(rusage.ru_utime.tv_usec/1000+rusage.ru_stime.tv_usec/1000));
3746  }
3747 #endif
3748 #endif
3749 #endif
3750 }
3751 
3752 #endif
3753 
3754 /*
3755  #] Timer :
3756  #[ Crash :
3757 
3758  Routine for debugging purposes
3759 */
3760 
3761 int Crash()
3762 {
3763  int retval;
3764 #ifdef DEBUGGING
3765  int *zero = 0;
3766  retval = *zero;
3767 #else
3768  retval = 0;
3769 #endif
3770  return(retval);
3771 }
3772 
3773 /*
3774  #] Crash :
3775  #[ TestTerm :
3776 */
3777 
3789 int TestTerm(WORD *term)
3790 {
3791  int errorcode = 0, coeffsize;
3792  WORD *t, *tt, *tstop, *endterm, *targ, *targstop, *funstop, *argterm;
3793  endterm = term + *term;
3794  coeffsize = ABS(endterm[-1]);
3795  if ( coeffsize >= *term ) {
3796  MLOCK(ErrorMessageLock);
3797  MesPrint("TestTerm: Internal inconsistency in term. Coefficient too big.");
3798  MUNLOCK(ErrorMessageLock);
3799  errorcode = 1;
3800  goto finish;
3801  }
3802  if ( ( coeffsize < 3 ) || ( ( coeffsize & 1 ) != 1 ) ) {
3803  MLOCK(ErrorMessageLock);
3804  MesPrint("TestTerm: Internal inconsistency in term. Wrong size coefficient.");
3805  MUNLOCK(ErrorMessageLock);
3806  errorcode = 2;
3807  goto finish;
3808  }
3809  t = term+1;
3810  tstop = endterm - coeffsize;
3811  while ( t < tstop ) {
3812  switch ( *t ) {
3813  case SYMBOL:
3814  case DOTPRODUCT:
3815  case INDEX:
3816  case VECTOR:
3817  case DELTA:
3818  case HAAKJE:
3819  break;
3820  case SNUMBER:
3821  case LNUMBER:
3822  MLOCK(ErrorMessageLock);
3823  MesPrint("TestTerm: Internal inconsistency in term. L or S number");
3824  MUNLOCK(ErrorMessageLock);
3825  errorcode = 3;
3826  goto finish;
3827  break;
3828  case EXPRESSION:
3829  case SUBEXPRESSION:
3830  case DOLLAREXPRESSION:
3831 /*
3832  MLOCK(ErrorMessageLock);
3833  MesPrint("TestTerm: Internal inconsistency in term. Expression survives.");
3834  MUNLOCK(ErrorMessageLock);
3835  errorcode = 4;
3836  goto finish;
3837 */
3838  break;
3839  case SETSET:
3840  case MINVECTOR:
3841  case SETEXP:
3842  case ARGFIELD:
3843  MLOCK(ErrorMessageLock);
3844  MesPrint("TestTerm: Internal inconsistency in term. Illegal subterm.");
3845  MUNLOCK(ErrorMessageLock);
3846  errorcode = 5;
3847  goto finish;
3848  break;
3849  case ARGWILD:
3850  break;
3851  default:
3852  if ( *t <= 0 ) {
3853  MLOCK(ErrorMessageLock);
3854  MesPrint("TestTerm: Internal inconsistency in term. Illegal subterm number.");
3855  MUNLOCK(ErrorMessageLock);
3856  errorcode = 6;
3857  goto finish;
3858  }
3859 /*
3860  This is a regular function.
3861 */
3862  if ( *t-FUNCTION >= NumFunctions ) {
3863  MLOCK(ErrorMessageLock);
3864  MesPrint("TestTerm: Internal inconsistency in term. Illegal function number");
3865  MUNLOCK(ErrorMessageLock);
3866  errorcode = 7;
3867  goto finish;
3868  }
3869  funstop = t + t[1];
3870  if ( funstop > tstop ) goto subtermsize;
3871  if ( t[2] != 0 ) {
3872  MLOCK(ErrorMessageLock);
3873  MesPrint("TestTerm: Internal inconsistency in term. Dirty flag nonzero.");
3874  MUNLOCK(ErrorMessageLock);
3875  errorcode = 8;
3876  goto finish;
3877  }
3878  targ = t + FUNHEAD;
3879  if ( targ > funstop ) {
3880  MLOCK(ErrorMessageLock);
3881  MesPrint("TestTerm: Internal inconsistency in term. Illegal function size.");
3882  MUNLOCK(ErrorMessageLock);
3883  errorcode = 9;
3884  goto finish;
3885  }
3886  if ( functions[*t-FUNCTION].spec >= TENSORFUNCTION ) {
3887  }
3888  else {
3889  while ( targ < funstop ) {
3890  if ( *targ < 0 ) {
3891  if ( *targ <= -(FUNCTION+NumFunctions) ) {
3892  MLOCK(ErrorMessageLock);
3893  MesPrint("TestTerm: Internal inconsistency in term. Illegal function number in argument.");
3894  MUNLOCK(ErrorMessageLock);
3895  errorcode = 10;
3896  goto finish;
3897  }
3898  if ( *targ <= -FUNCTION ) { targ++; }
3899  else {
3900  if ( ( *targ != -SYMBOL ) && ( *targ != -VECTOR )
3901  && ( *targ != -MINVECTOR )
3902  && ( *targ != -SNUMBER )
3903  && ( *targ != -ARGWILD )
3904  && ( *targ != -INDEX ) ) {
3905  MLOCK(ErrorMessageLock);
3906  MesPrint("TestTerm: Internal inconsistency in term. Illegal object in argument.");
3907  MUNLOCK(ErrorMessageLock);
3908  errorcode = 11;
3909  goto finish;
3910  }
3911  targ += 2;
3912  }
3913  }
3914  else if ( ( *targ < ARGHEAD ) || ( targ+*targ > funstop ) ) {
3915  MLOCK(ErrorMessageLock);
3916  MesPrint("TestTerm: Internal inconsistency in term. Illegal size of argument.");
3917  MUNLOCK(ErrorMessageLock);
3918  errorcode = 12;
3919  goto finish;
3920  }
3921  else if ( targ[1] != 0 ) {
3922  MLOCK(ErrorMessageLock);
3923  MesPrint("TestTerm: Internal inconsistency in term. Dirty flag in argument.");
3924  MUNLOCK(ErrorMessageLock);
3925  errorcode = 13;
3926  goto finish;
3927  }
3928  else {
3929  targstop = targ + *targ;
3930  argterm = targ + ARGHEAD;
3931  while ( argterm < targstop ) {
3932  if ( ( *argterm < 4 ) || ( argterm + *argterm > targstop ) ) {
3933  MLOCK(ErrorMessageLock);
3934  MesPrint("TestTerm: Internal inconsistency in term. Illegal termsize in argument.");
3935  MUNLOCK(ErrorMessageLock);
3936  errorcode = 14;
3937  goto finish;
3938  }
3939  if ( TestTerm(argterm) != 0 ) {
3940  MLOCK(ErrorMessageLock);
3941  MesPrint("TestTerm: Internal inconsistency in term. Called from TestTerm.");
3942  MUNLOCK(ErrorMessageLock);
3943  errorcode = 15;
3944  goto finish;
3945  }
3946  argterm += *argterm;
3947  }
3948  targ = targstop;
3949  }
3950  }
3951  }
3952  break;
3953  }
3954  tt = t + t[1];
3955  if ( tt > tstop ) {
3956 subtermsize:
3957  MLOCK(ErrorMessageLock);
3958  MesPrint("TestTerm: Internal inconsistency in term. Illegal subterm size.");
3959  MUNLOCK(ErrorMessageLock);
3960  errorcode = 100;
3961  goto finish;
3962  }
3963  t = tt;
3964  }
3965  return(errorcode);
3966 finish:
3967  return(errorcode);
3968 }
3969 
3970 /*
3971  #] TestTerm :
3972  #] Mixed :
3973 */
UBYTE * pointer
Definition: structs.h:692
char * name
Definition: structs.h:970
int PutPreVar(UBYTE *, UBYTE *, UBYTE *, int)
Definition: pre.c:642
UBYTE * buffer
Definition: structs.h:691
Definition: structs.h:633
int size
Definition: structs.h:209
#define NUMBERMEMSTARTNUM
Definition: tools.c:2574
UBYTE * top
Definition: structs.h:693
int num
Definition: structs.h:207
#define TERMMEMSTARTNUM
Definition: tools.c:2474
UBYTE * FoldName
Definition: structs.h:694
LONG TimeWallClock(WORD)
Definition: tools.c:3404
int CopyFile(char *, char *)
Definition: tools.c:1029
LONG PF_BroadcastNumber(LONG x)
Definition: parallel.c:2083
void * lijst
Definition: structs.h:205
UBYTE * name
Definition: structs.h:695
char * message
Definition: structs.h:206
int PF_Bcast(void *buffer, int count)
Definition: mpi.c:440
int maxnum
Definition: structs.h:208
Definition: structs.h:204
struct bit_field * one_byte
Definition: structs.h:909
LONG PF_WriteFileToFile(int handle, UBYTE *buffer, LONG size)
Definition: parallel.c:4371
UBYTE * pname
Definition: structs.h:696
int TestTerm(WORD *)
Definition: tools.c:3789
LONG TimeCPU(WORD)
Definition: tools.c:3478
struct bit_field set_of_char[32]
Definition: structs.h:903
int handle
Definition: structs.h:971