FORM  4.3
module.c
Go to the documentation of this file.
1 
7 /* #[ License : */
8 /*
9  * Copyright (C) 1984-2022 J.A.M. Vermaseren
10  * When using this file you are requested to refer to the publication
11  * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
12  * This is considered a matter of courtesy as the development was paid
13  * for by FOM the Dutch physics granting agency and we would like to
14  * be able to track its scientific use to convince FOM of its value
15  * for the community.
16  *
17  * This file is part of FORM.
18  *
19  * FORM is free software: you can redistribute it and/or modify it under the
20  * terms of the GNU General Public License as published by the Free Software
21  * Foundation, either version 3 of the License, or (at your option) any later
22  * version.
23  *
24  * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
25  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
26  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
27  * details.
28  *
29  * You should have received a copy of the GNU General Public License along
30  * with FORM. If not, see <http://www.gnu.org/licenses/>.
31  */
32 /* #] License : */
33 /*
34  #[ Includes :
35 */
36 
37 #include "form3.h"
38 
39 /*
40  #] Includes :
41  #[ Modules :
42  #[ ModuleInstruction :
43 
44  Enters after the . of .sort etc
45  We have word[[(options)][:commentary];]
46  Word is one of 'clear end global sort store'
47  Options are 'polyfun, endloopifunchanged, endloopifzero'
48  Additions for solving equations can be added to 'word'
49 
50  The flag in the moduleoptions is for telling whether the current
51  option can be followed by others. If it is > 0 it cannot.
52 */
53 
54 static KEYWORD ModuleWords[] = {
55  {"clear", (TFUN)0, CLEARMODULE, 0}
56  ,{"end", (TFUN)0, ENDMODULE, 0}
57  ,{"global", (TFUN)0, GLOBALMODULE, 0}
58  ,{"sort", (TFUN)0, SORTMODULE, 0}
59  ,{"store", (TFUN)0, STOREMODULE, 0}
60 };
61 
62 static KEYWORD ModuleOptions[] = {
63  {"inparallel", DoinParallel, 1, 1}
64  ,{"local", DoModLocal, MODLOCAL, 0}
65  ,{"maximum", DoModMax, MODMAX, 0}
66  ,{"minimum", DoModMin, MODMIN, 0}
67  ,{"noparallel", DoNoParallel, NOPARALLEL_USER,0}
68  ,{"notinparallel", DonotinParallel,0, 1}
69  ,{"parallel", DoParallel, PARALLELFLAG, 0}
70  ,{"polyfun", DoPolyfun, POLYFUN, 0}
71  ,{"polyratfun", DoPolyratfun, POLYFUN, 0}
72  ,{"processbucketsize", DoProcessBucket,0, 0}
73  ,{"sum", DoModSum, MODSUM, 0}
74 };
75 
76 int ModuleInstruction(int *moduletype, int *specialtype)
77 {
78  UBYTE *t, *s, *u, c;
79  KEYWORD *key;
80  int addit = 0, error = 0, i, j;
81  DUMMYUSE(specialtype);
82  LoadInstruction(0);
83  AC.firstctypemessage = 0;
84  s = AP.preStart; SKIPBLANKS(s)
85  t = EndOfToken(s); c = *t; *t = 0;
86  AC.origin = FROMPOINTINSTRUCTION;
87  key = FindKeyWord(AP.preStart,ModuleWords,sizeof(ModuleWords)/sizeof(KEYWORD));
88  if ( key == 0 ) {
89  MesPrint("@Unrecognized module terminator: %s",s);
90  error = 1;
91  key = ModuleWords;
92  while ( StrCmp((UBYTE *)key->name,(UBYTE *)"end") ) key++;
93  }
94  *t = c;
95  *moduletype = key->type;
96  SKIPBLANKS(t);
97  while ( *t == '(' ) { /* There are options */
98  s = t+1; SKIPBRA3(t)
99  if ( *t == 0 ) {
100  MesPrint("@Improper options field in . instruction");
101  error = 1;
102  }
103  else {
104  *t = 0;
105  if ( CoModOption(s) ) error = 1;
106  *t++ = ')';
107  }
108  }
109  if ( *t == ':' ) { /* There is an 'advertisement' */
110  t++;
111  SKIPBLANKS(t)
112  s = t; i = 0;
113  while ( *t && *t != ';' ) {
114  if ( *t == '\\' ) t++;
115  t++; i++;
116  }
117  u = t;
118  while ( u > s && u[-1] == ' ' ) { u--; i--; }
119  if ( *u == '\\' ) { u++; i++; }
120  for ( j = COMMERCIALSIZE-1; j >= 0; j-- ) {
121  if ( i <= 0 ) break;
122  AC.Commercial[j] = *--u; i--;
123  if ( u > s && u[-1] == '\\' ) u--;
124  }
125  for ( ; j >= 0; j-- ) AC.Commercial[j] = ' ';
126  AC.Commercial[COMMERCIALSIZE] = 0;
127  addit += 2;
128  }
129  if ( addit && *t != ';' ) {
130  MesPrint("@Improper ending of . instruction");
131  error = -1;
132  }
133  return(error);
134 }
135 
136 /*
137  #] ModuleInstruction :
138  #[ CoModuleOption :
139 
140  ModuleOption, options;
141 */
142 
143 int CoModuleOption(UBYTE *s)
144 {
145  UBYTE *t,*tt,c;
146  KEYWORD *option;
147  int error = 0, polyflag = 0;
148  AC.origin = FROMMODULEOPTION;
149  if ( *s ) do {
150  s = ToToken(s);
151  t = EndOfToken(s);
152  c = *t; *t = 0;
153  option = FindKeyWord(s,ModuleOptions,
154  sizeof(ModuleOptions)/sizeof(KEYWORD));
155  if ( option == 0 ) {
156  if ( polyflag ) {
157  *t = c; t++; s = SkipAName(t);
158  polyflag = 0;
159  continue;
160  }
161  else {
162  MesPrint("@Unrecognized module option: %s",s);
163  error = 1;
164  polyflag = 0;
165  *t = c;
166  }
167  }
168  else {
169  *t = c;
170  SKIPBLANKS(t)
171  if ( (option->func)(t) ) error = 1;
172  }
173  if ( StrCmp((UBYTE *)(option->name),(UBYTE *)("polyfun")) == 0
174  || StrCmp((UBYTE *)(option->name),(UBYTE *)("polyratfun")) == 0 ) {
175  polyflag = 1;
176  }
177  else polyflag = 0;
178  if ( option->flags > 0 ) return(error);
179  while ( *t ) {
180  if ( *t == ',' ) {
181  tt = t+1;
182  while ( *tt == ',' ) tt++;
183  if ( *tt != '$' ) break;
184  t = tt+1;
185  }
186  if ( *t == ')' ) break;
187  if ( *t == '(' ) SKIPBRA3(t)
188  else if ( *t == '{' ) SKIPBRA2(t)
189  else if ( *t == '[' ) SKIPBRA1(t)
190  t++;
191  }
192  s = t;
193  } while ( *s == ',' );
194  if ( *s ) {
195  MesPrint("@Unrecognized module option: %s",s);
196  error = 1;
197  }
198  return(error);
199 }
200 
201 /*
202  #] CoModuleOption :
203  #[ CoModOption :
204 
205  To be called from a .instruction.
206  Only recognizes polyfun. The newer ones should be via the
207  ModuleOption statement.
208 */
209 
210 int CoModOption(UBYTE *s)
211 {
212  UBYTE *t,c;
213  int error = 0;
214  AC.origin = FROMPOINTINSTRUCTION;
215  if ( *s ) do {
216  s = ToToken(s);
217  t = EndOfToken(s);
218  c = *t; *t = 0;
219  if ( StrICmp(s,(UBYTE *)"polyfun") == 0 ) {
220  *t = c;
221  SKIPBLANKS(t)
222  if ( DoPolyfun(t) ) error = 1;
223  }
224  else if ( StrICmp(s,(UBYTE *)"polyratfun") == 0 ) {
225  *t = c;
226  SKIPBLANKS(t)
227  if ( DoPolyratfun(t) ) error = 1;
228  }
229  else {
230  MesPrint("@Unrecognized module option in .instruction: %s",s);
231  error = 1;
232  *t = c;
233  }
234  while ( *t ) {
235  if ( *t == ',' || *t == ')' ) break;
236  if ( *t == '(' ) SKIPBRA3(t)
237  else if ( *t == '{' ) SKIPBRA2(t)
238  else if ( *t == '[' ) SKIPBRA1(t)
239  t++;
240  }
241  s = t;
242  } while ( *s == ',' );
243  if ( *s ) {
244  MesPrint("@Unrecognized module option in .instruction: %s",s);
245  error = 1;
246  }
247  return(error);
248 }
249 
250 /*
251  #] CoModOption :
252  #[ SetSpecialMode :
253 */
254 
255 VOID SetSpecialMode(int moduletype, int specialtype)
256 {
257  DUMMYUSE(moduletype); DUMMYUSE(specialtype);
258 }
259 
260 /*
261  #] SetSpecialMode :
262  #[ MakeGlobal :
263 
264 VOID MakeGlobal()
265 {
266 }
267 
268  #] MakeGlobal :
269  #[ ExecModule :
270 */
271 
272 int ExecModule(int moduletype)
273 {
274  return(DoExecute(moduletype,0));
275 }
276 
277 /*
278  #] ExecModule :
279  #[ ExecStore :
280 */
281 
282 int ExecStore()
283 {
284  return(0);
285 }
286 
287 /*
288  #] ExecStore :
289  #[ FullCleanUp :
290 
291  Remark 27-oct-2005 by JV
292  This routine (and CleanUp in startup.c) may still need some work:
293  What to do with preprocessor variables
294  What to do with files we write to
295 */
296 
297 VOID FullCleanUp()
298 {
299  int j;
300 
301  while ( AC.CurrentStream->previous >= 0 )
302  AC.CurrentStream = CloseStream(AC.CurrentStream);
303  AP.PreSwitchLevel = AP.PreIfLevel = 0;
304 
305  for ( j = NumProcedures-1; j >= 0; j-- ) {
306  if ( Procedures[j].name ) M_free(Procedures[j].name,"name of procedure");
307  if ( Procedures[j].p.buffer ) M_free(Procedures[j].p.buffer,"buffer of procedure");
308  }
309  NumProcedures = 0;
310 
311  while ( NumPre > AP.gNumPre ) {
312  NumPre--;
313  M_free(PreVar[NumPre].name,"PreVar[NumPre].name");
314  PreVar[NumPre].name = PreVar[NumPre].value = 0;
315  }
316 
317  AC.DidClean = 0;
318  for ( j = 0; j < NumExpressions; j++ ) {
319  AC.exprnames->namenode[Expressions[j].node].type = CDELETE;
320  AC.DidClean = 1;
321  }
322 
323  CompactifyTree(AC.exprnames,EXPRNAMES);
324 
325  for ( j = AO.NumDictionaries-1; j >= 0; j-- ) {
326  RemoveDictionary(AO.Dictionaries[j]);
327  M_free(AO.Dictionaries[j],"Dictionary");
328  }
329  AO.NumDictionaries = AO.gNumDictionaries = 0;
330  M_free(AO.Dictionaries,"Dictionaries");
331  AO.Dictionaries = 0;
332  AO.SizeDictionaries = 0;
333  AP.OpenDictionary = 0;
334  AO.CurrentDictionary = 0;
335 
336  AP.ComChar = AP.cComChar;
337  if ( AP.procedureExtension ) M_free(AP.procedureExtension,"procedureextension");
338  AP.procedureExtension = strDup1(AP.cprocedureExtension,"procedureextension");
339 
340  AC.StatsFlag = AM.gStatsFlag = AM.ggStatsFlag;
341  AC.extrasymbols = AM.gextrasymbols = AM.ggextrasymbols;
342  AC.extrasym[0] = AM.gextrasym[0] = AM.ggextrasym[0] = 'Z';
343  AC.extrasym[1] = AM.gextrasym[1] = AM.ggextrasym[1] = 0;
344  AO.NoSpacesInNumbers = AM.gNoSpacesInNumbers = AM.ggNoSpacesInNumbers;
345  AO.IndentSpace = AM.gIndentSpace = AM.ggIndentSpace;
346  AC.ThreadStats = AM.gThreadStats = AM.ggThreadStats;
347  AC.OldFactArgFlag = AM.gOldFactArgFlag = AM.ggOldFactArgFlag;
348  AC.FinalStats = AM.gFinalStats = AM.ggFinalStats;
349  AC.OldGCDflag = AM.gOldGCDflag = AM.ggOldGCDflag;
350  AC.ThreadsFlag = AM.gThreadsFlag = AM.ggThreadsFlag;
351  if ( AC.ThreadsFlag && AM.totalnumberofthreads > 1 ) AS.MultiThreaded = 1;
352  AC.ThreadBucketSize = AM.gThreadBucketSize = AM.ggThreadBucketSize;
353  AC.ThreadBalancing = AM.gThreadBalancing = AM.ggThreadBalancing;
354  AC.ThreadSortFileSynch = AM.gThreadSortFileSynch = AM.ggThreadSortFileSynch;
355  AC.ShortStatsMax = AM.gShortStatsMax = AM.ggShortStatsMax;
356  AC.SizeCommuteInSet = AM.gSizeCommuteInSet = 0;
357 
358  NumExpressions = 0;
359  if ( DeleteStore(0) < 0 ) {
360  MesPrint("@Cannot restart the storage file");
361  Terminate(-1);
362  }
363  RemoveDollars();
364  CleanUp(1);
365  ResetVariables(2);
366  IniVars();
367 }
368 
369 /*
370  #] FullCleanUp :
371  #[ DoPolyfun :
372 */
373 
374 int DoPolyfun(UBYTE *s)
375 {
376  GETIDENTITY
377  UBYTE *t, c;
378  WORD funnum, eqsign = 0;
379  if ( AC.origin == FROMPOINTINSTRUCTION ) {
380  if ( *s == 0 || *s == ',' || *s == ')' ) {
381  AR.PolyFun = 0; AR.PolyFunType = 0;
382  return(0);
383  }
384  if ( *s != '=' ) {
385  MesPrint("@Proper use in point instructions is: PolyFun[=functionname]");
386  return(-1);
387  }
388  eqsign = 1;
389  }
390  else {
391  if ( *s == 0 ) {
392  AR.PolyFun = 0; AR.PolyFunType = 0;
393  return(0);
394  }
395  if ( *s != '=' && *s != ',' ) {
396  MesPrint("@Proper use is: PolyFun[{ ,=}functionname]");
397  return(-1);
398  }
399  if ( *s == '=' ) eqsign = 1;
400  }
401  s++;
402  SKIPBLANKS(s)
403  t = EndOfToken(s);
404  c = *t; *t = 0;
405 
406  if ( GetName(AC.varnames,s,&funnum,WITHAUTO) != CFUNCTION ) {
407  if ( AC.origin != FROMPOINTINSTRUCTION && eqsign == 0 ) {
408  AR.PolyFun = 0; AR.PolyFunType = 0;
409  return(0);
410  }
411  MesPrint("@ %s is not a properly declared function",s);
412  *t = c;
413  return(-1);
414  }
415  if ( functions[funnum].spec != 0 || functions[funnum].commute != 0 ) {
416  MesPrint("@The PolyFun must be a regular commuting function!");
417  *t = c;
418  return(-1);
419  }
420  AR.PolyFun = funnum+FUNCTION; AR.PolyFunType = 1;
421  *t = c;
422  SKIPBLANKS(t)
423  if ( *t && *t != ',' && *t != ')' ) {
424  t++; c = *t; *t = 0;
425  MesPrint("@Improper ending of end-of-module instruction: %s",s);
426  *t = c;
427  return(-1);
428  }
429  return(0);
430 }
431 
432 /*
433  #] DoPolyfun :
434  #[ DoPolyratfun :
435 */
436 
437 int DoPolyratfun(UBYTE *s)
438 {
439  GETIDENTITY
440  UBYTE *t, c;
441  WORD funnum;
442  if ( AC.origin == FROMPOINTINSTRUCTION ) {
443  if ( *s == 0 || *s == ',' || *s == ')' ) {
444  AR.PolyFun = 0; AR.PolyFunType = 0; AR.PolyFunInv = 0; AR.PolyFunExp = 0;
445  return(0);
446  }
447  if ( *s != '=' ) {
448  MesPrint("@Proper use in point instructions is: PolyRatFun[=functionname[+functionname]]");
449  return(-1);
450  }
451  }
452  else {
453  if ( *s == 0 ) {
454  AR.PolyFun = 0; AR.PolyFunType = 0; AR.PolyFunInv = 0; AR.PolyFunExp = 0;
455  return(0);
456  }
457  if ( *s != '=' && *s != ',' ) {
458  MesPrint("@Proper use is: PolyRatFun[{ ,=}functionname[+functionname]]");
459  return(-1);
460  }
461  }
462  s++;
463  SKIPBLANKS(s)
464  t = EndOfToken(s);
465  c = *t; *t = 0;
466 
467  if ( GetName(AC.varnames,s,&funnum,WITHAUTO) != CFUNCTION ) {
468 Error1:;
469  MesPrint("@ %s is not a properly declared function",s);
470  *t = c;
471  return(-1);
472  }
473  if ( functions[funnum].spec != 0 || functions[funnum].commute != 0 ) {
474 Error2:;
475  MesPrint("@The PolyRatFun must be a regular commuting function!");
476  *t = c;
477  return(-1);
478  }
479  AR.PolyFun = funnum+FUNCTION; AR.PolyFunType = 2;
480  AR.PolyFunInv = 0;
481  AR.PolyFunExp = 0;
482  AC.PolyRatFunChanged = 1;
483  *t = c;
484  if ( *t == '+' ) {
485  t++; s = t;
486  t = EndOfToken(s);
487  c = *t; *t = 0;
488  if ( GetName(AC.varnames,s,&funnum,WITHAUTO) != CFUNCTION ) goto Error1;
489  if ( functions[funnum].spec != 0 || functions[funnum].commute != 0 ) goto Error2;
490  AR.PolyFunInv = funnum+FUNCTION;
491  *t = c;
492  }
493  SKIPBLANKS(t)
494  if ( *t && *t != ',' && *t != ')' ) {
495  t++; c = *t; *t = 0;
496  MesPrint("@Improper ending of end-of-module instruction: %s",s);
497  *t = c;
498  return(-1);
499  }
500  return(0);
501 }
502 
503 /*
504  #] DoPolyratfun :
505  #[ DoNoParallel :
506 */
507 
508 int DoNoParallel(UBYTE *s)
509 {
510  if ( *s == 0 || *s == ',' || *s == ')' ) {
511  AC.mparallelflag |= NOPARALLEL_USER;
512  return(0);
513  }
514  MesPrint("@NoParallel should not have extra parameters");
515  return(-1);
516 }
517 
518 /*
519  #] DoNoParallel :
520  #[ DoParallel :
521 */
522 
523 int DoParallel(UBYTE *s)
524 {
525  if ( *s == 0 || *s == ',' || *s == ')' ) {
526  AC.mparallelflag &= ~NOPARALLEL_USER;
527  return(0);
528  }
529  MesPrint("@Parallel should not have extra parameters");
530  return(-1);
531 }
532 
533 /*
534  #] DoParallel :
535  #[ DoModSum :
536 */
537 
538 int DoModSum(UBYTE *s)
539 {
540  while ( *s == ',' ) s++;
541  if ( *s != '$' ) {
542  MesPrint("@Module Sum should mention which $-variables");
543  return(-1);
544  }
545  s = DoModDollar(s,MODSUM);
546  if ( s && *s != 0 && *s != ')' ) {
547  MesPrint("@Irregular end of Sum option of Module statement");
548  return(-1);
549  }
550  return(0);
551 }
552 
553 /*
554  #] DoModSum :
555  #[ DoModMax :
556 */
557 
558 int DoModMax(UBYTE *s)
559 {
560  while ( *s == ',' ) s++;
561  if ( *s != '$' ) {
562  MesPrint("@Module Maximum should mention which $-variables");
563  return(-1);
564  }
565  s = DoModDollar(s,MODMAX);
566  if ( s && *s != 0 ) {
567  MesPrint("@Irregular end of Maximum option of Module statement");
568  return(-1);
569  }
570  return(0);
571 }
572 
573 /*
574  #] DoModMax :
575  #[ DoModMin :
576 */
577 
578 int DoModMin(UBYTE *s)
579 {
580  while ( *s == ',' ) s++;
581  if ( *s != '$' ) {
582  MesPrint("@Module Minimum should mention which $-variables");
583  return(-1);
584  }
585  s = DoModDollar(s,MODMIN);
586  if ( s && *s != 0 ) {
587  MesPrint("@Irregular end of Minimum option of Module statement");
588  return(-1);
589  }
590  return(0);
591 }
592 
593 /*
594  #] DoModMin :
595  #[ DoModLocal :
596 */
597 
598 int DoModLocal(UBYTE *s)
599 {
600  while ( *s == ',' ) s++;
601  if ( *s != '$' ) {
602  MesPrint("@ModuleOption Local should mention which $-variables");
603  return(-1);
604  }
605  s = DoModDollar(s,MODLOCAL);
606  if ( s && *s != 0 ) {
607  MesPrint("@Irregular end of Local option of ModuleOption statement");
608  return(-1);
609  }
610  return(0);
611 }
612 
613 /*
614  #] DoModLocal :
615  #[ DoProcessBucket :
616 */
617 
618 int DoProcessBucket(UBYTE *s)
619 {
620  LONG x;
621  while ( *s == ',' || *s == '=' ) s++;
622  ParseNumber(x,s)
623  if ( *s && *s != ' ' && *s != '\t' ) {
624  MesPrint("&Numerical value expected for ProcessBucketSize");
625  return(1);
626  }
627  AC.mProcessBucketSize = x;
628  return(0);
629 }
630 
631 /*
632  #] DoProcessBucket :
633  #[ DoModDollar :
634 */
635 
636 UBYTE * DoModDollar(UBYTE *s, int type)
637 {
638  UBYTE *name, c;
639  WORD number;
640  MODOPTDOLLAR *md;
641  while ( *s == '$' ) {
642 /*
643  Read the name of the dollar
644  Mark the type
645 */
646  s++;
647  name = s;
648  if ( FG.cTable[*s] == 0 ) {
649  while ( FG.cTable[*s] == 0 || FG.cTable[*s] == 1 ) s++;
650  c = *s; *s = 0;
651  number = GetDollar(name);
652  if ( number < 0 ) {
653  number = AddDollar(s,0,0,0);
654  Warning("&Undefined $-variable in module statement");
655  }
656  md = (MODOPTDOLLAR *)FromList(&AC.ModOptDolList);
657  md->number = number;
658  md->type = type;
659 #ifdef WITHPTHREADS
660  if ( type == MODLOCAL ) {
661  int j, i;
662  DOLLARS dglobal, dlocal;
663  md->dstruct = (DOLLARS)Malloc1(
664  sizeof(struct DoLlArS)*AM.totalnumberofthreads,"Local DOLLARS");
665 /*
666  Now copy the global dollar into the local copies.
667  This can be nontrivial if the value needs an allocation.
668  We don't really need the locks.
669 */
670  dglobal = Dollars + number;
671  for ( j = 0; j < AM.totalnumberofthreads; j++ ) {
672  dlocal = md->dstruct + j;
673  dlocal->index = dglobal->index;
674  dlocal->node = dglobal->node;
675  dlocal->type = dglobal->type;
676  dlocal->name = dglobal->name;
677  dlocal->size = dglobal->size;
678  dlocal->where = dglobal->where;
679  if ( dlocal->size > 0 ) {
680  dlocal->where = (WORD *)Malloc1((dlocal->size+1)*sizeof(WORD),"Local dollar value");
681  for ( i = 0; i < dlocal->size; i++ )
682  dlocal->where[i] = dglobal->where[i];
683  dlocal->where[dlocal->size] = 0;
684  }
685  dlocal->pthreadslockread = dummylock;
686  dlocal->pthreadslockwrite = dummylock;
687  dlocal->nfactors = dglobal->nfactors;
688  if ( dglobal->nfactors > 1 ) {
689  int nsize;
690  WORD *t, *m;
691  dlocal->factors = (FACDOLLAR *)Malloc1(dglobal->nfactors*sizeof(FACDOLLAR),"Dollar factors");
692  for ( i = 0; i < dglobal->nfactors; i++ ) {
693  nsize = dglobal->factors[i].size;
694  dlocal->factors[i].type = DOLUNDEFINED;
695  dlocal->factors[i].value = dglobal->factors[i].value;
696  if ( ( dlocal->factors[i].size = nsize ) > 0 ) {
697  dlocal->factors[i].where = t = (WORD *)Malloc1(sizeof(WORD)*(nsize+1),"DollarCopyFactor");
698  m = dglobal->factors[i].where;
699  NCOPY(t,m,nsize);
700  *t = 0;
701  }
702  else {
703  dlocal->factors[i].where = 0;
704  }
705  }
706  }
707  else { dlocal->factors = 0; }
708  }
709  }
710  else {
711  md->dstruct = 0;
712  }
713 #endif
714  *s = c;
715  }
716  else {
717  MesPrint("&Illegal name for $-variable in module option");
718  while ( *s != ',' && *s != 0 && *s != ')' ) s++;
719  }
720  while ( *s == ',' ) s++;
721  }
722  return(s);
723 }
724 
725 /*
726  #] DoModDollar :
727  #[ DoinParallel :
728 
729  The idea is that we should have the commands
730  ModuleOption,InParallel;
731  ModuleOption,InParallel,name1,name2,...,namen;
732  ModuleOption,NotInParallel,name1,name2,...,namen;
733  The advantage over the InParallel statement is that this statement
734  comes after the definition of the expressions.
735 */
736 
737 int DoinParallel(UBYTE *s)
738 {
739  return(DoInParallel(s,1));
740 }
741 
742 /*
743  #] DoinParallel :
744  #[ DonotinParallel :
745 */
746 
747 int DonotinParallel(UBYTE *s)
748 {
749  return(DoInParallel(s,0));
750 }
751 
752 /*
753  #] DonotinParallel :
754  #] Modules :
755  #[ External :
756  #[ DoExecStatement :
757 */
758 
759 int DoExecStatement()
760 {
761 #ifdef WITHSYSTEM
762  FLUSHCONSOLE;
763  if ( system((char *)(AP.preStart)) ) return(-1);
764  return(0);
765 #else
766  Error0("External programs not implemented on this computer/system");
767  return(-1);
768 #endif
769 }
770 
771 /*
772  #] DoExecStatement :
773  #[ DoPipeStatement :
774 */
775 
776 int DoPipeStatement()
777 {
778 #ifdef WITHPIPE
779  FLUSHCONSOLE;
780  if ( OpenStream(AP.preStart,PIPESTREAM,0,PRENOACTION) == 0 ) return(-1);
781  return(0);
782 #else
783  Error0("Pipes not implemented on this computer/system");
784  return(-1);
785 #endif
786 }
787 
788 /*
789  #] DoPipeStatement :
790  #] External :
791 */