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
54static 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
62static 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
76int 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
143int 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
210int 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
255VOID SetSpecialMode(int moduletype, int specialtype)
256{
257 DUMMYUSE(moduletype); DUMMYUSE(specialtype);
258}
259
260/*
261 #] SetSpecialMode :
262 #[ MakeGlobal :
263
264VOID MakeGlobal()
265{
266}
267
268 #] MakeGlobal :
269 #[ ExecModule :
270*/
271
272int ExecModule(int moduletype)
273{
274 return(DoExecute(moduletype,0));
275}
276
277/*
278 #] ExecModule :
279 #[ ExecStore :
280*/
281
282int 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
297VOID 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
374int 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
437int 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 ) {
468Error1:;
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 ) {
474Error2:;
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
508int 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
523int 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
538int 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
558int 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
578int 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
598int 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
618int 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
636UBYTE * 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
737int DoinParallel(UBYTE *s)
738{
739 return(DoInParallel(s,1));
740}
741
742/*
743 #] DoinParallel :
744 #[ DonotinParallel :
745*/
746
747int DonotinParallel(UBYTE *s)
748{
749 return(DoInParallel(s,0));
750}
751
752/*
753 #] DonotinParallel :
754 #] Modules :
755 #[ External :
756 #[ DoExecStatement :
757*/
758
759int 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
776int 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*/