FORM v5.0.1-23-g7a8f756
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 = NULL;
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 == NULL ) {
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 == NULL ) 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 == NULL ) {
722 sp = GetSetupPar((UBYTE *)"tempdir");
723 if ( ( sp->flags & USEDFLAG ) != USEDFLAG ) {
724 AM.TempDir = (UBYTE *)getenv("FORMTMP");
725 if ( AM.TempDir == NULL ) AM.TempDir = emptystring;
726 }
727 else AM.TempDir = (UBYTE *)(sp->value);
728 }
729 if ( AM.TempSortDir == NULL ) {
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 == NULL ) 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.OldPRFSignFlag = 0;
1345 AC.WTimeStatsFlag = AM.gWTimeStatsFlag = AM.ggWTimeStatsFlag = 0;
1346 AM.gcNumDollars = AP.DollarList.num;
1347 AC.SizeCommuteInSet = AM.gSizeCommuteInSet = 0;
1348#ifdef WITHFLOAT
1349 AC.MaxWeight = AM.gMaxWeight = AM.ggMaxWeight = MAXWEIGHT;
1350 AC.DefaultPrecision = AM.gDefaultPrecision = AM.ggDefaultPrecision = DEFAULTPRECISION;
1351#endif
1352 AC.CommuteInSet = 0;
1353
1354 AM.PrintTotalSize = 0;
1355
1356 AO.NoSpacesInNumbers = AM.gNoSpacesInNumbers = AM.ggNoSpacesInNumbers = 0;
1357 AO.IndentSpace = AM.gIndentSpace = AM.ggIndentSpace = INDENTSPACE;
1358 AO.BlockSpaces = 0;
1359 AO.OptimizationLevel = 0;
1360 PUTZERO(AS.MaxExprSize);
1361 PUTZERO(AC.StoreFileSize);
1362
1363#ifdef WITHPTHREADS
1364 AC.inputnumbers = 0;
1365 AC.pfirstnum = 0;
1366 AC.numpfirstnum = AC.sizepfirstnum = 0;
1367#endif
1368 AC.MemDebugFlag = 1;
1369
1370#ifdef WITHEXTERNALCHANNEL
1371 AX.currentExternalChannel=0;
1372 AX.killSignal=SIGKILL;
1373 AX.killWholeGroup=1;
1374 AX.daemonize=1;
1375 AX.currentPrompt=0;
1376 AX.timeout=1000;/*One second to initialize preset channels*/
1377 AX.shellname=strDup1((UBYTE *)"/bin/sh -c","external channel shellname");
1378 AX.stderrname=strDup1((UBYTE *)"/dev/null","external channel stderrname");
1379#endif
1380}
1381
1382/*
1383 #] StartVariables :
1384 #[ StartMore :
1385*/
1386
1387void StartMore(void)
1388{
1389#ifdef WITHEXTERNALCHANNEL
1390 /*If env.variable "FORM_PIPES" is defined, we have to initialize
1391 corresponding pre-set external channels, see file extcmd.c.*/
1392 /*This line must be after all setup settings: in future, timeout
1393 could be changed at setup.*/
1394 if(AX.timeout>=0)/*if AX.timeout<0, this was done by cmdline option -pipe*/
1395 initPresetExternalChannels((UBYTE*)getenv("FORM_PIPES"),AX.timeout);
1396#endif
1397
1398#ifdef WITHMPI
1399/*
1400 Define preprocessor variable PARALLELTASK_ as a process number, 0 is the master
1401 Define preprocessor variable NPARALLELTASKS_ as a total number of processes
1402*/
1403 {
1404 UBYTE buf[32];
1405 snprintf((char*)buf,32,"%d",PF.me);
1406 PutPreVar((UBYTE *)"PARALLELTASK_",buf,0,0);
1407 snprintf((char*)buf,32,"%d",PF.numtasks);
1408 PutPreVar((UBYTE *)"NPARALLELTASKS_",buf,0,0);
1409 }
1410#else
1411 PutPreVar((UBYTE *)"PARALLELTASK_",(UBYTE *)"0",0,0);
1412 PutPreVar((UBYTE *)"NPARALLELTASKS_",(UBYTE *)"1",0,0);
1413#endif
1414
1415 PutPreVar((UBYTE *)"NAME_",AM.InputFileName ? AM.InputFileName : (UBYTE *)"STDIN",0,0);
1416}
1417
1418/*
1419 #] StartMore :
1420 #[ IniVars :
1421
1422 This routine initializes the parameters that may change during the run.
1423*/
1424
1425void IniVars(void)
1426{
1427#ifdef WITHPTHREADS
1428 GETIDENTITY
1429#else
1430 WORD *t;
1431#endif
1432 WORD *fi, i, one = 1;
1433 CBUF *C = cbuf+AC.cbufnum;
1434
1435#ifdef WITHPTHREADS
1436 UBYTE buf[32];
1437 snprintf((char*)buf,32,"%d",AM.totalnumberofthreads);
1438 PutPreVar((UBYTE *)"NTHREADS_",buf,0,1);
1439#else
1440 PutPreVar((UBYTE *)"NTHREADS_",(UBYTE *)"1",0,1);
1441#endif
1442
1443 AC.ShortStats = 0;
1444 AC.WarnFlag = 1;
1445 AR.SortType = AC.SortType = AC.lSortType = AM.gSortType;
1446 AC.OutputMode = 72;
1447 AC.OutputSpaces = NORMALFORMAT;
1448 AR.Eside = 0;
1449 AC.DumNum = 0;
1450 AC.ncmod = AM.gncmod = 0;
1451 AC.modmode = AM.gmodmode = 0;
1452 AC.npowmod = AM.gnpowmod = 0;
1453 AC.halfmod = 0; AC.nhalfmod = 0;
1454 AC.modinverses = 0;
1455 AC.lPolyFun = AM.gPolyFun = 0;
1456 AC.lPolyFunInv = AM.gPolyFunInv = 0;
1457 AC.lPolyFunType = AM.gPolyFunType = 0;
1458 AC.lPolyFunExp = AM.gPolyFunExp = 0;
1459 AC.lPolyFunVar = AM.gPolyFunVar = 0;
1460 AC.lPolyFunPow = AM.gPolyFunPow = 0;
1461#ifdef WITHFLINT
1462 AC.FlintPolyFlag = 1;
1463#else
1464 AC.FlintPolyFlag = 0;
1465#endif
1466 AC.DirtPow = 0;
1467 AC.lDefDim = AM.gDefDim = 4;
1468 AC.lDefDim4 = AM.gDefDim4 = 0;
1469 AC.lUnitTrace = AM.gUnitTrace = 4;
1470 AC.NamesFlag = AM.gNamesFlag = 0;
1471 AC.CodesFlag = AM.gCodesFlag = 0;
1472 /* Printing a backtrace on crash is on by default for both normal and debug
1473 modes if FORM has been compiled with backtrace support. */
1474#ifdef ENABLE_BACKTRACE
1475 AC.PrintBacktraceFlag = 1;
1476#else
1477 AC.PrintBacktraceFlag = 0;
1478#endif
1479 /* Human-readable statistics are off by default */
1480 AC.HumanStatsFlag = 0;
1481 AC.extrasymbols = AM.gextrasymbols = AM.ggextrasymbols = 0;
1482 AC.extrasym = (UBYTE *)Malloc1(2*sizeof(UBYTE),"extrasym");
1483 AM.gextrasym = (UBYTE *)Malloc1(2*sizeof(UBYTE),"extrasym");
1484 AM.ggextrasym = (UBYTE *)Malloc1(2*sizeof(UBYTE),"extrasym");
1485 AC.extrasym[0] = AM.gextrasym[0] = AM.ggextrasym[0] = 'Z';
1486 AC.extrasym[1] = AM.gextrasym[1] = AM.ggextrasym[1] = 0;
1487 AC.TokensWriteFlag = AM.gTokensWriteFlag = 0;
1488 AC.SetupFlag = 0;
1489 AC.LineLength = AM.gLineLength = 79;
1490 AC.NwildC = 0;
1491 AC.OutputMode = 0;
1492 AM.gOutputMode = 0;
1493 AC.OutputSpaces = NORMALFORMAT;
1494 AM.gOutputSpaces = NORMALFORMAT;
1495 AC.OutNumberType = RATIONALMODE;
1496 AM.gOutNumberType = RATIONALMODE;
1497#ifdef WITHZLIB
1498 AR.gzipCompress = GZIPDEFAULT;
1499 AR.FoStage4[0].ziobuffer = 0;
1500 AR.FoStage4[1].ziobuffer = 0;
1501#ifdef WITHZSTD
1502 /* Zstd compression is on by default, if we have compiled with it */
1503 ZWRAP_useZSTDcompression(1);
1504#endif
1505#endif
1506 AR.BracketOn = 0;
1507 AC.bracketindexflag = 0;
1508 AT.bracketindexflag = 0;
1509 AT.bracketinfo = 0;
1510 AO.IsBracket = 0;
1511 AM.gfunpowers = AC.funpowers = COMFUNPOWERS;
1512 AC.parallelflag = AM.gparallelflag;
1513 AC.properorderflag = AM.gproperorderflag = PROPERORDERFLAG;
1514 AC.ProcessBucketSize = AC.mProcessBucketSize = AM.gProcessBucketSize;
1515 AC.ThreadBucketSize = AM.gThreadBucketSize;
1516 AC.ShortStatsMax = 0;
1517 AM.gShortStatsMax = 0;
1518 AM.ggShortStatsMax = 0;
1519
1520 GlobalSymbols = NumSymbols;
1521 GlobalIndices = NumIndices;
1522 GlobalVectors = NumVectors;
1523 GlobalFunctions = NumFunctions;
1524 GlobalSets = NumSets;
1525 GlobalSetElements = NumSetElements;
1526 AC.modpowers = (UWORD *)0;
1527
1528 i = AM.OffsetIndex;
1529 fi = AC.FixIndices;
1530 if ( i > 0 ) do { *fi++ = one; } while ( --i >= 0 );
1531 AR.sLevel = -1;
1532 AM.Ordering[0] = 5;
1533 AM.Ordering[1] = 6;
1534 AM.Ordering[2] = 7;
1535 AM.Ordering[3] = 0;
1536 AM.Ordering[4] = 1;
1537 AM.Ordering[5] = 2;
1538 AM.Ordering[6] = 3;
1539 AM.Ordering[7] = 4;
1540 for ( i = 8; i < 15; i++ ) AM.Ordering[i] = i;
1541 AM.gUniTrace[0] =
1542 AC.lUniTrace[0] = SNUMBER;
1543 AM.gUniTrace[1] =
1544 AC.lUniTrace[1] =
1545 AM.gUniTrace[2] =
1546 AC.lUniTrace[2] = 4;
1547 AM.gUniTrace[3] =
1548 AC.lUniTrace[3] = 1;
1549#ifdef WITHPTHREADS
1550 AS.Balancing = 0;
1551#else
1552 AT.MinVecArg[0] = 7+ARGHEAD;
1553 AT.MinVecArg[ARGHEAD] = 7;
1554 AT.MinVecArg[1+ARGHEAD] = INDEX;
1555 AT.MinVecArg[2+ARGHEAD] = 3;
1556 AT.MinVecArg[3+ARGHEAD] = 0;
1557 AT.MinVecArg[4+ARGHEAD] = 1;
1558 AT.MinVecArg[5+ARGHEAD] = 1;
1559 AT.MinVecArg[6+ARGHEAD] = -3;
1560 t = AT.FunArg;
1561 *t++ = 4+ARGHEAD+FUNHEAD;
1562 for ( i = 1; i < ARGHEAD; i++ ) *t++ = 0;
1563 *t++ = 4+FUNHEAD;
1564 *t++ = 0;
1565 *t++ = FUNHEAD;
1566 for ( i = 2; i < FUNHEAD; i++ ) *t++ = 0;
1567 *t++ = 1; *t++ = 1; *t++ = 3;
1568
1569#ifdef WITHMPI
1570 AS.printflag = 0;
1571#endif
1572
1573 AT.comsym[0] = 8;
1574 AT.comsym[1] = SYMBOL;
1575 AT.comsym[2] = 4;
1576 AT.comsym[3] = 0;
1577 AT.comsym[4] = 1;
1578 AT.comsym[5] = 1;
1579 AT.comsym[6] = 1;
1580 AT.comsym[7] = 3;
1581 AT.comnum[0] = 4;
1582 AT.comnum[1] = 1;
1583 AT.comnum[2] = 1;
1584 AT.comnum[3] = 3;
1585 AT.comfun[0] = FUNHEAD+4;
1586 AT.comfun[1] = FUNCTION;
1587 AT.comfun[2] = FUNHEAD;
1588 AT.comfun[3] = 0;
1589#if FUNHEAD == 4
1590 AT.comfun[4] = 0;
1591#endif
1592 AT.comfun[FUNHEAD+1] = 1;
1593 AT.comfun[FUNHEAD+2] = 1;
1594 AT.comfun[FUNHEAD+3] = 3;
1595 AT.comind[0] = 7;
1596 AT.comind[1] = INDEX;
1597 AT.comind[2] = 3;
1598 AT.comind[3] = 0;
1599 AT.comind[4] = 1;
1600 AT.comind[5] = 1;
1601 AT.comind[6] = 3;
1602 AT.locwildvalue[0] = SUBEXPRESSION;
1603 AT.locwildvalue[1] = SUBEXPSIZE;
1604 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.locwildvalue[i] = 0;
1605 AT.mulpat[0] = TYPEMULT;
1606 AT.mulpat[1] = SUBEXPSIZE+3;
1607 AT.mulpat[2] = 0;
1608 AT.mulpat[3] = SUBEXPRESSION;
1609 AT.mulpat[4] = SUBEXPSIZE;
1610 AT.mulpat[5] = 0;
1611 AT.mulpat[6] = 1;
1612 for ( i = 7; i < SUBEXPSIZE+5; i++ ) AT.mulpat[i] = 0;
1613 AT.proexp[0] = SUBEXPSIZE+4;
1614 AT.proexp[1] = EXPRESSION;
1615 AT.proexp[2] = SUBEXPSIZE;
1616 AT.proexp[3] = -1;
1617 AT.proexp[4] = 1;
1618 for ( i = 5; i < SUBEXPSIZE+1; i++ ) AT.proexp[i] = 0;
1619 AT.proexp[SUBEXPSIZE+1] = 1;
1620 AT.proexp[SUBEXPSIZE+2] = 1;
1621 AT.proexp[SUBEXPSIZE+3] = 3;
1622 AT.proexp[SUBEXPSIZE+4] = 0;
1623 AT.dummysubexp[0] = SUBEXPRESSION;
1624 AT.dummysubexp[1] = SUBEXPSIZE+4;
1625 for ( i = 2; i < SUBEXPSIZE; i++ ) AT.dummysubexp[i] = 0;
1626 AT.dummysubexp[SUBEXPSIZE] = WILDDUMMY;
1627 AT.dummysubexp[SUBEXPSIZE+1] = 4;
1628 AT.dummysubexp[SUBEXPSIZE+2] = 0;
1629 AT.dummysubexp[SUBEXPSIZE+3] = 0;
1630
1631 AT.inprimelist = -1;
1632 AT.sizeprimelist = 0;
1633 AT.primelist = 0;
1634 AT.LeaveNegative = 0;
1635 AT.TrimPower = 0;
1636 AN.SplitScratch = 0;
1637 AN.SplitScratchSize = AN.InScratch = 0;
1638 AN.SplitScratch1 = 0;
1639 AN.SplitScratchSize1 = AN.InScratch1 = 0;
1640 AN.idfunctionflag = 0;
1641#endif
1642 AO.OutputLine = AO.OutFill = BufferForOutput;
1643 AO.FactorMode = 0;
1644 C->Pointer = C->Buffer;
1645
1646 AP.PreOut = 0;
1647 AP.ComChar = AP.cComChar;
1648 AC.cbufnum = AM.rbufnum; /* Select the default compiler buffer */
1649 AC.HideLevel = 0;
1650 AP.PreAssignFlag = 0;
1651}
1652
1653/*
1654 #] IniVars :
1655 #[ Signal handlers :
1656*/
1657/*[28apr2004 mt]:*/
1658#ifdef TRAPSIGNALS
1659
1660static int exitInProgress = 0;
1661static int trappedTerminate = 0;
1662
1663/*INTSIGHANDLER : some systems require a signal handler to return an integer,
1664 so define the macro INTSIGHANDLER if compiler fails:*/
1665#ifdef INTSIGHANDLER
1666static int onErrSig(int i)
1667#else
1668static void onErrSig(int i)
1669#endif
1670{
1671 if (exitInProgress){
1672 signal(i,SIG_DFL);/* Use default behaviour*/
1673 raise (i);/*reproduce trapped signal*/
1674#ifdef INTSIGHANDLER
1675 return(i);
1676#else
1677 return;
1678#endif
1679 }
1680 trappedTerminate = 1;
1681 /*[13jul2005 mt]*//*TerminateImpl(-1) on signal is here:*/
1682 Terminate(-1);
1683}
1684
1685#ifdef INTSIGHANDLER
1686static void setNewSig(int i, int (*handler)(int))
1687#else
1688static void setNewSig(int i, void (*handler)(int))
1689#endif
1690{
1691 if(! (i<NSIG) )/* Invalid signal -- see comments in the file */
1692 return;
1693 if ( signal(i,SIG_IGN) !=SIG_IGN)
1694 /* if compiler fails here, try to define INTSIGHANDLER):*/
1695 signal(i,handler);
1696}
1697
1698void setSignalHandlers(void)
1699{
1700 /* Reset various unrecoverable error signals:*/
1701 setNewSig(SIGSEGV,onErrSig);
1702 setNewSig(SIGFPE,onErrSig);
1703 setNewSig(SIGILL,onErrSig);
1704 setNewSig(SIGEMT,onErrSig);
1705 setNewSig(SIGSYS,onErrSig);
1706 setNewSig(SIGPIPE,onErrSig);
1707 setNewSig(SIGLOST,onErrSig);
1708 setNewSig(SIGXCPU,onErrSig);
1709 setNewSig(SIGXFSZ,onErrSig);
1710
1711 /* Reset interrupt signals:*/
1712 setNewSig(SIGTERM,onErrSig);
1713 setNewSig(SIGINT,onErrSig);
1714 setNewSig(SIGQUIT,onErrSig);
1715 setNewSig(SIGHUP,onErrSig);
1716 setNewSig(SIGALRM,onErrSig);
1717 setNewSig(SIGVTALRM,onErrSig);
1718/* setNewSig(SIGPROF,onErrSig); */ /* Why did Tentukov forbid profilers?? */
1719}
1720
1721#endif
1722/*:[28apr2004 mt]*/
1723/*
1724 #] Signal handlers :
1725 #[ main :
1726*/
1727
1728#ifdef WITHPTHREADS
1729ALLPRIVATES *ABdummy[10];
1730#endif
1731
1732int main(int argc, char **argv)
1733{
1734 int retval;
1735 bzero((void *)(&A),sizeof(A)); /* make sure A is initialized at zero */
1736 iniTools();
1737#ifdef TRAPSIGNALS
1738 setSignalHandlers();
1739#endif
1740#ifdef WINDOWS
1741 _setmode(_fileno(stdout),O_BINARY);
1742#endif
1743
1744#ifdef WITHPTHREADS
1745 AB = ABdummy;
1746 StartHandleLock();
1747 BeginIdentities();
1748#else
1749 AM.SumTime = TimeCPU(0);
1750 TimeWallClock(0);
1751#endif
1752
1753#ifdef WITHMPI
1754 if ( PF_Init(&argc,&argv) ) exit(-1);
1755#endif
1756
1757 StartFiles();
1759#ifdef WITHMPI
1760 /*
1761 * Here MesPrint() is ready. We turn on AS.printflag to print possible
1762 * errors occurring on slaves in the initialization. With AS.printflag = -1
1763 * MesPrint() does not use the synchronized output. This may lead broken
1764 * texts in the output somewhat, but it is safer to implement in this way
1765 * for the situation in which some of MesPrint() calls use MLOCK()-MUNLOCK()
1766 * and some do not. In future if we set AS.printflag = 1 and modify the
1767 * source code such that all MesPrint() calls are sandwiched by MLOCK()-
1768 * MUNLOCK(), we need also to modify the code for the master to catch
1769 * messages corresponding to MUNLOCK() calls at some point.
1770 *
1771 * AS.printflag will be set to 0 in IniVars() to prevent slaves from
1772 * printing redundant errors in the preprocessor and compiler (e.g., syntax
1773 * errors).
1774 */
1775 AS.printflag = -1;
1776#endif
1777
1778 if ( ( retval = DoTail(argc,(UBYTE **)argv) ) != 0 ) {
1779 if ( retval > 0 ) Terminate(0);
1780 else Terminate(-1);
1781 }
1782 if ( DoSetups() ) Terminate(-2);
1783#ifdef WITHMPI
1784 /* It is messy if all errors in OpenInput() on slaves are printed. */
1785 AS.printflag = 0;
1786#endif
1787 if ( OpenInput() ) Terminate(-3);
1788#ifdef WITHMPI
1789 AS.printflag = -1;
1790#endif
1791 if ( TryEnvironment() ) Terminate(-2);
1792 if ( TryFileSetups() ) Terminate(-2);
1793 if ( MakeSetupAllocs() ) Terminate(-2);
1794 StartMore();
1795 InitRecovery();
1797 if ( AM.totalnumberofthreads == 0 ) AM.totalnumberofthreads = 1;
1798 AS.MultiThreaded = 0;
1799#ifdef WITHPTHREADS
1800 if ( AM.totalnumberofthreads > 1 ) AS.MultiThreaded = 1;
1801 ReserveTempFiles(1);
1802 StartAllThreads(AM.totalnumberofthreads);
1803 IniFbufs();
1804#else
1805 ReserveTempFiles(0);
1806 IniFbuffer(AT.fbufnum);
1807#endif
1808 if ( !AM.FromStdin ) PrintHeader(1);
1809 IniVars();
1810 Globalize(1);
1811#ifdef WITH_ALARM
1812 if ( AM.TimeLimit > 0 ) alarm(AM.TimeLimit);
1813#endif
1814#ifdef WITHFLINT
1816#endif
1817 TimeCPU(0);
1818 TimeChildren(0);
1819 TimeWallClock(0);
1820 PreProcessor();
1821 Terminate(0);
1822 return(0);
1823}
1824/*
1825 #] main :
1826 #[ CleanUp :
1827
1828 if par < 0 we have to keep the storage file.
1829 when par > 0 we ran into a .clear statement.
1830 In that case we keep the zero level input and the log file.
1831
1832*/
1833
1834void CleanUp(WORD par)
1835{
1836 GETIDENTITY
1837 int i;
1838
1839 if ( FG.fname ) {
1840#ifdef WITHPTHREADS
1841 if ( B ) {
1842#endif
1843 CleanUpSort(0);
1844 for ( i = 0; i < 3; i++ ) {
1845 if ( AR.Fscr[i].handle >= 0 ) {
1846 if ( AR.Fscr[i].name ) {
1847/*
1848 If there are more threads referring to the same file
1849 only the one with the name is the owner of the file.
1850*/
1851 CloseFile(AR.Fscr[i].handle);
1852 remove(AR.Fscr[i].name);
1853 }
1854 AR.Fscr[i].handle = - 1;
1855 AR.Fscr[i].POfill = 0;
1856 }
1857 }
1858#ifdef WITHPTHREADS
1859 }
1860#endif
1861 if ( par > 0 ) {
1862/*
1863 Close all input levels above the lowest?
1864*/
1865 }
1866 if ( AC.StoreHandle >= 0 && par <= 0 ) {
1867#ifdef TRAPSIGNALS
1868 if ( trappedTerminate ) { /* We don't throw .str if it has contents */
1869 POSITION pos;
1870 PUTZERO(pos);
1871 SeekFile(AC.StoreHandle,&pos,SEEK_END);
1872 if ( ISNOTZEROPOS(pos) ) {
1873 CloseFile(AC.StoreHandle);
1874 goto dontremove;
1875 }
1876 }
1877 CloseFile(AC.StoreHandle);
1878#ifdef WITHPTHREADS
1879 if ( B )
1880#endif
1881 if ( par >= 0 || AR.StoreData.Handle < 0 || AM.ClearStore ) {
1882 remove(FG.fname);
1883 }
1884dontremove:;
1885#else
1886 CloseFile(AC.StoreHandle);
1887#ifdef WITHPTHREADS
1888 if ( B )
1889#endif
1890 if ( par >= 0 || AR.StoreData.Handle < 0 || AM.ClearStore > 0 ) {
1891 remove(FG.fname);
1892 }
1893#endif
1894 }
1895 }
1896 ClearSpectators(CLEARMODULE);
1897/*
1898 Remove recovery file on exit if everything went well
1899*/
1900 if ( par == 0 ) {
1902 }
1903/*
1904 Now the final message concerning the total time
1905*/
1906 if ( AC.LogHandle >= 0 && par <= 0 ) {
1907 WORD lh = AC.LogHandle;
1908 AC.LogHandle = -1;
1909#ifdef WITHMPI
1910 if ( PF.me == MASTER ) /* Only the master opened the real file. */
1911#endif
1912 CloseFile(lh);
1913 }
1914}
1915
1916/*
1917 #] CleanUp :
1918 #[ TerminateImpl :
1919*/
1920
1921static int firstterminate = 1;
1922
1923void TerminateImpl(int errorcode, const char* file, int line, const char* function)
1924{
1925#ifdef WITHMPI
1926 if ( errorcode && firstterminate && !PF.notMyFault ) {
1927#else
1928 if ( errorcode && firstterminate ) {
1929#endif
1930 firstterminate = 0;
1931
1932 MLOCK(ErrorMessageLock);
1933#ifdef WITHPTHREADS
1934 MesPrint("Program terminating in thread %w at &");
1935#elif defined(WITHMPI)
1936 MesPrint("Program terminating in process %w at &");
1937#else
1938 MesPrint("Program terminating at &");
1939#endif
1940 MesPrint("Terminate called from %s:%d (%s)", file, line, function);
1941
1942 if ( AC.PrintBacktraceFlag ) {
1943#ifdef ENABLE_BACKTRACE
1944 void *stack[64];
1945 int stacksize, stop = 0;
1946 stacksize = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
1947
1948 /* First check whether eu-addr2line is available */
1949 if ( !system("command -v eu-addr2line > /dev/null 2>&1") ) {
1950 MesPrint("Backtrace:");
1951 for (int i = 0; i < stacksize && !stop; i++) {
1952 FILE *fp;
1953 char cmd[512];
1954 // Leave an initial space
1955 cmd[0] = ' ';
1956 MesPrint("%#%2d:%", i);
1957 snprintf(cmd+1, sizeof(cmd)-1, "eu-addr2line -s --pretty-print -f -i '%p' --pid=%d\n", stack[i], getpid());
1958 fp = popen(cmd+1, "r");
1959 while ( fgets(cmd+1, sizeof(cmd)-1, fp) != NULL ) {
1960 MesPrint("%s", cmd);
1961 /* Don't show functions lower than "main" (or thread equivalent) */
1962 if ( strstr(cmd, " main ") || strstr(cmd, " RunThread ") || strstr(cmd, " RunSortBot ") ) {
1963 stop = 1;
1964 }
1965 }
1966 pclose(fp);
1967 }
1968 }
1969#ifdef LINUX
1970 else if ( !system("command -v addr2line > /dev/null 2>&1") ) {
1971 /* Get the executable path. */
1972 char exe_path[PATH_MAX];
1973 {
1974 ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
1975 if ( len != -1 ) {
1976 exe_path[len] = '\0';
1977 }
1978 else {
1979 goto backtrace_fallback;
1980 }
1981 }
1982 /* Assume PIE binary and get the base address. */
1983 uintptr_t base_address = 0;
1984 {
1985 char line[256];
1986 FILE *maps = fopen("/proc/self/maps", "r");
1987 if ( !maps ) {
1988 goto backtrace_fallback;
1989 }
1990 /* See the format used by nommu_region_show() in fs/proc/nommu.c of the Linux source. */
1991 if ( fgets(line, sizeof(line), maps) ) {
1992 sscanf(line, "%" SCNxPTR "-", &base_address);
1993 }
1994 else {
1995 fclose(maps);
1996 goto backtrace_fallback;
1997 }
1998 fclose(maps);
1999 }
2000 char **strings;
2001 strings = backtrace_symbols(stack, stacksize);
2002 MesPrint("Backtrace:");
2003 for ( int i = 0; i < stacksize && !stop; i++ ) {
2004 FILE *fp;
2005 char cmd[PATH_MAX + 512];
2006 // Leave an initial space
2007 cmd[0] = ' ';
2008 uintptr_t addr = (uintptr_t)stack[i] - base_address;
2009 MesPrint("%#%2d:%", i);
2010 snprintf(cmd+1, sizeof(cmd)-1, "addr2line -e \"%s\" -i -p -s -f -C 0x%" PRIxPTR, exe_path, addr);
2011 fp = popen(cmd+1, "r");
2012 while ( fgets(cmd+1, sizeof(cmd)-1, fp) != NULL ) {
2013 MesPrint("%s", cmd);
2014 /* Don't show functions lower than "main" */
2015 if ( strstr(cmd, " main ") || strstr(cmd, " RunThread ") || strstr(cmd, " RunSortBot ") ) {
2016 stop = 1;
2017 }
2018 }
2019 pclose(fp);
2020 }
2021 free(strings);
2022 }
2023#endif
2024 else {
2025 /* eu-addr2line not found */
2026#ifdef LINUX
2027backtrace_fallback: ;
2028#endif
2029 char **strings;
2030 strings = backtrace_symbols(stack, stacksize);
2031 MesPrint("Backtrace:");
2032 for ( int i = 0; i < stacksize && !stop; i++ ) {
2033 char *p = strings[i];
2034 while ( *p && *p != '(' ) p++;
2035 MesPrint("%#%2d: %s\n", i, p);
2036 /* Don't show functions lower than "main" (or thread equivalent) */
2037 if ( strstr(p, "(main+") || strstr(p, "(RunThread+") || strstr(p, "(RunSortBot+") ) {
2038 stop = 1;
2039 }
2040 }
2041#ifdef LINUX
2042 MesPrint("Please install addr2line or eu-addr2line for readable stack information.");
2043#else
2044 MesPrint("Please install eu-addr2line for readable stack information.");
2045#endif
2046 free(strings);
2047 }
2048#else
2049 MesPrint("FORM compiled without backtrace support.");
2050#endif
2051 } /* if ( AC.PrintBacktraceFlag) { */
2052
2053 MUNLOCK(ErrorMessageLock);
2054
2055#ifdef WITHMPI
2056 PF_PreTerminate(errorcode);
2057#endif
2058 Crash();
2059 }
2060#ifdef TRAPSIGNALS
2061 exitInProgress=1;
2062#endif
2063#ifdef WITHEXTERNALCHANNEL
2064/*
2065 This function can be called from the error handler, so it is better to
2066 clean up all started processes before any activity:
2067*/
2068 closeAllExternalChannels();
2069 AX.currentExternalChannel=0;
2070 /*[08may2006 mt]:*/
2071 AX.killSignal=SIGKILL;
2072 AX.killWholeGroup=1;
2073 AX.daemonize=1;
2074 /*:[08may2006 mt]*/
2075 if(AX.currentPrompt){
2076 M_free(AX.currentPrompt,"external channel prompt");
2077 AX.currentPrompt=0;
2078 }
2079 /*[08may2006 mt]:*/
2080 if(AX.shellname){
2081 M_free(AX.shellname,"external channel shellname");
2082 AX.shellname=0;
2083 }
2084 if(AX.stderrname){
2085 M_free(AX.stderrname,"external channel stderrname");
2086 AX.stderrname=0;
2087 }
2088 /*:[08may2006 mt]*/
2089#endif
2090#ifdef WITHPTHREADS
2091 if ( !WhoAmI() && !errorcode ) {
2092 TerminateAllThreads();
2093 }
2094#endif
2095 if ( AC.FinalStats ) {
2096 if ( AM.PrintTotalSize ) {
2097 MesPrint("Max. space for expressions: %19p bytes",&(AS.MaxExprSize));
2098 }
2099 PrintRunningTime();
2100 }
2101#ifdef WITHMPI
2102 if ( AM.HoldFlag && PF.me == MASTER ) {
2103 WriteFile(AM.StdOut,(UBYTE *)("Hit any key "),12);
2105 getchar();
2106 }
2107#else
2108 if ( AM.HoldFlag ) {
2109 WriteFile(AM.StdOut,(UBYTE *)("Hit any key "),12);
2110 getchar();
2111 }
2112#endif
2113#ifdef WITHMPI
2114 PF_Terminate(errorcode);
2115#endif
2116/*
2117 We are about to terminate the program. If we are using flint, call the cleanup function.
2118 This keeps valgrind happy.
2119*/
2120#ifdef WITHFLINT
2121 flint_final_cleanup_master();
2122#endif
2123 CleanUp(errorcode);
2124 M_print();
2125#ifdef VMS
2126 P_term(errorcode? 0: 1);
2127#else
2128 P_term(errorcode);
2129#endif
2130}
2131
2132/*
2133 #] TerminateImpl :
2134 #[ PrintDeprecation :
2135*/
2136
2143void PrintDeprecation(const char *feature, const char *issue) {
2144#ifdef WITHMPI
2145 if ( PF.me != MASTER ) return;
2146#endif
2147 if ( AM.IgnoreDeprecation ) return;
2148
2149 UBYTE *e = (UBYTE *)getenv("FORM_IGNORE_DEPRECATION");
2150 if ( e && e[0] && StrCmp(e, (UBYTE *)"0") && StrICmp(e, (UBYTE *)"false") && StrICmp(e, (UBYTE *)"no") ) return;
2151
2152 MesPrint("DeprecationWarning: We are considering deprecating %s.", feature);
2153 MesPrint("If you want this support to continue, leave a comment at:");
2154 MesPrint("");
2155 MesPrint(" https://github.com/form-dev/form/%s", issue);
2156 MesPrint("");
2157 MesPrint("Otherwise, it will be discontinued in the future.");
2158 MesPrint("To suppress this warning, use the -ignore-deprecation command line option or");
2159 MesPrint("set the environment variable FORM_IGNORE_DEPRECATION=1.");
2160}
2161
2162/*
2163 #] PrintDeprecation :
2164 #[ PrintRunningTime :
2165*/
2166
2167void PrintRunningTime(void)
2168{
2169#if (defined(WITHPTHREADS) && (defined(WITHPOSIXCLOCK) || defined(WINDOWS))) || defined(WITHMPI)
2170 LONG mastertime;
2171 LONG workertime;
2172 LONG wallclocktime;
2173 LONG totaltime;
2174#if defined(WITHPTHREADS)
2175 if ( AB[0] != 0 ) {
2176 workertime = GetWorkerTimes();
2177#else
2178 workertime = PF_GetSlaveTimes(); /* must be called on all processors */
2179 if ( PF.me == MASTER ) {
2180#endif
2181 mastertime = AM.SumTime + TimeCPU(1);
2182 wallclocktime = TimeWallClock(1);
2183 totaltime = mastertime+workertime;
2184 if ( !AM.silent ) {
2185 MesPrint(" %l.%2i sec + %l.%2i sec: %l.%2i sec out of %l.%2i sec",
2186 mastertime/1000,(WORD)((mastertime%1000)/10),
2187 workertime/1000,(WORD)((workertime%1000)/10),
2188 totaltime/1000,(WORD)((totaltime%1000)/10),
2189 wallclocktime/100,(WORD)(wallclocktime%100));
2190 }
2191 }
2192#else
2193 LONG mastertime = AM.SumTime + TimeCPU(1);
2194 LONG wallclocktime = TimeWallClock(1);
2195 if ( !AM.silent ) {
2196 MesPrint(" %l.%2i sec out of %l.%2i sec",
2197 mastertime/1000,(WORD)((mastertime%1000)/10),
2198 wallclocktime/100,(WORD)(wallclocktime%100));
2199 }
2200#endif
2201}
2202
2203/*
2204 #] PrintRunningTime :
2205 #[ GetRunningTime :
2206*/
2207
2208LONG GetRunningTime(void)
2209{
2210#if defined(WITHPTHREADS) && (defined(WITHPOSIXCLOCK) || defined(WINDOWS))
2211 LONG mastertime;
2212 if ( AB[0] != 0 ) {
2213/*
2214#if ( defined(APPLE64) || defined(APPLE32) )
2215 mastertime = AM.SumTime + TimeCPU(1);
2216 return(mastertime);
2217#else
2218*/
2219 LONG workertime = GetWorkerTimes();
2220 mastertime = AM.SumTime + TimeCPU(1);
2221 return(mastertime+workertime);
2222/*
2223#endif
2224*/
2225 }
2226 else {
2227 return(AM.SumTime + TimeCPU(1));
2228 }
2229#elif defined(WITHMPI)
2230 LONG mastertime, t = 0;
2231 LONG workertime = PF_GetSlaveTimes(); /* must be called on all processors */
2232 if ( PF.me == MASTER ) {
2233 mastertime = AM.SumTime + TimeCPU(1);
2234 t = mastertime + workertime;
2235 }
2236 return PF_BroadcastNumber(t); /* must be called on all processors */
2237#else
2238 return(AM.SumTime + TimeCPU(1));
2239#endif
2240}
2241
2242/*
2243 #] GetRunningTime :
2244*/
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:4603
LONG TimeWallClock(WORD)
Definition tools.c:3415
void PrintFeatureList(void)
Definition features.cc:131
WORD Compare1(PHEAD WORD *, WORD *, WORD)
Definition sort.c:2375
LONG TimeCPU(WORD)
Definition tools.c:3489
int PutPreVar(UBYTE *, UBYTE *, UBYTE *, int)
Definition pre.c:724
void flint_check_version(void)
Definition flintwrap.cc:323
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:2143
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