FORM v5.0.0-35-g6318119
startup.c
Go to the documentation of this file.
1
8/* #[ License : */
9/*
10 * Copyright (C) 1984-2026 J.A.M. Vermaseren
11 * When using this file you are requested to refer to the publication
12 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
13 * This is considered a matter of courtesy as the development was paid
14 * for by FOM the Dutch physics granting agency and we would like to
15 * be able to track its scientific use to convince FOM of its value
16 * for the community.
17 *
18 * This file is part of FORM.
19 *
20 * FORM is free software: you can redistribute it and/or modify it under the
21 * terms of the GNU General Public License as published by the Free Software
22 * Foundation, either version 3 of the License, or (at your option) any later
23 * version.
24 *
25 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
26 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
27 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
28 * details.
29 *
30 * You should have received a copy of the GNU General Public License along
31 * with FORM. If not, see <http://www.gnu.org/licenses/>.
32 */
33/* #] License : */
34/*
35 #[ includes :
36*/
37
38#include "form3.h"
39#include "inivar.h"
40
41#ifdef TRAPSIGNALS
42#include "portsignals.h"
43#else
44#include <signal.h>
45#endif
46#ifdef ENABLE_BACKTRACE
47 #include <execinfo.h>
48#ifdef LINUX
49 #include <stdint.h>
50 #include <inttypes.h>
51#endif
52#endif
53
54/*
55 * A macro for translating the contents of `x' into a string after expanding.
56 */
57#define STRINGIFY(x) STRINGIFY__(x)
58#define STRINGIFY__(x) #x
59
60/*
61 * FORMNAME = "FORM" or "TFORM" or "ParFORM".
62 */
63#if defined(WITHPTHREADS)
64 #define FORMNAME "TFORM"
65#elif defined(WITHMPI)
66 #define FORMNAME "ParFORM"
67#else
68 #define FORMNAME "FORM"
69#endif
70
71/*
72 * VERSIONSTR is the version information printed in the header line.
73 */
74#ifdef HAVE_CONFIG_H
75 /* We have also version.h. */
76 #include "version.h"
77 #ifndef REPO_VERSION
78 #define REPO_VERSION STRINGIFY(REPO_MAJOR_VERSION) "." STRINGIFY(REPO_MINOR_VERSION) "." STRINGIFY(REPO_PATCH_VERSION)
79 #endif
80 #ifndef REPO_DATE
81 /* The build date, instead of the repo date. */
82 #define REPO_DATE __DATE__
83 #endif
84 #ifdef REPO_REVISION
85 #define VERSIONSTR FORMNAME " " REPO_VERSION " (" REPO_DATE ", " REPO_REVISION ")"
86 #else
87 #define VERSIONSTR FORMNAME " " REPO_VERSION " (" REPO_DATE ")"
88 #endif
89 #define MAJORVERSION REPO_MAJOR_VERSION
90 #define MINORVERSION REPO_MINOR_VERSION
91 #define PATCHVERSION REPO_PATCH_VERSION
92#else
93 /*
94 * Otherwise, form3.h defines MAJORVERSION, MINORVERSION, PATCHVERSION
95 * and PRODUCTIONDATE, possibly BETAVERSION.
96 */
97 #ifdef BETAVERSION
98 #define VERSIONSTR__ STRINGIFY(MAJORVERSION) "." STRINGIFY(MINORVERSION) "." STRINGIFY(PATCHVERSION) "Beta"
99 #else
100 #define VERSIONSTR__ STRINGIFY(MAJORVERSION) "." STRINGIFY(MINORVERSION) "." STRINGIFY(PATCHVERSION)
101 #endif
102 #define VERSIONSTR FORMNAME " " VERSIONSTR__ " (" PRODUCTIONDATE ")"
103#endif
104
105/*
106 #] includes :
107 #[ PrintHeader :
108*/
109
116static void PrintBuildInfo(void) {
117#if defined(__INTEL_LLVM_COMPILER)
118 MesPrint("Compiler: Intel LLVM oneAPI %d",__INTEL_LLVM_COMPILER);
119#elif defined(__INTEL_COMPILER)
120 MesPrint("Compiler: Intel Classic %d",__INTEL_COMPILER);
121#elif defined(__clang__) && defined(__apple_build_version__)
122 MesPrint("Compiler: Apple Clang %d.%d.%d (build %d)",__clang_major__,__clang_minor__,__clang_patchlevel__,__apple_build_version__);
123#elif defined(__clang__)
124 MesPrint("Compiler: Clang %d.%d.%d",__clang_major__,__clang_minor__,__clang_patchlevel__);
125#elif defined(__GNUC__)
126 MesPrint("Compiler: GCC %d.%d.%d",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__);
127#elif defined(_MSC_VER)
128 MesPrint("Compiler: MSVC %d",_MSC_VER);
129#else
130 MesPrint("Compiler: Unknown");
131#endif
132
133#if defined(__x86_64__) || defined(_M_X64)
134 MesPrint("Architecture: x86_64");
135#elif defined(__i386__) || defined(_M_IX86)
136 MesPrint("Architecture: x86 (32-bit)");
137#elif defined(__aarch64__) || defined(_M_ARM64)
138 MesPrint("Architecture: arm64");
139#elif defined(__arm__) || defined(_M_ARM)
140 MesPrint("Architecture: arm (32-bit)");
141#else
142 MesPrint("Architecture: Unknown");
143#endif
144}
145
154static void PrintHeader(int par)
155{
156#ifdef WITHMPI
157 if ( PF.me == MASTER && !AM.silent ) {
158#else
159 if ( !AM.silent ) {
160#endif
161 char buffer1[250], buffer2[80], *s = buffer1, *t = buffer2;
162 WORD length, n;
163 for ( n = 0; n < 250; n++ ) buffer1[n] = ' ';
164 /*
165 * NOTE: we expect that the compiler optimizes strlen("string literal")
166 * to just a number.
167 */
168 if ( strlen(VERSIONSTR) <= 100 ) {
169 strcpy(s,VERSIONSTR);
170 s += strlen(VERSIONSTR);
171 *s = 0;
172 }
173 else {
174 /*
175 * Truncate when it is too long.
176 */
177 strncpy(s,VERSIONSTR,97);
178 s[97] = '.';
179 s[98] = '.';
180 s[99] = ')';
181 s[100] = '\0';
182 s += 100;
183 }
184/*
185 By now we omit the message about 32/64 bits. It should all be 64.
186
187 s += snprintf(s,250-(s-buffer1)," %d-bits",(WORD)(sizeof(WORD)*16));
188 *s = 0;
189*/
190 if ( par == 1 ) {
191#if defined(WITHPTHREADS) || defined(WITHMPI)
192#if defined(WITHPTHREADS)
193 int nworkers = AM.totalnumberofthreads-1;
194#elif defined(WITHMPI)
195 int nworkers = PF.numtasks-1;
196#endif
197 s += snprintf(s,250-(s-buffer1)," %d worker",nworkers);
198 *s = 0;
199/* while ( *s ) s++; */
200 if ( nworkers != 1 ) {
201 *s++ = 's';
202 *s = '\0';
203 }
204#endif
205
206 snprintf(t,80-(t-buffer2),"Run: %s",MakeDate());
207 while ( *t ) t++;
208
209 /*
210 * Align the date to the right, if it fits in a line.
211 */
212 length = (s-buffer1) + (t-buffer2);
213 if ( length+2 <= AC.LineLength ) {
214 for ( n = AC.LineLength-length; n > 0; n-- ) *s++ = ' ';
215 *s = 0;
216 strcat(s,buffer2);
217 while ( *s ) s++;
218 }
219 else {
220 *s = 0;
221 strcat(s," ");
222 while ( *s ) s++;
223 *s = 0;
224 strcat(s,buffer2);
225 while ( *s ) s++;
226 }
227 }
228
229 /*
230 * If the header information doesn't fit in a line, we need to extend
231 * the line length temporarily.
232 */
233 length = s-buffer1;
234 if ( length <= AC.LineLength ) {
235 MesPrint("%s",buffer1);
236 }
237 else {
238 WORD oldLineLength = AC.LineLength;
239 AC.LineLength = length;
240 MesPrint("%s",buffer1);
241 AC.LineLength = oldLineLength;
242 }
243
244 if ( par == 2 ) {
246 PrintBuildInfo();
247 }
248 }
249#ifdef WINDOWS
250 PrintDeprecation("the native Windows version", "issues/623");
251#endif
252#if BITSINWORD == 16
253 PrintDeprecation("the 32-bit version", "issues/624");
254#endif
255#ifdef WITHMPI
256 PrintDeprecation("the MPI version (ParFORM)", "issues/625");
257#endif
258 if ( AC.CheckpointFlag ) {
259 PrintDeprecation("the checkpoint mechanism", "issues/626");
260 }
261}
262
263/*
264 #] PrintHeader :
265 #[ DoTail :
266
267 Routine reads the command tail and handles the commandline options.
268 It sets the flags for later actions and stored pathnames for
269 the setup file, include/prc/sub directories etc.
270 Finally the name of the program is passed on.
271 Note that we do not support interactive use yet. This will come
272 to pass in the distant future when we can couple STedi to FORM.
273 Routine made 23-feb-1993 by J.Vermaseren
274*/
275
276#ifdef WITHINTERACTION
277static UBYTE deflogname[] = "formsession.log";
278#endif
279
280#define TAKEPATH(x) if(s[1]== '=' ){x=s+2;} else{x=*argv++;argc--;}
281
282int DoTail(int argc, UBYTE **argv)
283{
284 int errorflag = 0, onlyversion = 1;
285 UBYTE *s, *t, *copy;
286 int threadnum = 0;
287 argc--; argv++;
288 AM.ClearStore = 0;
289 AM.TimeLimit = 0;
290 AM.LogType = -1;
291 AM.HoldFlag = AM.qError = AM.Interact = AM.FileOnlyFlag = 0;
292 AM.InputFileName = AM.LogFileName = AM.IncDir = AM.TempDir = AM.TempSortDir =
293 AM.SetupDir = AM.SetupFile = AM.Path = 0;
294 AM.FromStdin = 0;
295 /* Always use MultiRun, "-M" option is now ignored. */
296 AM.MultiRun = 1;
297 if ( argc < 1 ) {
298 onlyversion = 0;
299 goto printversion;
300 }
301 while ( argc >= 1 ) {
302 s = *argv++; argc--;
303 if ( *s == '-' || ( *s == '/' && ( argc > 0 || AM.Interact ) ) ) {
304 s++;
305 switch (*s) {
306 case 'c': /* Error checking only */
307 AM.qError = 1; break;
308 case 'C': /* Next arg is filename of log file */
309 TAKEPATH(AM.LogFileName) break;
310 case 'D':
311 case 'd': /* Next arg is define preprocessor var. */
312 t = copy = strDup1(*argv,"Dotail");
313 while ( *t && *t != '=' ) t++;
314 if ( *t == 0 ) {
315 if ( PutPreVar(copy,(UBYTE *)"1",0,0) < 0 ) return(-1);
316 }
317 else {
318 *t++ = 0;
319 if ( PutPreVar(copy,t,0,0) < 0 ) return(-1);
320 t[-1] = '=';
321 }
322 M_free(copy,"-d prevar");
323 argv++; argc--; break;
324 case 'f': /* Output only to regular log file */
325 AM.FileOnlyFlag = 1; AM.LogType = 0; break;
326 case 'F': /* Output only to log file. Further like L. */
327 AM.FileOnlyFlag = 1; AM.LogType = 1; break;
328 case 'h': /* For old systems: wait for key before exit */
329 AM.HoldFlag = 1; break;
330 case 'i':
331 if ( StrCmp(s, (UBYTE *)"ignore-deprecation") == 0 ) {
332 AM.IgnoreDeprecation = 1;
333 break;
334 }
335#ifdef WITHINTERACTION
336 /* Interactive session (not used yet) */
337 AM.Interact = 1;
338 break;
339#else
340 goto IllegalOption;
341#endif
342 case 'I': /* Next arg is dir for inc/prc/sub files */
343 TAKEPATH(AM.IncDir) break;
344 case 'l': /* Make regular log file */
345 if ( s[1] == 'l' ) AM.LogType = 1; /*compatibility! */
346 else AM.LogType = 0;
347 break;
348 case 'L': /* Make log file with only final statistics */
349 AM.LogType = 1; break;
350 case 'M': /* Multirun. Name of tempfiles will contain PID */
351 /* This option is now ignored. We always use MultiRun. */
352 /* AM.MultiRun = 1; */
353 break;
354 case 'm': /* Read number of threads */
355 case 'w': /* Read number of workers */
356 t = s++;
357 threadnum = 0;
358 while ( *s >= '0' && *s <= '9' )
359 threadnum = 10*threadnum + *s++ - '0';
360 if ( *s ) {
361#ifdef WITHMPI
362 if ( PF.me == MASTER )
363#endif
364 printf("Illegal value for option m or w: %s\n",t);
365 errorflag++;
366 }
367/* if ( threadnum == 1 ) threadnum = 0; */
368 threadnum++;
369 break;
370 case 'W': /* Print the wall-clock time on the master. */
371 AM.ggWTimeStatsFlag = 1;
372 break;
373/*
374 case 'n':
375 Reserved for number of slaves without MPI
376*/
377 case 'p':
378#ifdef WITHEXTERNALCHANNEL
379 /*There are two possibilities: -p|-pipe*/
380 if(s[1]=='i'){
381 if( (s[2]=='p')&&(s[3]=='e')&&(s[4]=='\0') ){
382 argc--;
383 /*Initialize pre-set external channels, see
384 the file extcmd.c:*/
385 if(initPresetExternalChannels(*argv++,AX.timeout)<1){
386#ifdef WITHMPI
387 if ( PF.me == MASTER )
388#endif
389 printf("Error initializing preset external channels\n");
390 errorflag++;
391 }
392 AX.timeout=-1;/*This indicates that preset channels
393 are initialized from cmdline*/
394 }else{
395#ifdef WITHMPI
396 if ( PF.me == MASTER )
397#endif
398 printf("Illegal option in call of FORM: %s\n",s);
399 errorflag++;
400 }
401 }else
402#else
403 if ( s[1] ) {
404 if ( ( s[1]=='i' ) && ( s[2] == 'p' ) && (s[3] == 'e' )
405 && ( s[4] == '\0' ) ){
406#ifdef WITHMPI
407 if ( PF.me == MASTER )
408#endif
409 printf("Illegal option: Pipes not supported on this system.\n");
410 }
411 else {
412#ifdef WITHMPI
413 if ( PF.me == MASTER )
414#endif
415 printf("Illegal option: %s\n",s);
416 }
417 errorflag++;
418 }
419 else
420#endif
421 {
422 /* Next arg is a path variable like in environment */
423 TAKEPATH(AM.Path)
424 }
425 break;
426 case 'q': /* Quiet option. Only output. Same as -si */
427 AM.silent = 1; break;
428 case 'R': /* recover from saved snapshot */
429 AC.CheckpointFlag = -1;
430 break;
431 case 's': /* Next arg is dir with form.set to be used */
432 if ( ( s[1] == 'o' ) && ( s[2] == 'r' ) && ( s[3] == 't' ) ) {
433 if(s[4]== '=' ) {
434 AM.TempSortDir = s+5;
435 }
436 else {
437 AM.TempSortDir = *argv++;
438 argc--;
439 }
440 }
441 else if ( s[1] == 'i' ) { /* compatibility: silent/quiet */
442 AM.silent = 1;
443 }
444 else {
445 TAKEPATH(AM.SetupDir)
446 }
447 break;
448 case 'S': /* Next arg is setup file */
449 TAKEPATH(AM.SetupFile) break;
450 case 't': /* Next arg is directory for temp files */
451 if ( s[1] == 's' ) {
452 s++;
453 AM.havesortdir = 1;
454 TAKEPATH(AM.TempSortDir)
455 }
456 else {
457 TAKEPATH(AM.TempDir)
458 }
459 break;
460 case 'T': /* Print the total size used at end of job */
461 AM.PrintTotalSize = 1; break;
462 case 'v': /* Print version information */
463 AC.FinalStats = 0;
464 if ( s[1] == 'v' ) { /* verbose version information */
465 PrintHeader(2);
466 return(1);
467 }
468printversion:;
469 PrintHeader(0);
470 if ( onlyversion ) return(1);
471 goto NoFile;
472 case 'y': /* Preprocessor dumps output. No compilation. */
473 AP.PreDebug = PREPROONLY; break;
474 case 'z': /* The number following is a time limit in sec. */
475 t = s++;
476 AM.TimeLimit = 0;
477 while ( *s >= '0' && *s <= '9' )
478 AM.TimeLimit = 10*AM.TimeLimit + *s++ - '0';
479 break;
480 case 'Z': /* Removes the .str file on crash, no matter its contents */
481 AM.ClearStore = 1; break;
482 case '\0': /* "-" to use STDIN for the input. */
483#ifdef WITHMPI
484 /* At the moment, ParFORM doesn't implement STDIN broadcasts. */
485 if ( PF.me == MASTER )
486 printf("Sorry, reading STDIN as input is currently not supported by ParFORM\n");
487 errorflag++;
488#endif
489 AM.FromStdin = 1;
490 AC.NoShowInput = 1; // disable input echoing by default
491 break;
492 default:
493 if ( FG.cTable[*s] == 1 ) {
494 AM.SkipClears = 0; t = s;
495 while ( FG.cTable[*t] == 1 )
496 AM.SkipClears = 10*AM.SkipClears + *t++ - '0';
497 if ( *t != 0 ) {
498#ifdef WITHMPI
499 if ( PF.me == MASTER )
500#endif
501 printf("Illegal numerical option in call of FORM: %s\n",s);
502 errorflag++;
503 }
504 }
505 else {
506IllegalOption:
507#ifdef WITHMPI
508 if ( PF.me == MASTER )
509#endif
510 printf("Illegal option in call of FORM: %s\n",s);
511 errorflag++;
512 }
513 break;
514 }
515 }
516 else if ( argc == 0 && !AM.Interact ) AM.InputFileName = argv[-1];
517 else {
518#ifdef WITHMPI
519 if ( PF.me == MASTER )
520#endif
521 printf("Illegal option in call of FORM: %s\n",s);
522 errorflag++;
523 }
524 }
525 AM.totalnumberofthreads = threadnum;
526 if ( AM.InputFileName ) {
527 if ( AM.FromStdin ) {
528 printf("STDIN and the input filename cannot be specified simultaneously\n");
529 errorflag++;
530 }
531 s = AM.InputFileName;
532 while ( *s ) s++;
533 if ( s < AM.InputFileName+4 ||
534 s[-4] != '.' || s[-3] != 'f' || s[-2] != 'r' || s[-1] != 'm' ) {
535 t = (UBYTE *)Malloc1((s-AM.InputFileName)+5,"adding .frm");
536 s = AM.InputFileName;
537 AM.InputFileName = t;
538 while ( *s ) *t++ = *s++;
539 *t++ = '.'; *t++ = 'f'; *t++ = 'r'; *t++ = 'm'; *t = 0;
540 }
541 if ( AM.LogType >= 0 && AM.LogFileName == 0 ) {
542 AM.LogFileName = strDup1(AM.InputFileName,"name of logfile");
543 s = AM.LogFileName;
544 while ( *s ) s++;
545 s[-3] = 'l'; s[-2] = 'o'; s[-1] = 'g';
546 }
547 }
548#ifdef WITHINTERACTION
549 else if ( AM.Interact ) {
550 if ( AM.LogType >= 0 ) {
551/*
552 We may have to do better than just taking a name.
553 It is not unique! This will be left for later.
554*/
555 AM.LogFileName = deflogname;
556 }
557 }
558#endif
559 else if ( AM.FromStdin ) {
560 /* Do nothing. */
561 }
562 else {
563NoFile:
564#ifdef WITHMPI
565 if ( PF.me == MASTER )
566#endif
567 printf("No filename specified in call of FORM\n");
568 errorflag++;
569 }
570 if ( AM.Path == 0 ) AM.Path = (UBYTE *)getenv("FORMPATH");
571 if ( AM.Path ) {
572 /*
573 * AM.Path is taken from argv or getenv. Reallocate it to avoid invalid
574 * frees when AM.Path has to be changed.
575 */
576 AM.Path = strDup1(AM.Path,"DoTail Path");
577 }
578 return(errorflag);
579}
580
581/*
582 #] DoTail :
583 #[ OpenInput :
584
585 Major task here after opening is to skip the proper number of
586 .clear instructions if so desired without using interpretation
587*/
588
589int OpenInput(void)
590{
591 int oldNoShowInput = AC.NoShowInput;
592 UBYTE c;
593 if ( !AM.Interact ) {
594 if ( AM.FromStdin ) {
595 if ( OpenStream(0,INPUTSTREAM,0,PRENOACTION) == 0 ) {
596 Error0("Cannot open STDIN");
597 return(-1);
598 }
599 }
600 else {
601 if ( OpenStream(AM.InputFileName,FILESTREAM,0,PRENOACTION) == 0 ) {
602 Error1("Cannot open file",AM.InputFileName);
603 return(-1);
604 }
605 if ( AC.CurrentStream->inbuffer <= 0 ) {
606 Error1("No input in file",AM.InputFileName);
607 return(-1);
608 }
609 }
610 AC.NoShowInput = 1;
611 while ( AM.SkipClears > 0 ) {
612 c = GetInput();
613 if ( c == ENDOFINPUT ) {
614 Error0("Not enough .clear instructions in input file");
615 }
616 if ( c == '\\' ) {
617 c = GetInput();
618 if ( c == ENDOFINPUT )
619 Error0("Not enough .clear instructions in input file");
620 continue;
621 }
622 if ( c == ' ' || c == '\t' ) continue;
623 if ( c == '.' ) {
624 c = GetInput();
625 if ( tolower(c) == 'c' ) {
626 c = GetInput();
627 if ( tolower(c) == 'l' ) {
628 c = GetInput();
629 if ( tolower(c) == 'e' ) {
630 c = GetInput();
631 if ( tolower(c) == 'a' ) {
632 c = GetInput();
633 if ( tolower(c) == 'r' ) {
634 c = GetInput();
635 if ( FG.cTable[c] > 2 ) {
636 AM.SkipClears--;
637 }
638 }
639 }
640 }
641 }
642 }
643 while ( c != '\n' && c != '\r' && c != ENDOFINPUT ) {
644 c = GetInput();
645 if ( c == '\\' ) c = GetInput();
646 }
647 }
648 else if ( c == '\n' || c == '\r' ) continue;
649 else {
650 while ( ( c = GetInput() ) != '\n' && c != '\r' ) {
651 if ( c == ENDOFINPUT ) {
652 Error0("Not enough .clear instructions in input file");
653 }
654 }
655 }
656 }
657 AC.NoShowInput = oldNoShowInput;
658 }
659 if ( AM.LogFileName ) {
660#ifdef WITHMPI
661 if ( PF.me != MASTER ) {
662 /*
663 * Only the master writes to the log file. On slaves, we need
664 * a dummy handle, without opening the file.
665 */
666 extern FILES **filelist; /* in tools.c */
667 int i = CreateHandle();
668 RWLOCKW(AM.handlelock);
669 filelist[i] = (FILES *)123; /* Must be nonzero to prevent a reuse in CreateHandle. */
670 UNRWLOCK(AM.handlelock);
671 AC.LogHandle = i;
672 }
673 else
674#endif
675 if ( AC.CheckpointFlag != -1 ) {
676 if ( ( AC.LogHandle = CreateLogFile((char *)(AM.LogFileName)) ) < 0 ) {
677 Error1("Cannot create logfile",AM.LogFileName);
678 return(-1);
679 }
680 }
681 else {
682 if ( ( AC.LogHandle = OpenAddFile((char *)(AM.LogFileName)) ) < 0 ) {
683 Error1("Cannot re-open logfile",AM.LogFileName);
684 return(-1);
685 }
686 }
687 }
688 return(0);
689}
690
691/*
692 #] OpenInput :
693 #[ ReserveTempFiles :
694
695 Order of preference:
696 a: if there is a path in the commandtail, take that.
697 b: if none, try in the form.set file.
698 c: if still none, try in the environment for the variable FORMTMP
699 d: if still none, try the current directory.
700
701 The parameter indicates action in the case of multithreaded running.
702 par = 0 : We just run on a single processor. Keep everything normal.
703 par = 1 : Multithreaded running startup phase 1.
704 par = 2 : Multithreaded running startup phase 2.
705*/
706
707UBYTE *emptystring = (UBYTE *)".";
708UBYTE *defaulttempfilename = (UBYTE *)"xformxxx.str";
709/* This is the length of the above default, but with 7 spaces for PID digits
710 instead of the "xxx". (Previously FORM used 5 digits and this value was 14) */
711#define DEFAULTFNAMELENGTH 16
712
713void ReserveTempFiles(int par)
714{
715 GETIDENTITY
716 SETUPPARAMETERS *sp;
717 UBYTE *s, *t, *tenddir, *tenddir2, c;
718 int i = 0;
719 WORD j;
720 if ( par == 0 || par == 1 ) {
721 if ( AM.TempDir == 0 ) {
722 sp = GetSetupPar((UBYTE *)"tempdir");
723 if ( ( sp->flags & USEDFLAG ) != USEDFLAG ) {
724 AM.TempDir = (UBYTE *)getenv("FORMTMP");
725 if ( AM.TempDir == 0 ) AM.TempDir = emptystring;
726 }
727 else AM.TempDir = (UBYTE *)(sp->value);
728 }
729 if ( AM.TempSortDir == 0 ) {
730 if ( AM.havesortdir ) {
731 sp = GetSetupPar((UBYTE *)"tempsortdir");
732 AM.TempSortDir = (UBYTE *)(sp->value);
733 }
734 else {
735 AM.TempSortDir = (UBYTE *)getenv("FORMTMPSORT");
736 if ( AM.TempSortDir == 0 ) AM.TempSortDir = AM.TempDir;
737 }
738 }
739/*
740 We have now in principle a path but we will use its first element only.
741 Later that should become more complicated. Then we will use a path and
742 when one device is full we can continue on the next one.
743*/
744 s = AM.TempDir; i = 200; /* Some extra for VMS */
745 while ( *s && *s != PATHSEPARATOR ) { if ( *s == '\\' ) s++; s++; i++; }
746 FG.fnamesize = sizeof(UBYTE)*(i+DEFAULTFNAMELENGTH);
747 FG.fname = (char *)Malloc1(FG.fnamesize,"name for temporary files");
748 s = AM.TempDir; t = (UBYTE *)FG.fname;
749 while ( *s && *s != PATHSEPARATOR ) { if ( *s == '\\' ) s++; *t++ = *s++; }
750 if ( (char *)t > FG.fname && t[-1] != SEPARATOR && t[-1] != ALTSEPARATOR )
751 *t++ = SEPARATOR;
752 *t = 0;
753 tenddir = t;
754 FG.fnamebase = t-(UBYTE *)(FG.fname);
755
756 s = AM.TempSortDir; i = 200; /* Some extra for VMS */
757 while ( *s && *s != PATHSEPARATOR ) { if ( *s == '\\' ) s++; s++; i++; }
758
759 FG.fname2size = sizeof(UBYTE)*(i+DEFAULTFNAMELENGTH);
760 FG.fname2 = (char *)Malloc1(FG.fname2size,"name for sort files");
761 s = AM.TempSortDir; t = (UBYTE *)FG.fname2;
762 while ( *s && *s != PATHSEPARATOR ) { if ( *s == '\\' ) s++; *t++ = *s++; }
763 if ( (char *)t > FG.fname2 && t[-1] != SEPARATOR && t[-1] != ALTSEPARATOR )
764 *t++ = SEPARATOR;
765 *t = 0;
766 tenddir2 = t;
767 FG.fname2base = t-(UBYTE *)(FG.fname2);
768
769 t = tenddir;
770 s = defaulttempfilename;
771#ifdef WITHMPI
772 {
773 int iii;
774 iii = snprintf((char*)t,FG.fnamesize-((char*)t-FG.fname),"%d",PF.me);
775 t+= iii;
776 s+= iii; /* in case defaulttmpfilename is too short */
777 }
778#endif
779 while ( *s ) *t++ = *s++;
780 *t = 0;
781/*
782 There are problems when running many FORM jobs at the same time
783 from make or minos. If they start up simultaneously, occasionally
784 they can make the same .str file. We prevent this with first trying
785 a file that contains the digits of the pid. If this file
786 has already been taken we fall back on the old scheme.
787 The whole is controlled with the -M (MultiRun) parameter in the
788 command tail.
789*/
790 if ( AM.MultiRun ) {
791 int num = ((int)GetPID())%10000000;
792 t += 4;
793 *t = 0;
794 t[-1] = 'r';
795 t[-2] = 't';
796 t[-3] = 's';
797 t[-4] = '.';
798 t[-5] = (UBYTE)('0' + num%10);
799 t[-6] = (UBYTE)('0' + (num/10)%10);
800 t[-7] = (UBYTE)('0' + (num/100)%10);
801 t[-8] = (UBYTE)('0' + (num/1000)%10);
802 t[-9] = (UBYTE)('0' + (num/10000)%10);
803 t[-10] = (UBYTE)('0' + (num/100000)%10);
804 t[-11] = (UBYTE)('0' + num/1000000);
805 if ( ( AC.StoreHandle = CreateFile((char *)FG.fname) ) < 0 ) {
806 t[-5] = 'x'; t[-6] = 'x'; t[-7] = 'x'; t[-8] = 'x'; t[-9] = 'x'; t[-10] = 'x'; t[-11] = 'x';
807 goto classic;
808 }
809 }
810 else
811 {
812classic:;
813 for(;;) {
814 if ( ( AC.StoreHandle = OpenFile((char *)FG.fname) ) < 0 ) {
815 if ( ( AC.StoreHandle = CreateFile((char *)FG.fname) ) >= 0 ) break;
816 }
817 else CloseFile(AC.StoreHandle);
818 c = t[-5];
819 if ( c == 'x' ) t[-5] = '0';
820 else if ( c == '9' ) {
821 t[-5] = '0';
822 c = t[-6];
823 if ( c == 'x' ) t[-6] = '0';
824 else if ( c == '9' ) {
825 t[-6] = '0';
826 c = t[-7];
827 if ( c == 'x' ) t[-7] = '0';
828 else if ( c == '9' ) {
829/*
830 Note that we tried 1111 names!
831*/
832 MesPrint("Name space for temp files exhausted");
833 t[-7] = 0;
834 MesPrint("Please remove files of the type %s or try a different directory"
835 ,FG.fname);
836 Terminate(-1);
837 }
838 else t[-7] = (UBYTE)(c+1);
839 }
840 else t[-6] = (UBYTE)(c+1);
841 }
842 else t[-5] = (UBYTE)(c+1);
843 }
844 }
845/*
846 Now we should make sure that the tempsortdir cq tempsortfilename makes it
847 into a similar construction.
848*/
849 s = tenddir; t = tenddir2; while ( *s ) *t++ = *s++;
850 *t = 0;
851
852/*
853 Now we should assign a name to the main sort file and the two stage 4 files.
854*/
855 AM.S0->file.name = (char *)Malloc1(sizeof(char)*(i+DEFAULTFNAMELENGTH),"name for temporary files");
856 s = (UBYTE *)AM.S0->file.name;
857 t = (UBYTE *)FG.fname2;
858 i = 1;
859 while ( *t ) { *s++ = *t++; i++; }
860 s[-2] = 'o'; *s = 0;
861 }
862/*
863 Try to create the sort file already, so we can Terminate earlier if this fails.
864*/
865#ifdef WITHPTHREADS
866 if ( par <= 1 ) {
867#endif
868 if ( ( AM.S0->file.handle = CreateFile((char *)AM.S0->file.name) ) < 0 ) {
869 MesPrint("Could not create sort file: %s", AM.S0->file.name);
870 Terminate(-1);
871 };
872 /* Close and clean up the test file */
873 CloseFile(AM.S0->file.handle);
874 AM.S0->file.handle = -1;
875 remove(AM.S0->file.name);
876#ifdef WITHPTHREADS
877 }
878#endif
879/*
880 With the stage4 and scratch file names we have to be a bit more careful.
881 They are to be allocated after the threads are initialized when there
882 are threads of course.
883*/
884 if ( par == 0 ) {
885 s = (UBYTE *)((void *)(FG.fname2)); i = 0;
886 while ( *s ) { s++; i++; }
887 /* +1 for null terminator */
888 s = (UBYTE *)Malloc1(sizeof(char)*(i+1),"name for stage4 file a");
889 AR.FoStage4[1].name = (char *)s;
890 t = (UBYTE *)FG.fname2;
891 while ( *t ) *s++ = *t++;
892 s[-2] = '4'; s[-1] = 'a'; *s = 0;
893 s = (UBYTE *)((void *)(FG.fname)); i = 0;
894 while ( *s ) { s++; i++; }
895 /* +1 for null terminator */
896 s = (UBYTE *)Malloc1(sizeof(char)*(i+1),"name for stage4 file b");
897 AR.FoStage4[0].name = (char *)s;
898 t = (UBYTE *)FG.fname;
899 while ( *t ) *s++ = *t++;
900 s[-2] = '4'; s[-1] = 'b'; *s = 0;
901 for ( j = 0; j < 3; j++ ) {
902 /* +1 for null terminator */
903 s = (UBYTE *)Malloc1(sizeof(char)*(i+1),"name for scratch file");
904 AR.Fscr[j].name = (char *)s;
905 t = (UBYTE *)FG.fname;
906 while ( *t ) *s++ = *t++;
907 s[-2] = 'c'; s[-1] = (UBYTE)('0'+j); *s = 0;
908 }
909 }
910#ifdef WITHPTHREADS
911 else if ( par == 2 ) {
912 size_t tname;
913 s = (UBYTE *)((void *)(FG.fname2)); i = 0;
914 while ( *s ) { s++; i++; }
915 /* +1 for null terminator, +10 for 32bit int, +1 for "." */
916 tname = sizeof(char)*(i+12);
917 s = (UBYTE *)Malloc1(tname,"name for stage4 file a");
918 snprintf((char *)s,tname,"%s.%d",FG.fname2,AT.identity);
919 s[i-2] = '4'; s[i-1] = 'a';
920 AR.FoStage4[1].name = (char *)s;
921 s = (UBYTE *)((void *)(FG.fname)); i = 0;
922 while ( *s ) { s++; i++; }
923 /* +1 for null terminator, +10 for 32bit int, +1 for "." */
924 tname = sizeof(char)*(i+12);
925 s = (UBYTE *)Malloc1(tname,"name for stage4 file b");
926 snprintf((char *)s,tname,"%s.%d",FG.fname,AT.identity);
927 s[i-2] = '4'; s[i-1] = 'b';
928 AR.FoStage4[0].name = (char *)s;
929 if ( AT.identity == 0 ) {
930 for ( j = 0; j < 3; j++ ) {
931 /* +1 for null terminator */
932 s = (UBYTE *)Malloc1(sizeof(char)*(i+1),"name for scratch file");
933 AR.Fscr[j].name = (char *)s;
934 t = (UBYTE *)FG.fname;
935 while ( *t ) *s++ = *t++;
936 s[-2] = 'c'; s[-1] = (UBYTE)('0'+j); *s = 0;
937 }
938 }
939 }
940#endif
941}
942
943/*
944 #] ReserveTempFiles :
945 #[ StartVariables :
946*/
947
948#ifdef WITHPTHREADS
949ALLPRIVATES *DummyPointer = 0;
950#endif
951
953{
954 int i, ii;
955 PUTZERO(AM.zeropos);
956 StartPrepro();
957/*
958 The module counter:
959*/
960 AC.CModule=0;
961#ifdef WITHPTHREADS
962/*
963 We need a value in AB because in the startup some routines may call AB[0].
964*/
965 AB = (ALLPRIVATES **)&DummyPointer;
966#endif
967/*
968 separators used to delimit arguments in #call and #do, by default ',' and '|':
969 Be sure, it is en empty set:
970*/
971 set_sub(AC.separators,AC.separators,AC.separators);
972 set_set(',',AC.separators);
973 set_set('|',AC.separators);
974
975 AM.BracketFactors[0] = 8;
976 AM.BracketFactors[1] = SYMBOL;
977 AM.BracketFactors[2] = 4;
978 AM.BracketFactors[3] = FACTORSYMBOL;
979 AM.BracketFactors[4] = 1;
980 AM.BracketFactors[5] = 1;
981 AM.BracketFactors[6] = 1;
982 AM.BracketFactors[7] = 3;
983
984 AM.SkipClears = 0;
985 AC.Cnumpows = 0;
986 AC.OutputMode = 72;
987 AC.OutputSpaces = NORMALFORMAT;
988 AC.LineLength = 79;
989 AM.gIsFortran90 = AC.IsFortran90 = ISNOTFORTRAN90;
990 AM.gFortran90Kind = AC.Fortran90Kind = 0;
991 AM.gCnumpows = 0;
992 AC.exprfillwarning = 0;
993 AM.gLineLength = 79;
994 AM.OutBufSize = 80;
995 AM.MaxStreamSize = MAXFILESTREAMSIZE;
996 AP.MaxPreAssignLevel = 4;
997 AC.iBufferSize = 512;
998 AP.pSize = 128;
999 AP.MaxPreIfLevel = 10;
1000 AP.cComChar = AP.ComChar = '*';
1001 AP.firstnamespace = 0;
1002 AP.lastnamespace = 0;
1003 AP.fullnamesize = 127;
1004 AP.fullname = (UBYTE *)Malloc1((AP.fullnamesize+1)*sizeof(UBYTE),"AP.fullname");
1005 AM.OffsetVector = -2*WILDOFFSET+MINSPEC;
1006 AC.cbufList.num = 0;
1007 AM.hparallelflag = AM.gparallelflag =
1008 AC.parallelflag = AC.mparallelflag = PARALLELFLAG;
1009#ifdef WITHMPI
1010 if ( PF.numtasks < 2 ) AM.hparallelflag |= NOPARALLEL_NPROC;
1011#endif
1012 AC.tablefilling = 0;
1013 AC.models = 0;
1014 AC.nummodels = 0;
1015 AC.ModelLevel = 0;
1016 AC.modelspace = 0;
1017 AM.resetTimeOnClear = 1;
1018 AM.gnumextrasym = AM.ggnumextrasym = 0;
1019 AM.havesortdir = 0;
1020 AM.SpectatorFiles = 0;
1021 AM.NumSpectatorFiles = 0;
1022 AM.SizeForSpectatorFiles = 0;
1023/*
1024 Information for the lists of variables. Part of error message and size:
1025*/
1026 AP.ProcList.message = "procedure";
1027 AP.ProcList.size = sizeof(PROCEDURE);
1028 AP.LoopList.message = "doloop";
1029 AP.LoopList.size = sizeof(DOLOOP);
1030 AP.PreVarList.message = "PreVariable";
1031 AP.PreVarList.size = sizeof(PREVAR);
1032 AC.SymbolList.message = "symbol";
1033 AC.SymbolList.size = sizeof(struct SyMbOl);
1034 AC.IndexList.message = "index";
1035 AC.IndexList.size = sizeof(struct InDeX);
1036 AC.VectorList.message = "vector";
1037 AC.VectorList.size = sizeof(struct VeCtOr);
1038 AC.FunctionList.message = "function";
1039 AC.FunctionList.size = sizeof(struct FuNcTiOn);
1040 AC.SetList.message = "set";
1041 AC.SetList.size = sizeof(struct SeTs);
1042 AC.SetElementList.message = "set element";
1043 AC.SetElementList.size = sizeof(WORD);
1044 AC.ExpressionList.message = "expression";
1045 AC.ExpressionList.size = sizeof(struct ExPrEsSiOn);
1046 AC.cbufList.message = "compiler buffer";
1047 AC.cbufList.size = sizeof(CBUF);
1048 AC.ChannelList.message = "channel buffer";
1049 AC.ChannelList.size = sizeof(CHANNEL);
1050 AP.DollarList.message = "$-variable";
1051 AP.DollarList.size = sizeof(struct DoLlArS);
1052 AC.DubiousList.message = "ambiguous variable";
1053 AC.DubiousList.size = sizeof(struct DuBiOuS);
1054 AC.TableBaseList.message = "list of tablebases";
1055 AC.TableBaseList.size = sizeof(DBASE);
1056 AC.TestValue = 0;
1057 AC.InnerTest = 0;
1058
1059 AC.AutoSymbolList.message = "autosymbol";
1060 AC.AutoSymbolList.size = sizeof(struct SyMbOl);
1061 AC.AutoIndexList.message = "autoindex";
1062 AC.AutoIndexList.size = sizeof(struct InDeX);
1063 AC.AutoVectorList.message = "autovector";
1064 AC.AutoVectorList.size = sizeof(struct VeCtOr);
1065 AC.AutoFunctionList.message = "autofunction";
1066 AC.AutoFunctionList.size = sizeof(struct FuNcTiOn);
1067 AC.PotModDolList.message = "potentially modified dollar";
1068 AC.PotModDolList.size = sizeof(WORD);
1069 AC.ModOptDolList.message = "moduleoptiondollar";
1070 AC.ModOptDolList.size = sizeof(MODOPTDOLLAR);
1071
1072 AO.FortDotChar = '_';
1073 AO.ErrorBlock = 0;
1074 AC.firstconstindex = 1;
1075 AO.Optimize.mctsconstant.fval = 1.0;
1076 AO.Optimize.horner = O_MCTS;
1077 AO.Optimize.hornerdirection = O_FORWARDORBACKWARD;
1078 AO.Optimize.method = O_GREEDY;
1079 AO.Optimize.mctstimelimit = 0;
1080 AO.Optimize.mctsnumexpand = 1000;
1081 AO.Optimize.mctsnumkeep = 10;
1082 AO.Optimize.mctsnumrepeat = 1;
1083 AO.Optimize.greedytimelimit = 0;
1084 AO.Optimize.greedyminnum = 10;
1085 AO.Optimize.greedymaxperc = 5;
1086 AO.Optimize.printstats = 0;
1087 AO.Optimize.debugflags = 0;
1088 AO.OptimizeResult.code = NULL;
1089 AO.inscheme = 0;
1090 AO.schemenum = 0;
1091 AO.wpos = 0;
1092 AO.wpoin = 0;
1093 AO.wlen = 0;
1094 AM.dollarzero = 0;
1095 AC.doloopstack = 0;
1096 AC.doloopstacksize = 0;
1097 AC.dolooplevel = 0;
1098/*
1099 Set up the main name trees:
1100*/
1101 AC.varnames = MakeNameTree();
1102 AC.exprnames = MakeNameTree();
1103 AC.dollarnames = MakeNameTree();
1104 AC.autonames = MakeNameTree();
1105 AC.activenames = &(AC.varnames);
1106 AP.preError = 0;
1107/*
1108 Initialize the compiler:
1109*/
1110 inictable();
1111 AM.rbufnum = inicbufs(); /* Regular compiler buffer */
1112#ifndef WITHPTHREADS
1113 AT.ebufnum = inicbufs(); /* Buffer for extras during execution */
1114 AT.fbufnum = inicbufs(); /* Buffer for caching in factorization */
1115 AT.allbufnum = inicbufs(); /* Buffer for id,all */
1116 AT.aebufnum = inicbufs(); /* Buffer for id,all */
1117 AN.tryterm = 0;
1118#else
1119 AS.MasterSort = 0;
1120#endif
1121 AM.dbufnum = inicbufs(); /* Buffer for dollar variables */
1122 AM.sbufnum = inicbufs(); /* Subterm buffer for polynomials and optimization */
1123 AC.ffbufnum = inicbufs(); /* Buffer number for user defined factorizations */
1124 AM.zbufnum = inicbufs(); /* For very special values */
1125 {
1126 CBUF *C = cbuf+AM.zbufnum;
1127 WORD one[5] = {4,1,1,3,0};
1128 WORD zero = 0;
1129 AddRHS(AM.zbufnum,1);
1130 AM.zerorhs = C->numrhs;
1131 AddNtoC(AM.zbufnum,1,&zero,17);
1132 AddRHS(AM.zbufnum,1);
1133 AM.onerhs = C->numrhs;
1134 AddNtoC(AM.zbufnum,5,one,17);
1135 }
1136 AP.inside.inscbuf = inicbufs(); /* For the #inside instruction */
1137/*
1138 Enter the built in objects
1139*/
1140 AC.Symbols = &(AC.SymbolList);
1141 AC.Indices = &(AC.IndexList);
1142 AC.Vectors = &(AC.VectorList);
1143 AC.Functions = &(AC.FunctionList);
1144 AC.vetofilling = 0;
1145
1146 AddDollar((UBYTE *)"$",DOLUNDEFINED,0,0);
1147
1148 cbuf[AM.dbufnum].mnumlhs = cbuf[AM.dbufnum].numlhs;
1149 cbuf[AM.dbufnum].mnumrhs = cbuf[AM.dbufnum].numrhs;
1150
1151 AddSymbol((UBYTE *)"i_",-MAXPOWER,MAXPOWER,VARTYPEIMAGINARY,0);
1152 AddSymbol((UBYTE *)"pi_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1153/*
1154 coeff_ should have the number COEFFSYMBOL and den_ the number DENOMINATOR
1155 and the three should be in this order!
1156*/
1157 AddSymbol((UBYTE *)"coeff_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1158 AddSymbol((UBYTE *)"num_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1159 AddSymbol((UBYTE *)"den_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1160 AddSymbol((UBYTE *)"xarg_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1161 AddSymbol((UBYTE *)"dimension_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1162 AddSymbol((UBYTE *)"factor_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1163 AddSymbol((UBYTE *)"sep_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1164 AddSymbol((UBYTE *)"ee_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1165 AddSymbol((UBYTE *)"em_",-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1166 i = BUILTINSYMBOLS; /* update this in ftypes.h when we add new symbols */
1167/*
1168 Next we add a number of dummy symbols for ensuring that the user defined
1169 symbols start at a fixed given number FIRSTUSERSYMBOL
1170 We do want to give them unique names though that the user cannot access.
1171*/
1172 {
1173 char dumstr[20];
1174 for ( ; i < FIRSTUSERSYMBOL; i++ ) {
1175 snprintf(dumstr,20,":%d:",i);
1176 AddSymbol((UBYTE *)dumstr,-MAXPOWER,MAXPOWER,VARTYPENONE,0);
1177 }
1178 }
1179
1180 AddIndex((UBYTE *)"iarg_",4,0);
1181 AddVector((UBYTE *)"parg_",VARTYPENONE,0);
1182
1183 AM.NumFixedFunctions = sizeof(fixedfunctions)/sizeof(struct fixedfun);
1184 for ( i = 0; i < AM.NumFixedFunctions; i++ ) {
1185 ii = AddFunction((UBYTE *)fixedfunctions[i].name
1186 ,fixedfunctions[i].commu
1187 ,fixedfunctions[i].tensor
1188 ,fixedfunctions[i].complx
1189 ,fixedfunctions[i].symmetric
1190 ,0,-1,-1);
1191 if ( fixedfunctions[i].tensor == GAMMAFUNCTION )
1192 functions[ii].flags |= COULDCOMMUTE;
1193 }
1194/*
1195 Next we add a number of dummy functions for ensuring that the user defined
1196 functions start at a fixed given number FIRSTUSERFUNCTION.
1197 We do want to give them unique names though that the user cannot access.
1198*/
1199 {
1200 char dumstr[20];
1201 for ( ; i < FIRSTUSERFUNCTION-FUNCTION; i++ ) {
1202 snprintf(dumstr,20,"::%d::",i);
1203 AddFunction((UBYTE *)dumstr,0,0,0,0,0,-1,-1);
1204 }
1205 }
1206 AM.NumFixedSets = sizeof(fixedsets)/sizeof(struct fixedset);
1207 for ( i = 0; i < AM.NumFixedSets; i++ ) {
1208 ii = AddSet((UBYTE *)fixedsets[i].name,fixedsets[i].dimension);
1209 Sets[ii].type = fixedsets[i].type;
1210 }
1211 AM.RepMax = MAXREPEAT;
1212#ifndef WITHPTHREADS
1213 AT.RepCount = (int *)Malloc1((LONG)((AM.RepMax+3)*sizeof(int)),"repeat buffers");
1214 AN.RepPoint = AT.RepCount;
1215 AT.RepTop = AT.RepCount + AM.RepMax;
1216 AN.polysortflag = 0;
1217 AN.subsubveto = 0;
1218#endif
1219 AC.NumWildcardNames = 0;
1220 AC.WildcardBufferSize = 50;
1221 AC.WildcardNames = (UBYTE *)Malloc1((LONG)AC.WildcardBufferSize,"argument list names");
1222#ifndef WITHPTHREADS
1223 AT.WildArgTaken = (WORD *)Malloc1((LONG)AC.WildcardBufferSize*sizeof(WORD)/2
1224 ,"argument list names");
1225 AT.WildcardBufferSize = AC.WildcardBufferSize;
1226 AR.CompareRoutine = (COMPAREDUMMY)(&Compare1);
1227 AT.nfac = AT.nBer = 0;
1228 AT.factorials = 0;
1229 AT.bernoullis = 0;
1230 AR.wranfia = 0;
1231 AR.wranfcall = 0;
1232 AR.wranfnpair1 = NPAIR1;
1233 AR.wranfnpair2 = NPAIR2;
1234 AR.wranfseed = 0;
1235
1236 AT.NormData = Malloc1(sizeof(*(AT.NormData)), "NormData pointers");
1237 AT.NormDataSize = 1;
1238 AT.NormData[0] = AllocNormData();
1239 AT.NormDepth = 0;
1240#endif
1241 AM.atstartup = 1;
1242 AM.oldnumextrasymbols = strDup1((UBYTE *)"OLDNUMEXTRASYMBOLS_","oldnumextrasymbols");
1243 PutPreVar((UBYTE *)"VERSION_",(UBYTE *)STRINGIFY(MAJORVERSION),0,0);
1244 PutPreVar((UBYTE *)"SUBVERSION_",(UBYTE *)STRINGIFY(MINORVERSION),0,0);
1245 PutPreVar((UBYTE *)"SUBSUBVERSION_",(UBYTE *)STRINGIFY(PATCHVERSION),0,0);
1246 PutPreVar((UBYTE *)"DATE_",(UBYTE *)MakeDate(),0,0);
1247 PutPreVar((UBYTE *)"random_",(UBYTE *)"________",0,0);
1248 PutPreVar((UBYTE *)"optimminvar_",(UBYTE *)("0"),0,0);
1249 PutPreVar((UBYTE *)"optimmaxvar_",(UBYTE *)("0"),0,0);
1250 PutPreVar(AM.oldnumextrasymbols,(UBYTE *)("0"),0,0);
1251 PutPreVar((UBYTE *)"optimvalue_",(UBYTE *)("0"),0,0);
1252 PutPreVar((UBYTE *)"optimscheme_",(UBYTE *)("0"),0,0);
1253 PutPreVar((UBYTE *)"tolower_",(UBYTE *)("0"),0,0);
1254 PutPreVar((UBYTE *)"toupper_",(UBYTE *)("0"),0,0);
1255 PutPreVar((UBYTE *)"takeleft_",(UBYTE *)("0"),0,0);
1256 PutPreVar((UBYTE *)"takeright_",(UBYTE *)("0"),0,0);
1257 PutPreVar((UBYTE *)"keepleft_",(UBYTE *)("0"),0,0);
1258 PutPreVar((UBYTE *)"keepright_",(UBYTE *)("0"),0,0);
1259 PutPreVar((UBYTE *)"SYSTEMERROR_",(UBYTE *)("0"),0,0);
1260/*
1261 Next are the flags to control diagram generation filters
1262*/
1263 #define STR2(x) #x
1264 #define STR(x) STR2(x)
1265 PutPreVar((UBYTE *)"TOPOLOGIESONLY_" ,(UBYTE*)(STR(TOPOLOGIESONLY)) ,0,0);
1266 PutPreVar((UBYTE *)"WITHOUTNODES_" ,(UBYTE*)(STR(WITHOUTNODES)) ,0,0);
1267 PutPreVar((UBYTE *)"WITHEDGES_" ,(UBYTE*)(STR(WITHEDGES)) ,0,0);
1268 PutPreVar((UBYTE *)"WITHBLOCKS_" ,(UBYTE*)(STR(WITHBLOCKS)) ,0,0);
1269 PutPreVar((UBYTE *)"WITHONEPISETS_" ,(UBYTE*)(STR(WITHONEPISETS)) ,0,0);
1270 PutPreVar((UBYTE *)"WITHSYMMETRIZEI_",(UBYTE*)(STR(WITHSYMMETRIZEI)),0,0);
1271 PutPreVar((UBYTE *)"WITHSYMMETRIZEF_",(UBYTE*)(STR(WITHSYMMETRIZEF)),0,0);
1272 // This is not an "option" preprocessor var but is set by "external" particle definitions
1273// PutPreVar((UBYTE *)"CHECKEXTERN_" ,(UBYTE*)(STR(CHECKEXTERN)) ,0,0);
1274 PutPreVar((UBYTE *)"ONEPI_" ,(UBYTE*)(STR(ONEPARTI)) ,0,0);
1275 PutPreVar((UBYTE *)"ONEPR_" ,(UBYTE*)(STR(ONEPARTR)) ,0,0);
1276 PutPreVar((UBYTE *)"ONSHELL_" ,(UBYTE*)(STR(ONSHELL)) ,0,0);
1277 PutPreVar((UBYTE *)"OFFSHELL_" ,(UBYTE*)(STR(OFFSHELL)) ,0,0);
1278 PutPreVar((UBYTE *)"NOSIGMA_" ,(UBYTE*)(STR(NOSIGMA)) ,0,0);
1279 PutPreVar((UBYTE *)"SIGMA_" ,(UBYTE*)(STR(SIGMA)) ,0,0);
1280 PutPreVar((UBYTE *)"NOSNAIL_" ,(UBYTE*)(STR(NOSNAIL)) ,0,0);
1281 PutPreVar((UBYTE *)"SNAIL_" ,(UBYTE*)(STR(SNAIL)) ,0,0);
1282 PutPreVar((UBYTE *)"NOTADPOLE_" ,(UBYTE*)(STR(NOTADPOLE)) ,0,0);
1283 PutPreVar((UBYTE *)"TADPOLE_" ,(UBYTE*)(STR(TADPOLE)) ,0,0);
1284 PutPreVar((UBYTE *)"SIMPLE_" ,(UBYTE*)(STR(SIMPLE)) ,0,0);
1285 PutPreVar((UBYTE *)"NOTSIMPLE_" ,(UBYTE*)(STR(NOTSIMPLE)) ,0,0);
1286 PutPreVar((UBYTE *)"BIPART_" ,(UBYTE*)(STR(BIPART)) ,0,0);
1287 PutPreVar((UBYTE *)"NONBIPART_" ,(UBYTE*)(STR(NONBIPART)) ,0,0);
1288 PutPreVar((UBYTE *)"CYCLI_" ,(UBYTE*)(STR(CYCLI)) ,0,0);
1289 PutPreVar((UBYTE *)"CYCLR_" ,(UBYTE*)(STR(CYCLR)) ,0,0);
1290 PutPreVar((UBYTE *)"FLOOP_" ,(UBYTE*)(STR(FLOOP)) ,0,0);
1291 PutPreVar((UBYTE *)"NOTFLOOP_" ,(UBYTE*)(STR(NOTFLOOP)) ,0,0);
1292
1293 {
1294 char buf[41]; /* up to 128-bit */
1295 LONG pid;
1296#ifndef WITHMPI
1297 pid = GetPID();
1298#else
1299 pid = ( PF.me == MASTER ) ? GetPID() : (LONG)0;
1300 pid = PF_BroadcastNumber(pid);
1301#endif
1302 LongCopy(pid,buf);
1303 PutPreVar((UBYTE *)"PID_",(UBYTE *)buf,0,0);
1304 }
1305 AM.atstartup = 0;
1306 AP.MaxPreTypes = 10;
1307 AP.NumPreTypes = 0;
1308 AP.PreTypes = (int *)Malloc1(sizeof(int)*(AP.MaxPreTypes+1),"preprocessor types");
1309 AP.inside.buffer = 0;
1310 AP.inside.size = 0;
1311
1312 AC.SortType = AC.lSortType = AM.gSortType = SORTLOWFIRST;
1313#ifdef WITHPTHREADS
1314#else
1315 AR.SortType = AC.SortType;
1316#endif
1317 AC.LogHandle = -1;
1318 AC.SetList.numtemp = AC.SetList.num;
1319 AC.SetElementList.numtemp = AC.SetElementList.num;
1320
1321 GetName(AC.varnames,(UBYTE *)"exp_",&AM.expnum,NOAUTO);
1322 GetName(AC.varnames,(UBYTE *)"denom_",&AM.denomnum,NOAUTO);
1323 GetName(AC.varnames,(UBYTE *)"fac_",&AM.facnum,NOAUTO);
1324 GetName(AC.varnames,(UBYTE *)"invfac_",&AM.invfacnum,NOAUTO);
1325 GetName(AC.varnames,(UBYTE *)"sum_",&AM.sumnum,NOAUTO);
1326 GetName(AC.varnames,(UBYTE *)"sump_",&AM.sumpnum,NOAUTO);
1327 GetName(AC.varnames,(UBYTE *)"term_",&AM.termfunnum,NOAUTO);
1328 GetName(AC.varnames,(UBYTE *)"match_",&AM.matchfunnum,NOAUTO);
1329 GetName(AC.varnames,(UBYTE *)"count_",&AM.countfunnum,NOAUTO);
1330 AM.termfunnum += FUNCTION;
1331 AM.matchfunnum += FUNCTION;
1332 AM.countfunnum += FUNCTION;
1333
1334 AC.ThreadStats = AM.gThreadStats = AM.ggThreadStats = 1;
1335 AC.FinalStats = AM.gFinalStats = AM.ggFinalStats = 1;
1336 AC.StatsFlag = AM.gStatsFlag = AM.ggStatsFlag = 1;
1337 AC.ThreadsFlag = AM.gThreadsFlag = AM.ggThreadsFlag = 1;
1338 AC.ThreadBalancing = AM.gThreadBalancing = AM.ggThreadBalancing = 1;
1339 AC.ThreadSortFileSynch = AM.gThreadSortFileSynch = AM.ggThreadSortFileSynch = 0;
1340 AC.ProcessStats = AM.gProcessStats = AM.ggProcessStats = 1;
1341 AC.OldParallelStats = AM.gOldParallelStats = AM.ggOldParallelStats = 0;
1342 AC.OldFactArgFlag = AM.gOldFactArgFlag = AM.ggOldFactArgFlag = NEWFACTARG;
1343 AC.OldGCDflag = AM.gOldGCDflag = AM.ggOldGCDflag = 1;
1344 AC.WTimeStatsFlag = AM.gWTimeStatsFlag = AM.ggWTimeStatsFlag = 0;
1345 AM.gcNumDollars = AP.DollarList.num;
1346 AC.SizeCommuteInSet = AM.gSizeCommuteInSet = 0;
1347#ifdef WITHFLOAT
1348 AC.MaxWeight = AM.gMaxWeight = AM.ggMaxWeight = MAXWEIGHT;
1349 AC.DefaultPrecision = AM.gDefaultPrecision = AM.ggDefaultPrecision = DEFAULTPRECISION;
1350#endif
1351 AC.CommuteInSet = 0;
1352
1353 AM.PrintTotalSize = 0;
1354
1355 AO.NoSpacesInNumbers = AM.gNoSpacesInNumbers = AM.ggNoSpacesInNumbers = 0;
1356 AO.IndentSpace = AM.gIndentSpace = AM.ggIndentSpace = INDENTSPACE;
1357 AO.BlockSpaces = 0;
1358 AO.OptimizationLevel = 0;
1359 PUTZERO(AS.MaxExprSize);
1360 PUTZERO(AC.StoreFileSize);
1361
1362#ifdef WITHPTHREADS
1363 AC.inputnumbers = 0;
1364 AC.pfirstnum = 0;
1365 AC.numpfirstnum = AC.sizepfirstnum = 0;
1366#endif
1367 AC.MemDebugFlag = 1;
1368
1369#ifdef WITHEXTERNALCHANNEL
1370 AX.currentExternalChannel=0;
1371 AX.killSignal=SIGKILL;
1372 AX.killWholeGroup=1;
1373 AX.daemonize=1;
1374 AX.currentPrompt=0;
1375 AX.timeout=1000;/*One second to initialize preset channels*/
1376 AX.shellname=strDup1((UBYTE *)"/bin/sh -c","external channel shellname");
1377 AX.stderrname=strDup1((UBYTE *)"/dev/null","external channel stderrname");
1378#endif
1379}
1380
1381/*
1382 #] StartVariables :
1383 #[ StartMore :
1384*/
1385
1386void StartMore(void)
1387{
1388#ifdef WITHEXTERNALCHANNEL
1389 /*If env.variable "FORM_PIPES" is defined, we have to initialize
1390 corresponding pre-set external channels, see file extcmd.c.*/
1391 /*This line must be after all setup settings: in future, timeout
1392 could be changed at setup.*/
1393 if(AX.timeout>=0)/*if AX.timeout<0, this was done by cmdline option -pipe*/
1394 initPresetExternalChannels((UBYTE*)getenv("FORM_PIPES"),AX.timeout);
1395#endif
1396
1397#ifdef WITHMPI
1398/*
1399 Define preprocessor variable PARALLELTASK_ as a process number, 0 is the master
1400 Define preprocessor variable NPARALLELTASKS_ as a total number of processes
1401*/
1402 {
1403 UBYTE buf[32];
1404 snprintf((char*)buf,32,"%d",PF.me);
1405 PutPreVar((UBYTE *)"PARALLELTASK_",buf,0,0);
1406 snprintf((char*)buf,32,"%d",PF.numtasks);
1407 PutPreVar((UBYTE *)"NPARALLELTASKS_",buf,0,0);
1408 }
1409#else
1410 PutPreVar((UBYTE *)"PARALLELTASK_",(UBYTE *)"0",0,0);
1411 PutPreVar((UBYTE *)"NPARALLELTASKS_",(UBYTE *)"1",0,0);
1412#endif
1413
1414 PutPreVar((UBYTE *)"NAME_",AM.InputFileName ? AM.InputFileName : (UBYTE *)"STDIN",0,0);
1415}
1416
1417/*
1418 #] StartMore :
1419 #[ IniVars :
1420
1421 This routine initializes the parameters that may change during the run.
1422*/
1423
1424void IniVars(void)
1425{
1426#ifdef WITHPTHREADS
1427 GETIDENTITY
1428#else
1429 WORD *t;
1430#endif
1431 WORD *fi, i, one = 1;
1432 CBUF *C = cbuf+AC.cbufnum;
1433
1434#ifdef WITHPTHREADS
1435 UBYTE buf[32];
1436 snprintf((char*)buf,32,"%d",AM.totalnumberofthreads);
1437 PutPreVar((UBYTE *)"NTHREADS_",buf,0,1);
1438#else
1439 PutPreVar((UBYTE *)"NTHREADS_",(UBYTE *)"1",0,1);
1440#endif
1441
1442 AC.ShortStats = 0;
1443 AC.WarnFlag = 1;
1444 AR.SortType = AC.SortType = AC.lSortType = AM.gSortType;
1445 AC.OutputMode = 72;
1446 AC.OutputSpaces = NORMALFORMAT;
1447 AR.Eside = 0;
1448 AC.DumNum = 0;
1449 AC.ncmod = AM.gncmod = 0;
1450 AC.modmode = AM.gmodmode = 0;
1451 AC.npowmod = AM.gnpowmod = 0;
1452 AC.halfmod = 0; AC.nhalfmod = 0;
1453 AC.modinverses = 0;
1454 AC.lPolyFun = AM.gPolyFun = 0;
1455 AC.lPolyFunInv = AM.gPolyFunInv = 0;
1456 AC.lPolyFunType = AM.gPolyFunType = 0;
1457 AC.lPolyFunExp = AM.gPolyFunExp = 0;
1458 AC.lPolyFunVar = AM.gPolyFunVar = 0;
1459 AC.lPolyFunPow = AM.gPolyFunPow = 0;
1460#ifdef WITHFLINT
1461 AC.FlintPolyFlag = 1;
1462#else
1463 AC.FlintPolyFlag = 0;
1464#endif
1465 AC.DirtPow = 0;
1466 AC.lDefDim = AM.gDefDim = 4;
1467 AC.lDefDim4 = AM.gDefDim4 = 0;
1468 AC.lUnitTrace = AM.gUnitTrace = 4;
1469 AC.NamesFlag = AM.gNamesFlag = 0;
1470 AC.CodesFlag = AM.gCodesFlag = 0;
1471 /* Printing a backtrace on crash is on by default for both normal and debug
1472 modes if FORM has been compiled with backtrace support. */
1473#ifdef ENABLE_BACKTRACE
1474 AC.PrintBacktraceFlag = 1;
1475#else
1476 AC.PrintBacktraceFlag = 0;
1477#endif
1478 /* Human-readable statistics are off by default */
1479 AC.HumanStatsFlag = 0;
1480 AC.extrasymbols = AM.gextrasymbols = AM.ggextrasymbols = 0;
1481 AC.extrasym = (UBYTE *)Malloc1(2*sizeof(UBYTE),"extrasym");
1482 AM.gextrasym = (UBYTE *)Malloc1(2*sizeof(UBYTE),"extrasym");
1483 AM.ggextrasym = (UBYTE *)Malloc1(2*sizeof(UBYTE),"extrasym");
1484 AC.extrasym[0] = AM.gextrasym[0] = AM.ggextrasym[0] = 'Z';
1485 AC.extrasym[1] = AM.gextrasym[1] = AM.ggextrasym[1] = 0;
1486 AC.TokensWriteFlag = AM.gTokensWriteFlag = 0;
1487 AC.SetupFlag = 0;
1488 AC.LineLength = AM.gLineLength = 79;
1489 AC.NwildC = 0;
1490 AC.OutputMode = 0;
1491 AM.gOutputMode = 0;
1492 AC.OutputSpaces = NORMALFORMAT;
1493 AM.gOutputSpaces = NORMALFORMAT;
1494 AC.OutNumberType = RATIONALMODE;
1495 AM.gOutNumberType = RATIONALMODE;
1496#ifdef WITHZLIB
1497 AR.gzipCompress = GZIPDEFAULT;
1498 AR.FoStage4[0].ziobuffer = 0;
1499 AR.FoStage4[1].ziobuffer = 0;
1500#ifdef WITHZSTD
1501 /* Zstd compression is on by default, if we have compiled with it */
1502 ZWRAP_useZSTDcompression(1);
1503#endif
1504#endif
1505 AR.BracketOn = 0;
1506 AC.bracketindexflag = 0;
1507 AT.bracketindexflag = 0;
1508 AT.bracketinfo = 0;
1509 AO.IsBracket = 0;
1510 AM.gfunpowers = AC.funpowers = COMFUNPOWERS;
1511 AC.parallelflag = AM.gparallelflag;
1512 AC.properorderflag = AM.gproperorderflag = PROPERORDERFLAG;
1513 AC.ProcessBucketSize = AC.mProcessBucketSize = AM.gProcessBucketSize;
1514 AC.ThreadBucketSize = AM.gThreadBucketSize;
1515 AC.ShortStatsMax = 0;
1516 AM.gShortStatsMax = 0;
1517 AM.ggShortStatsMax = 0;
1518
1519 GlobalSymbols = NumSymbols;
1520 GlobalIndices = NumIndices;
1521 GlobalVectors = NumVectors;
1522 GlobalFunctions = NumFunctions;
1523 GlobalSets = NumSets;
1524 GlobalSetElements = NumSetElements;
1525 AC.modpowers = (UWORD *)0;
1526
1527 i = AM.OffsetIndex;
1528 fi = AC.FixIndices;
1529 if ( i > 0 ) do { *fi++ = one; } while ( --i >= 0 );
1530 AR.sLevel = -1;
1531 AM.Ordering[0] = 5;
1532 AM.Ordering[1] = 6;
1533 AM.Ordering[2] = 7;
1534 AM.Ordering[3] = 0;
1535 AM.Ordering[4] = 1;
1536 AM.Ordering[5] = 2;
1537 AM.Ordering[6] = 3;
1538 AM.Ordering[7] = 4;
1539 for ( i = 8; i < 15; i++ ) AM.Ordering[i] = i;
1540 AM.gUniTrace[0] =
1541 AC.lUniTrace[0] = SNUMBER;
1542 AM.gUniTrace[1] =
1543 AC.lUniTrace[1] =
1544 AM.gUniTrace[2] =
1545 AC.lUniTrace[2] = 4;
1546 AM.gUniTrace[3] =
1547 AC.lUniTrace[3] = 1;
1548#ifdef WITHPTHREADS
1549 AS.Balancing = 0;
1550#else
1551 AT.MinVecArg[0] = 7+ARGHEAD;
1552 AT.MinVecArg[ARGHEAD] = 7;
1553 AT.MinVecArg[1+ARGHEAD] = INDEX;
1554 AT.MinVecArg[2+ARGHEAD] = 3;
1555 AT.MinVecArg[3+ARGHEAD] = 0;
1556 AT.MinVecArg[4+ARGHEAD] = 1;
1557 AT.MinVecArg[5+ARGHEAD] = 1;
1558 AT.MinVecArg[6+ARGHEAD] = -3;
1559 t = AT.FunArg;
1560 *t++ = 4+ARGHEAD+FUNHEAD;
1561 for ( i = 1; i < ARGHEAD; i++ ) *t++ = 0;
1562 *t++ = 4+FUNHEAD;
1563 *t++ = 0;
1564 *t++ = FUNHEAD;
1565 for ( i = 2; i < FUNHEAD; i++ ) *t++ = 0;
1566 *t++ = 1; *t++ = 1; *t++ = 3;
1567
1568#ifdef WITHMPI
1569 AS.printflag = 0;
1570#endif
1571
1572 AT.comsym[0] = 8;
1573 AT.comsym[1] = SYMBOL;
1574 AT.comsym[2] = 4;
1575 AT.comsym[3] = 0;
1576 AT.comsym[4] = 1;
1577 AT.comsym[5] = 1;
1578 AT.comsym[6] = 1;
1579 AT.comsym[7] = 3;
1580 AT.comnum[0] = 4;
1581 AT.comnum[1] = 1;
1582 AT.comnum[2] = 1;
1583 AT.comnum[3] = 3;
1584 AT.comfun[0] = FUNHEAD+4;
1585 AT.comfun[1] = FUNCTION;
1586 AT.comfun[2] = FUNHEAD;
1587 AT.comfun[3] = 0;
1588#if FUNHEAD == 4
1589 AT.comfun[4] = 0;
1590#endif
1591 AT.comfun[FUNHEAD+1] = 1;
1592 AT.comfun[FUNHEAD+2] = 1;
1593 AT.comfun[FUNHEAD+3] = 3;
1594 AT.comind[0] = 7;
1595 AT.comind[1] = INDEX;
1596 AT.comind[2] = 3;
1597 AT.comind[3] = 0;
1598 AT.comind[4] = 1;
1599 AT.comind[5] = 1;
1600 AT.comind[6] = 3;
1601 AT.locwildvalue[0] = SUBEXPRESSION;
1602 AT.locwildvalue[1] = SUBEXPSIZE;
1603 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.locwildvalue[i] = 0;
1604 AT.mulpat[0] = TYPEMULT;
1605 AT.mulpat[1] = SUBEXPSIZE+3;
1606 AT.mulpat[2] = 0;
1607 AT.mulpat[3] = SUBEXPRESSION;
1608 AT.mulpat[4] = SUBEXPSIZE;
1609 AT.mulpat[5] = 0;
1610 AT.mulpat[6] = 1;
1611 for ( i = 7; i < SUBEXPSIZE+5; i++ ) AT.mulpat[i] = 0;
1612 AT.proexp[0] = SUBEXPSIZE+4;
1613 AT.proexp[1] = EXPRESSION;
1614 AT.proexp[2] = SUBEXPSIZE;
1615 AT.proexp[3] = -1;
1616 AT.proexp[4] = 1;
1617 for ( i = 5; i < SUBEXPSIZE+1; i++ ) AT.proexp[i] = 0;
1618 AT.proexp[SUBEXPSIZE+1] = 1;
1619 AT.proexp[SUBEXPSIZE+2] = 1;
1620 AT.proexp[SUBEXPSIZE+3] = 3;
1621 AT.proexp[SUBEXPSIZE+4] = 0;
1622 AT.dummysubexp[0] = SUBEXPRESSION;
1623 AT.dummysubexp[1] = SUBEXPSIZE+4;
1624 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.dummysubexp[i] = 0;
1625 AT.dummysubexp[SUBEXPSIZE] = WILDDUMMY;
1626 AT.dummysubexp[SUBEXPSIZE+1] = 4;
1627 AT.dummysubexp[SUBEXPSIZE+2] = 0;
1628 AT.dummysubexp[SUBEXPSIZE+3] = 0;
1629
1630 AT.inprimelist = -1;
1631 AT.sizeprimelist = 0;
1632 AT.primelist = 0;
1633 AT.LeaveNegative = 0;
1634 AT.TrimPower = 0;
1635 AN.SplitScratch = 0;
1636 AN.SplitScratchSize = AN.InScratch = 0;
1637 AN.SplitScratch1 = 0;
1638 AN.SplitScratchSize1 = AN.InScratch1 = 0;
1639 AN.idfunctionflag = 0;
1640#endif
1641 AO.OutputLine = AO.OutFill = BufferForOutput;
1642 AO.FactorMode = 0;
1643 C->Pointer = C->Buffer;
1644
1645 AP.PreOut = 0;
1646 AP.ComChar = AP.cComChar;
1647 AC.cbufnum = AM.rbufnum; /* Select the default compiler buffer */
1648 AC.HideLevel = 0;
1649 AP.PreAssignFlag = 0;
1650}
1651
1652/*
1653 #] IniVars :
1654 #[ Signal handlers :
1655*/
1656/*[28apr2004 mt]:*/
1657#ifdef TRAPSIGNALS
1658
1659static int exitInProgress = 0;
1660static int trappedTerminate = 0;
1661
1662/*INTSIGHANDLER : some systems require a signal handler to return an integer,
1663 so define the macro INTSIGHANDLER if compiler fails:*/
1664#ifdef INTSIGHANDLER
1665static int onErrSig(int i)
1666#else
1667static void onErrSig(int i)
1668#endif
1669{
1670 if (exitInProgress){
1671 signal(i,SIG_DFL);/* Use default behaviour*/
1672 raise (i);/*reproduce trapped signal*/
1673#ifdef INTSIGHANDLER
1674 return(i);
1675#else
1676 return;
1677#endif
1678 }
1679 trappedTerminate = 1;
1680 /*[13jul2005 mt]*//*TerminateImpl(-1) on signal is here:*/
1681 Terminate(-1);
1682}
1683
1684#ifdef INTSIGHANDLER
1685static void setNewSig(int i, int (*handler)(int))
1686#else
1687static void setNewSig(int i, void (*handler)(int))
1688#endif
1689{
1690 if(! (i<NSIG) )/* Invalid signal -- see comments in the file */
1691 return;
1692 if ( signal(i,SIG_IGN) !=SIG_IGN)
1693 /* if compiler fails here, try to define INTSIGHANDLER):*/
1694 signal(i,handler);
1695}
1696
1697void setSignalHandlers(void)
1698{
1699 /* Reset various unrecoverable error signals:*/
1700 setNewSig(SIGSEGV,onErrSig);
1701 setNewSig(SIGFPE,onErrSig);
1702 setNewSig(SIGILL,onErrSig);
1703 setNewSig(SIGEMT,onErrSig);
1704 setNewSig(SIGSYS,onErrSig);
1705 setNewSig(SIGPIPE,onErrSig);
1706 setNewSig(SIGLOST,onErrSig);
1707 setNewSig(SIGXCPU,onErrSig);
1708 setNewSig(SIGXFSZ,onErrSig);
1709
1710 /* Reset interrupt signals:*/
1711 setNewSig(SIGTERM,onErrSig);
1712 setNewSig(SIGINT,onErrSig);
1713 setNewSig(SIGQUIT,onErrSig);
1714 setNewSig(SIGHUP,onErrSig);
1715 setNewSig(SIGALRM,onErrSig);
1716 setNewSig(SIGVTALRM,onErrSig);
1717/* setNewSig(SIGPROF,onErrSig); */ /* Why did Tentukov forbid profilers?? */
1718}
1719
1720#endif
1721/*:[28apr2004 mt]*/
1722/*
1723 #] Signal handlers :
1724 #[ main :
1725*/
1726
1727#ifdef WITHPTHREADS
1728ALLPRIVATES *ABdummy[10];
1729#endif
1730
1731int main(int argc, char **argv)
1732{
1733 int retval;
1734 bzero((void *)(&A),sizeof(A)); /* make sure A is initialized at zero */
1735 iniTools();
1736#ifdef TRAPSIGNALS
1737 setSignalHandlers();
1738#endif
1739#ifdef WINDOWS
1740 _setmode(_fileno(stdout),O_BINARY);
1741#endif
1742
1743#ifdef WITHPTHREADS
1744 AB = ABdummy;
1745 StartHandleLock();
1746 BeginIdentities();
1747#else
1748 AM.SumTime = TimeCPU(0);
1749 TimeWallClock(0);
1750#endif
1751
1752#ifdef WITHMPI
1753 if ( PF_Init(&argc,&argv) ) exit(-1);
1754#endif
1755
1756 StartFiles();
1758#ifdef WITHMPI
1759 /*
1760 * Here MesPrint() is ready. We turn on AS.printflag to print possible
1761 * errors occurring on slaves in the initialization. With AS.printflag = -1
1762 * MesPrint() does not use the synchronized output. This may lead broken
1763 * texts in the output somewhat, but it is safer to implement in this way
1764 * for the situation in which some of MesPrint() calls use MLOCK()-MUNLOCK()
1765 * and some do not. In future if we set AS.printflag = 1 and modify the
1766 * source code such that all MesPrint() calls are sandwiched by MLOCK()-
1767 * MUNLOCK(), we need also to modify the code for the master to catch
1768 * messages corresponding to MUNLOCK() calls at some point.
1769 *
1770 * AS.printflag will be set to 0 in IniVars() to prevent slaves from
1771 * printing redundant errors in the preprocessor and compiler (e.g., syntax
1772 * errors).
1773 */
1774 AS.printflag = -1;
1775#endif
1776
1777 if ( ( retval = DoTail(argc,(UBYTE **)argv) ) != 0 ) {
1778 if ( retval > 0 ) Terminate(0);
1779 else Terminate(-1);
1780 }
1781 if ( DoSetups() ) Terminate(-2);
1782#ifdef WITHMPI
1783 /* It is messy if all errors in OpenInput() on slaves are printed. */
1784 AS.printflag = 0;
1785#endif
1786 if ( OpenInput() ) Terminate(-3);
1787#ifdef WITHMPI
1788 AS.printflag = -1;
1789#endif
1790 if ( TryEnvironment() ) Terminate(-2);
1791 if ( TryFileSetups() ) Terminate(-2);
1792 if ( MakeSetupAllocs() ) Terminate(-2);
1793 StartMore();
1794 InitRecovery();
1796 if ( AM.totalnumberofthreads == 0 ) AM.totalnumberofthreads = 1;
1797 AS.MultiThreaded = 0;
1798#ifdef WITHPTHREADS
1799 if ( AM.totalnumberofthreads > 1 ) AS.MultiThreaded = 1;
1800 ReserveTempFiles(1);
1801 StartAllThreads(AM.totalnumberofthreads);
1802 IniFbufs();
1803#else
1804 ReserveTempFiles(0);
1805 IniFbuffer(AT.fbufnum);
1806#endif
1807 if ( !AM.FromStdin ) PrintHeader(1);
1808 IniVars();
1809 Globalize(1);
1810#ifdef WITH_ALARM
1811 if ( AM.TimeLimit > 0 ) alarm(AM.TimeLimit);
1812#endif
1813#ifdef WITHFLINT
1815#endif
1816 TimeCPU(0);
1817 TimeChildren(0);
1818 TimeWallClock(0);
1819 PreProcessor();
1820 Terminate(0);
1821 return(0);
1822}
1823/*
1824 #] main :
1825 #[ CleanUp :
1826
1827 if par < 0 we have to keep the storage file.
1828 when par > 0 we ran into a .clear statement.
1829 In that case we keep the zero level input and the log file.
1830
1831*/
1832
1833void CleanUp(WORD par)
1834{
1835 GETIDENTITY
1836 int i;
1837
1838 if ( FG.fname ) {
1839#ifdef WITHPTHREADS
1840 if ( B ) {
1841#endif
1842 CleanUpSort(0);
1843 for ( i = 0; i < 3; i++ ) {
1844 if ( AR.Fscr[i].handle >= 0 ) {
1845 if ( AR.Fscr[i].name ) {
1846/*
1847 If there are more threads referring to the same file
1848 only the one with the name is the owner of the file.
1849*/
1850 CloseFile(AR.Fscr[i].handle);
1851 remove(AR.Fscr[i].name);
1852 }
1853 AR.Fscr[i].handle = - 1;
1854 AR.Fscr[i].POfill = 0;
1855 }
1856 }
1857#ifdef WITHPTHREADS
1858 }
1859#endif
1860 if ( par > 0 ) {
1861/*
1862 Close all input levels above the lowest?
1863*/
1864 }
1865 if ( AC.StoreHandle >= 0 && par <= 0 ) {
1866#ifdef TRAPSIGNALS
1867 if ( trappedTerminate ) { /* We don't throw .str if it has contents */
1868 POSITION pos;
1869 PUTZERO(pos);
1870 SeekFile(AC.StoreHandle,&pos,SEEK_END);
1871 if ( ISNOTZEROPOS(pos) ) {
1872 CloseFile(AC.StoreHandle);
1873 goto dontremove;
1874 }
1875 }
1876 CloseFile(AC.StoreHandle);
1877#ifdef WITHPTHREADS
1878 if ( B )
1879#endif
1880 if ( par >= 0 || AR.StoreData.Handle < 0 || AM.ClearStore ) {
1881 remove(FG.fname);
1882 }
1883dontremove:;
1884#else
1885 CloseFile(AC.StoreHandle);
1886#ifdef WITHPTHREADS
1887 if ( B )
1888#endif
1889 if ( par >= 0 || AR.StoreData.Handle < 0 || AM.ClearStore > 0 ) {
1890 remove(FG.fname);
1891 }
1892#endif
1893 }
1894 }
1895 ClearSpectators(CLEARMODULE);
1896/*
1897 Remove recovery file on exit if everything went well
1898*/
1899 if ( par == 0 ) {
1901 }
1902/*
1903 Now the final message concerning the total time
1904*/
1905 if ( AC.LogHandle >= 0 && par <= 0 ) {
1906 WORD lh = AC.LogHandle;
1907 AC.LogHandle = -1;
1908#ifdef WITHMPI
1909 if ( PF.me == MASTER ) /* Only the master opened the real file. */
1910#endif
1911 CloseFile(lh);
1912 }
1913}
1914
1915/*
1916 #] CleanUp :
1917 #[ TerminateImpl :
1918*/
1919
1920static int firstterminate = 1;
1921
1922void TerminateImpl(int errorcode, const char* file, int line, const char* function)
1923{
1924#ifdef WITHMPI
1925 if ( errorcode && firstterminate && !PF.notMyFault ) {
1926#else
1927 if ( errorcode && firstterminate ) {
1928#endif
1929 firstterminate = 0;
1930
1931 MLOCK(ErrorMessageLock);
1932#ifdef WITHPTHREADS
1933 MesPrint("Program terminating in thread %w at &");
1934#elif defined(WITHMPI)
1935 MesPrint("Program terminating in process %w at &");
1936#else
1937 MesPrint("Program terminating at &");
1938#endif
1939 MesPrint("Terminate called from %s:%d (%s)", file, line, function);
1940
1941 if ( AC.PrintBacktraceFlag ) {
1942#ifdef ENABLE_BACKTRACE
1943 void *stack[64];
1944 int stacksize, stop = 0;
1945 stacksize = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
1946
1947 /* First check whether eu-addr2line is available */
1948 if ( !system("command -v eu-addr2line > /dev/null 2>&1") ) {
1949 MesPrint("Backtrace:");
1950 for (int i = 0; i < stacksize && !stop; i++) {
1951 FILE *fp;
1952 char cmd[512];
1953 // Leave an initial space
1954 cmd[0] = ' ';
1955 MesPrint("%#%2d:%", i);
1956 snprintf(cmd+1, sizeof(cmd)-1, "eu-addr2line -s --pretty-print -f -i '%p' --pid=%d\n", stack[i], getpid());
1957 fp = popen(cmd+1, "r");
1958 while ( fgets(cmd+1, sizeof(cmd)-1, fp) != NULL ) {
1959 MesPrint("%s", cmd);
1960 /* Don't show functions lower than "main" (or thread equivalent) */
1961 if ( strstr(cmd, " main ") || strstr(cmd, " RunThread ") || strstr(cmd, " RunSortBot ") ) {
1962 stop = 1;
1963 }
1964 }
1965 pclose(fp);
1966 }
1967 }
1968#ifdef LINUX
1969 else if ( !system("command -v addr2line > /dev/null 2>&1") ) {
1970 /* Get the executable path. */
1971 char exe_path[PATH_MAX];
1972 {
1973 ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
1974 if ( len != -1 ) {
1975 exe_path[len] = '\0';
1976 }
1977 else {
1978 goto backtrace_fallback;
1979 }
1980 }
1981 /* Assume PIE binary and get the base address. */
1982 uintptr_t base_address = 0;
1983 {
1984 char line[256];
1985 FILE *maps = fopen("/proc/self/maps", "r");
1986 if ( !maps ) {
1987 goto backtrace_fallback;
1988 }
1989 /* See the format used by nommu_region_show() in fs/proc/nommu.c of the Linux source. */
1990 if ( fgets(line, sizeof(line), maps) ) {
1991 sscanf(line, "%" SCNxPTR "-", &base_address);
1992 }
1993 else {
1994 fclose(maps);
1995 goto backtrace_fallback;
1996 }
1997 fclose(maps);
1998 }
1999 char **strings;
2000 strings = backtrace_symbols(stack, stacksize);
2001 MesPrint("Backtrace:");
2002 for ( int i = 0; i < stacksize && !stop; i++ ) {
2003 FILE *fp;
2004 char cmd[PATH_MAX + 512];
2005 // Leave an initial space
2006 cmd[0] = ' ';
2007 uintptr_t addr = (uintptr_t)stack[i] - base_address;
2008 MesPrint("%#%2d:%", i);
2009 snprintf(cmd+1, sizeof(cmd)-1, "addr2line -e \"%s\" -i -p -s -f -C 0x%" PRIxPTR, exe_path, addr);
2010 fp = popen(cmd+1, "r");
2011 while ( fgets(cmd+1, sizeof(cmd)-1, fp) != NULL ) {
2012 MesPrint("%s", cmd);
2013 /* Don't show functions lower than "main" */
2014 if ( strstr(cmd, " main ") || strstr(cmd, " RunThread ") || strstr(cmd, " RunSortBot ") ) {
2015 stop = 1;
2016 }
2017 }
2018 pclose(fp);
2019 }
2020 free(strings);
2021 }
2022#endif
2023 else {
2024 /* eu-addr2line not found */
2025#ifdef LINUX
2026backtrace_fallback: ;
2027#endif
2028 char **strings;
2029 strings = backtrace_symbols(stack, stacksize);
2030 MesPrint("Backtrace:");
2031 for ( int i = 0; i < stacksize && !stop; i++ ) {
2032 char *p = strings[i];
2033 while ( *p && *p != '(' ) p++;
2034 MesPrint("%#%2d: %s\n", i, p);
2035 /* Don't show functions lower than "main" (or thread equivalent) */
2036 if ( strstr(p, "(main+") || strstr(p, "(RunThread+") || strstr(p, "(RunSortBot+") ) {
2037 stop = 1;
2038 }
2039 }
2040#ifdef LINUX
2041 MesPrint("Please install addr2line or eu-addr2line for readable stack information.");
2042#else
2043 MesPrint("Please install eu-addr2line for readable stack information.");
2044#endif
2045 free(strings);
2046 }
2047#else
2048 MesPrint("FORM compiled without backtrace support.");
2049#endif
2050 } /* if ( AC.PrintBacktraceFlag) { */
2051
2052 MUNLOCK(ErrorMessageLock);
2053
2054#ifdef WITHMPI
2055 PF_PreTerminate(errorcode);
2056#endif
2057 Crash();
2058 }
2059#ifdef TRAPSIGNALS
2060 exitInProgress=1;
2061#endif
2062#ifdef WITHEXTERNALCHANNEL
2063/*
2064 This function can be called from the error handler, so it is better to
2065 clean up all started processes before any activity:
2066*/
2067 closeAllExternalChannels();
2068 AX.currentExternalChannel=0;
2069 /*[08may2006 mt]:*/
2070 AX.killSignal=SIGKILL;
2071 AX.killWholeGroup=1;
2072 AX.daemonize=1;
2073 /*:[08may2006 mt]*/
2074 if(AX.currentPrompt){
2075 M_free(AX.currentPrompt,"external channel prompt");
2076 AX.currentPrompt=0;
2077 }
2078 /*[08may2006 mt]:*/
2079 if(AX.shellname){
2080 M_free(AX.shellname,"external channel shellname");
2081 AX.shellname=0;
2082 }
2083 if(AX.stderrname){
2084 M_free(AX.stderrname,"external channel stderrname");
2085 AX.stderrname=0;
2086 }
2087 /*:[08may2006 mt]*/
2088#endif
2089#ifdef WITHPTHREADS
2090 if ( !WhoAmI() && !errorcode ) {
2091 TerminateAllThreads();
2092 }
2093#endif
2094 if ( AC.FinalStats ) {
2095 if ( AM.PrintTotalSize ) {
2096 MesPrint("Max. space for expressions: %19p bytes",&(AS.MaxExprSize));
2097 }
2098 PrintRunningTime();
2099 }
2100#ifdef WITHMPI
2101 if ( AM.HoldFlag && PF.me == MASTER ) {
2102 WriteFile(AM.StdOut,(UBYTE *)("Hit any key "),12);
2104 getchar();
2105 }
2106#else
2107 if ( AM.HoldFlag ) {
2108 WriteFile(AM.StdOut,(UBYTE *)("Hit any key "),12);
2109 getchar();
2110 }
2111#endif
2112#ifdef WITHMPI
2113 PF_Terminate(errorcode);
2114#endif
2115/*
2116 We are about to terminate the program. If we are using flint, call the cleanup function.
2117 This keeps valgrind happy.
2118*/
2119#ifdef WITHFLINT
2120 flint_final_cleanup_master();
2121#endif
2122 CleanUp(errorcode);
2123 M_print();
2124#ifdef VMS
2125 P_term(errorcode? 0: 1);
2126#else
2127 P_term(errorcode);
2128#endif
2129}
2130
2131/*
2132 #] TerminateImpl :
2133 #[ PrintDeprecation :
2134*/
2135
2142void PrintDeprecation(const char *feature, const char *issue) {
2143#ifdef WITHMPI
2144 if ( PF.me != MASTER ) return;
2145#endif
2146 if ( AM.IgnoreDeprecation ) return;
2147
2148 UBYTE *e = (UBYTE *)getenv("FORM_IGNORE_DEPRECATION");
2149 if ( e && e[0] && StrCmp(e, (UBYTE *)"0") && StrICmp(e, (UBYTE *)"false") && StrICmp(e, (UBYTE *)"no") ) return;
2150
2151 MesPrint("DeprecationWarning: We are considering deprecating %s.", feature);
2152 MesPrint("If you want this support to continue, leave a comment at:");
2153 MesPrint("");
2154 MesPrint(" https://github.com/form-dev/form/%s", issue);
2155 MesPrint("");
2156 MesPrint("Otherwise, it will be discontinued in the future.");
2157 MesPrint("To suppress this warning, use the -ignore-deprecation command line option or");
2158 MesPrint("set the environment variable FORM_IGNORE_DEPRECATION=1.");
2159}
2160
2161/*
2162 #] PrintDeprecation :
2163 #[ PrintRunningTime :
2164*/
2165
2166void PrintRunningTime(void)
2167{
2168#if (defined(WITHPTHREADS) && (defined(WITHPOSIXCLOCK) || defined(WINDOWS))) || defined(WITHMPI)
2169 LONG mastertime;
2170 LONG workertime;
2171 LONG wallclocktime;
2172 LONG totaltime;
2173#if defined(WITHPTHREADS)
2174 if ( AB[0] != 0 ) {
2175 workertime = GetWorkerTimes();
2176#else
2177 workertime = PF_GetSlaveTimes(); /* must be called on all processors */
2178 if ( PF.me == MASTER ) {
2179#endif
2180 mastertime = AM.SumTime + TimeCPU(1);
2181 wallclocktime = TimeWallClock(1);
2182 totaltime = mastertime+workertime;
2183 if ( !AM.silent ) {
2184 MesPrint(" %l.%2i sec + %l.%2i sec: %l.%2i sec out of %l.%2i sec",
2185 mastertime/1000,(WORD)((mastertime%1000)/10),
2186 workertime/1000,(WORD)((workertime%1000)/10),
2187 totaltime/1000,(WORD)((totaltime%1000)/10),
2188 wallclocktime/100,(WORD)(wallclocktime%100));
2189 }
2190 }
2191#else
2192 LONG mastertime = AM.SumTime + TimeCPU(1);
2193 LONG wallclocktime = TimeWallClock(1);
2194 if ( !AM.silent ) {
2195 MesPrint(" %l.%2i sec out of %l.%2i sec",
2196 mastertime/1000,(WORD)((mastertime%1000)/10),
2197 wallclocktime/100,(WORD)(wallclocktime%100));
2198 }
2199#endif
2200}
2201
2202/*
2203 #] PrintRunningTime :
2204 #[ GetRunningTime :
2205*/
2206
2207LONG GetRunningTime(void)
2208{
2209#if defined(WITHPTHREADS) && (defined(WITHPOSIXCLOCK) || defined(WINDOWS))
2210 LONG mastertime;
2211 if ( AB[0] != 0 ) {
2212/*
2213#if ( defined(APPLE64) || defined(APPLE32) )
2214 mastertime = AM.SumTime + TimeCPU(1);
2215 return(mastertime);
2216#else
2217*/
2218 LONG workertime = GetWorkerTimes();
2219 mastertime = AM.SumTime + TimeCPU(1);
2220 return(mastertime+workertime);
2221/*
2222#endif
2223*/
2224 }
2225 else {
2226 return(AM.SumTime + TimeCPU(1));
2227 }
2228#elif defined(WITHMPI)
2229 LONG mastertime, t = 0;
2230 LONG workertime = PF_GetSlaveTimes(); /* must be called on all processors */
2231 if ( PF.me == MASTER ) {
2232 mastertime = AM.SumTime + TimeCPU(1);
2233 t = mastertime + workertime;
2234 }
2235 return PF_BroadcastNumber(t); /* must be called on all processors */
2236#else
2237 return(AM.SumTime + TimeCPU(1));
2238#endif
2239}
2240
2241/*
2242 #] GetRunningTime :
2243*/
void InitRecovery(void)
Definition checkpoint.c:399
void DeleteRecoveryFile(void)
Definition checkpoint.c:333
int CheckRecoveryFile(void)
Definition checkpoint.c:278
WORD * AddRHS(int num, int type)
Definition comtool.c:214
int inicbufs(void)
Definition comtool.c:47
int IniFbuffer(WORD bufnum)
Definition comtool.c:614
int AddNtoC(int bufnum, int n, WORD *array, int par)
Definition comtool.c:317
void CleanUpSort(int)
Definition sort.c:4561
LONG TimeWallClock(WORD)
Definition tools.c:3413
void PrintFeatureList(void)
Definition features.cc:131
WORD Compare1(PHEAD WORD *, WORD *, WORD)
Definition sort.c:2341
LONG TimeCPU(WORD)
Definition tools.c:3487
int PutPreVar(UBYTE *, UBYTE *, UBYTE *, int)
Definition pre.c:724
void flint_check_version(void)
Definition flintwrap.cc:321
int PF_Init(int *argc, char ***argv)
Definition parallel.c:1947
LONG PF_GetSlaveTimes(void)
Definition parallel.c:2077
void PF_PreTerminate(int errorcode)
Definition parallel.c:2041
int PF_Terminate(int errorcode)
Definition parallel.c:2061
void PF_FlushStdOutBuffer(void)
Definition parallel.c:4492
LONG PF_BroadcastNumber(LONG x)
Definition parallel.c:2098
void StartVariables(void)
Definition startup.c:952
void PrintDeprecation(const char *feature, const char *issue)
Definition startup.c:2142
WORD * Buffer
Definition structs.h:971
WORD * Pointer
Definition structs.h:973
WORD symmetric
Definition structs.h:496
LONG name
Definition structs.h:490
Definition minos.h:123
struct CbUf CBUF
struct DoLoOp DOLOOP
struct ChAnNeL CHANNEL
struct pReVaR PREVAR