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