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