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