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