1 /** @file pre.c
2 *
3 * This is the preprocessor and all its routines.
4 */
5 /* #[ License : */
6 /*
7 * Copyright (C) 1984-2017 J.A.M. Vermaseren
8 * When using this file you are requested to refer to the publication
9 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
10 * This is considered a matter of courtesy as the development was paid
11 * for by FOM the Dutch physics granting agency and we would like to
12 * be able to track its scientific use to convince FOM of its value
13 * for the community.
14 *
15 * This file is part of FORM.
16 *
17 * FORM is free software: you can redistribute it and/or modify it under the
18 * terms of the GNU General Public License as published by the Free Software
19 * Foundation, either version 3 of the License, or (at your option) any later
20 * version.
21 *
22 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
23 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
25 * details.
26 *
27 * You should have received a copy of the GNU General Public License along
28 * with FORM. If not, see <http://www.gnu.org/licenses/>.
29 */
30 /* #] License : */
31 /*
32 #[ Includes :
33 */
34 #include "form3.h"
35
36 static UBYTE pushbackchar = 0;
37 static int oldmode = 0;
38 static int stopdelay = 0;
39 static STREAM *oldstream = 0;
40 static UBYTE underscore[2] = {'_',0};
41 static PREVAR *ThePreVar = 0;
42
43 static KEYWORD precommands[] = {
44 {"add" , DoPreAdd , 0, 0}
45 ,{"addseparator" , DoPreAddSeparator,0,0}
46 ,{"append" , DoPreAppend , 0, 0}
47 ,{"appendpath" , DoPreAppendPath, 0, 0}
48 ,{"assign" , DoPreAssign , 0, 0}
49 ,{"break" , DoPreBreak , 0, 0}
50 ,{"breakdo" , DoBreakDo , 0, 0}
51 ,{"call" , DoCall , 0, 0}
52 ,{"case" , DoPreCase , 0, 0}
53 ,{"clearoptimize", DoClearOptimize, 0, 0}
54 ,{"close" , DoPreClose , 0, 0}
55 ,{"closedictionary", DoPreCloseDictionary,0,0}
56 ,{"commentchar" , DoCommentChar , 0, 0}
57 ,{"create" , DoPreCreate , 0, 0}
58 ,{"debug" , DoDebug , 0, 0}
59 ,{"default" , DoPreDefault , 0, 0}
60 ,{"define" , DoDefine , 0, 0}
61 ,{"do" , DoDo , 0, 0}
62 ,{"else" , DoElse , 0, 0}
63 ,{"elseif" , DoElseif , 0, 0}
64 ,{"enddo" , DoEnddo , 0, 0}
65 ,{"endif" , DoEndif , 0, 0}
66 ,{"endinside" , DoEndInside , 0, 0}
67 ,{"endprocedure" , DoEndprocedure , 0, 0}
68 ,{"endswitch" , DoPreEndSwitch , 0, 0}
69 ,{"exchange" , DoPreExchange , 0, 0}
70 ,{"external" , DoExternal , 0, 0}
71 ,{"factdollar" , DoFactDollar , 0, 0}
72 ,{"fromexternal" , DoFromExternal , 0, 0}
73 ,{"if" , DoIf , 0, 0}
74 ,{"ifdef" , DoIfydef , 0, 0}
75 ,{"ifndef" , DoIfndef , 0, 0}
76 ,{"include" , DoInclude , 0, 0}
77 ,{"inside" , DoInside , 0, 0}
78 ,{"message" , DoMessage , 0, 0}
79 ,{"opendictionary", DoPreOpenDictionary,0,0}
80 ,{"optimize" , DoOptimize , 0, 0}
81 ,{"pipe" , DoPipe , 0, 0}
82 ,{"preout" , DoPreOut , 0, 0}
83 ,{"prependpath" , DoPrePrependPath,0, 0}
84 ,{"printtimes" , DoPrePrintTimes, 0, 0}
85 ,{"procedure" , DoProcedure , 0, 0}
86 ,{"procedureextension" , DoPrcExtension , 0, 0}
87 ,{"prompt" , DoPrompt , 0, 0}
88 ,{"redefine" , DoRedefine , 0, 0}
89 ,{"remove" , DoPreRemove , 0, 0}
90 ,{"reset" , DoPreReset , 0, 0}
91 ,{"reverseinclude" , DoReverseInclude , 0, 0}
92 ,{"rmexternal" , DoRmExternal , 0, 0}
93 ,{"rmseparator" , DoPreRmSeparator,0, 0}
94 ,{"setexternal" , DoSetExternal , 0, 0}
95 ,{"setexternalattr" , DoSetExternalAttr , 0, 0}
96 ,{"setrandom" , DoSetRandom , 0, 0}
97 ,{"show" , DoPreShow , 0, 0}
98 ,{"skipextrasymbols" , DoSkipExtraSymbols , 0, 0}
99 ,{"switch" , DoPreSwitch , 0, 0}
100 ,{"system" , DoSystem , 0, 0}
101 ,{"terminate" , DoTerminate , 0, 0}
102 ,{"timeoutafter" , DoTimeOutAfter , 0, 0}
103 ,{"toexternal" , DoToExternal , 0, 0}
104 ,{"undefine" , DoUndefine , 0, 0}
105 ,{"usedictionary", DoPreUseDictionary,0,0}
106 ,{"write" , DoPreWrite , 0, 0}
107 };
108
109 /*
110 #] Includes :
111 # [ PreProcessor :
112 #[ GetInput :
113
114 Gets one input character. If we reach the end of a stream
115 we pop to the previous stream and try again.
116 If there are no more streams we let this be known.
117 */
118
GetInput()119 UBYTE GetInput()
120 {
121 UBYTE c;
122 while ( AC.CurrentStream ) {
123 c = GetFromStream(AC.CurrentStream);
124 if ( c != ENDOFSTREAM ) {
125 #ifdef WITHMPI
126 if ( PF.me == MASTER
127 && AC.NoShowInput <= 0
128 && AC.CurrentStream->type != PREVARSTREAM )
129 #else
130 if ( AC.NoShowInput <= 0 && AC.CurrentStream->type != PREVARSTREAM )
131 #endif
132 CharOut(c);
133 return(c);
134 }
135 AC.CurrentStream = CloseStream(AC.CurrentStream);
136 if ( stopdelay && AC.CurrentStream == oldstream ) {
137 stopdelay = 0; AP.AllowDelay = 1;
138 }
139 }
140 return(ENDOFINPUT);
141 }
142
143 /*
144 #] GetInput :
145 #[ ClearPushback :
146 */
147
ClearPushback()148 VOID ClearPushback()
149 {
150 pushbackchar = 0;
151 }
152
153 /*
154 #] ClearPushback :
155 #[ GetChar :
156
157 Reads one character. If it encounters a quote it immediately
158 takes the whole preprocessor variable and opens a stream
159 for it and starts reading the stream.
160 Note that we have to take special precautions for escaped quotes.
161 That is why we remember the previous character. We allow the
162 (dubious?) construction of ending a stream with a backslash and
163 then using it to escape an object in the parent stream.
164 */
165
GetChar(int level)166 UBYTE GetChar(int level)
167 {
168 UBYTE namebuf[MAXPRENAMESIZE+2], c, *s, *t;
169 static UBYTE lastchar, charinbuf = 0;
170 int i, j, raiselow, olddelay;
171 STREAM *stream;
172 if ( level > 0 ) {
173 lastchar = '`';
174 goto higherlevel;
175 }
176 if ( pushbackchar ) { c = pushbackchar; pushbackchar = 0; return(c); }
177 if ( charinbuf ) { c = charinbuf; charinbuf = 0; return(c); }
178 c = GetInput();
179 for(;;) {
180 if ( c == '\\' ) {
181 charinbuf = GetInput();
182 if ( charinbuf != LINEFEED ) {
183 pushbackchar = charinbuf;
184 charinbuf = 0;
185 break;
186 }
187 charinbuf = 0; /* Escaped linefeed -> skip leading blanks */
188 while ( ( c = GetInput() ) == ' ' || c == '\t' ) {}
189 }
190 else if ( c == '\'' || c == '`' ) {
191 if ( AP.DelayPrevar == 1 && c == '\'' ) {
192 AP.DelayPrevar = 0;
193 break;
194 }
195 lastchar = c;
196 higherlevel:
197 c = GetInput();
198 if ( c == '!' && lastchar == '`' ) {
199 if ( stopdelay == 0 ) oldstream = AC.CurrentStream;
200 AP.AllowDelay = 0;
201 stopdelay = 1;
202 c = GetInput();
203 }
204 if ( c == '~' && lastchar == '`' ) {
205 if ( AP.AllowDelay ) {
206 pushbackchar = c;
207 c = lastchar;
208 AP.DelayPrevar = 1;
209 break;
210 }
211 }
212 else {
213 pushbackchar = c;
214 }
215 olddelay = AP.DelayPrevar;
216 AP.DelayPrevar = 0;
217 i = 0; lastchar = 0;
218 for (;;) {
219 if ( pushbackchar ) { c = pushbackchar; pushbackchar = 0; }
220 else { c = GetInput(); }
221 if ( c == ENDOFINPUT || ( ( c == '\'' || c == LINEFEED )
222 && lastchar != '\\' ) ) {
223 break;
224 }
225 if ( c == '{' ) { /* Try the preprocessor calculator */
226 if ( PreCalc() == 0 ) Terminate(-1);
227 c = GetInput(); /* This is either a { or a number */
228 if ( c == '{' ) {
229 MesPrint("@Illegal set inside preprocessor variable name");
230 Terminate(-1);
231 }
232 }
233 if ( c == '`' && lastchar != '\\' ) {
234 c = GetChar(1);
235 if ( c == ENDOFINPUT || ( ( c == '\'' || c == LINEFEED )
236 && lastchar != '\\' ) ) {
237 break;
238 }
239 }
240 if ( lastchar == '\\' ) { i--; lastchar = 0; }
241 else lastchar = c;
242 namebuf[i++] = c;
243 if ( i > MAXPRENAMESIZE ) {
244 namebuf[i] = 0;
245 Error1("Preprocessor variable name too long: ",namebuf);
246 }
247 }
248 namebuf[i++] = 0;
249 if ( c != '\'' ) {
250 Error1("Unmatched quotes for preprocessor variable",namebuf);
251 }
252 AP.DelayPrevar = olddelay;
253 if ( namebuf[0] == '$' ) {
254 raiselow = PRENOACTION;
255 if ( AP.PreproFlag && *AP.preStart) {
256 s = EndOfToken(AP.preStart);
257 c = *s; *s = 0;
258 if ( ( StrICmp(AP.preStart,(UBYTE *)"ifdef") == 0
259 || StrICmp(AP.preStart,(UBYTE *)"ifndef") == 0 )
260 && GetDollar(namebuf+1) < 0 ) {
261 *s = c; c = ' ';
262 break;
263 }
264 *s = c;
265 }
266 else {
267 s = EndOfToken(namebuf+1);
268 if ( *s == '[' ) { while ( *s ) s++; }
269 }
270 if ( *s == '-' && s[1] == '-' && s[2] == 0 )
271 raiselow = PRELOWERAFTER;
272 else if ( *s == '+' && s[1] == '+' && s[2] == 0 )
273 raiselow = PRERAISEAFTER;
274 c = *s; *s = 0;
275 if ( OpenStream(namebuf+1,DOLLARSTREAM,0,raiselow) == 0 ) {
276 *s = c;
277 MesPrint("@Undefined variable %s used as preprocessor variable",
278 namebuf);
279 Terminate(-1);
280 }
281 *s = c;
282 }
283 else {
284 raiselow = PRENOACTION;
285 if ( AP.PreproFlag && *AP.preStart) {
286 s = EndOfToken(AP.preStart);
287 c = *s; *s = 0;
288 if ( ( StrICmp(AP.preStart,(UBYTE *)"ifdef") == 0
289 || StrICmp(AP.preStart,(UBYTE *)"ifndef") == 0 )
290 && GetPreVar(namebuf,WITHOUTERROR) == 0 ) {
291 *s = c; c = ' ';
292 break;
293 }
294 *s = c;
295 }
296 s = EndOfToken(namebuf);
297 if ( *s == '_' ) s++;
298 if ( *s == '-' && s[1] == '-' && s[2] == 0 )
299 raiselow = PRELOWERAFTER;
300 else if ( *s == '+' && s[1] == '+' && s[2] == 0 )
301 raiselow = PRERAISEAFTER;
302 else if ( *s == '(' && namebuf[i-2] == ')' ) {
303 /*
304 Now count the arguments and separate them by zeroes
305 Check on the ?var construction and if present, reset
306 some comma's.
307 Make the assignments of the variables
308 Run the macro.
309 Undefine the variables
310 */
311 int nargs = 1;
312 PREVAR *p;
313 *s++ = 0; namebuf[i-2] = 0;
314 if ( StrICmp(namebuf,(UBYTE *)"random_") == 0 ) {
315 UBYTE *ranvalue;
316 ranvalue = PreRandom(s);
317 PutPreVar(namebuf,ranvalue,(UBYTE *)"?a",1);
318 M_free(ranvalue,"PreRandom");
319 goto dostream;
320 }
321 else if ( StrICmp(namebuf,(UBYTE *)"tolower_") == 0 ) {
322 UBYTE *ss = s;
323 while ( *ss ) { *ss = (UBYTE)(tolower(*ss)); ss++; }
324 PutPreVar(namebuf,s,(UBYTE *)"?a",1);
325 goto dostream;
326 }
327 else if ( StrICmp(namebuf,(UBYTE *)"toupper_") == 0 ) {
328 UBYTE *ss = s;
329 while ( *ss ) { *ss = (UBYTE)(toupper(*ss)); ss++; }
330 PutPreVar(namebuf,s,(UBYTE *)"?a",1);
331 goto dostream;
332 }
333 while ( *s ) {
334 if ( *s == '\\' ) s++;
335 if ( *s == ',' ) { *s = 0; nargs++; }
336 s++;
337 }
338 GetPreVar(namebuf,WITHERROR);
339 p = ThePreVar;
340 if ( p == 0 ) {
341 MesPrint("@Illegal use of arguments in preprocessor variable %s",namebuf);
342 Terminate(-1);
343 }
344 if ( p->nargs <= 0 || ( p->wildarg == 0 && nargs != p->nargs )
345 || ( p->wildarg > 0 && nargs < p->nargs-1 ) ) {
346 MesPrint("@Arguments of macro %s do not match",namebuf);
347 Terminate(-1);
348 }
349 if ( p->wildarg > 0 ) {
350 /*
351 Change some zeroes into commas
352 */
353 s = namebuf;
354 for ( j = 0; j < p->wildarg; j++ ) {
355 while ( *s ) s++;
356 s++;
357 }
358 for ( j = 0; j < nargs-p->nargs; j++ ) {
359 while ( *s ) s++;
360 *s++ = ',';
361 }
362 }
363 /*
364 Now we can make the assignments
365 */
366 s = namebuf;
367 while ( *s ) s++;
368 s++;
369 t = p->argnames;
370 for ( j = 0; j < p->nargs; j++ ) {
371 if ( ( nargs == p->nargs-1 ) && ( *t == '?' ) ) {
372 PutPreVar(t,0,0,0);
373 }
374 else {
375 PutPreVar(t,s,0,0);
376 while ( *s ) s++;
377 s++;
378 }
379 while ( *t ) t++;
380 t++;
381 }
382 }
383 dostream:;
384 if ( ( stream = OpenStream(namebuf,PREVARSTREAM,0,raiselow) ) == 0 ) {
385 /*
386 Eat comma before or after. This is `no value'
387 */
388 }
389 else if ( stream->inbuffer == 0 ) {
390 c = GetInput();
391 if ( level > 0 && c == '\'' ) return(c);
392 goto endofloop;
393 }
394 }
395 c = GetInput();
396 }
397 else if ( c == '{' ) { /* Try the preprocessor calculator */
398 if ( PreCalc() == 0 ) Terminate(-1);
399 c = GetInput(); /* This is either a { or a number */
400 break;
401 }
402 else break;
403 endofloop:;
404 }
405 return(c);
406 }
407
408 /*
409 #] GetChar :
410 #[ CharOut :
411 */
412
CharOut(UBYTE c)413 VOID CharOut(UBYTE c)
414 {
415 if ( c == LINEFEED ) {
416 AM.OutBuffer[AP.InOutBuf++] = c;
417 WriteString(INPUTOUT,AM.OutBuffer,AP.InOutBuf);
418 AP.InOutBuf = 0;
419 }
420 else {
421 if ( AP.InOutBuf >= AM.OutBufSize || c == LINEFEED ) {
422 WriteString(INPUTOUT,AM.OutBuffer,AP.InOutBuf);
423 AP.InOutBuf = 0;
424 }
425 AM.OutBuffer[AP.InOutBuf++] = c;
426 }
427 }
428
429 /*
430 #] CharOut :
431 #[ UnsetAllowDelay :
432 */
433
UnsetAllowDelay()434 VOID UnsetAllowDelay()
435 {
436 if ( ThePreVar != 0 ) {
437 if ( ThePreVar->nargs > 0 ) AP.AllowDelay = 0;
438 }
439 }
440
441 /*
442 #] UnsetAllowDelay :
443 #[ GetPreVar :
444
445 We use the model of a heap. If the same name has been used more
446 than once the last definition is used. This gives the impression
447 of local variables.
448
449 There are two types: The regular ones and the expression variables.
450 The last ones are like UNCHANGED_exprname and ZERO_exprname or
451 UNCHANGED_ and ZERO_.
452 */
453
454 static UBYTE *yes = (UBYTE *)"1";
455 static UBYTE *no = (UBYTE *)"0";
456 static UBYTE numintopolynomial[12];
457 #include "vector.h"
458 static Vector(UBYTE, exprstr); /* Used for numactiveexprs_ and activeexprnames_. */
459
GetPreVar(UBYTE * name,int flag)460 UBYTE *GetPreVar(UBYTE *name, int flag)
461 {
462 GETIDENTITY
463 int i, mode;
464 WORD number;
465 UBYTE *t, c = 0, *tt = 0;
466 t = name; while ( *t ) t++;
467 if ( t[-1] == '-' && t[-2] == '-' && t-2 > name && t[-3] != '_' ) {
468 t -= 2; c = *t; *t = 0; tt = t;
469 }
470 else if ( t[-1] == '+' && t[-2] == '+' && t-2 > name && t[-3] != '_' ) {
471 t -= 2; c = *t; *t = 0; tt = t;
472 }
473 else if ( StrICmp(name,(UBYTE *)"time_") == 0 ) {
474 UBYTE millibuf[24];
475 LONG millitime, timepart;
476 int timepart1, timepart2;
477 static char timestring[40];
478 /* millitime = TimeCPU(1); */
479 millitime = GetRunningTime();
480 timepart = millitime%1000;
481 millitime /= 1000;
482 timepart /= 10;
483 timepart1 = timepart / 10;
484 timepart2 = timepart % 10;
485 NumToStr(millibuf,millitime);
486 sprintf(timestring,"%s.%1d%1d",millibuf,timepart1,timepart2);
487 return((UBYTE *)timestring);
488 }
489 else if ( ( StrICmp(name,(UBYTE *)"timer_") == 0 )
490 || ( StrICmp(name,(UBYTE *)"stopwatch_") == 0 ) ) {
491 static char timestring[40];
492 sprintf(timestring,"%ld",(GetRunningTime() - AP.StopWatchZero));
493 return((UBYTE *)timestring);
494 }
495 else if ( StrICmp(name, (UBYTE *)"numactiveexprs_") == 0 ) {
496 /* the number of active expressions */
497 int n = 0;
498 for ( i = 0; i < NumExpressions; i++ ) {
499 EXPRESSIONS e = Expressions + i;
500 switch ( e->status ) {
501 case LOCALEXPRESSION:
502 case GLOBALEXPRESSION:
503 case UNHIDELEXPRESSION:
504 case UNHIDEGEXPRESSION:
505 case INTOHIDELEXPRESSION:
506 case INTOHIDEGEXPRESSION:
507 n++;
508 break;
509 }
510 }
511 VectorReserve(exprstr, 41); /* up to 128-bit */
512 LongCopy(n, (char *)VectorPtr(exprstr));
513 return VectorPtr(exprstr);
514 }
515 else if ( StrICmp(name, (UBYTE *)"activeexprnames_") == 0 ) {
516 /* the list of active expressions separated by commas */
517 int j = 0;
518 VectorReserve(exprstr, 16); /* at least 1 character for '\0' */
519 for ( i = 0; i < NumExpressions; i++ ) {
520 UBYTE *p, *s;
521 int len, k;
522 EXPRESSIONS e = Expressions + i;
523 switch ( e->status ) {
524 case LOCALEXPRESSION:
525 case GLOBALEXPRESSION:
526 case UNHIDELEXPRESSION:
527 case UNHIDEGEXPRESSION:
528 case INTOHIDELEXPRESSION:
529 case INTOHIDEGEXPRESSION:
530 s = AC.exprnames->namebuffer + e->name;
531 len = StrLen(s);
532 VectorSize(exprstr) = j; /* j bytes must be copied in extending the buffer. */
533 VectorReserve(exprstr, j + len * 2 + 1);
534 p = VectorPtr(exprstr);
535 if ( j > 0 ) p[j++] = ',';
536 for ( k = 0; k < len; k++ ) {
537 if ( s[k] == ',' || s[k] == '|' ) p[j++] = '\\';
538 p[j++] = s[k];
539 }
540 break;
541 }
542 }
543 VectorPtr(exprstr)[j] = '\0';
544 return VectorPtr(exprstr);
545 }
546 else if ( StrICmp(name, (UBYTE *)"path_") == 0 ) {
547 /* the current FORM path (for debugging both in .c and .frm) */
548 if ( AM.Path ) {
549 return(AM.Path);
550 }
551 else {
552 return((UBYTE *)"");
553 }
554 }
555 t = name;
556 while ( *t && *t != '_' ) t++;
557 for ( i = NumPre-1; i >= 0; i-- ) {
558 if ( *t == '_' && ( StrICmp(name,PreVar[i].name) == 0 ) ) {
559 if ( c ) *tt = c;
560 ThePreVar = PreVar+i;
561 return(PreVar[i].value);
562 }
563 else if ( StrCmp(name,PreVar[i].name) == 0 ) {
564 if ( c ) *tt = c;
565 ThePreVar = PreVar+i;
566 return(PreVar[i].value);
567 }
568 }
569 if ( *t == '_' ) {
570 if ( StrICmp(name,(UBYTE *)"EXTRASYMBOLS_") == 0 ) goto extrashort;
571 *t = 0;
572 if ( StrICmp(name,(UBYTE *)"UNCHANGED") == 0 ) mode = 1;
573 else if ( StrICmp(name,(UBYTE *)"ZERO") == 0 ) mode = 0;
574 else if ( StrICmp(name,(UBYTE *)"SHOWINPUT") == 0 ) {
575 *t++ = '_';
576 if ( c ) *tt = c;
577 if ( AC.NoShowInput > 0 ) return(no);
578 else return(yes);
579 }
580 else if ( StrICmp(name,(UBYTE *)"EXTRASYMBOLS") == 0 ) {
581 *t++ = '_';
582 extrashort:;
583 number = cbuf[AM.sbufnum].numrhs;
584 t = numintopolynomial;
585 NumCopy(number,t);
586 return(numintopolynomial);
587 }
588 else mode = -1;
589 *t++ = '_';
590 if ( mode >= 0 ) {
591 ThePreVar = 0;
592 if ( *t ) {
593 if ( GetName(AC.exprnames,t,&number,NOAUTO) == CEXPRESSION ) {
594 if ( c ) *tt = c;
595 if ( ( Expressions[number].vflags & ( 1 << mode ) ) != 0 )
596 return(yes);
597 else return(no);
598 }
599 }
600 else {
601 /*
602 Here we have to test all active results.
603 These are in `negative' so the flags have to be zero.
604 */
605 if ( c ) *tt = c;
606 if ( ( AR.expflags & ( 1 << mode ) ) == 0 ) return(yes);
607 else return(no);
608 }
609 }
610 }
611 if ( ( t = (UBYTE *)(getenv((char *)(name))) ) != 0 ) {
612 if ( c ) *tt = c;
613 ThePreVar = 0;
614 return(t);
615 }
616 if ( c ) *tt = c;
617 if ( flag == WITHERROR ) {
618 Error1("Undefined preprocessor variable",name);
619 }
620 return(0);
621 }
622
623 /*
624 #] GetPreVar :
625 #[ PutPreVar :
626 */
627
628 /**
629 * Inserts/Updates a preprocessor variable in the name administration.
630 *
631 * @param name Character string with the variable name.
632 * @param value Character string with a possible value.
633 * Special case: if this argument is zero, then we have no
634 * value. Note: This is different from having an empty
635 * argument! This should only occur when the name starts
636 * with a ?
637 * @param args Character string with possible arguments.
638 * @param mode =0: always create a new name entry, =1: try to do a
639 * redefinition if possible.
640 * @return Index of used entry in name list.
641 */
PutPreVar(UBYTE * name,UBYTE * value,UBYTE * args,int mode)642 int PutPreVar(UBYTE *name, UBYTE *value, UBYTE *args, int mode)
643 {
644 int i, ii, num = 2, nnum = 2, numargs = 0;
645 UBYTE *s, *t, *u = 0;
646 PREVAR *p;
647 if ( value == 0 && name[0] != '?' ) {
648 MesPrint("@Illegal empty value for preprocessor variable %s",name);
649 Terminate(-1);
650 }
651 if ( args ) {
652 s = args; num++;
653 while ( *s ) {
654 if ( *s != ' ' && *s != '\t' ) num++;
655 s++;
656 }
657 }
658 if ( mode == 1 ) {
659 i = NumPre;
660 while ( --i >= 0 ) {
661 if ( StrCmp(name,PreVar[i].name) == 0 ) {
662 u = PreVar[i].name;
663 break;
664 }
665 }
666 }
667 else i = -1;
668 if ( i < 0 ) { p = (PREVAR *)FromList(&AP.PreVarList); ii = p - PreVar; }
669 else { p = &(PreVar[i]); ii = i; }
670 if ( value ) {
671 s = value; while ( *s ) { s++; num++; }
672 }
673 else num = 1;
674 if ( i >= 0 ) {
675 if ( p->value ) {
676 s = p->value;
677 while ( *s ) { s++; nnum++; }
678 }
679 else nnum = 1;
680 if ( nnum >= num ) {
681 /*
682 We can keep this in place
683 */
684 if ( value && p->value ) {
685 s = value;
686 t = p->value;
687 while ( *s ) *t++ = *s++;
688 *t = 0;
689 }
690 else p->value = 0;
691 return(i);
692 }
693 }
694 s = name; while ( *s ) { s++; num++; }
695 t = (UBYTE *)Malloc1(num,"PreVariable");
696 p->name = t;
697 s = name; while ( *s ) *t++ = *s++; *t++ = 0;
698 if ( value ) {
699 p->value = t;
700 s = value; while ( *s ) *t++ = *s++; *t = 0;
701 if ( AM.atstartup && t[-1] == '\n' ) t[-1] = 0;
702 }
703 else p->value = 0;
704 p->wildarg = 0;
705 if ( args ) {
706 int first = 1;
707 t++; p->argnames = t;
708 s = args;
709 while ( *s ) {
710 if ( *s == ' ' || *s == '\t' ) { s++; continue; }
711 if ( *s == ',' ) {
712 s++; *t++ = 0; numargs++;
713 while ( *s == ' ' || *s == '\t' ) s++;
714 if ( *s == '?' ) {
715 if ( p->wildarg > 0 ) {
716 Error0("More than one ?var in #define");
717 }
718 p->wildarg = numargs;
719 }
720 }
721 else if ( *s == '?' && first ) {
722 p->wildarg = 1; *t++ = *s++;
723 }
724 else { *t++ = *s++; }
725 first = 0;
726 }
727 *t = 0;
728 numargs++;
729 p->nargs = numargs;
730 }
731 else {
732 p->nargs = 0;
733 p->argnames = 0;
734 }
735 if ( u ) M_free(u,"replace PreVar value");
736 return(ii);
737 }
738
739 /*
740 #] PutPreVar :
741 #[ PopPreVars :
742 */
743
PopPreVars(int tonumber)744 VOID PopPreVars(int tonumber)
745 {
746 PREVAR *p = &(PreVar[NumPre]);
747 while ( NumPre > tonumber ) {
748 NumPre--; p--;
749 M_free(p->name,"popping PreVar");
750 p->name = p->value = 0;
751 }
752 }
753
754 /*
755 #] PopPreVars :
756 #[ IniModule :
757 */
758
IniModule(int type)759 VOID IniModule(int type)
760 {
761 GETIDENTITY
762 WORD **w, i;
763 CBUF *C = cbuf+AC.cbufnum;
764 /*[05nov2003 mt]:*/
765 #ifdef WITHMPI
766 /* To prevent
767 * (1) FlushOut() and PutOut() on the slaves to send a mess to the master
768 * compiling a module,
769 * (2) EndSort() called from poly_factorize_expression() on the master
770 * waits for the slaves.
771 */
772 PF.parallel=0;
773 /*BTW, this was the bug preventing usage of more than 1 expression!*/
774 #endif
775
776 AR.BracketOn = 0;
777 AR.StoreData.dirtyflag = 0;
778 AC.bracketindexflag = 0;
779 AT.bracketindexflag = 0;
780
781 /*[06nov2003 mt]:*/
782 #ifdef WITHMPI
783 /* This flag may be set in the procedure tokenize(). */
784 AC.RhsExprInModuleFlag = 0;
785 /*[20oct2009 mt]:*/
786 PF.mkSlaveInfile=0;
787 PF.slavebuf.PObuffer=NULL;
788 for(i=0; i<NumExpressions; i++)
789 Expressions[i].vflags &= ~ISINRHS;
790 /*:[20oct2009 mt]*/
791 #endif
792 /*:[06nov2003 mt]*/
793
794 /*[19nov2003 mt]:*/
795 /*The module counter:*/
796 (AC.CModule)++;
797 /*:[19nov2003 mt]*/
798
799 if ( !type ) {
800 if ( C->rhs ) {
801 w = C->rhs; i = C->maxrhs;
802 do { *w++ = 0; } while ( --i > 0 );
803 }
804 if ( C->lhs ) {
805 w = C->lhs; i = C->maxlhs;
806 do { *w++ = 0; } while ( --i > 0 );
807 }
808 }
809 C->numlhs = C->numrhs = 0;
810 ClearTree(AC.cbufnum);
811 while ( AC.NumLabels > 0 ) {
812 AC.NumLabels--;
813 if ( AC.LabelNames[AC.NumLabels] ) M_free(AC.LabelNames[AC.NumLabels],"LabelName");
814 }
815
816 C->Pointer = C->Buffer;
817
818 AC.Commercial[0] = 0;
819
820 AC.IfStack = AC.IfHeap;
821 AC.arglevel = 0;
822 AC.termlevel = 0;
823 AC.IfLevel = 0;
824 AC.WhileLevel = 0;
825 AC.RepLevel = 0;
826 AC.insidelevel = 0;
827 AC.dolooplevel = 0;
828 AC.MustTestTable = 0;
829 AO.PrintType = 0; /* Otherwise statistics can get spoiled */
830 AC.ComDefer = 0;
831 AC.CollectFun = 0;
832 AM.S0->PolyWise = 0;
833 AC.SymChangeFlag = 0;
834 AP.lhdollarerror = 0;
835 AR.PolyFun = AC.lPolyFun;
836 AR.PolyFunInv = AC.lPolyFunInv;
837 AR.PolyFunType = AC.lPolyFunType;
838 AR.PolyFunExp = AC.lPolyFunExp;
839 AR.PolyFunVar = AC.lPolyFunVar;
840 AR.PolyFunPow = AC.lPolyFunPow;
841 AC.mparallelflag = AC.parallelflag | AM.hparallelflag;
842 AC.inparallelflag = 0;
843 AC.mProcessBucketSize = AC.ProcessBucketSize;
844 NumPotModdollars = 0;
845 AC.topolynomialflag = 0;
846 #ifdef WITHPTHREADS
847 if ( AM.totalnumberofthreads > 1 ) AS.MultiThreaded = 1;
848 else AS.MultiThreaded = 0;
849 for ( i = 1; i < AM.totalnumberofthreads; i++ ) {
850 AB[i]->T.S0->PolyWise = 0;
851 }
852 #endif
853 OpenTemp();
854 }
855
856 /*
857 #] IniModule :
858 #[ IniSpecialModule :
859 */
860
IniSpecialModule(int type)861 VOID IniSpecialModule(int type)
862 {
863 DUMMYUSE(type);
864 }
865
866 /*
867 #] IniSpecialModule :
868 #[ PreProcessor :
869 */
870
PreProcessor()871 VOID PreProcessor()
872 {
873 int moduletype = FIRSTMODULE;
874 int specialtype = 0;
875 int error1 = 0, error2 = 0, retcode, numstatement, retval;
876 UBYTE c, *t, *s;
877 AP.StopWatchZero = GetRunningTime();
878 AC.compiletype = 0;
879 AP.PreContinuation = 0;
880 AP.PreAssignLevel = 0;
881 AP.gNumPre = NumPre;
882 AC.iPointer = AC.iBuffer;
883 AC.iPointer[0] = 0;
884
885 if ( AC.CheckpointFlag == -1 ) DoRecovery(&moduletype);
886 AC.CheckpointStamp = Timer(0);
887
888 for(;;) {
889 /* if ( A.StatisticsFlag ) CharOut(LINEFEED); */
890
891 IniModule(moduletype);
892
893 /*Re-define preprocessor variable CMODULE_ as a current module number, starting from 1*/
894 /*The module counter is AC.CModule, it is incremented in IniModule*/
895 {
896 UBYTE buf[24];/*64/Log_2[10] = 19.3, this is enough for any integer*/
897 NumToStr(buf,AC.CModule);
898 PutPreVar((UBYTE *)"CMODULE_",buf,0,1);
899 }
900
901 if ( specialtype ) IniSpecialModule(specialtype);
902
903 numstatement = 0;
904 for(;;) { /* Read a single line/statement */
905 c = GetChar(0);
906 if ( c == AP.ComChar ) { /* This line is commentary */
907 LoadInstruction(5);
908 if ( AC.CurrentStream->FoldName ) {
909 t = AP.preStart;
910 if ( *t && t[1] && t[2] == '#' && t[3] == ']' ) {
911 t += 4;
912 while ( *t == ' ' || *t == '\t' ) t++;
913 s = AC.CurrentStream->FoldName;
914 while ( *s == *t ) { s++; t++; }
915 if ( *s == 0 && ( *t == ' ' || *t == '\t'
916 || *t == ':' ) ) {
917 while ( *t == ' ' || *t == '\t' ) t++;
918 if ( *t == ':' ) {
919 AC.CurrentStream = CloseStream(AC.CurrentStream);
920 }
921 }
922 }
923 }
924 *AP.preStart = 0;
925 continue;
926 }
927 while ( c == ' ' || c == '\t' ) c = GetChar(0);
928 if ( c == LINEFEED ) continue;
929 if ( c == ENDOFINPUT ) {
930 /* CharOut(LINEFEED); */
931 Warning(".end instruction generated");
932 moduletype = ENDMODULE; specialtype = 0;
933 goto endmodule; /* Fake one */
934 }
935 if ( c == '#' ) {
936 if ( PreProInstruction() ) { error1++; error2++; AP.preError++; }
937 *AP.preStart = 0;
938 }
939 else if ( c == '.' ) {
940 if ( ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ||
941 ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) ) {
942 LoadInstruction(1);
943 continue;
944 }
945 if ( ModuleInstruction(&moduletype,&specialtype) ) { error2++; AP.preError++; }
946 if ( specialtype ) SetSpecialMode(moduletype,specialtype);
947 if ( AP.PreInsideLevel != 0 ) {
948 MesPrint("@end of module instructions may not be used inside");
949 MesPrint("@the scope of a %#inside %#endinside construction.");
950 Terminate(-1);
951 }
952 if ( AC.RepLevel > 0 ) {
953 MesPrint("&EndRepeat statement(s) missing");
954 error2++; AP.preError++;
955 }
956 if ( AC.tablecheck == 0 ) {
957 AC.tablecheck = 1;
958 if ( TestTables() ) { error2++; AP.preError++; }
959 }
960 if ( AP.PreContinuation ) {
961 error1++; error2++;
962 MesPrint("&Unfinished statement. Missing ;?");
963 }
964 if ( moduletype == GLOBALMODULE ) MakeGlobal();
965 else {
966 endmodule: if ( error2 == 0 && AM.qError == 0 ) {
967 retcode = ExecModule(moduletype);
968 #ifdef WITHMPI
969 if(PF.slavebuf.PObuffer!=NULL){
970 M_free(PF.slavebuf.PObuffer,"PF inbuf");
971 PF.slavebuf.PObuffer=NULL;
972 }
973 #endif
974 UpdatePositions();
975 if ( retcode < 0 ) error1++;
976 if ( retcode ) { error2++; AP.preError++; }
977 }
978 else {
979 EXPRESSIONS e;
980 WORD j;
981 for ( j = 0, e = Expressions; j < NumExpressions; j++, e++ ) {
982 if ( e->replace == NEWLYDEFINEDEXPRESSION ) e->replace = REGULAREXPRESSION;
983 }
984 }
985 switch ( moduletype ) {
986 case STOREMODULE:
987 if ( ExecStore() ) error1++;
988 break;
989 case CLEARMODULE:
990 FullCleanUp();
991 error1 = error2 = AP.preError = 0;
992 AM.atstartup = 1;
993 PutPreVar((UBYTE *)"DATE_",(UBYTE *)MakeDate(),0,1);
994 AM.atstartup = 0;
995 if ( AM.resetTimeOnClear ) {
996 #ifdef WITHPTHREADS
997 ClearAllThreads();
998 #endif
999 AM.SumTime += TimeCPU(1);
1000 TimeCPU(0);
1001 }
1002 AP.StopWatchZero = GetRunningTime();
1003 break;
1004 case ENDMODULE:
1005 Terminate( -( error1 | error2 ) );
1006 }
1007 }
1008 AC.tablecheck = 0;
1009 AC.compiletype = 0;
1010 if ( AC.exprfillwarning > 0 ) {
1011 AC.exprfillwarning = 0;
1012 }
1013 if ( AC.CheckpointFlag && error1 == 0 && error2 == 0 ) DoCheckpoint(moduletype);
1014 break; /* start a new module */
1015 }
1016 else {
1017 if ( ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ||
1018 ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) ) {
1019 pushbackchar = c;
1020 LoadInstruction(5);
1021 continue;
1022 }
1023 UngetChar(c);
1024 if ( AP.PreContinuation ) {
1025 retval = LoadStatement(OLDSTATEMENT);
1026 }
1027 else {
1028 numstatement++;
1029 AC.CurrentStream->prevline = AC.CurrentStream->linenumber;
1030 retval = LoadStatement(NEWSTATEMENT);
1031 }
1032 if ( retval < 0 ) {
1033 error1++;
1034 if ( retval == -1 ) AP.PreContinuation = 0;
1035 else AP.PreContinuation = 1;
1036 TryRecover(0);
1037 }
1038 else if ( retval > 0 ) AP.PreContinuation = 0;
1039 else AP.PreContinuation = 1;
1040 if ( error1 == 0 && !AP.PreContinuation ) {
1041 if ( ( AP.PreDebug & PREPROONLY ) == 0 ) {
1042 int onpmd = NumPotModdollars;
1043 #ifdef WITHMPI
1044 WORD oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
1045 if ( AP.PreAssignFlag ) AC.RhsExprInModuleFlag = 0;
1046 #endif
1047 if ( AP.PreOut || ( AP.PreDebug & DUMPTOCOMPILER )
1048 == DUMPTOCOMPILER )
1049 MesPrint(" %s",AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]);
1050 retcode = CompileStatement(AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]);
1051 if ( retcode < 0 ) error1++;
1052 if ( retcode ) { error2++; AP.preError++; }
1053 if ( AP.PreAssignFlag ) {
1054 if ( retcode == 0 ) {
1055 if ( ( retcode = CatchDollar(0) ) < 0 ) error1++;
1056 else if ( retcode > 0 ) { error2++; AP.preError++; }
1057 }
1058 else CatchDollar(-1);
1059 POPPREASSIGNLEVEL;
1060 if ( AP.PreAssignLevel <=0 )
1061 AP.PreAssignFlag = 0;
1062 NumPotModdollars = onpmd;
1063 #ifdef WITHMPI
1064 AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
1065 #endif
1066 }
1067 }
1068 else {
1069 MesPrint(" %s",AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]);
1070 }
1071 }
1072 else if ( !AP.PreContinuation ) {
1073 if ( AP.PreAssignLevel > 0 ) {
1074 POPPREASSIGNLEVEL;
1075 if ( AP.PreAssignLevel <=0 )
1076 AP.PreAssignFlag = 0;
1077 }
1078 }
1079 /*
1080 if ( !AP.PreContinuation ) AP.PreAssignFlag = 0;
1081 */
1082 }
1083 }
1084 }
1085 }
1086
1087 /*
1088 #] PreProcessor :
1089 #[ PreProInstruction :
1090 */
1091
PreProInstruction()1092 int PreProInstruction()
1093 {
1094 UBYTE *s, *t;
1095 KEYWORD *key;
1096 AP.PreproFlag = 1;
1097 AP.preFill = 0;
1098 AP.AllowDelay = 0;
1099 AP.DelayPrevar = 0;
1100
1101 oldmode = 0;
1102 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) {
1103 LoadInstruction(3);
1104 if ( ( StrICmp(AP.preStart,(UBYTE *)"case") == 0
1105 || StrICmp(AP.preStart,(UBYTE *)"default") == 0 )
1106 && AP.PreSwitchModes[AP.PreSwitchLevel] == SEARCHINGPRECASE ) {
1107 LoadInstruction(0);
1108 }
1109 else if ( StrICmp(AP.preStart,(UBYTE *)"assign ") == 0 ) {}
1110 else { LoadInstruction(1); }
1111 }
1112 else if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) {
1113 LoadInstruction(3);
1114 if ( ( StrICmp(AP.preStart,(UBYTE *)"else") == 0
1115 || StrICmp(AP.preStart,(UBYTE *)"elseif") == 0 )
1116 && AP.PreIfStack[AP.PreIfLevel] == LOOKINGFORELSE ) {
1117 LoadInstruction(0);
1118 }
1119 else if ( StrICmp(AP.preStart,(UBYTE *)"assign ") == 0 ) {}
1120 else {
1121 LoadInstruction(1);
1122 }
1123 }
1124 else {
1125 LoadInstruction(0);
1126 }
1127 AP.PreproFlag = 0;
1128 t = AP.preStart;
1129 if ( *t == '-' ) {
1130 if ( AP.PreSwitchModes[AP.PreSwitchLevel] == EXECUTINGPRESWITCH
1131 && AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF )
1132 AC.NoShowInput = 1;
1133 }
1134 else if ( *t == '+' ) {
1135 if ( AP.PreSwitchModes[AP.PreSwitchLevel] == EXECUTINGPRESWITCH
1136 && AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF )
1137 AC.NoShowInput = 0;
1138 }
1139 else if ( *t == ':' ) {}
1140 else {
1141 retry:;
1142 key = FindKeyWord(t,precommands,sizeof(precommands)/sizeof(KEYWORD));
1143 s = EndOfToken(t);
1144 if ( key == 0 ) {
1145 if ( *s == ';' ) {
1146 *s = 0; goto retry;
1147 }
1148 else {
1149 *s = 0;
1150 MesPrint("@Unrecognized preprocessor instruction: %s",t);
1151 return(-1);
1152 }
1153 }
1154 while ( *s == ' ' || *s == '\t' || *s == ',' ) s++;
1155 t = s;
1156 while ( *t ) t++;
1157 while ( ( t[-1] == ';' ) && ( t[-2] != '\\' ) ) {
1158 t--; *t = 0;
1159 }
1160 return((key->func)(s));
1161 }
1162 return(0);
1163 }
1164
1165 /*
1166 #] PreProInstruction :
1167 #[ LoadInstruction :
1168
1169 0: preprocessor instruction that may involve matching of brackets
1170 1: runs straight to end-of-line
1171 2: runs to ;
1172 3: only gets one word without `' interpretation.
1173 5: with pushbackchar, but inside commentary. -> 1
1174
1175 To be added:
1176 In define, redefine, call and listed do we may have delayed substitution
1177 of preprocessor variables.
1178 */
1179
LoadInstruction(int mode)1180 int LoadInstruction(int mode)
1181 {
1182 UBYTE *s, *sstart, *t, c, cp;
1183 LONG position, fillpos = 0;
1184 int bralevel = 0, parlevel = 0, first = 1;
1185 int quotelevel = 0;
1186 if ( AP.preFill ) {
1187 s = AP.preFill;
1188 AP.preFill = 0;
1189 if ( s[1] != LINEFEED && s[1] != ENDOFINPUT ) {
1190 s[0] = s[1]; s++;
1191 }
1192 else { oldmode = mode; return(0); }
1193 }
1194 else { s = AP.preStart; }
1195 sstart = s; *s = 0;
1196 for(;;) {
1197 if ( ( mode & 1 ) == 1 ) {
1198 if ( pushbackchar && ( mode == 3 || mode == 5 ) ) {
1199 c = pushbackchar; pushbackchar = 0;
1200 }
1201 else c = GetInput();
1202 }
1203 else {
1204 c = GetChar(0);
1205 }
1206
1207 if ( mode == 2 && c == ';' ) break;
1208 if ( ( mode == 1 || mode == 5 ) && c == LINEFEED ) break;
1209 if ( mode == 3 && FG.cTable[c] != 0 ) {
1210 if ( c == '$' ) {
1211 pushbackchar = '$';
1212 *s++ = 'a'; *s++ = 's'; *s++ = 's'; *s++ = 'i';
1213 *s++ = 'g'; *s++ = 'n'; *s++ = ' '; *s = 0;
1214 }
1215 AP.preFill = s; *s++ = 0; *s = c;
1216 oldmode = mode;
1217 return(0);
1218 }
1219 if ( mode == 0 && first ) {
1220 if ( c == '$' ) {
1221 dodollar: s = sstart;
1222 *s++ = 'a'; *s++ = 's'; *s++ = 's'; *s++ = 'i';
1223 *s++ = 'g'; *s++ = 'n'; *s = 0;
1224 pushbackchar = c;
1225 oldmode = mode;
1226 return(0);
1227 }
1228 if ( c == ' ' || c == '\t' || c == ',' ) {}
1229 else first = 0;
1230 }
1231 else if ( mode == 1 && first && c == '$' && oldmode == 3 ) goto dodollar;
1232 if ( c == ENDOFINPUT || ( c == LINEFEED
1233 /* && bralevel == 0 */
1234 && quotelevel == 0 ) ) {
1235 if ( mode == 2 && c == ENDOFINPUT ) {
1236 MesPrint("@Unexpected end of instruction");
1237 oldmode = mode;
1238 return(-1);
1239 }
1240 /*
1241 if ( mode == 0 && bralevel ) {
1242 MesPrint("@Unmatched brackets");
1243 oldmode = mode;
1244 return(-1);
1245 }
1246 */
1247 if ( mode != 2 ) break;
1248 }
1249 if ( quotelevel ) {
1250 if ( c == '\\' ) {
1251 if ( ( mode == 1 ) || ( mode == 5 ) ) c = GetInput();
1252 else {
1253 c = GetChar(0);
1254 }
1255 if ( c == ENDOFINPUT ) {
1256 MesPrint("@Unmatched \"");
1257 if ( mode == 2 && c == ENDOFINPUT ) {
1258 MesPrint("@Unexpected end of instruction");
1259 }
1260 /*
1261 if ( mode == 0 && bralevel ) {
1262 MesPrint("@Unmatched brackets");
1263 }
1264 */
1265 oldmode = mode;
1266 return(-1);
1267 }
1268 else if ( c == LINEFEED ) {}
1269 else if ( c == '"' ) { *s++ = '\\'; }
1270 else {
1271 *s++ = '\\';
1272 }
1273 }
1274 else if ( c == '"' ) {
1275 quotelevel = 0;
1276 AP.AllowDelay = 0;
1277 }
1278 }
1279 else if ( c == '\\' ) {
1280 if ( ( mode == 1 ) || ( mode == 5 ) ) cp = GetInput();
1281 else {
1282 cp = GetChar(0);
1283 }
1284 if ( cp == LINEFEED ) continue;
1285 if ( mode != 2 || cp != ';' ) *s++ = c;
1286 c = cp;
1287 }
1288 else if ( c == '"' ) {
1289 /*
1290 Now look back in the buffer and determine what the keyword is.
1291 If it is define or redefine, put AllowDelay to 1.
1292 */
1293 t = AP.preStart;
1294 while ( FG.cTable[*t] <= 1 ) t++;
1295 cp = *t; *t = 0;
1296 if ( ( StrICmp(AP.preStart,(UBYTE *)"define") == 0 )
1297 || ( StrICmp(AP.preStart,(UBYTE *)"redefine") == 0 ) ) {
1298 AP.AllowDelay = 1;
1299 oldstream = AC.CurrentStream;
1300 }
1301 *t = cp;
1302 quotelevel = 1;
1303 }
1304 else if ( quotelevel == 0 && bralevel == 0 && c == '(' ) {
1305 t = AP.preStart;
1306 while ( FG.cTable[*t] <= 1 ) t++;
1307 cp = *t; *t = 0;
1308 if ( ( parlevel == 0 )
1309 && ( StrICmp(AP.preStart,(UBYTE *)"call") == 0 ) ) {
1310 AP.AllowDelay = 1;
1311 oldstream = AC.CurrentStream;
1312 }
1313 *t = cp;
1314 parlevel++;
1315 }
1316 else if ( quotelevel == 0 && bralevel == 0 && c == ')' ) {
1317 parlevel--;
1318 }
1319 else if ( quotelevel == 0 && parlevel == 0 && c == '{' ) {
1320 t = AP.preStart;
1321 while ( FG.cTable[*t] <= 1 ) t++;
1322 cp = *t; *t = 0;
1323 if ( ( bralevel == 0 )
1324 && ( ( StrICmp(AP.preStart,(UBYTE *)"call") == 0 )
1325 || ( StrICmp(AP.preStart,(UBYTE *)"do") == 0 ) ) ) {
1326 AP.AllowDelay = 1;
1327 oldstream = AC.CurrentStream;
1328 }
1329 *t = cp;
1330 bralevel++;
1331 }
1332 else if ( quotelevel == 0 && parlevel == 0 && c == '}' ) {
1333 bralevel--;
1334 if ( bralevel < 0 ) {
1335 if ( mode != 5 ) {
1336 MesPrint("@Unmatched brackets");
1337 oldmode = mode;
1338 return(-1);
1339 }
1340 bralevel = 0;
1341 }
1342 }
1343 if ( s >= (AP.preStop-1) ) {
1344 UBYTE **ppp;
1345 position = s - AP.preStart;
1346 if ( AP.preFill ) fillpos = AP.preFill - AP.preStart;
1347 ppp = &(AP.preStart); /* to avoid a compiler warning */
1348 if ( DoubleLList((VOID ***)ppp,&AP.pSize,sizeof(UBYTE),
1349 "instruction buffer") ) { *s = 0; oldmode = mode; return(-1); }
1350 AP.preStop = AP.preStart + AP.pSize-3;
1351 s = AP.preStart + position;
1352 if ( AP.preFill ) AP.preFill = fillpos + AP.preStart;
1353 }
1354 *s++ = c;
1355 }
1356 *s = 0;
1357 oldmode = mode;
1358 if ( mode == 0 ) {
1359 if ( ExpandTripleDots(1) < 0 ) return(-1);
1360 }
1361 return(0);
1362 }
1363
1364 /*
1365 #] LoadInstruction :
1366 #[ LoadStatement :
1367
1368 Puts the current string together in the input buffer.
1369 Does things like placing comma's where needed and expand ...
1370 We force a comma after the keyword. Before 8-sep-2009 the program might
1371 not put a comma if a + or - followed. And then the compiler ate
1372 the + or - and we needed repair code in the routines that used the
1373 + or - (Print, modulus, multiply and (a)bracket). This worked but
1374 the problem was with statements like Dimension -4; which then would
1375 be processed as Dimension 4; (JV)
1376 */
1377
LoadStatement(int type)1378 int LoadStatement(int type)
1379 {
1380 UBYTE *s, c, cp;
1381 int retval = 0, stringlevel = 0, newstatement = 0;
1382 if ( type == NEWSTATEMENT ) { AP.eat = 1; newstatement = 1;
1383 s = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; }
1384 else { s = AC.iPointer; *s = 0; c = ' '; goto blank; }
1385 *s = 0;
1386 for(;;) {
1387 c = GetChar(0);
1388 if ( c == ENDOFINPUT ) { retval = -1; break; }
1389 if ( stringlevel == 0 ) {
1390 if ( c == LINEFEED ) { retval = 0; break; }
1391 if ( c == ';' ) {
1392 if ( AP.eat < 0 ) s--;
1393 while ( ( c = GetChar(0) ) == ' ' || c == '\t' ) {}
1394 if ( c != LINEFEED ) UngetChar(c);
1395 retval = 1;
1396 break;
1397 }
1398 }
1399 if ( c == '\\' ) {
1400 cp = GetChar(0);
1401 if ( cp == LINEFEED ) continue;
1402 *s++ = c;
1403 c = cp;
1404 }
1405 if ( c == '"' ) {
1406 if ( stringlevel == 0 ) stringlevel = 1;
1407 else stringlevel = 0;
1408 AP.eat = 0;
1409 }
1410 else if ( stringlevel == 0 ) {
1411 if ( c == '\t' ) c = ' ';
1412 if ( c == ' ' ) {
1413 blank: if ( newstatement < 0 ) newstatement = 0;
1414 if ( AP.eat && ( newstatement == 0 ) ) continue;
1415 c = ',';
1416 AP.eat = -2;
1417 if ( newstatement > 0 ) newstatement = -1;
1418 }
1419 else if ( chartype[c] <= 3 ) {
1420 AP.eat = 0;
1421 if ( newstatement < 0 ) newstatement = 0;
1422 }
1423 else if ( c == ',' ) {
1424 if ( newstatement > 0 ) {
1425 newstatement = -1;
1426 AP.eat = -2;
1427 }
1428 /* else if ( AP.eat == -2 ) { s--; } */
1429 else if ( AP.eat == -2 ) { AP.eat = 1; continue; }
1430 else { goto doall; }
1431 }
1432 else {
1433 doall:; if ( AP.eat < 0 ) {
1434 if ( newstatement == 0 ) s--;
1435 else { newstatement = 0; }
1436 }
1437 else if ( newstatement == 1 ) newstatement = 0;
1438 AP.eat = 1;
1439 if ( c == '*' && s > AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel] && s[-1] == '*' ) {
1440 s[-1] = '^';
1441 continue;
1442 }
1443 }
1444 }
1445 if ( s >= AC.iStop ) {
1446 if ( !AP.iBufError ) {
1447 LONG position = s - AC.iBuffer;
1448 LONG position2 = AC.iPointer - AC.iBuffer;
1449 UBYTE **ppp = &(AC.iBuffer); /* to avoid a compiler warning */
1450 if ( DoubleLList((VOID ***)ppp,&AC.iBufferSize
1451 ,sizeof(UBYTE),"statement buffer") ) {
1452 *s = 0; retval = -1; AP.iBufError = 1;
1453 }
1454 AC.iPointer = AC.iBuffer + position2;
1455 AC.iStop = AC.iBuffer + AC.iBufferSize-2;
1456 s = AC.iBuffer + position;
1457 }
1458 if ( AP.iBufError ) {
1459 for(;;){
1460 c = GetChar(0);
1461 if ( c == ENDOFINPUT ) { retval = -1; break; }
1462 if ( c == '"' ) {
1463 if ( stringlevel > 0 ) stringlevel = 0;
1464 else stringlevel = 1;
1465 }
1466 else if ( c == LINEFEED && !stringlevel ) { retval = -2; break; }
1467 else if ( c == ';' && !stringlevel ) {
1468 while ( ( c = GetChar(0) ) == ' ' || c == '\t' ) {}
1469 if ( c != LINEFEED ) UngetChar(c);
1470 retval = -1;
1471 break;
1472 }
1473 else if ( c == '\\' ) c = GetChar(0);
1474 }
1475 break;
1476 }
1477 }
1478 *s++ = c;
1479 }
1480 AC.iPointer = s;
1481 *s = 0;
1482 if ( stringlevel > 0 ) {
1483 MesPrint("@Unbalanced \". Runaway string");
1484 retval = -1;
1485 }
1486 if ( retval == 1 ) {
1487 if ( ExpandTripleDots(0) < 0 ) retval = -1;
1488 }
1489 return(retval);
1490 }
1491
1492 /*
1493 #] LoadStatement :
1494 #[ ExpandTripleDots :
1495 */
1496
IsSignChar(UBYTE c)1497 static inline int IsSignChar(UBYTE c)
1498 {
1499 return c == '+' || c == '-';
1500 }
1501
IsAlphanumericChar(UBYTE c)1502 static inline int IsAlphanumericChar(UBYTE c)
1503 {
1504 return FG.cTable[c] == 0 || FG.cTable[c] == 1;
1505 }
1506
CanParseSignedNumber(const UBYTE * s)1507 static inline int CanParseSignedNumber(const UBYTE *s)
1508 {
1509 while ( IsSignChar(*s) ) s++;
1510 return FG.cTable[*s] == 1;
1511 }
1512
ExpandTripleDots(int par)1513 int ExpandTripleDots(int par)
1514 {
1515 UBYTE *s, *s1, *s2, *n1, *n2, *t1, *t2, *startp, operator1, operator2, c, cc;
1516 UBYTE *nBuffer, *strngs, *Buffer, *Stop;
1517 LONG withquestion, x1, x2, y1, y2, number, inc, newsize, pow, fullsize;
1518 int i, error = 0, i1 ,i2, ii, *nums = 0;
1519
1520 if ( par == 0 ) {
1521 Buffer = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; Stop = AC.iStop;
1522 }
1523 else {
1524 Buffer = AP.preStart; Stop = AP.preStop;
1525 }
1526 s = Buffer; while ( *s ) s++;
1527 fullsize = s - Buffer;
1528 if ( fullsize < 7 ) return(error);
1529
1530 s = Buffer+2;
1531 while ( *s ) {
1532 if ( *s != '.' || ( s[-1] != ',' && FG.cTable[s[-1]] != 5 ) )
1533 { s++; continue; }
1534 if ( s[-1] == '%' || s[-1] == '^' || s[1] != '.' || s[2] != '.' )
1535 { s++; continue; }
1536 s1 = s - 2;
1537 s += 3;
1538 if ( *s != s[-4] && ( *s != '+' || s[-4] != '-' )
1539 && ( *s != '-' || s[-4] != '+' ) ) {
1540 MesPrint("&Improper operators for ...");
1541 error = -1;
1542 }
1543 operator1 = s[-4];
1544 operator2 = *s++;
1545 if ( operator1 == ':' ) operator1 = '.';
1546 if ( operator2 == ':' ) operator2 = '.';
1547 /*
1548 We have now O1...O2 (O stands for operator)
1549 Full syntax is
1550 [str]#1[?]O1...O2[str]#2[?] (Special case)
1551 in which both strings are identical and if one ? then also the other.
1552 <pattern1>O1...O2<pattern2> (General case)
1553 in which the difference in the patterns is just numerical.
1554 */
1555 s2 = s; /* the beginning of the second string */
1556 if ( *s2 != '<' || *s1 != '>' ) { /* Special case */
1557 startp = s1+1;
1558 withquestion = ( *s1 == '?' ); s1--;
1559 while ( FG.cTable[*s1] == 1 && s1 >= Buffer ) s1--;
1560 n1 = s1+1; /* Beginning of first number */
1561 if ( FG.cTable[*n1] != 1 ) {
1562 MesPrint("&No first number in ... operator");
1563 error = -1;
1564 }
1565 while ( FG.cTable[*s1] <= 1 && s1 >= Buffer ) s1--;
1566 s1++;
1567 /*
1568 We have now the first string from s1 to n1, number from n1
1569 */
1570 t1 = s1; t2 = s2;
1571 while ( t1 < n1 && *t1 == *t2 ) { t1++; t2++; }
1572 n2 = t2;
1573 if ( FG.cTable[*t2] != 1 ) {
1574 MesPrint("&No second number in ... operator");
1575 error = -1;
1576 }
1577 x2 = 0;
1578 while ( FG.cTable[*t2] == 1 ) x2 = 10*x2 + *t2++ - '0';
1579 x1 = 0;
1580 while ( FG.cTable[*t1] == 1 ) x1 = 10*x1 + *t1++ - '0';
1581 if ( withquestion != ( *t2 == '?' ) ) {
1582 MesPrint("&Improper use of ? in ... operator");
1583 if ( *t2 == '?' ) t2++;
1584 error = -1;
1585 }
1586 else if ( withquestion ) t2++;
1587 if ( FG.cTable[*t2] <= 2 ) {
1588 MesPrint("&Illegal object after ... construction");
1589 error = -1;
1590 }
1591 c = *n1; *n1 = 0; s = t2;
1592 if ( error ) continue;
1593 /*
1594 At this point the syntax has been fulfilled. We have
1595 str in s1.
1596 x1,x2 are #1,#2
1597 operator1,operator2 are the two operators.
1598 s points at whatever comes after.
1599 Expansion will have to be computed.
1600 */
1601 if ( x2 < x1 ) { number = x1-x2; inc = -1; y1 = x2; y2 = x1; }
1602 else { number = x2-x1; inc = 1; y1 = x1; y2 = x2; }
1603 newsize = (number+1)*(n1-s1) /* the strings */
1604 + number /* the operators */
1605 +(number+1)*(withquestion?1:0) /* questionmarks */
1606 +(number+1); /* last digits */
1607 pow = 10;
1608 for ( i = 1; i < 10; i++, pow *= 10 ) {
1609 if ( y1 >= pow ) newsize += number+1;
1610 else if ( y2 >= pow ) newsize += y2-pow+1;
1611 else break;
1612 }
1613 while ( Buffer+(fullsize+newsize-(s-s1)) >= Stop ) {
1614 LONG strpos = s1-Buffer;
1615 LONG endstr = n1-Buffer;
1616 LONG startq = startp - Buffer;
1617 LONG position = s - Buffer;
1618 UBYTE **ppp;
1619 if ( par == 0 ) {
1620 LONG position2 = AC.iPointer - AC.iBuffer;
1621 ppp = &(AC.iBuffer); /* to avoid a compiler warning */
1622 if ( DoubleLList((VOID ***)ppp,&AC.iBufferSize
1623 ,sizeof(UBYTE),"statement buffer") ) {
1624 Terminate(-1);
1625 }
1626 AC.iPointer = AC.iBuffer + position2;
1627 AC.iStop = AC.iBuffer + AC.iBufferSize-2;
1628 Buffer = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; Stop = AC.iStop;
1629 }
1630 else {
1631 LONG fillpos = 0;
1632 if ( AP.preFill ) fillpos = AP.preFill - AP.preStart;
1633 ppp = &(AP.preStart); /* to avoid a compiler warning */
1634 if ( DoubleLList((VOID ***)ppp,&AP.pSize,sizeof(UBYTE),
1635 "instruction buffer") ) {
1636 Terminate(-1);
1637 }
1638 AP.preStop = AP.preStart + AP.pSize-3;
1639 if ( AP.preFill ) AP.preFill = fillpos + AP.preStart;
1640 Buffer = AP.preStart; Stop = AP.preStop;
1641 }
1642 s = Buffer + position;
1643 n1 = Buffer + endstr;
1644 s1 = Buffer + strpos;
1645 startp = Buffer + startq;
1646 }
1647 /*
1648 We have space for the expansion in the buffer.
1649 There are two cases: new size > old size
1650 old size >= new size
1651 Note that whereever we move things, it will be at least startp.
1652 */
1653 if ( newsize > (s-s1) ) {
1654 t2 = Buffer + fullsize;
1655 t1 = t2 + (newsize - (s-s1));
1656 *t1 = 0;
1657 while ( t2 > s ) { *--t1 = *--t2; }
1658 }
1659 else if ( newsize < (s-s1) ) {
1660 t1 = s1 + newsize; t2 = s; s = t1;
1661 while ( *t2 ) *t1++ = *t2++;
1662 *t1 = 0;
1663 }
1664 for ( x1 += inc, t1 = startp; number > 0; number--, x1 += inc ) {
1665 *t1++ = operator1;
1666 cc = operator1; operator1 = operator2; operator2 = cc;
1667 t2 = s1; while ( *t2 ) *t1++ = *t2++;
1668 x2 = x1; n2 = t1;
1669 do {
1670 *t1++ = '0' + x2 % 10;
1671 x2 /= 10;
1672 } while ( x2 );
1673 s2 = t1 - 1;
1674 while ( s2 > n2 ) { cc = *s2; *s2 = *n2; *n2++ = cc; s2--; }
1675 if ( withquestion ) *t1++ = '?';
1676 }
1677 fullsize += newsize - ( s - s1 );
1678 *n1 = c;
1679 }
1680 else { /* General case. Find the patterns first */
1681 t1 = s1; s1--;
1682 while ( s1 > Buffer ) {
1683 if ( *s1 == '<' ) break;
1684 s1--;
1685 }
1686 t2 = s2;
1687 while ( *t2 ) {
1688 if ( *t2 == '>' ) break;
1689 t2++;
1690 }
1691 if ( *s1 != '<' || *t2 != '>' ) {
1692 MesPrint("&Illegal attempt to use ... operator");
1693 return(-1);
1694 }
1695 s1++; s2++; /* Pointers to the patterns */
1696 nums = (int *)Malloc1((t1-s1)*2*(sizeof(int)+sizeof(UBYTE))
1697 ,"Expand ...");
1698 strngs = (UBYTE *)(nums + 2*(t1-s1));
1699 n1 = s1; n2 = s2; ii = -1; i = 0;
1700 s = strngs;
1701 while ( n1 < t1 || n2 < t2 ) {
1702 /* Check the next characters can be parsed as numbers including signs. */
1703 if ( CanParseSignedNumber(n1) && CanParseSignedNumber(n2) ) {
1704 /*
1705 * Don't allow the cases that one has the sign and the other doesn't,
1706 * and the meaning changes without the sign. For example,
1707 * <f(1)>+...+<f(3)> Allowed
1708 * <f(-2)>+...+<f(2)> Allowed
1709 * <f(x-2)>+...+<f(x+2)> Allowed
1710 * <f(x-2)>+...+<f(x2)> Not allowed
1711 */
1712 int sign1 = IsSignChar(*n1);
1713 int sign2 = IsSignChar(*n2);
1714 int inword1 = s1 < n1 && IsAlphanumericChar(n1[-1]);
1715 int inword2 = s2 < n2 && IsAlphanumericChar(n2[-1]);
1716 if ( ( sign1 ^ sign2 ) && ( inword1 || inword2 ) ) break; /* Not allowed. */
1717 if ( sign1 || sign2 ) {
1718 *s++ = '+'; /* Marker indicating we need the sign. */
1719 }
1720 } else {
1721 /* If they are not numbers, they should be same. */
1722 if ( *n1 == *n2 ) { *s++ = *n1++; n2++; continue; }
1723 else break;
1724 }
1725 ParseSignedNumber(x1,n1)
1726 ParseSignedNumber(x2,n2)
1727 if ( x1 == x2 ) {
1728 if ( s != strngs && ( s[-1] == '+' || s[-1] == '-' ) ) {
1729 /* We need the sign. */
1730 s--;
1731 if ( x1 >= 0 ) {
1732 *s++ = '+';
1733 }
1734 }
1735 s = NumCopy(x1, s);
1736 }
1737 else {
1738 nums[2*i] = x1; nums[2*i+1] = x2;
1739 i++; *s++ = 0;
1740 }
1741 }
1742 if ( n1 < t1 || n2 < t2 ) {
1743 MesPrint("&Improper use of ... operator.");
1744 theend: M_free(nums,"Expand ...");
1745 return(-1);
1746 }
1747 *s = 0;
1748 if ( i == 0 ) ii = 0;
1749 else {
1750 ii = nums[0] - nums[1];
1751 if ( ii < 0 ) ii = -ii;
1752 for ( x1 = 1; x1 < i; x1++ ) {
1753 x2 = nums[2*x1]-nums[2*x1+1];
1754 if ( x2 < 0 ) x2 = -x2;
1755 if ( x2 != ii ) {
1756 MesPrint("&Improper synchronization of numbers in ... operator");
1757 goto theend;
1758 }
1759 }
1760 }
1761 ii++;
1762 /*
1763 We have now proper syntax.
1764 There are i+1 strings in strngs and i pairs of numbers
1765 in nums. Each time a start value and a finish value.
1766 We have ii steps. If ii <= 2, it will fit in the existing
1767 allocation. But this is hardly useful.
1768 We make a new allocation and copy from the old.
1769 Compute space.
1770 */
1771 x2 = s - strngs - i; /* -1 for eond-of-string and +1 for the operator*/
1772 for ( i1 = 0; i1 < i; i1++ ) {
1773 i2 = nums[2*i1];
1774 x1 = nums[2*i1+1];
1775 if ( i2 < 0 ) i2 = -i2;
1776 if ( x1 < 0 ) x1 = -x1;
1777 if ( x1 > i2 ) i2 = x1;
1778 x1 = 2;
1779 while ( i2 > 0 ) { i2 /= 10; x1++; }
1780 x2 += x1;
1781 }
1782 x2 *= ii; /* Space for the expanded string (a bit more) */
1783 x2 += fullsize;
1784 x2 += 5; /* This will definitely hold everything */
1785 x2 += sizeof(UBYTE *);
1786 x2 = x2 - (x2 & (sizeof(UBYTE *)-1));
1787
1788 nBuffer = (UBYTE *)Malloc1(x2,"input buffer");
1789 n1 = nBuffer; s = Buffer; s1--;
1790 while ( s < s1 ) *n1++ = *s++;
1791 /*
1792 Solution of the special case that no comma was generated
1793 due to the presence of < to start the pattern.
1794 We get a comma when the word before ends in an alphanumeric
1795 character, a _ or a ] and the word inside starts with an
1796 alphanumeric character, a [ (or an _ (for future considerations))
1797 */
1798 if ( ( ( n1 > nBuffer ) && ( ( FG.cTable[n1[-1]] <= 1 )
1799 || ( n1[-1] == '_' ) || ( n1[-1] == ']' ) ) ) &&
1800 ( ( FG.cTable[strngs[0]] <= 1 ) || ( strngs[0] == '[' )
1801 || ( strngs[0] == '_' ) ) ) *n1++ = ',';
1802
1803 for ( i1 = 0; i1 < ii; i1++ ) {
1804 s = strngs; while ( *s ) *n1++ = *s++;
1805 for ( i2 = 0; i2 < i; i2++ ) {
1806 if ( n1 > nBuffer && IsSignChar(n1[-1]) ) {
1807 /* We need the sign of counters. */
1808 n1--;
1809 if ( nums[2*i2] >= 0 ) {
1810 *n1++ = '+';
1811 }
1812 }
1813 n1 = NumCopy((WORD)(nums[2*i2]),n1);
1814 if ( nums[2*i2] > nums[2*i2+1] ) nums[2*i2]--;
1815 else nums[2*i2]++;
1816 s++; while ( *s ) *n1++ = *s++;
1817 }
1818 if ( ( i1 & 1 ) == 0 ) *n1++ = operator1;
1819 else *n1++ = operator2;
1820 }
1821 n1--; /* drop the trailing operator */
1822 s = t2 + 1; n2 = n1;
1823 /*
1824 Similar extra comma
1825 */
1826 if ( ( ( ( FG.cTable[n1[-1]] <= 1 )
1827 || ( n1[-1] == '_' ) || ( n1[-1] == ']' ) ) ) &&
1828 ( ( FG.cTable[s[0]] <= 1 ) || ( s[0] == '[' )
1829 || ( s[0] == '_' ) ) ) *n1++ = ',';
1830
1831 while ( *s ) *n1++ = *s++;
1832 *n1 = 0;
1833 if ( par == 0 ) {
1834 LONG nnn1 = n1-nBuffer;
1835 LONG nnn2 = n2-nBuffer;
1836 LONG nnn3;
1837 while ( AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel] + x2 >= AC.iStop ) {
1838 LONG position = s-Buffer;
1839 LONG position2 = AC.iPointer - AC.iBuffer;
1840 UBYTE **ppp;
1841 ppp = &(AC.iBuffer); /* to avoid a compiler warning */
1842 if ( DoubleLList((VOID ***)ppp,&AC.iBufferSize
1843 ,sizeof(UBYTE),"statement buffer") ) {
1844 Terminate(-1);
1845 }
1846 AC.iPointer = AC.iBuffer + position2;
1847 AC.iStop = AC.iBuffer + AC.iBufferSize-2;
1848 Buffer = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; Stop = AC.iStop;
1849 s = Buffer + position;
1850 }
1851 /*
1852 This can be improved. We only have to start from the first term.
1853 */
1854 for ( nnn3 = 0; nnn3 < nnn1; nnn3++ ) Buffer[nnn3] = nBuffer[nnn3];
1855 Buffer[nnn3] = 0;
1856 n1 = Buffer + nnn1;
1857 n2 = Buffer + nnn2;
1858 M_free(nBuffer,"input buffer");
1859 M_free(nums,"Expand ...");
1860 }
1861 else { /* Comes here only inside a real preprocessor instruction */
1862 AP.preStop = nBuffer + x2 - 2;
1863 AP.pSize = x2;
1864 M_free(AP.preStart,"input buffer");
1865 M_free(nums,"Expand ...");
1866 AP.preStart = nBuffer;
1867 Buffer = AP.preStart; Stop = AP.preStop;
1868 }
1869 fullsize = n1 - Buffer;
1870 s = n2;
1871 }
1872 }
1873 return(error);
1874 }
1875
1876 /*
1877 #] ExpandTripleDots :
1878 #[ FindKeyWord :
1879 */
1880
FindKeyWord(UBYTE * theword,KEYWORD * table,int size)1881 KEYWORD *FindKeyWord(UBYTE *theword, KEYWORD *table, int size)
1882 {
1883 int low,med,hi;
1884 UBYTE *s1, *s2;
1885 low = 0;
1886 hi = size-1;
1887 while ( hi >= low ) {
1888 med = (hi+low)/2;
1889 s1 = (UBYTE *)(table[med].name);
1890 s2 = theword;
1891 while ( *s1 && tolower(*s1) == tolower(*s2) ) { s1++; s2++; }
1892 if ( *s1 == 0 &&
1893 /*[30apr2004 mt]:*/
1894 /* The bug!:
1895 FG.cTable[*s2] != 1 && FG.cTable[*s2] != 2
1896 */
1897 FG.cTable[*s2] != 0 && FG.cTable[*s2] != 1
1898 /* ( *s2 == ' ' || *s2 == '\t' || *s2 == 0 || *s2 == ',' || *s2 == '(' ) */
1899 )
1900 return(table+med);
1901 if ( tolower(*s2) > tolower(*s1) ) low = med+1;
1902 else hi = med - 1;
1903 }
1904 return(0);
1905 }
1906
1907 /*
1908 #] FindKeyWord :
1909 #[ FindInKeyWord :
1910 */
1911
FindInKeyWord(UBYTE * theword,KEYWORD * table,int size)1912 KEYWORD *FindInKeyWord(UBYTE *theword, KEYWORD *table, int size)
1913 {
1914 int i;
1915 UBYTE *s1, *s2;
1916 for ( i = 0; i < size; i++ ) {
1917 s1 = (UBYTE *)(table[i].name);
1918 s2 = theword;
1919 while ( *s1 && tolower(*s1) == tolower(*s2) ) { s1++; s2++; }
1920 if ( *s2 == 0 || *s2 == ' ' || *s2 == ',' || *s2 == '\t' )
1921 return(table+i);
1922 }
1923 return(0);
1924 }
1925
1926 /*
1927 #] FindInKeyWord :
1928 #[ TheDefine :
1929 */
1930
1931 /**
1932 * Preprocessor assignment. Possible arguments and values are treated and the
1933 * new preprocessor variable is put into the name administration.
1934 *
1935 * @param s Pointer to the character string following the preprocessor
1936 * command.
1937 * @param mode Bitmask. 0-bit clear: always create a new name entry, 0-bit
1938 * set: try to redefine an existing name, 1-bit set: ignore
1939 * preprocessor if/switch status.
1940 * @return zero: no errors, negative number: errors.
1941 */
TheDefine(UBYTE * s,int mode)1942 int TheDefine(UBYTE *s, int mode)
1943 {
1944 UBYTE *name, *value, *valpoin, *args = 0, c;
1945 if ( ( mode & 2 ) == 0 ) {
1946 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
1947 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
1948 }
1949 else { mode &= ~2; }
1950 name = s;
1951 if ( chartype[*s] != 0 ) goto illname;
1952 s++;
1953 while ( chartype[*s] <= 1 ) s++;
1954 value = s;
1955 while ( *s == ' ' || *s == '\t' ) s++;
1956 c = *s; *value = 0;
1957 if ( c == 0 ) {
1958 if ( PutPreVar(name,(UBYTE *)"1",0,mode) < 0 ) return(-1);
1959 return(0);
1960 }
1961 if ( c == '(' ) { /* arguments. scan for correctness */
1962 s++; args = s;
1963 for (;;) {
1964 if ( chartype[*s] != 0 ) goto illarg;
1965 s++;
1966 while ( chartype[*s] <= 1 ) s++;
1967 while ( *s == ' ' || *s == '\t' ) s++;
1968 if ( *s == ')' ) break;
1969 if ( *s != ',' ) goto illargs;
1970 s++;
1971 while ( *s == ' ' || *s == '\t' ) s++;
1972 }
1973 *s++ = 0;
1974 while ( *s == ' ' || *s == '\t' ) s++;
1975 c = *s;
1976 }
1977 if ( c == '"' ) {
1978 s++; valpoin = value = s;
1979 while ( *s != '"' ) {
1980 if ( *s == '\\' ) {
1981 if ( s[1] == 'n' ) { *valpoin++ = LINEFEED; s += 2; }
1982 else if ( s[1] == '"' ) { *valpoin++ = '"'; s += 2; }
1983 else if ( s[1] == 0 ) goto illval;
1984 else { *valpoin++ = *s++; *valpoin++ = *s++; }
1985 }
1986 else *valpoin++ = *s++;
1987 }
1988 *valpoin = 0;
1989 if ( PutPreVar(name,value,args,mode) < 0 ) return(-1);
1990 }
1991 else {
1992 MesPrint("@Illegal string for preprocessor variable %s. Forgotten double quotes (\") ?",name);
1993 return(-1);
1994 }
1995 return(0);
1996 illname:;
1997 MesPrint("@Illegally formed name of preprocessor variable");
1998 return(-1);
1999 illarg:;
2000 MesPrint("@Illegally formed name of argument of preprocessor definition");
2001 return(-1);
2002 illargs:;
2003 MesPrint("@Illegally formed arguments of preprocessor definition");
2004 return(-1);
2005 illval:;
2006 MesPrint("@Illegal valpoin for preprocessor variable %s",name);
2007 return(-1);
2008 }
2009
2010 /*
2011 #] TheDefine :
2012 #[ DoCommentChar :
2013 */
2014
DoCommentChar(UBYTE * s)2015 int DoCommentChar(UBYTE *s)
2016 {
2017 UBYTE c;
2018 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2019 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2020 while ( *s == ' ' || *s == '\t' ) s++;
2021 if ( *s == 0 || *s == '\n' ) {
2022 MesPrint("@No valid comment character specified");
2023 return(-1);
2024 }
2025 c = *s++;
2026 while ( *s == ' ' || *s == '\t' ) s++;
2027 if ( *s != 0 && *s != '\n' ) {
2028 MesPrint("@Comment character should be a single valid character");
2029 return(-1);
2030 }
2031 AP.ComChar = c;
2032 return(0);
2033 }
2034
2035 /*
2036 #] DoCommentChar :
2037 #[ DoPreAssign :
2038
2039 Routine assigns a 'value' to a $variable.
2040 Syntax: #assign
2041 next line(s) a statement of the type
2042 $name = expression;
2043 Note: at the moment of the assign there cannot be an 'open' statement.
2044 */
2045
DoPreAssign(UBYTE * s)2046 int DoPreAssign(UBYTE *s)
2047 {
2048 int error = 0;
2049 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) {
2050 return(0);
2051 }
2052 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) {
2053 return(0);
2054 }
2055 if ( *s ) {
2056 MesPrint("@Illegal characters in %#assign instruction");
2057 error = 1;
2058 }
2059 PUSHPREASSIGNLEVEL;
2060 AP.PreAssignFlag = 1;
2061 /*
2062 if ( AP.PreContinuation ) {
2063 MesPrint("@Assign instructions cannot occur inside statements");
2064 MesPrint("@Missing ; ?");
2065 AP.PreContinuation = 0;
2066 error = 1;
2067 }
2068 */
2069 return(error);
2070 }
2071
2072 /*
2073 #] DoPreAssign :
2074 #[ DoDefine :
2075 */
2076
DoDefine(UBYTE * s)2077 int DoDefine(UBYTE *s)
2078 {
2079 return(TheDefine(s,0));
2080 }
2081
2082 /*
2083 #] DoDefine :
2084 #[ DoRedefine :
2085 */
2086
DoRedefine(UBYTE * s)2087 int DoRedefine(UBYTE *s)
2088 {
2089 return(TheDefine(s,1));
2090 }
2091
2092 /*
2093 #] DoRedefine :
2094 #[ ClearMacro :
2095
2096 Undefines the arguments of a macro after its use.
2097 */
2098
ClearMacro(UBYTE * name)2099 int ClearMacro(UBYTE *name)
2100 {
2101 int i;
2102 PREVAR *p;
2103 UBYTE *s;
2104 for ( i = NumPre-1, p = &(PreVar[NumPre-1]); i >= 0; i--, p-- ) {
2105 if ( StrCmp(name,p->name) == 0 ) break;
2106 }
2107 if ( i < 0 ) return(-1);
2108 if ( p->nargs <= 0 ) return(0);
2109 s = p->argnames;
2110 for ( i = 0; i < p->nargs; i++ ) {
2111 TheUndefine(s);
2112 while ( *s ) s++;
2113 s++;
2114 }
2115 return(0);
2116 }
2117
2118 /*
2119 #] ClearMacro :
2120 #[ TheUndefine :
2121
2122 There is a complication here. If there are redefine statements
2123 they will be pointing at the wrong variable if their number is
2124 greater than the number of the variable we pop.
2125 */
2126
TheUndefine(UBYTE * name)2127 int TheUndefine(UBYTE *name)
2128 {
2129 int i, inum, error = 0;
2130 PREVAR *p;
2131 for ( i = NumPre-1, p = &(PreVar[NumPre-1]); i >= 0; i--, p-- ) {
2132 if ( StrCmp(name,p->name) == 0 ) {
2133 M_free(p->name,"undefining PreVar");
2134 NumPre--;
2135 inum = i;
2136 while ( i < NumPre ) {
2137 p->name = p[1].name;
2138 p->value = p[1].value;
2139 p++; i++;
2140 }
2141 p->name = 0; p->value = 0;
2142 {
2143 CBUF *CC = cbuf + AC.cbufnum;
2144 int j, k;
2145 for ( j = 1; j <= CC->numlhs; j++ ) {
2146 if ( CC->lhs[j][0] == TYPEREDEFPRE ) {
2147 if ( CC->lhs[j][2] > inum ) CC->lhs[j][2]--;
2148 else if ( CC->lhs[j][2] == inum ) {
2149 for ( k = inum - 1; k >= 0; k-- )
2150 if ( StrCmp(name, PreVar[k].name) == 0 ) break;
2151 if ( k >= 0 ) CC->lhs[j][2] = k;
2152 else {
2153 MesPrint("@Conflict between undefining a preprocessor variable and a redefine statement");
2154 error = 1;
2155 }
2156 }
2157 }
2158 }
2159 #ifdef PARALLELCODE
2160 for ( j = 0; j < AC.numpfirstnum; j++ ) {
2161 if ( AC.pfirstnum[j] > inum ) AC.pfirstnum[j]--;
2162 else if ( AC.pfirstnum[j] == inum ) {
2163 for ( k = inum - 1; k >= 0; k-- )
2164 if ( StrCmp(name, PreVar[k].name) == 0 ) break;
2165 if ( k >= 0 ) AC.pfirstnum[j] = k;
2166 }
2167 }
2168 #endif
2169 }
2170 break;
2171 }
2172 }
2173 return(error);
2174 }
2175
2176 /*
2177 #] TheUndefine :
2178 #[ DoUndefine :
2179 */
2180
DoUndefine(UBYTE * s)2181 int DoUndefine(UBYTE *s)
2182 {
2183 UBYTE *name, *t;
2184 int error = 0, retval;
2185 /*
2186 int i;
2187 PREVAR *p;
2188 */
2189 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2190 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2191 name = s;
2192 if ( chartype[*s] != 0 ) goto illname;
2193 s++;
2194 while ( chartype[*s] <= 1 ) s++;
2195 t = s;
2196 if ( *s && *s != ' ' && *s != '\t' ) goto illname;
2197 while ( *s == ' ' || *s == '\t' ) s++;
2198 if ( *s ) {
2199 MesPrint("@Undefine should just have a variable name");
2200 error = -1;
2201 }
2202 *t = 0;
2203 if ( ( retval = TheUndefine(name) ) != 0 ) {
2204 if ( error == 0 ) return(retval);
2205 if ( error > 0 ) error = retval;
2206 }
2207 /*
2208 for ( i = NumPre-1, p = &(PreVar[NumPre-1]); i >= 0; i--, p-- ) {
2209 if ( StrCmp(name,p->name) == 0 ) {
2210 M_free(p->name,"undefining PreVar");
2211 NumPre--;
2212 while ( i < NumPre ) {
2213 p->name = p[1].name;
2214 p->value = p[1].value;
2215 p++; i++;
2216 }
2217 p->name = 0; p->value = 0;
2218 break;
2219 }
2220 }
2221 */
2222 return(error);
2223 illname:;
2224 MesPrint("@Illegally formed name of preprocessor variable");
2225 return(-1);
2226 }
2227
2228 /*
2229 #] DoUndefine :
2230 #[ DoInclude :
2231 */
2232
DoInclude(UBYTE * s)2233 int DoInclude(UBYTE *s) { return(Include(s,FILESTREAM)); }
2234
2235 /*
2236 #] DoInclude :
2237 #[ DoReverseInclude :
2238 */
2239
DoReverseInclude(UBYTE * s)2240 int DoReverseInclude(UBYTE *s) { return(Include(s,REVERSEFILESTREAM)); }
2241
2242 /*
2243 #] DoReverseInclude :
2244 #[ Include :
2245 */
2246
Include(UBYTE * s,int type)2247 int Include(UBYTE *s, int type)
2248 {
2249 UBYTE *name = s, *fold, *t, c, c1 = 0, c2 = 0, c3 = 0;
2250 int str1offset, withnolist = AC.NoShowInput;
2251 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2252 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2253 if ( *s == '-' || *s == '+' ) {
2254 if ( *s == '-' ) withnolist = 1;
2255 else withnolist = 0;
2256 s++;
2257 while ( *s == ' ' || *s == '\t' ) s++;
2258 name = s;
2259 }
2260 if ( *s == '"' ) {
2261 while ( *s && *s != '"' ) {
2262 if ( *s == '\\' ) s++;
2263 s++;
2264 }
2265 t = s++;
2266 }
2267 else {
2268 while ( *s && *s != ' ' && *s != '\t' ) {
2269 if ( *s == '\\' ) s++;
2270 s++;
2271 }
2272 t = s;
2273 }
2274 while ( *s == ' ' || *s == '\t' ) s++;
2275 if ( *s == '#' ) {
2276 *t = 0;
2277 s++;
2278 while ( *s == ' ' || *s == '\t' ) s++;
2279 fold = s;
2280 if ( *s == 0 ) {
2281 MesPrint("@Empty fold name");
2282 return(-1);
2283 }
2284 continue_fold:
2285 while ( *s && *s != ' ' && *s != '\t' ) {
2286 if ( *s == '\\' ) s++;
2287 s++;
2288 }
2289 t = s;
2290 while ( *s == ' ' || *s == '\t' ) s++;
2291 if ( *s ) {
2292 /*
2293 * A non-whitespace character is found. Continue parsing the fold.
2294 */
2295 goto continue_fold;
2296 }
2297 }
2298 else if ( *s == 0 ) {
2299 fold = 0;
2300 }
2301 else {
2302 MesPrint("@Improper syntax for file name");
2303 return(-1);
2304 }
2305 *t = 0;
2306 if ( fold ) {
2307 fold = strDup1(fold,"foldname");
2308 }
2309 /*
2310 We have the name of the file in 'name' and the fold in 'fold' (or NULL)
2311 */
2312 if ( OpenStream(name,type,0,PRENOACTION) == 0 ) {
2313 if ( fold ) { M_free(fold,"foldname"); fold = 0; }
2314 return(-1);
2315 }
2316 if ( fold ) {
2317 LONG position = -1;
2318 int foldopen = 0;
2319 LONG linenum = 0, prevline = 0;
2320 name = strDup1(name,"name of include file");
2321 AC.CurrentStream->FoldName = strDup1(fold,"name of fold");
2322 AC.NoShowInput++;
2323 for(;;) {
2324 c = GetFromStream(AC.CurrentStream);
2325 if ( c == ENDOFSTREAM ) {
2326 AC.CurrentStream = CloseStream(AC.CurrentStream);
2327 goto nofold;
2328 }
2329 if ( c == AP.ComChar ) {
2330 str1offset = AC.CurrentStream-AC.Streams;
2331 LoadInstruction(1);
2332 if ( AC.CurrentStream != str1offset+AC.Streams ) {
2333 c = ENDOFSTREAM;
2334 }
2335 else {
2336 t = AP.preStart;
2337 if ( t[2] == '#' && ( ( t[3] == '[' && !foldopen )
2338 || ( t[3] == ']' && foldopen ) ) ) {
2339 t += 4;
2340 while ( *t == ' ' || *t == '\t' ) t++;
2341 s = AC.CurrentStream->FoldName;
2342 while ( *s == *t ) { s++; t++; }
2343 if ( *s == 0 && ( *t == ' ' || *t == '\t'
2344 || *t == ':' ) ) {
2345 while ( *t == ' ' || *t == '\t' ) t++;
2346 if ( *t == ':' ) {
2347 if ( foldopen == 0 ) {
2348 foldopen = 1;
2349 position = GetStreamPosition(AC.CurrentStream);
2350 linenum = AC.CurrentStream->linenumber;
2351 prevline = AC.CurrentStream->prevline;
2352 c3 = AC.CurrentStream->isnextchar;
2353 c1 = AC.CurrentStream->nextchar[0];
2354 c2 = AC.CurrentStream->nextchar[1];
2355 }
2356 else {
2357 foldopen = 0;
2358 PositionStream(AC.CurrentStream,position);
2359 AC.CurrentStream->linenumber = linenum;
2360 AC.CurrentStream->prevline = prevline;
2361 AC.CurrentStream->eqnum = 1;
2362 AC.NoShowInput--;
2363 AC.CurrentStream->isnextchar = c3;
2364 AC.CurrentStream->nextchar[0] = c1;
2365 AC.CurrentStream->nextchar[1] = c2;
2366 break;
2367 }
2368 }
2369 }
2370 }
2371 }
2372 }
2373 else {
2374 while ( c != LINEFEED && c != ENDOFSTREAM ) {
2375 c = GetFromStream(AC.CurrentStream);
2376 if ( c == ENDOFSTREAM ) {
2377 AC.CurrentStream = CloseStream(AC.CurrentStream);
2378 break;
2379 }
2380 }
2381 }
2382 if ( c == ENDOFSTREAM ) {
2383 nofold:
2384 MesPrint("@Cannot find fold %s in file %s",fold,name);
2385 UngetChar(c);
2386 AC.NoShowInput--;
2387 M_free(name,"name of include file");
2388 Terminate(-1);
2389 }
2390 }
2391 M_free(name,"name of include file");
2392 }
2393 AC.NoShowInput = withnolist;
2394 if ( fold ) { M_free(fold,"foldname"); fold = 0; }
2395 return(0);
2396 }
2397
2398 /*
2399 #] Include :
2400 #[ DoPreExchange :
2401
2402 Exchanges the names of expressions or the contents of dollars
2403 Syntax:
2404 #exchange expr1,expr2
2405 #exchange $var1,$var2
2406 */
2407
DoPreExchange(UBYTE * s)2408 int DoPreExchange(UBYTE *s)
2409 {
2410 int error = 0;
2411 UBYTE *s1, *s2;
2412 WORD num1, num2;
2413 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2414 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2415 while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
2416 if ( *s == '$' ) {
2417 s++; s1 = s; while ( FG.cTable[*s] <= 1 ) s++;
2418 if ( *s != ',' && *s != ' ' && *s != '\t' ) goto syntax;
2419 *s++ = 0;
2420 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
2421 if ( *s != '$' ) goto syntax;
2422 s++; s2 = s; while ( FG.cTable[*s] <= 1 ) s++;
2423 if ( *s != 0 && *s != ';' ) goto syntax;
2424 *s = 0;
2425 if ( ( num1 = GetDollar(s1) ) <= 0 ) {
2426 MesPrint("@$%s has not been defined (yet)",s1);
2427 error = 1;
2428 }
2429 if ( ( num2 = GetDollar(s2) ) <= 0 ) {
2430 MesPrint("@$%s has not been defined (yet)",s2);
2431 error = 1;
2432 }
2433 if ( error == 0 ) {
2434 ExchangeDollars((int)num1,(int)num2);
2435 }
2436 }
2437 else {
2438 s1 = s; s = SkipAName(s);
2439 if ( *s != ',' && *s != ' ' && *s != '\t' ) goto syntax;
2440 *s++ = 0;
2441 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
2442 if ( FG.cTable[*s] != 0 && *s != '[' ) goto syntax;
2443 s2 = s; s = SkipAName(s);
2444 if ( *s != 0 && *s != ';' ) goto syntax;
2445 *s = 0;
2446 if ( GetName(AC.exprnames,s1,&num1,NOAUTO) != CEXPRESSION ) {
2447 MesPrint("@%s is not an expression",s1);
2448 error = 1;
2449 }
2450 if ( GetName(AC.exprnames,s2,&num2,NOAUTO) != CEXPRESSION ) {
2451 MesPrint("@%s is not an expression",s2);
2452 error = 1;
2453 }
2454 if ( error == 0 ) {
2455 ExchangeExpressions((int)num1,(int)num2);
2456 }
2457 }
2458 return(error);
2459 syntax:
2460 MesPrint("@Proper syntax: %#exchange expr1,expr2 or %#exchange $var1,$var2");
2461 return(1);
2462 }
2463
2464 /*
2465 #] DoPreExchange :
2466 #[ DoCall :
2467 */
2468
DoCall(UBYTE * s)2469 int DoCall(UBYTE *s)
2470 {
2471 UBYTE *t, *u, *v, *name, c, cp, *args1, *args2, *t1, *t2, *wild = 0;
2472 int bratype = 0, wildargs = 0, inwildargs = 0, nwildargs = 0;
2473 PROCEDURE *p;
2474 int streamoffset;
2475 int i, namesize, narg1, narg2, bralevel, numpre;
2476 LONG i1, i2;
2477 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2478 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2479 /*
2480 1: Get the name of the procedure.
2481 2: Locate the procedure.
2482 */
2483 name = s; s = EndOfToken(s); c = *s; *s = 0;
2484 for ( i = NumProcedures-1; i >= 0; i-- ) {
2485 if ( StrCmp(Procedures[i].name,name) == 0 ) break;
2486 }
2487 p = (PROCEDURE *)FromList(&AP.ProcList);
2488 if ( i < 0 ) { /* Try to find a file */
2489 namesize = 0;
2490 t = name;
2491 while ( *t ) { t++; namesize++; }
2492 t = AP.procedureExtension;
2493 while ( *t ) { t++; namesize++; }
2494 t = p->name = (UBYTE *)Malloc1(namesize+2,"procedure");
2495 u = name;
2496 while ( *u ) *t++ = *u++;
2497 *t++ = '.';
2498 v = AP.procedureExtension;
2499 while ( *v ) *t++ = *v++;
2500 *t = 0;
2501 p->loadmode = 0; /* buffer should be freed at end */
2502 p->p.buffer = LoadInputFile(p->name,PROCEDUREFILE);
2503 if ( p->p.buffer == 0 ) return(-1);
2504 t[-4] = 0;
2505 }
2506 else {
2507 p->p.buffer = Procedures[i].p.buffer;
2508 p->name = Procedures[i].name;
2509 p->loadmode = 1;
2510 }
2511 t = p->p.buffer;
2512 SKIPBLANKS(t)
2513 if ( *t++ != '#' ) goto wrongfile;
2514 SKIPBLANKS(t)
2515 t += 9;
2516 SKIPBLANKS(t)
2517 u = EndOfToken(t);
2518 cp = *u; *u = 0;
2519 if ( StrCmp(t,name) != 0 ) goto wrongfile;
2520 *u = cp;
2521 *s = c;
2522 /*
2523 The pointer p points to the contents of the procedure (in memory)
2524 Now we have to match the arguments. u points to after the name
2525 in the 'file', s to after the name in the call statement.
2526 */
2527 bralevel = narg1 = narg2 = 0; args2 = u;
2528 SKIPBLANKS(u)
2529 if ( *u == '(' ) {
2530 u++; SKIPBLANKS(u)
2531 args2 = u;
2532 while ( *u != ')' ) {
2533 if ( *u == '?' ) { wildargs++; u++; nwildargs = narg2+1; }
2534 narg2++; u = EndOfToken(u); SKIPBLANKS(u)
2535 if ( *u == ',' ) { u++; SKIPBLANKS(u) }
2536 else if ( *u != ')' || ( wildargs > 1 ) ) {
2537 MesPrint("@Illegal argument field in procedure %s",p->name);
2538 return(-1);
2539 }
2540 }
2541 }
2542 while ( *u != LINEFEED ) u++;
2543 SKIPBLANKS(s)
2544 args1 = s+1;
2545 if ( *s == '(' ) bratype = 1;
2546 do {
2547 if ( *s == '{' && bratype == 0 ) bralevel++;
2548 else if ( *s == '(' && bratype == 1 ) bralevel++;
2549 else if ( *s == '}' && bratype == 0 ) {
2550 bralevel--;
2551 if ( bralevel == 0 ) {
2552 *s = 0; narg1++;
2553 if ( wildargs && narg1 == nwildargs ) wild = s;
2554 }
2555 }
2556 else if ( *s == ')' && bratype == 1 ) {
2557 bralevel--;
2558 if ( bralevel == 0 ) {
2559 *s = 0; narg1++;
2560 if ( wildargs && narg1 == nwildargs ) wild = s;
2561 }
2562 }
2563 /*[12dec2003 mt]:*/
2564 /*else if ( *s == ',' || *s == '|' ) {*/
2565 else if (set_in(*s,AC.separators)) {/*Function set_in see in
2566 file tools.c*/
2567 /*:[12dec2003 mt]*/
2568 *s = 0; narg1++;
2569 if ( wildargs && narg1 == nwildargs ) wild = s;
2570 }
2571 else if ( *s == '\\' ) s++;
2572 s++;
2573 } while ( bralevel > 0 );
2574 if ( wildargs && narg1 >= narg2-1 ) {
2575 inwildargs = narg1-narg2+1;
2576 if ( inwildargs == 0 ) nwildargs = 0;
2577 else {
2578 while ( inwildargs > 1 ) {
2579 *wild = ',';
2580 while ( *wild ) wild++;
2581 inwildargs--;
2582 }
2583 }
2584 }
2585 else if ( narg1 != narg2 && ( narg2 != 0 || narg1 != 1 || *args1 != 0 ) ) {
2586 MesPrint("@Arguments of procedure %s are not matching",p->name);
2587 return(-1);
2588 }
2589 numpre = -NumPre-1; /* For the stream */
2590 for ( i = 0; i < narg2; i++ ) {
2591 t = args2;
2592 if ( *t == '?' ) {
2593 args2++;
2594 }
2595 if ( *t == '?' && inwildargs == 0 ) {
2596 args2 = EndOfToken(args2); c = *args2; *args2 = 0;
2597 if ( PutPreVar(t,(UBYTE *)"",0,0) < 0 ) return(-1);
2598 }
2599 else {
2600 args2 = EndOfToken(args2); c = *args2; *args2 = 0;
2601 t1 = t2 = args1;
2602 while ( *t1 ) {
2603 if ( *t1 == '\\' ) t1++;
2604 if ( t1 != t2 ) *t2 = *t1;
2605 t2++; t1++;
2606 }
2607 *t2 = 0;
2608 if ( PutPreVar(t,args1,0,0) < 0 ) return(-1);
2609 args1 = t1+1; /* Next argument */
2610 }
2611 *args2 = c; SKIPBLANKS(args2) /* skip to next name */
2612 args2++; SKIPBLANKS(args2)
2613 }
2614 streamoffset = AC.CurrentStream - AC.Streams;
2615 args1 = AC.CurrentStream->name;
2616 AC.CurrentStream->name = p->name;
2617 i1 = AC.CurrentStream->linenumber;
2618 i2 = AC.CurrentStream->prevline;
2619 AC.CurrentStream->prevline =
2620 AC.CurrentStream->linenumber = 2;
2621 OpenStream(u+1,PREREADSTREAM3,numpre,PRENOACTION);
2622 AC.Streams[streamoffset].name = args1;
2623 AC.Streams[streamoffset].linenumber = i1;
2624 AC.Streams[streamoffset].prevline = i2;
2625 AddToPreTypes(PRETYPEPROCEDURE);
2626 return(0);
2627 wrongfile:;
2628 if ( i < 0 ) MesPrint("@File %s is not a proper procedure",p->name);
2629 else MesPrint("!!!Internal error with procedure names: %s",name);
2630 return(-1);
2631 }
2632
2633 /*
2634 #] DoCall :
2635 #[ DoDebug :
2636 */
2637
DoDebug(UBYTE * s)2638 int DoDebug(UBYTE *s)
2639 {
2640 int x;
2641 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2642 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2643 NeedNumber(x,s,nonumber)
2644 if ( x < 0 || x >(PREPROONLY
2645 | DUMPTOCOMPILER
2646 | DUMPOUTTERMS
2647 | DUMPINTERMS
2648 | DUMPTOSORT
2649 | DUMPTOPARALLEL
2650 #ifdef WITHPTHREADS
2651 | THREADSDEBUG
2652 #endif
2653 ) ) goto nonumber;
2654 AP.PreDebug = 0;
2655 if ( ( x & PREPROONLY ) != 0 ) AP.PreDebug |= PREPROONLY; /* 1 */
2656 if ( ( x & DUMPTOCOMPILER ) != 0 ) AP.PreDebug |= DUMPTOCOMPILER; /* 2 */
2657 if ( ( x & DUMPOUTTERMS ) != 0 ) AP.PreDebug |= DUMPOUTTERMS; /* 4 */
2658 if ( ( x & DUMPINTERMS ) != 0 ) AP.PreDebug |= DUMPINTERMS; /* 8 */
2659 if ( ( x & DUMPTOSORT ) != 0 ) AP.PreDebug |= DUMPTOSORT; /* 16 */
2660 if ( ( x & DUMPTOPARALLEL ) != 0 ) AP.PreDebug |= DUMPTOPARALLEL; /* 32 */
2661 #ifdef WITHPTHREADS
2662 if ( ( x & THREADSDEBUG ) != 0 ) AP.PreDebug |= THREADSDEBUG; /* 64 */
2663 #endif
2664 return(0);
2665 nonumber:
2666 MesPrint("@Illegal argument for debug instruction");
2667 return(1);
2668 }
2669
2670 /*
2671 #] DoDebug :
2672 #[ DoTerminate :
2673 */
2674
DoTerminate(UBYTE * s)2675 int DoTerminate(UBYTE *s)
2676 {
2677 int x;
2678 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2679 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2680 if ( *s ) {
2681 NeedNumber(x,s,nonumber)
2682 Terminate(x);
2683 }
2684 else {
2685 Terminate(-1);
2686 }
2687 return(0);
2688 nonumber:
2689 MesPrint("@Illegal argument for terminate instruction");
2690 return(1);
2691 }
2692
2693 /*
2694 #] DoTerminate :
2695 #[ DoDo :
2696
2697 The do loop has three varieties:
2698 #do i = num1,num2 [,num3]
2699 #do i = {string1,string2,....,stringn}
2700 The | as separator is also allowed for backwards compatibility
2701 #do i = expression One by one all terms of the expression
2702 */
2703
DoDo(UBYTE * s)2704 int DoDo(UBYTE *s)
2705 {
2706 GETIDENTITY
2707 UBYTE *t, c, *u, *uu;
2708 DOLOOP *loop;
2709 WORD expnum;
2710 LONG linenum = AC.CurrentStream->linenumber;
2711 int oldNoShowInput = AC.NoShowInput, i, oldpreassignflag;
2712
2713 if ( ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH )
2714 || ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ) {
2715 if ( PreSkip((UBYTE *)"do",(UBYTE *)"enddo",1) ) return(-1);
2716 return(0);
2717 }
2718
2719 /*
2720 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2721 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2722 */
2723 AddToPreTypes(PRETYPEDO);
2724
2725 loop = (DOLOOP *)FromList(&AP.LoopList);
2726 loop->firstdollar = loop->lastdollar = loop->incdollar = -1;
2727 loop->NumPreTypes = AP.NumPreTypes-1;
2728 loop->PreIfLevel = AP.PreIfLevel;
2729 loop->PreSwitchLevel = AP.PreSwitchLevel;
2730 AC.NoShowInput = 1;
2731 if ( PreLoad(&(loop->p),(UBYTE *)"do",(UBYTE *)"enddo",1,"doloop") ) return(-1);
2732 AC.NoShowInput = oldNoShowInput;
2733 loop->NoShowInput = AC.NoShowInput;
2734 /*
2735 Get now the name. We have to take great care when the name is terminated!
2736 */
2737 s = loop->p.buffer + (s - AP.preStart);
2738 SKIPBLANKS(s)
2739 loop->name = s;
2740 if ( chartype[*s] != 0 ) goto illname;
2741 s++;
2742 while ( chartype[*s] <= 1 ) s++;
2743 t = s;
2744 while ( *s == ' ' || *s == '\t' ) s++;
2745 if ( *s != '=' ) goto illdo;
2746 s++;
2747 while ( *s == ' ' || *s == '\t' ) s++;
2748 *t = 0;
2749
2750 if ( *s == '{' ) {
2751 loop->type = LISTEDLOOP;
2752 s++; loop->vars = s;
2753 loop->lastnum = 0;
2754 while ( *s != '}' && *s != 0 ) {
2755 if ( set_in(*s,AC.separators) ) { *s = 0; loop->lastnum++; }
2756 else if ( *s == '\\' ) s++;
2757 s++;
2758 }
2759 if ( *s == 0 ) goto illdo;
2760 *s++ = 0;
2761 loop->lastnum++;
2762 loop->firstnum = 0;
2763 loop->contents = s;
2764 }
2765 else if ( *s == '-' || *s == '+' || chartype[*s] == 1 || *s == '$' ) {
2766 loop->type = NUMERICALLOOP;
2767 t = s;
2768 while ( *s && *s != ',' ) s++;
2769 if ( *s == 0 ) goto illdo;
2770 if ( *t == '$' ) {
2771 c = *s; *s = 0;
2772 if ( GetName(AC.dollarnames,t+1,&loop->firstdollar,NOAUTO) != CDOLLAR ) {
2773 MesPrint("@%s is undefined in first parameter in %#do instruction",t);
2774 return(-1);
2775 }
2776 loop->firstnum = DolToLong(BHEAD loop->firstdollar);
2777 if ( AN.ErrorInDollar ) {
2778 MesPrint("@%s does not evaluate into a valid loop parameter",t);
2779 return(-1);
2780 }
2781 *s++ = c;
2782 }
2783 else {
2784 *s = '}';
2785 if ( PreEval(t,&loop->firstnum) == 0 ) goto illdo;
2786 *s++ = ',';
2787 }
2788 t = s;
2789 while ( *s && *s != ',' && *s != ';' && *s != LINEFEED ) s++;
2790 c = *s;
2791 if ( *t == '$' ) {
2792 *s = 0;
2793 if ( GetName(AC.dollarnames,t+1,&loop->lastdollar,NOAUTO) != CDOLLAR ) {
2794 MesPrint("@%s is undefined in second parameter in %#do instruction",t);
2795 return(-1);
2796 }
2797 loop->lastnum = DolToLong(BHEAD loop->lastdollar);
2798 if ( AN.ErrorInDollar ) {
2799 MesPrint("@%s does not evaluate into a valid loop parameter",t);
2800 return(-1);
2801 }
2802 *s++ = c;
2803 }
2804 else {
2805 *s = '}';
2806 if ( PreEval(t,&loop->lastnum) == 0 ) goto illdo;
2807 *s++ = c;
2808 }
2809 if ( c == ',' ) {
2810 t = s;
2811 while ( *s && *s != ';' && *s != LINEFEED ) s++;
2812 if ( *t == '$' ) {
2813 c = *s; *s = 0;
2814 if ( GetName(AC.dollarnames,t+1,&loop->incdollar,NOAUTO) != CDOLLAR ) {
2815 MesPrint("@%s is undefined in third parameter in %#do instruction",t);
2816 return(-1);
2817 }
2818 loop->incnum = DolToLong(BHEAD loop->incdollar);
2819 if ( AN.ErrorInDollar ) {
2820 MesPrint("@%s does not evaluate into a valid loop parameter",t);
2821 return(-1);
2822 }
2823 *s++ = c;
2824 }
2825 else {
2826 c = *s; *s = '}';
2827 if ( PreEval(t,&loop->incnum) == 0 ) goto illdo;
2828 *s++ = c;
2829 }
2830 }
2831 else loop->incnum = 1;
2832 loop->contents = s;
2833 }
2834 else if ( ( chartype[*s] == 0 ) || ( *s == '[' ) ) {
2835 int oldNumPotModdollars = NumPotModdollars;
2836 #ifdef WITHMPI
2837 WORD oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
2838 AC.RhsExprInModuleFlag = 0;
2839 #endif
2840 t = s;
2841 if ( ( s = SkipAName(s) ) == 0 ) goto illdo;
2842 c = *s; *s = 0;
2843 if ( GetName(AC.exprnames,t,&expnum,NOAUTO) == CEXPRESSION ) {
2844 loop->type = ONEEXPRESSION;
2845 /*
2846 We should remember the expression by name for when it gets
2847 renumbered!!! If it gets deleted there will be a crash or at
2848 least the loop terminates.
2849 */
2850 loop->vars = t;
2851 }
2852 else goto illdo;
2853 if ( c == ',' || c == '\t' || c == ';' ) { s++; }
2854 else if ( c != 0 && c != '\n' ) goto illdo;
2855 while ( *s == ',' || *s == '\t' || *s == ';' ) s++;
2856 if ( *s != 0 && *s != '\n' ) goto illdo;
2857 loop->firstnum = 0;
2858 s++;
2859 loop->contents = s;
2860 loop->incnum = 0;
2861 /*
2862 Next determine size of statement and allocate space
2863 */
2864 while ( *t ) t++;
2865 i = t - loop->vars;
2866 t = loop->name;
2867 while ( *t ) { t++; i++; }
2868 i += 4;
2869 loop->dollarname = Malloc1((LONG)i,"do-loop instruction");
2870 /*
2871 Construct the statement
2872 */
2873 u = loop->dollarname;
2874 *u++ = '$'; t = loop->name; while ( *t ) *u++ = *t++;
2875 *u++ = '_'; uu = u; *u++ = '='; t = loop->vars;
2876 while ( *t ) *u++ = *t++;
2877 *t = 0; *u = 0;
2878 /*
2879 Compile and put in dollar variable.
2880 Note that we remember the dollar by name and that this name ends in _
2881 */
2882 oldpreassignflag = AP.PreAssignFlag;
2883 AP.PreAssignFlag = 2;
2884 CompileStatement(loop->dollarname);
2885 if ( CatchDollar(0) ) {
2886 MesPrint("@Cannot load expression in do loop");
2887 return(-1);
2888 }
2889 AP.PreAssignFlag = oldpreassignflag;
2890 NumPotModdollars = oldNumPotModdollars;
2891 #ifdef WITHMPI
2892 AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
2893 #endif
2894 *uu = 0;
2895 }
2896 else goto illdo; /* Syntax problems */
2897 loop->errorsinloop = 0;
2898 /* loop->startlinenumber = linenum+1; 5-oct-2000 One too much? */
2899 loop->startlinenumber = linenum;
2900 PutPreVar(loop->name,(UBYTE *)"0",0,0);
2901 loop->firstloopcall = 1;
2902 return(DoEnddo(s));
2903 illname:;
2904 MesPrint("@Improper name for do loop variable");
2905 return(-1);
2906 illdo:;
2907 MesPrint("@Improper syntax in do loop instruction");
2908 return(-1);
2909 }
2910
2911 /*
2912 #] DoDo :
2913 #[ DoBreakDo :
2914
2915 #dobreak [num]
2916 jumps out of num #do-loops (if there are that many) (default is 1)
2917 */
2918
DoBreakDo(UBYTE * s)2919 int DoBreakDo(UBYTE *s)
2920 {
2921 DOLOOP *loop;
2922 WORD levels;
2923
2924 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2925 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2926
2927 if ( NumDoLoops <= 0 ) {
2928 MesPrint("@%#dobreak without %#do");
2929 return(1);
2930 }
2931 /*
2932 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEDO ) { MessPreNesting(4); return(-1); }
2933 */
2934 while ( *s && ( *s == ',' || *s == ' ' || *s == '\t' ) ) s++;
2935 if ( *s == 0 ) {
2936 levels = 1;
2937 }
2938 else if ( FG.cTable[*s] == 1 ) {
2939 levels = 0;
2940 while ( *s >= '0' && *s <= '9' ) { levels = 10*levels + *s++ - '0'; }
2941 if ( *s != 0 ) goto improper;
2942 }
2943 else {
2944 improper:
2945 MesPrint("@Improper syntax of %#dobreak instruction");
2946 return(1);
2947 }
2948 if ( levels > NumDoLoops ) {
2949 MesPrint("@Too many loop levels requested in %#breakdo instruction");
2950 Terminate(-1);
2951 }
2952 while ( levels > 0 ) {
2953 while ( AC.CurrentStream->type != PREREADSTREAM
2954 && AC.CurrentStream->type != PREREADSTREAM2
2955 && AC.CurrentStream->type != PREREADSTREAM3 ) {
2956 AC.CurrentStream = CloseStream(AC.CurrentStream);
2957 }
2958 while ( AP.PreTypes[AP.NumPreTypes] != PRETYPEDO
2959 && AP.PreTypes[AP.NumPreTypes] != PRETYPEPROCEDURE ) AP.NumPreTypes--;
2960 if ( AC.CurrentStream->type == PREREADSTREAM3
2961 || AP.PreTypes[AP.NumPreTypes] == PRETYPEPROCEDURE ) {
2962 MesPrint("@Trying to jump out of a procedure with a %#breakdo instruction");
2963 Terminate(-1);
2964 }
2965 loop = &(DoLoops[NumDoLoops-1]);
2966 AP.NumPreTypes = loop->NumPreTypes;
2967 AP.PreIfLevel = loop->PreIfLevel;
2968 AP.PreSwitchLevel = loop->PreSwitchLevel;
2969 /*
2970 AP.NumPreTypes--;
2971 */
2972 NumDoLoops--;
2973 DoUndefine(loop->name);
2974 M_free(loop->p.buffer,"loop->p.buffer");
2975 loop->firstloopcall = 0;
2976
2977 AC.CurrentStream = CloseStream(AC.CurrentStream);
2978 levels--;
2979 }
2980 return(0);
2981 }
2982
2983 /*
2984 #] DoBreakDo :
2985 #[ DoElse :
2986 */
2987
DoElse(UBYTE * s)2988 int DoElse(UBYTE *s)
2989 {
2990 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEIF ) {
2991 if ( AP.PreIfLevel <= 0 ) MesPrint("@%#else without corresponding %#if");
2992 else MessPreNesting(1);
2993 return(-1);
2994 }
2995 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2996 while ( *s == ' ' ) s++;
2997 if ( tolower(*s) == 'i' && tolower(s[1]) == 'f' && s[2]
2998 && FG.cTable[s[2]] > 1 && s[2] != '_' ) {
2999 s += 2;
3000 while ( *s == ' ' ) s++;
3001 return(DoElseif(s));
3002 }
3003 if ( AP.PreIfLevel <= 0 ) {
3004 MesPrint("@%#else without corresponding %#if");
3005 return(-1);
3006 }
3007 switch ( AP.PreIfStack[AP.PreIfLevel] ) {
3008 case EXECUTINGIF:
3009 AP.PreIfStack[AP.PreIfLevel] = LOOKINGFORENDIF;
3010 break;
3011 case LOOKINGFORELSE:
3012 AP.PreIfStack[AP.PreIfLevel] = EXECUTINGIF;
3013 break;
3014 case LOOKINGFORENDIF:
3015 break;
3016 }
3017 return(0);
3018 }
3019
3020 /*
3021 #] DoElse :
3022 #[ DoElseif :
3023 */
3024
DoElseif(UBYTE * s)3025 int DoElseif(UBYTE *s)
3026 {
3027 int condition;
3028 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEIF ) {
3029 if ( AP.PreIfLevel <= 0 ) MesPrint("@%#elseif without corresponding %#if");
3030 else MessPreNesting(2);
3031 return(-1);
3032 }
3033 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3034 if ( AP.PreIfLevel <= 0 ) {
3035 MesPrint("@%#elseif without corresponding %#if");
3036 return(-1);
3037 }
3038 switch ( AP.PreIfStack[AP.PreIfLevel] ) {
3039 case EXECUTINGIF:
3040 AP.PreIfStack[AP.PreIfLevel] = LOOKINGFORENDIF;
3041 break;
3042 case LOOKINGFORELSE:
3043 if ( ( condition = EvalPreIf(s) ) < 0 ) return(-1);
3044 AP.PreIfStack[AP.PreIfLevel] = condition;
3045 break;
3046 case LOOKINGFORENDIF:
3047 break;
3048 }
3049 return(0);
3050 }
3051
3052 /*
3053 #] DoElseif :
3054 #[ DoEnddo :
3055
3056 At the first call there is no stream yet.
3057 After that we have to close the stream and start a new one.
3058 */
3059
DoEnddo(UBYTE * s)3060 int DoEnddo(UBYTE *s)
3061 {
3062 GETIDENTITY
3063 DOLOOP *loop;
3064 UBYTE *t, *tt, *value, numstr[16];
3065 LONG xval;
3066 int xsign, retval;
3067 DUMMYUSE(s);
3068 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3069 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3070 /*
3071 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ||
3072 AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) {
3073 if ( AP.PreTypes[AP.NumPreTypes] == PRETYPEDO ) AP.NumPreTypes--;
3074 else { MessPreNesting(3); return(-1); }
3075 return(0);
3076 }
3077 */
3078 if ( NumDoLoops <= 0 ) {
3079 MesPrint("@%#enddo without %#do");
3080 return(1);
3081 }
3082 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEDO ) { MessPreNesting(4); return(-1); }
3083 loop = &(DoLoops[NumDoLoops-1]);
3084 if ( !loop->firstloopcall ) AC.CurrentStream = CloseStream(AC.CurrentStream);
3085
3086 if ( loop->errorsinloop ) {
3087 MesPrint("++++Errors in Loop");
3088 goto finish;
3089 }
3090 if ( loop->type == LISTEDLOOP ) {
3091 if ( loop->firstnum >= loop->lastnum ) goto finish;
3092 loop->firstnum++;
3093 t = value = loop->vars;
3094 while ( *value ) value++;
3095 value++;
3096 loop->vars = value;
3097 value = tt = t;
3098 while ( *value ) {
3099 if ( *value == '\\' ) value++;
3100 *tt++ = *value++;
3101 }
3102 *tt = 0;
3103 PutPreVar(loop->name,t,0,1); /* We overwrite the definition */
3104 }
3105 else if ( loop->type == NUMERICALLOOP ) {
3106
3107 if ( !loop->firstloopcall ) {
3108 /*
3109 Test whether the variable was changed inside the loop into
3110 a different numerical value. If so, adjust.
3111 */
3112 t = GetPreVar(loop->name,WITHOUTERROR);
3113 if ( t ) {
3114 value = t;
3115 xsign = 1;
3116 while ( *value && ( *value == ' '
3117 || *value == '-' || *value == '+' ) ) {
3118 if ( *value == '-' ) xsign = -xsign;
3119 value++;
3120 }
3121 t = value; xval = 0;
3122 while ( *value >= '0' && *value <= '9' ) xval = 10*xval + *value++ - '0';
3123 while ( *value && *value == ' ' ) value++;
3124 if ( *value == 0 ) {
3125 /*
3126 Now we may substitute the loopvalue.
3127 */
3128 if ( xsign < 0 ) xval = -xval;
3129 if ( loop->incdollar >= 0 ) {
3130 loop->incnum = DolToLong(BHEAD loop->incdollar);
3131 if ( AN.ErrorInDollar ) {
3132 MesPrint("@%s does not evaluate into a valid third loop parameter",DOLLARNAME(Dollars,loop->incdollar));
3133 return(-1);
3134 }
3135 }
3136 loop->firstnum = xval + loop->incnum;
3137 }
3138 }
3139 if ( loop->lastdollar >= 0 ) {
3140 loop->lastnum = DolToLong(BHEAD loop->lastdollar);
3141 if ( AN.ErrorInDollar ) {
3142 MesPrint("@%s does not evaluate into a valid second loop parameter",DOLLARNAME(Dollars,loop->lastdollar));
3143 return(-1);
3144 }
3145 }
3146 }
3147 if ( ( loop->incnum > 0 && loop->firstnum > loop->lastnum )
3148 || ( loop->incnum < 0 && loop->firstnum < loop->lastnum ) ) goto finish;
3149 NumToStr(numstr,loop->firstnum);
3150 t = numstr;
3151 loop->firstnum += loop->incnum;
3152 PutPreVar(loop->name,t,0,1); /* We overwrite the definition */
3153 }
3154 else if ( loop->type == ONEEXPRESSION ) {
3155 /*
3156 Find the dollar expression
3157 */
3158 WORD numdollar = GetDollar(loop->dollarname+1);
3159 DOLLARS d = Dollars + numdollar;
3160 WORD *w, *dw, v, *ww;
3161 if ( (d->where) == 0 ) {
3162 d->type = DOLUNDEFINED;
3163 M_free(loop->dollarname,"do-loop instruction");
3164 goto finish;
3165 }
3166 w = d->where + loop->incnum;
3167 if ( *w == 0 ) {
3168 M_free(d->where,"dollar");
3169 d->where = 0;
3170 d->type = DOLUNDEFINED;
3171 M_free(loop->dollarname,"do-loop instruction");
3172 goto finish;
3173 }
3174 loop->incnum += *w;
3175 /*
3176 Now the term has to be converted to text.
3177 */
3178 ww = w + *w; v = *ww; *ww = 0;
3179 dw = d->where; d->where = w;
3180 t = WriteDollarToBuffer(numdollar,1);
3181 d->where = dw; *ww = v;
3182 PutPreVar(loop->name,t,0,1); /* We overwrite the definition */
3183 M_free(t,"dollar");
3184 }
3185 if ( loop->firstloopcall ) OpenStream(loop->contents,PREREADSTREAM2,0,PRENOACTION);
3186 else OpenStream(loop->contents,PREREADSTREAM,0,PRENOACTION);
3187 AC.CurrentStream->prevline =
3188 AC.CurrentStream->linenumber = loop->startlinenumber;
3189 AC.CurrentStream->eqnum = 0;
3190 loop->firstloopcall = 0;
3191 return(0);
3192 finish:;
3193 NumDoLoops--;
3194 retval = DoUndefine(loop->name);
3195 M_free(loop->p.buffer,"loop->p.buffer");
3196 loop->firstloopcall = 0;
3197 AP.NumPreTypes--;
3198 return(retval);
3199 }
3200
3201 /*
3202 #] DoEnddo :
3203 #[ DoEndif :
3204 */
3205
DoEndif(UBYTE * s)3206 int DoEndif(UBYTE *s)
3207 {
3208 DUMMYUSE(s);
3209 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEIF ) {
3210 if ( AP.PreIfLevel <= 0 ) MesPrint("@%#endif without corresponding %#if");
3211 else MessPreNesting(5);
3212 return(-1);
3213 }
3214 AP.NumPreTypes--;
3215 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3216 if ( AP.PreIfLevel <= 0 ) {
3217 MesPrint("@%#endif without corresponding %#if");
3218 return(-1);
3219 }
3220 AP.PreIfLevel--;
3221 return(0);
3222 }
3223
3224 /*
3225 #] DoEndif :
3226 #[ DoEndprocedure :
3227
3228 Action is simple: close the current stream if it is still
3229 the stream from which the statement came.
3230 Then pop the current procedure and all its local derivatives.
3231 if loadmode > 1 the procedure was defined locally.
3232 */
3233
DoEndprocedure(UBYTE * s)3234 int DoEndprocedure(UBYTE *s)
3235 {
3236 DUMMYUSE(s);
3237 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEPROCEDURE ) {
3238 MessPreNesting(6);
3239 return(-1);
3240 }
3241 AP.NumPreTypes--;
3242 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3243 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3244 AC.CurrentStream = CloseStream(AC.CurrentStream);
3245 do {
3246 NumProcedures--;
3247 if ( Procedures[NumProcedures].loadmode == 0 ) {
3248 M_free(Procedures[NumProcedures].p.buffer,"procedures buffer");
3249 M_free(Procedures[NumProcedures].name,"procedures name");
3250 }
3251 } while ( Procedures[NumProcedures].loadmode > 1 );
3252 return(0);
3253 }
3254
3255 /*
3256 #] DoEndprocedure :
3257 #[ DoIf :
3258 */
3259
DoIf(UBYTE * s)3260 int DoIf(UBYTE *s)
3261 {
3262 int condition;
3263 AddToPreTypes(PRETYPEIF);
3264 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3265 if ( AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF ) {
3266 condition = EvalPreIf(s);
3267 if ( condition < 0 ) return(-1);
3268 }
3269 else condition = LOOKINGFORENDIF;
3270 if ( AP.PreIfLevel+1 >= AP.MaxPreIfLevel ) {
3271 int **ppp = &AP.PreIfStack; /* To avoid a compiler warning */
3272 if ( DoubleList((VOID ***)ppp,&AP.MaxPreIfLevel,sizeof(int),
3273 "PreIfLevels") ) return(-1);
3274 }
3275 AP.PreIfStack[++AP.PreIfLevel] = condition;
3276 return(0);
3277 }
3278
3279 /*
3280 #] DoIf :
3281 #[ DoIfdef :
3282 */
3283
DoIfdef(UBYTE * s,int par)3284 int DoIfdef(UBYTE *s, int par)
3285 {
3286 int condition;
3287 AddToPreTypes(PRETYPEIF);
3288 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3289 if ( AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF ) {
3290 while ( *s == ' ' || *s == '\t' ) s++;
3291 if ( ( *s == 0 ) == ( par == 1 ) ) condition = LOOKINGFORELSE;
3292 else condition = EXECUTINGIF;
3293 }
3294 else condition = LOOKINGFORENDIF;
3295 if ( AP.PreIfLevel+1 >= AP.MaxPreIfLevel ) {
3296 int **ppp = &AP.PreIfStack; /* to avoid a compiler warning */
3297 if ( DoubleList((VOID ***)ppp,&AP.MaxPreIfLevel,sizeof(int),
3298 "PreIfLevels") ) return(-1);
3299 }
3300 AP.PreIfStack[++AP.PreIfLevel] = condition;
3301 return(0);
3302 }
3303
3304 /*
3305 #] DoIfdef :
3306 #[ DoIfydef :
3307 */
3308
DoIfydef(UBYTE * s)3309 int DoIfydef(UBYTE *s)
3310 {
3311 return DoIfdef(s,1);
3312 }
3313
3314 /*
3315 #] DoIfydef :
3316 #[ DoIfndef :
3317 */
3318
DoIfndef(UBYTE * s)3319 int DoIfndef(UBYTE *s)
3320 {
3321 return DoIfdef(s,2);
3322 }
3323
3324 /*
3325 #] DoIfndef :
3326 #[ DoInside :
3327
3328 #inside $var1,...,$varn
3329 statements without .sort
3330 #endinside
3331
3332 executes the statements on the contents of the $ variables as if they
3333 are a module. The results are put back in the dollar variables.
3334 To do this right we need a struct with
3335 old compiler buffer
3336 list of numbers of dollars
3337 length of the list
3338 length of the array containing the list
3339 Because we need to compose statements, the statement buffer must be
3340 empty. This means that we have to test for that. Same at the end. We
3341 must have a completed statement.
3342 */
3343
DoInside(UBYTE * s)3344 int DoInside(UBYTE *s)
3345 {
3346 GETIDENTITY
3347 int numdol, error = 0;
3348 WORD *nb, newsize, i;
3349 UBYTE *name, c;
3350 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3351 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3352 if ( AP.PreInsideLevel != 0 ) {
3353 MesPrint("@Illegal nesting of %#inside/%#endinside instructions");
3354 return(-1);
3355 }
3356 /*
3357 if ( AP.PreContinuation ) {
3358 error = -1;
3359 MesPrint("@%#inside cannot be inside a regular statement");
3360 }
3361 */
3362 PUSHPREASSIGNLEVEL
3363 /*
3364 Now the dollars to do
3365 */
3366 AP.inside.numdollars = 0;
3367 for(;;) {
3368 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
3369 if ( *s == 0 ) break;
3370 if ( *s != '$' ) {
3371 MesPrint("@%#inside instruction can have only $ variables for parameters");
3372 return(-1);
3373 }
3374 s++;
3375 name = s;
3376 while (chartype[*s] <= 1 ) s++;
3377 c = *s; *s = 0;
3378 if ( ( numdol = GetDollar(name) ) < 0 ) {
3379 MesPrint("@%#inside: $%s has not (yet) been defined",name);
3380 *s = c;
3381 error = -1;
3382 }
3383 else {
3384 *s = c;
3385 if ( AP.inside.numdollars >= AP.inside.size ) {
3386 if ( AP.inside.buffer == 0 ) newsize = 20;
3387 else newsize = 2*AP.inside.size;
3388 nb = (WORD *)Malloc1(newsize*sizeof(WORD),"insidebuffer");
3389 if ( AP.inside.buffer ) {
3390 for ( i = 0; i < AP.inside.size; i++ ) nb[i] = AP.inside.buffer[i];
3391 M_free(AP.inside.buffer,"insidebuffer");
3392 }
3393 AP.inside.buffer = nb;
3394 AP.inside.size = newsize;
3395 }
3396 AP.inside.buffer[AP.inside.numdollars++] = numdol;
3397 }
3398 }
3399 /*
3400 We have to store the configuration of the compiler buffer, so that
3401 we know where to start executing and how to reset the buffer.
3402 */
3403 AP.inside.oldcompiletype = AC.compiletype;
3404 AP.inside.oldparallelflag = AC.mparallelflag;
3405 AP.inside.oldnumpotmoddollars = NumPotModdollars;
3406 AP.inside.oldcbuf = AC.cbufnum;
3407 AP.inside.oldrbuf = AM.rbufnum;
3408 AP.inside.oldcnumlhs = AR.Cnumlhs,
3409 AddToPreTypes(PRETYPEINSIDE);
3410 AP.PreInsideLevel = 1;
3411 AC.cbufnum = AP.inside.inscbuf;
3412 AM.rbufnum = AP.inside.inscbuf;
3413 clearcbuf(AC.cbufnum);
3414 AC.compiletype = 0;
3415 AC.mparallelflag = PARALLELFLAG;
3416 #ifdef WITHMPI
3417 /*
3418 * We use AC.RhsExprInModuleFlag, PotModdollars, and AC.pfirstnum
3419 * in order to check (1) whether there are expression names in RHS,
3420 * (2) which dollar variables can be modified, and (3) which
3421 * preprocessor variables can be redefined, in #inside.
3422 * We store the current values of them, and then reset them.
3423 */
3424 PF_StoreInsideInfo();
3425 AC.RhsExprInModuleFlag = 0;
3426 NumPotModdollars = 0;
3427 AC.numpfirstnum = 0;
3428 #endif
3429 return(error);
3430 }
3431
3432 /*
3433 #] DoInside :
3434 #[ DoEndInside :
3435 */
3436
DoEndInside(UBYTE * s)3437 int DoEndInside(UBYTE *s)
3438 {
3439 GETIDENTITY
3440 WORD numdol, *oldworkpointer = AT.WorkPointer, *term, *t, j, i;
3441 DOLLARS d, nd;
3442 WORD oldbracketon = AR.BracketOn;
3443 WORD *oldcompresspointer = AR.CompressPointer;
3444 int oldmultithreaded = AS.MultiThreaded;
3445 /* int oldmparallelflag = AC.mparallelflag; */
3446 FILEHANDLE *f;
3447 #ifdef WITHMPI
3448 int error = 0;
3449 #endif
3450 DUMMYUSE(s);
3451 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3452 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3453 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEINSIDE ) {
3454 if ( AP.PreInsideLevel != 1 ) MesPrint("@%#endinside without corresponding %#inside");
3455 else MessPreNesting(11);
3456 return(-1);
3457 }
3458 AP.NumPreTypes--;
3459 if ( AP.PreInsideLevel != 1 ) {
3460 MesPrint("@%#endinside without corresponding %#inside");
3461 return(-1);
3462 }
3463 if ( AP.PreContinuation ) {
3464 MesPrint("@%#endinside: previous statement not terminated.");
3465 Terminate(-1);
3466 }
3467 AC.compiletype = AP.inside.oldcompiletype;
3468 AR.Cnumlhs = cbuf[AM.rbufnum].numlhs;
3469 #ifdef WITHMPI
3470 /*
3471 * If the #inside...#endinside contains expressions in RHS, only the master executes it
3472 * and then broadcasts the result to the all slaves. If not, the all processes execute
3473 * it and in this case no MPI interactions are needed.
3474 */
3475 if ( PF.me == MASTER || !AC.RhsExprInModuleFlag ) {
3476 #endif
3477 AR.BracketOn = 0;
3478 AS.MultiThreaded = 0;
3479 /* AC.mparallelflag = PARALLELFLAG; */
3480 if ( AR.CompressPointer == 0 ) AR.CompressPointer = AR.CompressBuffer;
3481 f = AR.infile; AR.infile = AR.outfile; AR.outfile = f;
3482 /*
3483 Now we have to execute the statements on the proper dollars.
3484 */
3485 for ( i = 0; i < AP.inside.numdollars; i++ ) {
3486 numdol = AP.inside.buffer[i];
3487 nd = d = Dollars + numdol;
3488 if ( d->type != DOLZERO ) {
3489 if ( d->type != DOLTERMS ) nd = DolToTerms(BHEAD numdol);
3490 term = nd->where;
3491 NewSort(BHEAD0);
3492 NewSort(BHEAD0);
3493 AR.MaxDum = AM.IndDum;
3494 while ( *term ) {
3495 t = oldworkpointer; j = *term;
3496 NCOPY(t,term,j);
3497 AT.WorkPointer = t;
3498 AN.IndDum = AM.IndDum;
3499 AR.CurDum = ReNumber(BHEAD term);
3500 if ( Generator(BHEAD oldworkpointer,0) ) {
3501 MesPrint("@Called from %#endinside");
3502 MesPrint("@Evaluating variable $%s",DOLLARNAME(Dollars,numdol));
3503 Terminate(-1);
3504 }
3505 }
3506 AT.WorkPointer = oldworkpointer;
3507 CleanDollarFactors(d);
3508 if ( d->where ) { M_free(d->where,"dollar contents"); d->where = 0; }
3509 EndSort(BHEAD (WORD *)((VOID *)(&(d->where))),2);
3510 LowerSortLevel();
3511 term = d->where; while ( *term ) term += *term;
3512 d->size = term - d->where;
3513 if ( nd != d ) M_free(nd,"Copy of dollar variable");
3514 if ( d->where[0] == 0 ) {
3515 M_free(d->where,"dollar contents"); d->where = 0;
3516 d->type = DOLZERO;
3517 }
3518 }
3519 }
3520 #ifdef WITHMPI
3521 }
3522 if ( AC.RhsExprInModuleFlag ) {
3523 /*
3524 * The only master executed the statements in #inside.
3525 * We need to broadcast the result to the all slaves.
3526 */
3527 for ( i = 0; i < AP.inside.numdollars; i++ ) {
3528 /*
3529 * Mark $-variables specified in the #inside instruction as modified
3530 * such that they will be broadcast.
3531 */
3532 AddPotModdollar(AP.inside.buffer[i]);
3533 }
3534 /* Now actual broadcast of modified variables. */
3535 if ( NumPotModdollars > 0 ) {
3536 error = PF_BroadcastModifiedDollars();
3537 if ( error ) goto cleanup;
3538 }
3539 if ( AC.numpfirstnum > 0 ) {
3540 error = PF_BroadcastRedefinedPreVars();
3541 if ( error ) goto cleanup;
3542 }
3543 }
3544 cleanup:
3545 #endif
3546 f = AR.infile; AR.infile = AR.outfile; AR.outfile = f;
3547 AC.cbufnum = AP.inside.oldcbuf;
3548 AM.rbufnum = AP.inside.oldrbuf;
3549 AR.Cnumlhs = AP.inside.oldcnumlhs;
3550 AR.BracketOn = oldbracketon;
3551 AP.PreInsideLevel = 0;
3552 AR.CompressPointer = oldcompresspointer;
3553 AS.MultiThreaded = oldmultithreaded;
3554 AC.mparallelflag = AP.inside.oldparallelflag;
3555 NumPotModdollars = AP.inside.oldnumpotmoddollars;
3556 POPPREASSIGNLEVEL
3557 #ifdef WITHMPI
3558 PF_RestoreInsideInfo();
3559 if ( error ) return error;
3560 #endif
3561 return(0);
3562 }
3563
3564 /*
3565 #] DoEndInside :
3566 #[ DoMessage :
3567 */
3568
DoMessage(UBYTE * s)3569 int DoMessage(UBYTE *s)
3570 {
3571 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3572 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3573 while ( *s == ' ' || *s == '\t' ) s++;
3574 MesPrint("~~~%s",s);
3575 return(0);
3576 }
3577
3578 /*
3579 #] DoMessage :
3580 #[ DoPipe :
3581 */
3582
DoPipe(UBYTE * s)3583 int DoPipe(UBYTE *s)
3584 {
3585 #ifndef WITHPIPE
3586 DUMMYUSE(s);
3587 #endif
3588 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3589 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3590 #ifdef WITHPIPE
3591 FLUSHCONSOLE;
3592 while ( *s == ' ' || *s == '\t' ) s++;
3593 if ( OpenStream(s,PIPESTREAM,0,PRENOACTION) == 0 ) return(-1);
3594 return(0);
3595 #else
3596 Error0("Pipes not implemented on this computer/system");
3597 return(-1);
3598 #endif
3599 }
3600
3601 /*
3602 #] DoPipe :
3603 #[ DoPrcExtension :
3604 */
3605
DoPrcExtension(UBYTE * s)3606 int DoPrcExtension(UBYTE *s)
3607 {
3608 UBYTE *t, *u, c;
3609 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3610 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3611 while ( *s == ' ' || *s == '\t' ) s++;
3612 if ( *s == 0 || *s == '\n' ) {
3613 MesPrint("@No valid procedure extension specified");
3614 return(-1);
3615 }
3616 if ( FG.cTable[*s] != 0 ) {
3617 MesPrint("@Procedure extension should be a string starting with an alphabetic character. No whitespace.");
3618 return(-1);
3619 }
3620 t = s;
3621 while ( *s && *s != '\n' && *s != ' ' && *s != '\t' ) s++;
3622 u = s;
3623 while ( *s == ' ' || *s == '\t' ) s++;
3624 if ( *s != 0 && *s != '\n' ) {
3625 MesPrint("@Too many parameters in ProcedureExtension instruction");
3626 return(-1);
3627 }
3628 c = *u; *u = 0;
3629 if ( AP.procedureExtension ) M_free(AP.procedureExtension,"ProcedureExtension");
3630 AP.procedureExtension = strDup1(t,"ProcedureExtension");
3631 *u = c;
3632 return(0);
3633 }
3634
3635 /*
3636 #] DoPrcExtension :
3637 #[ DoPreOut :
3638 */
3639
DoPreOut(UBYTE * s)3640 int DoPreOut(UBYTE *s)
3641 {
3642 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3643 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3644 if ( tolower(*s) == 'o' ) {
3645 if ( tolower(s[1]) == 'n' && s[2] == 0 ) {
3646 AP.PreOut = 1;
3647 return(0);
3648 }
3649 if ( tolower(s[1]) == 'f' && tolower(s[2]) == 'f' && s[3] == 0 ) {
3650 AP.PreOut = 0;
3651 return(0);
3652 }
3653 }
3654 MesPrint("@Illegal option in PreOut instruction");
3655 return(-1);
3656 }
3657
3658 /*
3659 #] DoPreOut :
3660 #[ DoPrePrintTimes :
3661 */
3662
DoPrePrintTimes(UBYTE * s)3663 int DoPrePrintTimes(UBYTE *s)
3664 {
3665 DUMMYUSE(s);
3666 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3667 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3668 PrintRunningTime();
3669 return(0);
3670 }
3671
3672 /*
3673 #] DoPrePrintTimes :
3674 #[ DoPreAppend :
3675
3676 Syntax:
3677 #append <filename>
3678 */
3679
DoPreAppend(UBYTE * s)3680 int DoPreAppend(UBYTE *s)
3681 {
3682 UBYTE *name, *to;
3683
3684 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3685 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3686 if ( AP.preError ) return(0);
3687 while ( *s == ' ' || *s == '\t' ) s++;
3688 /*
3689 Determine where to write
3690 */
3691 if ( *s == '<' ) {
3692 s++;
3693 name = to = s;
3694 while ( *s && *s != '>' ) {
3695 if ( *s == '\\' ) s++;
3696 *to++ = *s++;
3697 }
3698 if ( *s == 0 ) {
3699 MesPrint("@Improper termination of filename");
3700 return(-1);
3701 }
3702 s++;
3703 *to = 0;
3704 if ( *name ) { GetAppendChannel((char *)name); }
3705 else goto improper;
3706 }
3707 else {
3708 improper:
3709 MesPrint("@Proper syntax is: %#append <filename>");
3710 return(-1);
3711 }
3712 return(0);
3713 }
3714
3715 /*
3716 #] DoPreAppend :
3717 #[ DoPreCreate :
3718
3719 Syntax:
3720 #create <filename>
3721 */
3722
DoPreCreate(UBYTE * s)3723 int DoPreCreate(UBYTE *s)
3724 {
3725 UBYTE *name, *to;
3726
3727 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3728 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3729 if ( AP.preError ) return(0);
3730 while ( *s == ' ' || *s == '\t' ) s++;
3731 /*
3732 Determine where to write
3733 */
3734 if ( *s == '<' ) {
3735 s++;
3736 name = to = s;
3737 while ( *s && *s != '>' ) {
3738 if ( *s == '\\' ) s++;
3739 *to++ = *s++;
3740 }
3741 if ( *s == 0 ) {
3742 MesPrint("@Improper termination of filename");
3743 return(-1);
3744 }
3745 s++;
3746 *to = 0;
3747 if ( *name ) { GetChannel((char *)name,0); }
3748 else goto improper;
3749 }
3750 else {
3751 improper:
3752 MesPrint("@Proper syntax is: %#create <filename>");
3753 return(-1);
3754 }
3755 return(0);
3756 }
3757
3758 /*
3759 #] DoPreCreate :
3760 #[ DoPreRemove :
3761 */
3762
DoPreRemove(UBYTE * s)3763 int DoPreRemove(UBYTE *s)
3764 {
3765 UBYTE *name, *to;
3766 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3767 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3768 if ( AP.preError ) return(0);
3769 while ( *s == ' ' || *s == '\t' ) s++;
3770 if ( *s == '<' ) { s++; }
3771 else {
3772 MesPrint("@Proper syntax is: %#remove <filename>");
3773 return(-1);
3774 }
3775 name = to = s;
3776 while ( *s && *s != '>' ) {
3777 if ( *s == '\\' ) s++;
3778 *to++ = *s++;
3779 }
3780 if ( *s == 0 ) {
3781 MesPrint("@Improper filename");
3782 return(-1);
3783 }
3784 s++;
3785 *to = 0;
3786 CloseChannel((char *)name);
3787 remove((char *)name);
3788 return(0);
3789 }
3790
3791 /*
3792 #] DoPreRemove :
3793 #[ DoPreClose :
3794 */
3795
DoPreClose(UBYTE * s)3796 int DoPreClose(UBYTE *s)
3797 {
3798 UBYTE *name, *to;
3799 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3800 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3801 if ( AP.preError ) return(0);
3802 while ( *s == ' ' || *s == '\t' ) s++;
3803 if ( *s == '<' ) { s++; }
3804 else {
3805 MesPrint("@Proper syntax is: %#close <filename>");
3806 return(-1);
3807 }
3808 name = to = s;
3809 while ( *s && *s != '>' ) {
3810 if ( *s == '\\' ) s++;
3811 *to++ = *s++;
3812 }
3813 if ( *s == 0 ) {
3814 MesPrint("@Improper filename");
3815 return(-1);
3816 }
3817 s++;
3818 *to = 0;
3819 return(CloseChannel((char *)name));
3820 }
3821
3822 /*
3823 #] DoPreClose :
3824 #[ DoPreWrite :
3825
3826 Syntax:
3827 #write [<filename>] "formatstring" [,objects]
3828 The format string can contain the following special objects/codes
3829 \n newline
3830 \t tab
3831 \! if last entry in string: no linefeed at end
3832 \b put \ in output
3833 %$ $-variable (to be found among the objects)
3834 %e expression (name to be found among the objects)
3835 %E expression without ; (name to be found among the objects)
3836 %s string (to be found among the objects) (with or without "")
3837 %S subterms (see PrintSubtermList)
3838 */
3839
DoPreWrite(UBYTE * s)3840 int DoPreWrite(UBYTE *s)
3841 {
3842 HANDLERS h;
3843
3844 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3845 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3846 if ( AP.preError ) return(0);
3847
3848 #ifdef WITHMPI
3849 if ( PF.me != MASTER ) return 0;
3850 #endif
3851
3852 h.oldsilent = AM.silent;
3853 h.newlogonly = h.oldlogonly = AM.FileOnlyFlag;
3854 h.newhandle = h.oldhandle = AC.LogHandle;
3855 h.oldprinttype = AO.PrintType;
3856
3857 while ( *s == ' ' || *s == '\t' ) s++;
3858 /*
3859 Determine where to write
3860 */
3861 if( (s=defineChannel(s,&h))==0 ) return(-1);
3862
3863 return(writeToChannel(WRITEOUT,s,&h));
3864 }
3865
3866 /*
3867 #] DoPreWrite :
3868 #[ DoProcedure :
3869
3870 We have to read this procedure into a buffer.
3871 The only complications are:
3872 1: we have to seek through the file to do this efficiently
3873 the file operations under VMS cannot do this properly
3874 (unless we use the proper ANSI structs?)
3875 This is the reason why we read whole input files under VMS.
3876 2: what to do when the same name is used twice.
3877 Note that we have to do the reading without substitution of
3878 preprocessor variables.
3879 */
3880
DoProcedure(UBYTE * s)3881 int DoProcedure(UBYTE *s)
3882 {
3883 UBYTE c;
3884 PROCEDURE *p;
3885 LONG i;
3886 if ( ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH )
3887 || ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ) {
3888 if ( PreSkip((UBYTE *)"procedure",(UBYTE *)"endprocedure",1) ) return(-1);
3889 return(0);
3890 }
3891 p = (PROCEDURE *)FromList(&AP.ProcList);
3892 if ( PreLoad(&(p->p),(UBYTE *)"procedure",(UBYTE *)"endprocedure"
3893 ,1,(char *)"procedure") ) return(-1);
3894
3895 p->loadmode = 2;
3896 s = p->p.buffer + 10;
3897 while ( *s == ' ' || *s == LINEFEED ) s++;
3898 if ( chartype[*s] ) {
3899 MesPrint("@Illegal name for procedure");
3900 return(-1);
3901 }
3902 p->name = s++;
3903 while ( chartype[*s] == 0 || chartype[*s] == 1 ) s++;
3904 c = *s; *s = 0;
3905 p->name = strDup1(p->name,"procedure");
3906 *s = c;
3907 /*
3908 Check for double names
3909 */
3910 for ( i = NumProcedures-2; i >= 0; i-- ) {
3911 if ( StrCmp(Procedures[i].name,p->name) == 0 ) {
3912 Error1("Multiple occurrence of procedure name ",p->name);
3913 }
3914 }
3915 return(0);
3916 }
3917
3918 /*
3919 #] DoProcedure :
3920 #[ DoPreBreak :
3921 */
3922
DoPreBreak(UBYTE * s)3923 int DoPreBreak(UBYTE *s)
3924 {
3925 DUMMYUSE(s);
3926 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3927 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
3928 if ( AP.PreSwitchLevel <= 0 )
3929 MesPrint("@Break without corresponding Switch");
3930 else MessPreNesting(7);
3931 return(-1);
3932 }
3933 if ( AP.PreSwitchLevel <= 0 ) {
3934 MesPrint("@Break without corresponding Switch");
3935 return(-1);
3936 }
3937 if ( AP.PreSwitchModes[AP.PreSwitchLevel] == EXECUTINGPRESWITCH )
3938 AP.PreSwitchModes[AP.PreSwitchLevel] = SEARCHINGPREENDSWITCH;
3939 return(0);
3940 }
3941
3942 /*
3943 #] DoPreBreak :
3944 #[ DoPreCase :
3945 */
3946
DoPreCase(UBYTE * s)3947 int DoPreCase(UBYTE *s)
3948 {
3949 UBYTE *t;
3950 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3951 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
3952 if ( AP.PreSwitchLevel <= 0 )
3953 MesPrint("@Case without corresponding Switch");
3954 else MessPreNesting(8);
3955 return(-1);
3956 }
3957 if ( AP.PreSwitchLevel <= 0 ) {
3958 MesPrint("@Case without corresponding Switch");
3959 return(-1);
3960 }
3961 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != SEARCHINGPRECASE ) return(0);
3962
3963 SKIPBLANKS(s)
3964 t = s;
3965 while ( *s ) { if ( *s == '\\' ) s++; s++; }
3966 while ( s > t && ( s[-1] == ' ' || s[-1] == '\t' ) && s[-2] != '\\' ) {
3967 if ( s[-2] == '\\' ) s--;
3968 s--;
3969 }
3970 if ( *t == '"' && s > t+1 && s[-1] == '"' && s[-2] != '\\' ) {
3971 t++; s--; *s = 0;
3972 }
3973 else *s = 0;
3974 s = AP.PreSwitchStrings[AP.PreSwitchLevel];
3975 while ( *t == *s && *t ) { s++; t++; }
3976 if ( *t || *s ) return(0); /* case did not match */
3977 AP.PreSwitchModes[AP.PreSwitchLevel] = EXECUTINGPRESWITCH;
3978 return(0);
3979 }
3980
3981 /*
3982 #] DoPreCase :
3983 #[ DoPreDefault :
3984 */
3985
DoPreDefault(UBYTE * s)3986 int DoPreDefault(UBYTE *s)
3987 {
3988 DUMMYUSE(s);
3989 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3990 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
3991 if ( AP.PreSwitchLevel <= 0 )
3992 MesPrint("@Default without corresponding Switch");
3993 else MessPreNesting(9);
3994 return(-1);
3995 }
3996 if ( AP.PreSwitchLevel <= 0 ) {
3997 MesPrint("@Default without corresponding Switch");
3998 return(-1);
3999 }
4000 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != SEARCHINGPRECASE ) return(0);
4001 AP.PreSwitchModes[AP.PreSwitchLevel] = EXECUTINGPRESWITCH;
4002 return(0);
4003 }
4004
4005 /*
4006 #] DoPreDefault :
4007 #[ DoPreEndSwitch :
4008 */
4009
DoPreEndSwitch(UBYTE * s)4010 int DoPreEndSwitch(UBYTE *s)
4011 {
4012 DUMMYUSE(s);
4013 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
4014 if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
4015 if ( AP.PreSwitchLevel <= 0 )
4016 MesPrint("@EndSwitch without corresponding Switch");
4017 else MessPreNesting(10);
4018 return(-1);
4019 }
4020 AP.NumPreTypes--;
4021 if ( AP.PreSwitchLevel <= 0 ) {
4022 MesPrint("@EndSwitch without corresponding Switch");
4023 return(-1);
4024 }
4025 M_free(AP.PreSwitchStrings[AP.PreSwitchLevel--],"pre switch string");
4026 return(0);
4027 }
4028
4029 /*
4030 #] DoPreEndSwitch :
4031 #[ DoPreSwitch :
4032
4033 There should be a string after this.
4034 We have to store it somewhere.
4035 */
4036
DoPreSwitch(UBYTE * s)4037 int DoPreSwitch(UBYTE *s)
4038 {
4039 UBYTE *t, *switchstring, **newstrings;
4040 int newnum, i, *newmodes;
4041 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
4042 SKIPBLANKS(s)
4043 t = s;
4044 while ( *s ) { if ( *s == '\\' ) s++; s++; }
4045 while ( s > t && ( s[-1] == ' ' || s[-1] == '\t' ) && s[-2] != '\\' ) {
4046 if ( s[-2] == '\\' ) s--;
4047 s--;
4048 }
4049 if ( *t == '"' && s > t+1 && s[-1] == '"' && s[-2] != '\\' ) {
4050 t++; s--; *s = 0;
4051 }
4052 else *s = 0;
4053 switchstring = (UBYTE *)Malloc1((s-t)+1,"case string");
4054 s = switchstring;
4055 while ( *t ) {
4056 if ( *t == '\\' ) t++;
4057 *s++ = *t++;
4058 }
4059 *s = 0;
4060 if ( AP.PreSwitchLevel >= AP.NumPreSwitchStrings ) {
4061 newnum = 2*AP.NumPreSwitchStrings;
4062 newstrings = (UBYTE **)Malloc1(sizeof(UBYTE *)*(newnum+1),"case strings");
4063 newmodes = (int *)Malloc1(sizeof(int)*(newnum+1),"case strings");
4064 for ( i = 0; i < AP.NumPreSwitchStrings; i++ )
4065 newstrings[i] = AP.PreSwitchStrings[i];
4066 M_free(AP.PreSwitchStrings,"AP.PreSwitchStrings");
4067 for ( i = 0; i <= AP.NumPreSwitchStrings; i++ )
4068 newmodes[i] = AP.PreSwitchModes[i];
4069 M_free(AP.PreSwitchModes,"AP.PreSwitchModes");
4070 AP.PreSwitchStrings = newstrings;
4071 AP.PreSwitchModes = newmodes;
4072 AP.NumPreSwitchStrings = newnum;
4073 }
4074 AP.PreSwitchStrings[++AP.PreSwitchLevel] = switchstring;
4075 if ( ( AP.PreSwitchLevel > 1 )
4076 && ( AP.PreSwitchModes[AP.PreSwitchLevel-1] != EXECUTINGPRESWITCH ) )
4077 AP.PreSwitchModes[AP.PreSwitchLevel] = SEARCHINGPREENDSWITCH;
4078 else
4079 AP.PreSwitchModes[AP.PreSwitchLevel] = SEARCHINGPRECASE;
4080 AddToPreTypes(PRETYPESWITCH);
4081 return(0);
4082 }
4083
4084 /*
4085 #] DoPreSwitch :
4086 #[ DoPreShow :
4087
4088 Print the contents of the preprocessor variables
4089 */
4090
DoPreShow(UBYTE * s)4091 int DoPreShow(UBYTE *s)
4092 {
4093 int i;
4094 UBYTE *name, c;
4095 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
4096 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
4097 while ( *s == ' ' || *s == '\t' ) s++;
4098 if ( *s == 0 ) {
4099 MesPrint("%#The preprocessor variables:");
4100 for ( i = 0; i < NumPre; i++ ) {
4101 MesPrint("%d: %s = \"%s\"",i,PreVar[i].name,PreVar[i].value);
4102 }
4103 }
4104 else {
4105 while ( *s ) {
4106 name = s; while ( *s && *s != ' ' && *s != '\t' && *s != ',' ) s++;
4107 c = *s; *s = 0;
4108 for ( i = 0; i < NumPre; i++ ) {
4109 if ( StrCmp(PreVar[i].name,name) == 0 )
4110 MesPrint("%d: %s = \"%s\"",i,PreVar[i].name,PreVar[i].value);
4111 }
4112 *s = c;
4113 while ( *s == ' ' || *s == '\t' ) s++;
4114 }
4115 }
4116 return(0);
4117 }
4118
4119 /*
4120 #] DoPreShow :
4121 #[ DoSystem :
4122 */
4123
4124 /*
4125 * A macro for translating the contents of `x' into a string after expanding.
4126 */
4127 #define STRINGIFY(x) STRINGIFY__(x)
4128 #define STRINGIFY__(x) #x
4129
DoSystem(UBYTE * s)4130 int DoSystem(UBYTE *s)
4131 {
4132 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
4133 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
4134 if ( AP.preError ) return(0);
4135 #ifdef WITHSYSTEM
4136 FLUSHCONSOLE;
4137 while ( *s == ' ' || *s == '\t' ) s++;
4138 if ( *s == '-' && s[1] == 'e' ) {
4139 LONG err;
4140 UBYTE str[24];
4141 s += 2;
4142 if ( *s != ' ' ) {
4143 MesPrint("@Syntax error in #system command.");
4144 return(-1);
4145 }
4146 while ( *s == ' ' || *s == '\t' ) s++;
4147 err = system((char *)s);
4148 NumToStr(str,err);
4149 PutPreVar((UBYTE *)"SYSTEMERROR_",str,0,1);
4150 }
4151 else if ( system((char *)s) ) {
4152 MesPrint("@System call returned with error condition");
4153 Terminate(-1);
4154 }
4155 return(0);
4156 #else
4157 Error0("External programs not implemented on this computer/system");
4158 return(-1);
4159 #endif
4160 }
4161
4162 /*
4163 #] DoSystem :
4164 #[ PreLoad :
4165
4166 Loads a loop or procedure into a special buffer.
4167 Note: The current instruction is already in the preStart buffer
4168 */
4169
PreLoad(PRELOAD * p,UBYTE * start,UBYTE * stop,int mode,char * message)4170 int PreLoad(PRELOAD *p, UBYTE *start, UBYTE *stop, int mode, char *message)
4171 {
4172 UBYTE *s, *t, *top, *newbuffer, c;
4173 LONG i, ppsize, linenum = AC.CurrentStream->linenumber;
4174 int size1, size2, level, com=0, last=1, strng = 0;
4175 p->size = AP.pSize;
4176 p->buffer = (UBYTE *)Malloc1(p->size+1,message);
4177 top = p->buffer + p->size - 2;
4178 t = p->buffer; *t++ = '#';
4179 s = start; size1 = size2 = 0;
4180 while ( *s ) { s++; size1++; }
4181 s = stop; while ( *s ) { s++; size2++; }
4182 s = AP.preStart; while ( *s ) *t++ = *s++; *t++ = LINEFEED;
4183 level = 1;
4184 i = 100;
4185 for (;;) {
4186 c = GetInput();
4187 if ( c == ENDOFINPUT ) {
4188 MesPrint("@Missing %#%s, Should match line %l",stop,linenum);
4189 return(-1);
4190 }
4191 if ( c == AP.ComChar && last == 1 ) com = 1;
4192 if ( c == LINEFEED ) { last = 1; com = 0; }
4193 else last = 0;
4194
4195 if ( ( c == '"' ) && ( com == 0 ) ) { strng ^= 1; }
4196
4197 if ( ( c == '#' ) && ( com == 0 ) ) i = 0;
4198 else i++;
4199
4200 if ( t >= top ) {
4201 ppsize = t - p->buffer;
4202 p->size *= 2;
4203 newbuffer = (UBYTE *)Malloc1(p->size,message);
4204 t = newbuffer; s = p->buffer;
4205 while ( --ppsize >= 0 ) *t++ = *s++;
4206 M_free(p->buffer,"loading do loop");
4207 p->buffer = newbuffer;
4208 top = p->buffer + p->size - 2;
4209 }
4210 *t++ = c;
4211 if ( strng == 0 ) {
4212 if ( ( i == size2 ) && ( com == 0 ) ) {
4213 *t = 0;
4214 if ( StrICmp(t-size2,(UBYTE *)(stop)) == 0 ) {
4215 while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
4216 level--;
4217 if ( level <= 0 ) break;
4218 if ( c == ENDOFINPUT ) Error1("Missing #",stop);
4219 *t++ = LINEFEED; *t = 0; last = 1;
4220 }
4221 }
4222 if ( ( i == size1 ) && mode && ( com == 0 ) ) {
4223 *t = 0;
4224 if ( StrICmp(t-size1,(UBYTE *)(start)) == 0 ) {
4225 /*
4226 while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
4227 if ( c == ENDOFINPUT ) Error1("Missing #",stop);
4228 */
4229 level++;
4230 }
4231 }
4232 if ( i == 1 && t[-2] == LINEFEED ) {
4233 if ( c == '-' ) AC.NoShowInput = 1;
4234 else if ( c == '+' ) AC.NoShowInput = 0;
4235 }
4236 }
4237 }
4238 *t++ = LINEFEED;
4239 *t = 0;
4240 return(0);
4241 }
4242
4243 /*
4244 #] PreLoad :
4245 #[ PreSkip :
4246
4247 Skips a loop or procedure.
4248 Note: The current instruction is already in the preStart buffer
4249 */
4250
4251 #define SKIPBUFSIZE 20
4252
PreSkip(UBYTE * start,UBYTE * stop,int mode)4253 int PreSkip(UBYTE *start, UBYTE *stop, int mode)
4254 {
4255 UBYTE *s, *t, buffer[SKIPBUFSIZE+2], c;
4256 LONG i, linenum = AC.CurrentStream->linenumber;
4257 int size1, size2, level, com=0, last=1;
4258
4259 t = buffer; *t++ = '#';
4260 s = start; size1 = size2 = 0;
4261 while ( *s ) { s++; size1++; }
4262 s = stop; while ( *s ) { s++; size2++; }
4263 level = 1;
4264 i = 0;
4265 for (;;) {
4266 c = GetInput();
4267 if ( c == ENDOFINPUT ) {
4268 MesPrint("@Missing %#%s, Should match line %l",stop,linenum);
4269 return(-1);
4270 }
4271 if ( c == AP.ComChar && last == 1 ) com = 1;
4272 if ( c == LINEFEED ) { last = 1; com = 0; i = 0; t = buffer; }
4273 else last = 0;
4274 if ( ( c == '#' ) && ( com == 0 ) ) { i = 0; t = buffer; }
4275 else i++;
4276
4277 if ( i < SKIPBUFSIZE ) *t++ = c;
4278 if ( ( i == size2 ) && ( com == 0 ) ) {
4279 *t = 0;
4280 if ( StrICmp(t-size2,(UBYTE *)(stop)) == 0 ) {
4281 while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
4282 level--;
4283 if ( level <= 0 ) {
4284 pushbackchar = LINEFEED;
4285 break;
4286 }
4287 if ( c == ENDOFINPUT ) Error1("Missing #",stop);
4288 i = 0; t = buffer;
4289 }
4290 }
4291 if ( ( i == size1 ) && mode && ( com == 0 ) ) {
4292 *t = 0;
4293 if ( StrICmp(t-size1,(UBYTE *)(start)) == 0 ) {
4294 while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
4295 level++;
4296 i = 0; t = buffer;
4297 }
4298 }
4299 }
4300 return(0);
4301 }
4302
4303 /*
4304 #] PreSkip :
4305 #[ StartPrepro :
4306 */
4307
StartPrepro()4308 VOID StartPrepro()
4309 {
4310 int **ppp;
4311 AP.MaxPreIfLevel = 2;
4312 ppp = &AP.PreIfStack;
4313 if ( DoubleList((VOID ***)ppp,&AP.MaxPreIfLevel,sizeof(int),
4314 "PreIfLevels") ) Terminate(-1);
4315 AP.PreIfLevel = 0; AP.PreIfStack[0] = EXECUTINGIF;
4316
4317 AP.NumPreSwitchStrings = 10;
4318 AP.PreSwitchStrings = (UBYTE **)Malloc1(sizeof(UBYTE *)*
4319 (AP.NumPreSwitchStrings+1),"case strings");
4320 AP.PreSwitchModes = (int *)Malloc1(sizeof(int)*
4321 (AP.NumPreSwitchStrings+1),"case strings");
4322 AP.PreSwitchModes[0] = EXECUTINGPRESWITCH;
4323 AP.PreSwitchLevel = 0;
4324 }
4325
4326 /*
4327 #] StartPrepro :
4328 #[ EvalPreIf :
4329
4330 Evaluates the condition in an if instruction.
4331 The return value is EXECUTINGIF if the condition is true.
4332 If it is false the returnvalue is LOOKINGFORELSE.
4333 An error gives a return value of -1
4334 */
4335
EvalPreIf(UBYTE * s)4336 int EvalPreIf(UBYTE *s)
4337 {
4338 UBYTE *t, *u;
4339 int val;
4340 t = s;
4341 while ( *t ) t++;
4342 *t++ = ')';
4343 *t = 0;
4344 if ( ( u = PreIfEval(s,&val) ) == 0 ) return(-1);
4345 if ( u < t ) {
4346 MesPrint("@Unmatched parentheses in condition");
4347 return(-1);
4348 }
4349 if ( val ) return(EXECUTINGIF);
4350 else return(LOOKINGFORELSE);
4351 }
4352
4353 /*
4354 #] EvalPreIf :
4355 #[ PreIfEval :
4356
4357 Used for recursions in the evaluation of a preprocessor if-condition.
4358 It determines whether the contents of () is true or false
4359 (or in error).
4360 The return value is the address of the first character after the
4361 closing parenthesis or null if there is an error.
4362 In value we find true(1) or false(0)
4363 We enter after the opening parenthesis.
4364 There are levels:
4365 0: orlevel: a || b
4366 1: andlevel: a && b
4367 2: eqlevel: a == b or a != b or a = b
4368 3: cmplevel: a > b or a >= b or a < b or a <= b or a >~ b etc
4369 */
4370
PreIfEval(UBYTE * s,int * value)4371 UBYTE *PreIfEval(UBYTE *s, int *value)
4372 {
4373 int orlevel = 0, andlevel = 0, eqlevel = 0, cmplevel = 0;
4374 int type, val;
4375 LONG val2;
4376 int ortype, orval, cmptype, cmpval, eqtype, eqval, andtype, andval;
4377 UBYTE *t, *eqt, *cmpt, c;
4378 int eqop, cmpop;
4379 ortype = orval = cmptype = cmpval = eqtype = eqval = andtype = andval = 0;
4380 eqop = cmpop = 0;
4381 eqt = cmpt = 0;
4382 *value = 0;
4383 while ( *s != ')' ) {
4384 while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
4385 t = s;
4386 s = pParseObject(s,&type,&val2);
4387 if ( s == 0 ) return(0);
4388 val = val2;
4389 c = *s;
4390 *s++ = 0; /* in case the object is a string without " */
4391 while ( c == ' ' || c == '\t' || c == '\n' || c == '\r' ) {
4392 c = *s; *s++ = 0;
4393 }
4394 if ( *t == '"' ) t++;
4395 switch(c) {
4396 case '|':
4397 if ( *s != '|' ) goto illoper;
4398 s++;
4399 /* fall through */
4400 case ')':
4401 if ( cmplevel ) {
4402 if ( type == 0 || cmptype == 0 ) goto illobject;
4403 val = PreCmp(type,val,t,cmptype,cmpval,cmpt,cmpop);
4404 type = 0;
4405 cmplevel = 0;
4406 }
4407 if ( eqlevel ) {
4408 val = PreEq(type,val,t,eqtype,eqval,eqt,eqop);
4409 type = 0;
4410 eqlevel = 0;
4411 }
4412 if ( andlevel ) {
4413 if ( andtype != 0 || type != 0 ) goto illobject;
4414 val &= andval;
4415 andlevel = 0;
4416 }
4417 if ( orlevel ) {
4418 if ( ortype != 0 || type != 0 ) goto illobject;
4419 val |= orval;
4420 }
4421 if ( c == ')' ) {
4422 *value = val;
4423 return(s);
4424 }
4425 orlevel = 1;
4426 orval = val;
4427 ortype = type;
4428 break;
4429 case '&':
4430 if ( *s != '&' ) goto illoper;
4431 s++;
4432 if ( cmplevel ) {
4433 if ( type == 0 || cmptype == 0 ) goto illobject;
4434 val = PreCmp(type,val,t,cmptype,cmpval,cmpt,cmpop);
4435 type = 0;
4436 cmplevel = 0;
4437 }
4438 if ( eqlevel ) {
4439 val = PreEq(type,val,t,eqtype,eqval,eqt,eqop);
4440 type = 0;
4441 eqlevel = 0;
4442 }
4443 if ( andlevel ) {
4444 if ( andtype != 0 || type != 0 ) goto illobject;
4445 val &= andval;
4446 }
4447 andlevel = 1;
4448 andval = val;
4449 andtype = type;
4450 break;
4451 case '!':
4452 case '=':
4453 if ( eqlevel ) goto illorder;
4454 if ( cmplevel ) {
4455 if ( type == 0 || cmptype == 0 ) goto illobject;
4456 val = PreCmp(type,val,t,cmptype,cmpval,cmpt,cmpop);
4457 type = 0;
4458 cmplevel = 0;
4459 }
4460 if ( c == '!' && *s != '=' ) goto illoper;
4461 if ( *s == '=' ) s++;
4462 if ( c == '!' ) eqop = 1;
4463 else eqop = 0;
4464 eqlevel = 1; eqt = t; eqval = val; eqtype = type;
4465 break;
4466 case '>':
4467 case '<':
4468 if ( cmplevel ) goto illorder;
4469 if ( c == '<' ) cmpop = -1;
4470 else cmpop = 1;
4471 cmplevel = 1; cmpt = t; cmpval = val; cmptype = type;
4472 if ( *s == '=' ) {
4473 s++;
4474 if ( *s == '~' ) { s++; cmpop *= 4; }
4475 else cmpop *= 2;
4476 }
4477 else if ( *s == '~' ) { s++; cmpop *= 3; }
4478 break;
4479 default:
4480 goto illoper;
4481 }
4482 }
4483 return(s);
4484 illorder:
4485 MesPrint("@illegal order of operators");
4486 return(0);
4487 illobject:
4488 MesPrint("@illegal object for this operator");
4489 return(0);
4490 illoper:
4491 MesPrint("@illegal operator");
4492 return(0);
4493 }
4494
4495 /*
4496 #] PreIfEval :
4497 #[ PreCmp :
4498 */
4499
PreCmp(int type,int val,UBYTE * t,int type2,int val2,UBYTE * t2,int cmpop)4500 int PreCmp(int type, int val, UBYTE *t, int type2, int val2, UBYTE *t2, int cmpop)
4501 {
4502 if ( type == 2 || type2 == 2 || cmpop < -2 || cmpop > 2 ) {
4503 if ( cmpop < 0 && cmpop > -3 ) cmpop -= 2;
4504 if ( cmpop > 0 && cmpop < 3 ) cmpop += 2;
4505 if ( cmpop == 3 ) val = StrCmp(t2,t) > 0;
4506 else if ( cmpop == 4 ) val = StrCmp(t2,t) >= 0;
4507 else if ( cmpop == -3 ) val = StrCmp(t2,t) < 0;
4508 else if ( cmpop == -4 ) val = StrCmp(t2,t) <= 0;
4509 }
4510 else {
4511 if ( cmpop == 1 ) val = ( val2 > val );
4512 else if ( cmpop == 2 ) val = ( val2 >= val );
4513 else if ( cmpop == -1 ) val = ( val2 < val );
4514 else if ( cmpop == -2 ) val = ( val2 <= val );
4515 }
4516 return(val);
4517 }
4518
4519 /*
4520 #] PreCmp :
4521 #[ PreEq :
4522 */
4523
PreEq(int type,int val,UBYTE * t,int type2,int val2,UBYTE * t2,int eqop)4524 int PreEq(int type, int val, UBYTE *t, int type2, int val2, UBYTE *t2, int eqop)
4525 {
4526 UBYTE str[20];
4527 if ( type == 2 || type2 == 2 ) {
4528 if ( type != 2 ) { NumToStr(str,val ); t = str; }
4529 if ( type2 != 2 ) { NumToStr(str,val2); t2 = str; }
4530 if ( eqop == 1 ) val = StrCmp(t,t2) != 0;
4531 else val = StrCmp(t,t2) == 0;
4532 }
4533 else {
4534 if ( eqop ) val = val != val2;
4535 else val = val == val2;
4536 }
4537 return(val);
4538 }
4539
4540 /*
4541 #] PreEq :
4542 #[ pParseObject :
4543
4544 Parses a preprocessor object. We can have:
4545 1: a number (type = 1)
4546 2: a string (type = 2)
4547 3: an expression between parentheses (type = 0)
4548 4: a special function (type = 3)
4549 If the object is not a number, an expression or a special operator
4550 we try to interprete it as a string.
4551 */
4552
pParseObject(UBYTE * s,int * type,LONG * val2)4553 UBYTE *pParseObject(UBYTE *s, int *type, LONG *val2)
4554 {
4555 UBYTE *t, c;
4556 int sign, val = 0;
4557 LONG x;
4558 while ( *s == ' ' || *s == '\t' ) s++;
4559 if ( *s == '(' ) {
4560 s++;
4561 while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
4562 s = PreIfEval(s,&val);
4563 *type = 0;
4564 *val2 = val;
4565 return(s);
4566 }
4567 else if ( *s == '$' && s[1] == '(' ) {
4568 s += 2;
4569 while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
4570 s = PreIfDollarEval(s,&val);
4571 *type = 0; *val2 = val;
4572 return(s);
4573 }
4574 if ( *s == 0 ) {
4575 illend:
4576 MesPrint("@illegal end of condition");
4577 return(0);
4578 }
4579 if ( *s == '"' ) {
4580 s++;
4581 while ( *s && *s != '"' ) {
4582 if ( *s == '\\' ) s++;
4583 s++;
4584 }
4585 if ( *s == 0 ) goto illend;
4586 else *s = 0;
4587 *type = 2;
4588 s++;
4589
4590 while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
4591
4592 return(s);
4593 }
4594 t = s; sign = 1; x = 0;
4595 if ( chartype[*t] == 0 ) { /* Special operators and strings without "" */
4596 do { t++; } while ( chartype[*t] <= 1 );
4597 if ( *t == '(' ) {
4598 WORD ttype;
4599 c = *t; *t = 0;
4600 if ( StrICmp(s,(UBYTE *)"termsin") == 0 ) {
4601 UBYTE *tt;
4602 WORD numdol, numexp;
4603 ttype = 0;
4604 together:
4605 *t++ = c;
4606 while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
4607 if ( *t == '$' ) {
4608 t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
4609 c = *tt; *tt = 0;
4610 if ( ( numdol = GetDollar(t) ) > 0 ) {
4611 *tt = c;
4612 if ( ttype == 1 ) {
4613 x = SizeOfDollar(numdol);
4614 }
4615 else {
4616 x = TermsInDollar(numdol);
4617 }
4618 }
4619 else {
4620 MesPrint("@$%s has not (yet) been defined",t);
4621 *tt = c;
4622 Terminate(-1);
4623 }
4624 }
4625 else {
4626 tt = SkipAName(t);
4627 c = *tt; *tt = 0;
4628 if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) {
4629 MesPrint("@%s has not (yet) been defined",t);
4630 *tt = c;
4631 Terminate(-1);
4632 }
4633 else {
4634 *tt = c;
4635 if ( ttype == 1 ) {
4636 x = SizeOfExpression(numexp);
4637 }
4638 else {
4639 x = TermsInExpression(numexp);
4640 }
4641 }
4642 }
4643 while ( *tt == ' ' || *tt == '\t'
4644 || *tt == '\n' || *tt == '\r' ) tt++;
4645 if ( *tt != ')' ) {
4646 MesPrint("@Improper use of terms($var) or terms(expr)");
4647 Terminate(-1);
4648 }
4649 *type = 3;
4650 s = tt+1;
4651 *val2 = x;
4652 return(s);
4653 }
4654 else if ( StrICmp(s,(UBYTE *)"sizeof") == 0 ) {
4655 ttype = 1;
4656 goto together;
4657 }
4658 else if ( StrICmp(s,(UBYTE *)"exists") == 0 ) {
4659 UBYTE *tt;
4660 WORD numdol, numexp;
4661 *t++ = c;
4662 while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
4663 if ( *t == '$' ) {
4664 t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
4665 c = *tt; *tt = 0;
4666 if ( ( numdol = GetDollar(t) ) >= 0 ) { x = 1; }
4667 else { x = 0; }
4668 *tt = c;
4669 }
4670 else {
4671 tt = SkipAName(t);
4672 c = *tt; *tt = 0;
4673 if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) { x = 0; }
4674 else { x = 1; }
4675 *tt = c;
4676 }
4677 while ( *tt == ' ' || *tt == '\t'
4678 || *tt == '\n' || *tt == '\r' ) tt++;
4679 if ( *tt != ')' ) {
4680 MesPrint("@Improper use of exists($var) or exists(expr)");
4681 Terminate(-1);
4682 }
4683 *type = 3;
4684 s = tt+1;
4685 *val2 = x;
4686 return(s);
4687 }
4688 else if ( StrICmp(s,(UBYTE *)"isnumerical") == 0 ) {
4689 GETIDENTITY
4690 UBYTE *tt;
4691 WORD numdol, numexp;
4692 *t++ = c;
4693 while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
4694 if ( *t == '$' ) {
4695 t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
4696 c = *tt; *tt = 0;
4697 if ( ( numdol = GetDollar(t) ) < 0 ) {
4698 MesPrint("@$ variable in isnumerical(%s) does not exist",t);
4699 Terminate(-1);
4700 }
4701 x = DolToLong(BHEAD numdol);
4702 if ( AN.ErrorInDollar ) {
4703 DOLLARS d = Dollars + numdol;
4704 x = 0;
4705 if ( d->type == DOLNUMBER || d->type == DOLTERMS ) {
4706 if ( d->where[0] == 0 ) x = 1;
4707 else if ( d->where[d->where[0]] == 0 ) {
4708 if ( ABS(d->where[d->where[0]-1]) == d->where[0]-1 )
4709 x = 1;
4710 }
4711 }
4712 }
4713 else x = 1;
4714 *tt = c;
4715 }
4716 else {
4717 tt = SkipAName(t);
4718 c = *tt; *tt = 0;
4719 if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) {
4720 MesPrint("@expression in isnumerical(%s) does not exist",t);
4721 Terminate(-1);
4722 }
4723 x = TermsInExpression(numexp);
4724 if ( x != 1 ) x = 0;
4725 else {
4726 WORD *term = AT.WorkPointer;
4727 if ( GetFirstTerm(term,numexp) < 0 ) {
4728 MesPrint("@error reading expression in isnumerical(%s)",t);
4729 Terminate(-1);
4730 }
4731 if ( *term == ABS(term[*term-1])+1 ) x = 1;
4732 else x = 0;
4733 }
4734 *tt = c;
4735 }
4736 while ( *tt == ' ' || *tt == '\t'
4737 || *tt == '\n' || *tt == '\r' ) tt++;
4738 if ( *tt != ')' ) {
4739 MesPrint("@Improper use of isnumerical($var) or numerical(expr)");
4740 Terminate(-1);
4741 }
4742 *type = 3;
4743 s = tt+1;
4744 *val2 = x;
4745 return(s);
4746 }
4747 else if ( StrICmp(s,(UBYTE *)("maxpowerof")) == 0 ) {
4748 UBYTE *tt;
4749 WORD numsym;
4750 int stype;
4751 *t++ = c;
4752 while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
4753 tt = SkipAName(t);
4754 c = *tt; *tt = 0;
4755 if ( ( stype = GetName(AC.varnames,t,&numsym,NOAUTO) ) == NAMENOTFOUND ) {
4756 MesPrint("@%s has not (yet) been defined",t);
4757 *tt = c;
4758 Terminate(-1);
4759 }
4760 else if ( stype != CSYMBOL ) {
4761 MesPrint("@%s should be a symbol",t);
4762 *tt = c;
4763 Terminate(-1);
4764 }
4765 else {
4766 *tt = c;
4767 x = symbols[numsym].maxpower;
4768 }
4769 while ( *tt == ' ' || *tt == '\t'
4770 || *tt == '\n' || *tt == '\r' ) tt++;
4771 if ( *tt != ')' ) {
4772 MesPrint("@Improper use of maxpowerof(symbol)");
4773 Terminate(-1);
4774 }
4775 *type = 3;
4776 s = tt+1;
4777 *val2 = x;
4778 return(s);
4779 }
4780 else if ( StrICmp(s,(UBYTE *)("minpowerof")) == 0 ) {
4781 UBYTE *tt;
4782 WORD numsym;
4783 int stype;
4784 *t++ = c;
4785 while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
4786 tt = SkipAName(t);
4787 c = *tt; *tt = 0;
4788 if ( ( stype = GetName(AC.varnames,t,&numsym,NOAUTO) ) == NAMENOTFOUND ) {
4789 MesPrint("@%s has not (yet) been defined",t);
4790 *tt = c;
4791 Terminate(-1);
4792 }
4793 else if ( stype != CSYMBOL ) {
4794 MesPrint("@%s should be a symbol",t);
4795 *tt = c;
4796 Terminate(-1);
4797 }
4798 else {
4799 *tt = c;
4800 x = symbols[numsym].minpower;
4801 }
4802 while ( *tt == ' ' || *tt == '\t'
4803 || *tt == '\n' || *tt == '\r' ) tt++;
4804 if ( *tt != ')' ) {
4805 MesPrint("@Improper use of minpowerof(symbol)");
4806 Terminate(-1);
4807 }
4808 *type = 3;
4809 s = tt+1;
4810 *val2 = x;
4811 return(s);
4812 }
4813 else if ( StrICmp(s,(UBYTE *)"isfactorized") == 0 ) {
4814 UBYTE *tt;
4815 WORD numdol, numexp;
4816 *t++ = c;
4817 while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
4818 if ( *t == '$' ) {
4819 t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
4820 c = *tt; *tt = 0;
4821 if ( ( numdol = GetDollar(t) ) > 0 ) {
4822 if ( Dollars[numdol].factors != 0 ) x = 1;
4823 else x = 0;
4824 }
4825 else {
4826 MesPrint("@ %s should be the name of an expression or a $ variable",t-1);
4827 Terminate(-1);
4828 }
4829 *tt = c;
4830 }
4831 else {
4832 tt = SkipAName(t);
4833 c = *tt; *tt = 0;
4834 if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) {
4835 MesPrint("@ %s should be the name of an expression or a $ variable",t);
4836 Terminate(-1);
4837 }
4838 else {
4839 if ( ( Expressions[numexp].vflags & ISFACTORIZED ) != 0 ) x = 1;
4840 else x = 0;
4841 }
4842 *tt = c;
4843 }
4844 while ( *tt == ' ' || *tt == '\t'
4845 || *tt == '\n' || *tt == '\r' ) tt++;
4846 if ( *tt != ')' ) {
4847 MesPrint("@Improper use of isfactorized($var) or isfactorized(expr)");
4848 Terminate(-1);
4849 }
4850 *type = 3;
4851 s = tt+1;
4852 *val2 = x;
4853 return(s);
4854 }
4855 else if ( StrICmp(s,(UBYTE *)"isdefined") == 0 ) {
4856 UBYTE *tt;
4857 *t++ = c;
4858 while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
4859 tt = SkipAName(t);
4860 c = *tt; *tt = 0;
4861 if ( GetPreVar(t,WITHOUTERROR) != 0 ) x = 1;
4862 else x = 0;
4863 *tt = c;
4864 while ( *tt == ' ' || *tt == '\t'
4865 || *tt == '\n' || *tt == '\r' ) tt++;
4866 if ( *tt != ')' ) {
4867 MesPrint("@Improper use of isdefined(var)");
4868 Terminate(-1);
4869 }
4870 *type = 3;
4871 s = tt+1;
4872 *val2 = x;
4873 return(s);
4874 }
4875 else *t = c;
4876 }
4877 else if ( *t == '=' || *t == '<' || *t == '>' || *t == '!'
4878 || *t == ')' || *t == ' ' || *t == '\t' || *t == 0 || *t == '\n' ) {
4879 *val2 = 0;
4880 *type = 2;
4881 return(t);
4882 }
4883 else {
4884 MesPrint("@Illegal use of string in preprocessor condition: %s",s);
4885 Terminate(-1);
4886 }
4887 }
4888 while ( *t == '-' || *t == '+' || *t == ' ' || *t == '\t' ) {
4889 if ( *t == '-' ) sign = -sign;
4890 t++;
4891 }
4892 while ( chartype[*t] == 1 ) { x = 10*x + *t++ - '0'; }
4893 while ( *t == ' ' || *t == '\t' ) t++;
4894 if ( chartype[*t] == 8 || *t == ')' || *t == '=' || *t == 0 ) {
4895 *val2 = sign > 0 ? x: -x;
4896 *type = 1;
4897 return(t);
4898 }
4899 while ( chartype[*t] != 8 && *t != ')' && *t != '=' && *t ) t++;
4900 while ( ( t > s ) && ( t[-1] == ' ' || t[-1] == '\t' ) ) t--;
4901 *type = 2;
4902 *val2 = val;
4903 return(t);
4904 }
4905
4906 /*
4907 #] pParseObject :
4908 #[ PreCalc :
4909
4910 To be called when a { is encountered.
4911 Action: read first till matching }. This is to be stored.
4912 Next we look whether this is a set or whether it can be
4913 evaluated. If it is a set we consider it as a new stream.
4914 The stream will have to be deallocated when read completely.
4915 If it is to be evaluated we do that and put the result in
4916 a stream.
4917 */
4918
PreCalc()4919 UBYTE *PreCalc()
4920 {
4921 UBYTE *buff, *s = 0, *t, *newb, c;
4922 int size, i, n, parlevel = 0, bralevel = 0;
4923 LONG answer;
4924 ULONG uanswer;
4925 size = n = 0;
4926 buff = 0; c = '{';
4927 for (;;) {
4928 if ( n >= size ) {
4929 if ( size == 0 ) size = 72;
4930 else size *= 2;
4931 if ( ( newb = (UBYTE *)Malloc1(size+2,"{}") ) == 0 ) return(0);
4932 s = newb;
4933 if ( buff ) {
4934 i = n;
4935 t = buff;
4936 NCOPYB(s,t,i);
4937 M_free(buff,"pre calc buffer");
4938 }
4939 else s = newb;
4940 buff = newb;
4941 }
4942 *s++ = c; n++;
4943 c = GetChar(0);
4944 if ( c == 0 ) {
4945 Error0("Unmatched {}");
4946 M_free(buff,"precalc buffer");
4947 return(0);
4948 }
4949 else if ( c == '{' ) { bralevel++; }
4950 else if ( c == '}' ) {
4951 if ( --bralevel < 0 ) { *s++ = c; *s = 0; break; }
4952 }
4953 else if ( c == '(' ) { parlevel++; }
4954 else if ( c == ')' ) {
4955 if ( --parlevel < 0 ) { *s++ = c; *s = 0; goto setstring; }
4956 }
4957 else if ( chartype[c] != 1 && chartype[c] != 5
4958 && chartype[c] != 6 && c != '!' && c != '&'
4959 && c != '|' && c != '\\' ) { *s++ = c; *s = 0; goto setstring; }
4960 }
4961 if ( parlevel > 0 ) goto setstring;
4962 /*
4963 Try now to evaluate the string.
4964 If it works, copy the resulting value back into buff as a string.
4965 */
4966 answer = 0;
4967 if ( PreEval(buff+1,&answer) == 0 ) goto setstring;
4968 t = buff + size;
4969 s = buff;
4970 if ( answer < 0 ) { *s++ = '-'; }
4971 uanswer = LongAbs(answer);
4972 n = 0;
4973 do {
4974 *--t = ( uanswer % 10 ) + '0';
4975 uanswer /= 10;
4976 n++;
4977 } while ( uanswer > 0 );
4978 NCOPYB(s,t,n);
4979 *s = 0;
4980 setstring:;
4981 /*
4982 Open a stream that contains the current string.
4983 Mark it to be removed after termination.
4984 */
4985 if ( OpenStream(buff,PRECALCSTREAM,0,PRENOACTION) == 0 ) return(0);
4986 return(buff);
4987 }
4988
4989 /*
4990 #] PreCalc :
4991 #[ PreEval :
4992
4993 Operations are:
4994 +, -, *, /, %, &, |, ^, !, ^% (postfix 2log), ^/ (postfix sqrt)
4995 */
4996
PreEval(UBYTE * s,LONG * x)4997 UBYTE *PreEval(UBYTE *s, LONG *x)
4998 {
4999 LONG y, z, a;
5000 int tobemultiplied, tobeadded = 1, expsign, i;
5001 UBYTE *t;
5002 *x = 0; a = 1;
5003 while ( *s == ' ' || *s == '\t' ) s++;
5004 for(;;){
5005 if ( *s == '+' || *s == '-' ) {
5006 if ( *s == '-' ) tobeadded = -1;
5007 else tobeadded = 1;
5008 s++;
5009 while ( *s == '-' || *s == '+' || *s == ' ' || *s == '\t' ) {
5010 if ( *s == '-' ) tobeadded = -tobeadded;
5011 s++;
5012 }
5013 }
5014 tobemultiplied = 0;
5015 for(;;){
5016 while ( *s == ' ' || *s == '\t' ) s++;
5017 if ( *s <= '9' && *s >= '0' ) {
5018 ULONG uy;
5019 ParseNumber(uy,s)
5020 y = uy; /* may cause an implementation-defined behaviour */
5021 }
5022 else if ( *s == '(' || *s == '{' ) {
5023 if ( ( t = PreEval(s+1,&y) ) == 0 ) return(0);
5024 s = t;
5025 }
5026 else return(0);
5027 while ( *s == ' ' || *s == '\t' ) s++;
5028 expsign = 1;
5029 while ( *s == '^' || *s == '!' ) {
5030 s++;
5031 if ( s[-1] == '!' ) { /* factorial of course */
5032 while ( *s == ' ' || *s == '\t' ) s++;
5033 if ( y < 0 ) {
5034 MesPrint("@Negative value in preprocessor factorial: %l",y);
5035 return(0);
5036 }
5037 else if ( y == 0 ) y = 1;
5038 else if ( y > 1 ) {
5039 z = y-1;
5040 while ( z > 0 ) { y = y*z; z--; }
5041 }
5042 continue;
5043 }
5044 else if ( *s == '%' ) { /* ^% is postfix 2log */
5045 s++;
5046 while ( *s == ' ' || *s == '\t' ) s++;
5047 z = y;
5048 if ( z <= 0 ) {
5049 MesPrint("@Illegal value in preprocessor logarithm: %l",z);
5050 return(0);
5051 }
5052 y = 0; z >>= 1;
5053 while ( z ) { y++; z >>= 1; }
5054 continue;
5055 }
5056 else if ( *s == '/' ) { /* ^/ is postfix sqrt */
5057 LONG yy, zz;
5058 s++;
5059 while ( *s == ' ' || *s == '\t' ) s++;
5060 z = y;
5061 if ( z <= 0 ) {
5062 MesPrint("@Illegal value in preprocessor square root: %l",z);
5063 return(0);
5064 }
5065 if ( z > 8 ) { /* Very crude integer square root */
5066 zz = z;
5067 yy = 0; zz >>= 1;
5068 while ( zz ) { yy++; zz >>= 1; }
5069 zz = z >> (yy/2); i = 10; y = 0;
5070 do {
5071 yy = zz/2 + z/(2*zz); i--;
5072 if ( y == yy ) break;
5073 y = zz; zz = yy;
5074 } while ( y != yy && i > 0 );
5075 while ( y*y < z ) y++;
5076 while ( y*y > z ) y--;
5077 }
5078 else if ( z >= 4 ) y = 2;
5079 else if ( z == 0 ) y = 0;
5080 else y = 1;
5081 continue;
5082 }
5083 while ( *s == ' ' || *s == '\t' ) s++;
5084 while ( *s == '-' || *s == '+' || *s == ' ' || *s == '\t' ) {
5085 if ( *s == '-' ) expsign = -expsign;
5086 }
5087 if ( *s <= '9' && *s >= '0' ) {
5088 ParseNumber(z,s)
5089 }
5090 else if ( *s == '(' || *s == '{' ) {
5091 if ( ( t = PreEval(s+1,&z) ) == 0 ) return(0);
5092 s = t;
5093 }
5094 else return(0);
5095 while ( *s == ' ' || *s == '\t' ) s++;
5096 y = iexp(y,(int)z);
5097 }
5098 if ( tobemultiplied == 0 ) {
5099 if ( expsign < 0 ) a = 1/y;
5100 else a = y;
5101 }
5102 else {
5103 if ( tobemultiplied > 2 && expsign != 1 ) {
5104 MesPrint("&Incorrect use of ^ with & or |. Use brackets!");
5105 Terminate(-1);
5106 }
5107 tobemultiplied *= expsign;
5108 if ( tobemultiplied == 1 ) a *= y;
5109 else if ( tobemultiplied == 3 ) a &= y;
5110 else if ( tobemultiplied == 4 ) a |= y;
5111 else {
5112 if ( y == 0 || tobemultiplied == -2 ) {
5113 MesPrint("@Division by zero in preprocessor calculator");
5114 Terminate(-1);
5115 }
5116 if ( tobemultiplied == 2 ) a %= y;
5117 else a /= y;
5118 }
5119 }
5120 if ( *s == '%' ) tobemultiplied = 2;
5121 else if ( *s == '*' ) tobemultiplied = 1;
5122 else if ( *s == '/' ) tobemultiplied = -1;
5123 else if ( *s == '&' ) tobemultiplied = 3;
5124 else if ( *s == '|' ) tobemultiplied = 4;
5125 else {
5126 ULONG ux, ua;
5127 ux = *x;
5128 ua = a;
5129 if ( tobeadded >= 0 ) ux += ua;
5130 else ux -= ua;
5131 *x = ULongToLong(ux);
5132 if ( *s == ')' || *s == '}' ) return(s+1);
5133 else if ( *s == '-' || *s == '+' ) { tobeadded = 1; break; }
5134 else return(0);
5135 }
5136 s++;
5137 }
5138 }
5139 /* return(0); */
5140 }
5141
5142 /*
5143 #] PreEval :
5144 #[ AddToPreTypes :
5145 */
5146
AddToPreTypes(int type)5147 void AddToPreTypes(int type)
5148 {
5149 if ( AP.NumPreTypes >= AP.MaxPreTypes ) {
5150 int i, *newlist = (int *)Malloc1(sizeof(int)*(2*AP.MaxPreTypes+1)
5151 ,"preprocessor type lists");
5152 for ( i = 0; i <= AP.MaxPreTypes; i++ ) newlist[i] = AP.PreTypes[i];
5153 M_free(AP.PreTypes,"preprocessor type lists");
5154 AP.PreTypes = newlist;
5155 AP.MaxPreTypes = 2*AP.MaxPreTypes;
5156 }
5157 AP.PreTypes[++AP.NumPreTypes] = type;
5158 }
5159
5160 /*
5161 #] AddToPreTypes :
5162 #[ MessPreNesting :
5163 */
5164
MessPreNesting(int par)5165 void MessPreNesting(int par)
5166 {
5167 MesPrint("@(%d)Illegal nesting of %#if, %#do, %#procedure and/or %#switch",par);
5168 }
5169
5170 /*
5171 #] MessPreNesting :
5172 #[ DoPreAddSeparator :
5173
5174 Preprocessor directives "addseparator" and "rmseparator" add/remove
5175 separator characters used to separate function arguments.
5176 Example:
5177
5178 #define QQ "a|g|a"
5179 #addseparator %
5180 *Comma must be quoted!:
5181 #rmseparator ","
5182 #rmseparator |
5183 #call H(a,a%`QQ')
5184
5185 Characters ' ', '\t' and '"' are ignored!
5186 */
5187
DoPreAddSeparator(UBYTE * s)5188 int DoPreAddSeparator(UBYTE *s)
5189 {
5190 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5191 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5192 for(;*s != '\0';s++){
5193 while ( *s == ' ' || *s == '\t' || *s == '"') s++;
5194 /* Todo:
5195 if ( set_in(*s,invalidseparators) ) {
5196 MesPrint("@Invalid separator specified");
5197 return(-1);
5198 }
5199 */
5200 set_set(*s,AC.separators);
5201 }
5202 return(0);
5203 }
5204
5205 /*
5206 #] DoPreAddSeparator :
5207 #[ DoPreRmSeparator :
5208
5209 See commentary with DoPreAddSeparator
5210
5211 Characters ' ', '\t' and '"' are ignored!
5212 */
DoPreRmSeparator(UBYTE * s)5213 int DoPreRmSeparator(UBYTE *s)
5214 {
5215 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5216 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5217 for(;*s != '\0';s++){
5218 while ( *s == ' ' || *s == '\t' || *s == '"') s++;
5219 set_del(*s,AC.separators);
5220 }
5221 return(0);
5222 }
5223
5224 /*
5225 #] DoPreRmSeparator :
5226 #[ DoExternal:
5227
5228 #external ["prevar"] command
5229 */
DoExternal(UBYTE * s)5230 int DoExternal(UBYTE *s)
5231 {
5232 #ifdef WITHEXTERNALCHANNEL
5233 UBYTE *prevar=0;
5234 int externalD= 0;
5235 #else
5236 DUMMYUSE(s);
5237 #endif
5238 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5239 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5240 if ( AP.preError ) return(0);
5241
5242 #ifdef WITHEXTERNALCHANNEL
5243 while ( *s == ' ' || *s == '\t' ) s++;
5244 if(*s == '"'){/*prevar to store the descriptor is defined*/
5245 prevar=++s;
5246
5247 if ( chartype[*s] == 0 )for(;*s != '"'; s++)switch(chartype[*s]){
5248 case 10:/*'\0' fits here*/
5249 MesPrint("@Can't finde closing \"");
5250 Terminate(-1);
5251 break;
5252 case 0:case 1: continue;
5253 default:
5254 break;
5255 }
5256 if(*s != '"'){
5257 MesPrint("@Illegal name of preprocessor variable to store external channel");
5258 return(-1);
5259 }
5260 *s='\0';
5261 for(s++; *s == ' ' || *s == '\t'; s++);
5262 }
5263
5264 if(*s == '\0'){
5265 MesPrint("@Illegal external command");
5266 return(-1);
5267 }
5268 /*here s is a command*/
5269 /*See the file extcmd.c*/
5270 /*[08may2006 mt]:*/
5271 externalD=openExternalChannel(
5272 s,
5273 AX.daemonize,
5274 AX.shellname,
5275 AX.stderrname);
5276 /*:[08may2006 mt]*/
5277 if(externalD<1){/*error?*/
5278 /*Not quite correct - terminate the program on error:*/
5279 Error1("Can't start external program",s);
5280 return(-1);
5281 }
5282 /*Now external command runs.*/
5283
5284 if(prevar){/*Store the external channel descriptor in the provided variable:*/
5285 UBYTE buf[21];/* 64/Log_2[10] = 19.3, so this is enough forever...*/
5286 NumToStr(buf,externalD);
5287 if ( PutPreVar(prevar,buf,0,1) < 0 ) return(-1);
5288 }
5289
5290 AX.currentExternalChannel=externalD;
5291 /*[08may2006 mt]:*/
5292 if(AX.currentPrompt!=0){/*Change default terminator*/
5293 if(setTerminatorForExternalChannel( (char *)AX.currentPrompt)){
5294 MesPrint("@Prompt is too long");
5295 return(-1);
5296 }
5297 }
5298 setKillModeForExternalChannel(AX.killSignal,AX.killWholeGroup);
5299 /*:[08may2006 mt]*/
5300 return(0);
5301 #else /*ifdef WITHEXTERNALCHANNEL*/
5302 Error0("External channel: not implemented on this computer/system");
5303 return(-1);
5304 #endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5305 }
5306
5307 /*
5308 #] DoExternal:
5309 #[ DoPrompt:
5310 #prompt string
5311 */
5312
DoPrompt(UBYTE * s)5313 int DoPrompt(UBYTE *s)
5314 {
5315 #ifndef WITHEXTERNALCHANNEL
5316 DUMMYUSE(s);
5317 #endif
5318 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5319 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5320
5321 #ifdef WITHEXTERNALCHANNEL
5322 while ( *s == ' ' || *s == '\t' ) s++;
5323 if ( AX.currentPrompt )
5324 M_free(AX.currentPrompt,"external channel prompt");
5325 if ( *s == '\0' )
5326 AX.currentPrompt = (UBYTE *)strDup1((UBYTE *)"","external channel prompt");
5327 else
5328 AX.currentPrompt = strDup1(s,"external channel prompt");
5329 if( setTerminatorForExternalChannel( (char *)AX.currentPrompt) > 0 ){
5330 MesPrint("@Prompt is too long");
5331 return(-1);
5332 }
5333 /*else: if 0, ok; if -1, there is no current channel-ok, just prompt is stored.*/
5334 return(0);
5335 #else /*ifdef WITHEXTERNALCHANNEL*/
5336 Error0("External channel: not implemented on this computer/system");
5337 return(-1);
5338 #endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5339 }
5340 /*
5341 #] DoPrompt:
5342 #[ DoSetExternal:
5343 #setexternal n
5344 */
5345
DoSetExternal(UBYTE * s)5346 int DoSetExternal(UBYTE *s)
5347 {
5348 #ifdef WITHEXTERNALCHANNEL
5349 int n=0;
5350 #else
5351 DUMMYUSE(s);
5352 #endif
5353 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5354 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5355 if ( AP.preError ) return(0);
5356
5357 #ifdef WITHEXTERNALCHANNEL
5358 while ( *s == ' ' || *s == '\t' ) s++;
5359 while ( chartype[*s] == 1 ) { n = 10*n + *s++ - '0'; }
5360 while ( *s == ' ' || *s == '\t' ) s++;
5361 if(*s!='\0'){
5362 MesPrint("@setexternal: number expected");
5363 return(-1);
5364 }
5365 if(selectExternalChannel(n)<0){
5366 MesPrint("@setexternal: invalid number");
5367 return(-1);
5368 }
5369 AX.currentExternalChannel=n;
5370 return(0);
5371 #else /*ifdef WITHEXTERNALCHANNEL*/
5372 Error0("External channel: not implemented on this computer/system");
5373 return(-1);
5374 #endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5375 }
5376 /*
5377 #] DoSetExternal:
5378 #[ DoSetExternalAttr:
5379 */
5380
pickupword(UBYTE * s)5381 static FORM_INLINE UBYTE *pickupword(UBYTE *s)
5382 {
5383
5384 for(;*s>' ';s++)switch(*s){
5385 case '=':
5386 case ',':
5387 case ';':
5388 return(s);
5389 }/*for(;*s>' ';s++)switch(*s)*/
5390 return(s);
5391 }
5392 /*Returns 0 if the first string (case insensitively) equal to
5393 the beginning of the second string (of length n):
5394 */
strINCmp(UBYTE * a,UBYTE * b,int n)5395 static inline int strINCmp(UBYTE *a, UBYTE *b, int n)
5396 {
5397 for(;n>0;n--)if(tolower(*a++)!=tolower(*b++))
5398 return(1);
5399 return(*a != '\0');
5400 }
5401
5402 #define KILL "kill"
5403 #define KILLALL "killall"
5404 #define DAEMON "daemon"
5405 #define SHELL "shell"
5406 #define STDERR "stderr"
5407
5408 #define TRUE_EXPR "true"
5409 #define FALSE_EXPR "false"
5410 #define NOSHELL "noshell"
5411 #define TERMINAL "terminal"
5412
5413 /*
5414 Expects comma-separated list of pairs name=value
5415 */
DoSetExternalAttr(UBYTE * s)5416 int DoSetExternalAttr(UBYTE *s)
5417 {
5418 #ifdef WITHEXTERNALCHANNEL
5419 int lnam,lval;
5420 UBYTE *nam,*val;
5421 #else
5422 DUMMYUSE(s);
5423 #endif
5424 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5425 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5426 if ( AP.preError ) return(0);
5427
5428 #ifdef WITHEXTERNALCHANNEL
5429 do{
5430 /*Read the name:*/
5431 while ( *s == ' ' || *s == '\t' ) s++;
5432 s=pickupword(nam=s);
5433 lnam=s-nam;
5434 while ( *s == ' ' || *s == '\t' ) s++;
5435 if(*s++!='='){
5436 MesPrint("@External channel:'=' expected instead of %s",s-1);
5437 return(-1);
5438 }
5439 /*Read the value:*/
5440 while ( *s == ' ' || *s == '\t' ) s++;
5441 val=s;
5442
5443 for(;;){
5444 UBYTE *m;
5445 s=pickupword(s);
5446 m=s;
5447 while ( *s == ' ' || *s == '\t' ) s++;
5448 if( (*s == ',')||(*s == '\n')||(*s == ';')||(*s == '\0') ){
5449 s=m;
5450 break;
5451 }
5452 }/*for(;;)*/
5453
5454 lval=s-val;
5455 while ( *s == ' ' || *s == '\t' ) s++;
5456
5457 if(strINCmp((UBYTE *)SHELL,nam,lnam)==0){
5458 if(AX.shellname!=NULL)
5459 M_free(AX.shellname,"external channel shellname");
5460 if(strINCmp((UBYTE *)NOSHELL,val,lval)==0)
5461 AX.shellname=NULL;
5462 else{
5463 UBYTE *ch,*b;
5464 b=ch=AX.shellname=Malloc1(lval+1,"external channel shellname");
5465 while(ch-b<lval)
5466 *ch++=*val++;
5467 *ch='\0';
5468 }
5469 }else if(strINCmp((UBYTE *)DAEMON,nam,lnam)==0){
5470 if(strINCmp((UBYTE *)TRUE_EXPR,val,lval)==0)
5471 AX.daemonize = 1;
5472 else if(strINCmp((UBYTE *)FALSE_EXPR,val,lval)==0)
5473 AX.daemonize = 0;
5474 else{
5475 MesPrint("@External channel:true or false expected for %s",DAEMON);
5476 return(-1);
5477 }
5478 }else if(strINCmp((UBYTE *)KILLALL,nam,lnam)==0){
5479 if(strINCmp((UBYTE *)TRUE_EXPR,val,lval)==0)
5480 AX.killWholeGroup = 1;
5481 else if(strINCmp((UBYTE *)FALSE_EXPR,val,lval)==0)
5482 AX.killWholeGroup = 0;
5483 else{
5484 MesPrint("@External channel: true or false expected for %s",KILLALL);
5485 return(-1);
5486 }
5487 }else if(strINCmp((UBYTE *)KILL,nam,lnam)==0){
5488 int i,n=0;
5489 for(i=0;i<lval;i++)
5490 if( *val>='0' && *val<= '9' )
5491 n = 10*n + *val++ - '0';
5492 else{
5493 MesPrint("@External channel: number expected for %s",KILL);
5494 return(-1);
5495 }
5496 AX.killSignal=n;
5497 }else if(strINCmp((UBYTE *)STDERR,nam,lnam)==0){
5498 if( AX.stderrname != NULL ) {
5499 M_free(AX.stderrname,"external channel stderrname");
5500 }
5501 if(strINCmp((UBYTE *)TERMINAL,val,lval)==0)
5502 AX.stderrname = NULL;
5503 else{
5504 UBYTE *ch,*b;
5505 b=ch=AX.stderrname=Malloc1(lval+1,"external channel stderrname");
5506 while(ch-b<lval)
5507 *ch++=*val++;
5508 *ch='\0';
5509 }
5510 }else{
5511 nam[lnam+1]='\0';
5512 MesPrint("@External channel: unrecognized attribute",nam);
5513 return(-1);
5514 }
5515 }while(*s++ == ',');
5516 if( (*(s-1)>' ')&&(*(s-1)!=';') ){
5517 MesPrint("@External channel: syntax error: %s",s-1);
5518 return(-1);
5519 }
5520 return(0);
5521 #else /*ifdef WITHEXTERNALCHANNEL*/
5522 Error0("External channel: not implemented on this computer/system");
5523 return(-1);
5524 #endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5525 }
5526 /*
5527 #] DoSetExternalAttr:
5528 #[ DoRmExternal:
5529 #rmexternal [n] (if 0, close all)
5530 */
5531
DoRmExternal(UBYTE * s)5532 int DoRmExternal(UBYTE *s)
5533 {
5534 #ifdef WITHEXTERNALCHANNEL
5535 int n = -1;
5536 #else
5537 DUMMYUSE(s);
5538 #endif
5539 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5540 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5541 if ( AP.preError ) return(0);
5542
5543 #ifdef WITHEXTERNALCHANNEL
5544 while ( *s == ' ' || *s == '\t' ) s++;
5545 if( chartype[*s] == 1 ){
5546 for(n=0; chartype[*s] == 1 ; s++) { n = 10*n + *s - '0'; }
5547 while ( *s == ' ' || *s == '\t' ) s++;
5548 }
5549 if(*s!='\0'){
5550 MesPrint("@rmexternal: invalid number");
5551 return(-1);
5552 }
5553 switch(n){
5554 case 0:/*Close all opened channels*/
5555 closeAllExternalChannels();
5556 AX.currentExternalChannel=0;
5557 /*Do not clean AX.currentPrompt!*/
5558 return(0);
5559 case -1:/*number is not specified - try current*/
5560 n=AX.currentExternalChannel;
5561 /* fall through */
5562 default:
5563 closeExternalChannel(n);/*No reaction for possible error*/
5564 }
5565 if (n == AX.currentExternalChannel)/*cleaned up by closeExternalChannel()*/
5566 AX.currentExternalChannel=0;
5567 return(0);
5568 #else /*ifdef WITHEXTERNALCHANNEL*/
5569 Error0("External channel: not implemented on this computer/system");
5570 return(-1);
5571 #endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5572
5573 }
5574 /*
5575 #] DoRmExternal:
5576 #[ DoFromExternal :
5577 #fromexternal
5578 is used to read the text from the running external
5579 program, the synthax is similar to the #include
5580 directive.
5581 #fromexternal "varname"
5582 is used to read the text from the running external
5583 program into the preprocessor variable varname.
5584 directive.
5585 #fromexternal "varname" maxlength
5586 is used to read the text from the running external
5587 program into the preprocessor variable varname.
5588 directive. Only first maxlength characters are
5589 stored.
5590
5591 FORM continues to read the running external
5592 program output until the extrenal program outputs a
5593 prompt.
5594
5595 */
5596
DoFromExternal(UBYTE * s)5597 int DoFromExternal(UBYTE *s)
5598 {
5599 #ifdef WITHEXTERNALCHANNEL
5600 UBYTE *prevar=0;
5601 int lbuf=-1;
5602 int withNoList=AC.NoShowInput;
5603 int oldpreassignflag;
5604 #else
5605 DUMMYUSE(s);
5606 #endif
5607 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5608 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5609 if ( AP.preError ) return(0);
5610 #ifdef WITHEXTERNALCHANNEL
5611
5612 FLUSHCONSOLE;
5613
5614 while ( *s == ' ' || *s == '\t' ) s++;
5615 /*[17may2006 mt]:*/
5616 if ( *s == '-' || *s == '+' ) {
5617 if ( *s == '-' )
5618 withNoList = 1;
5619 else
5620 withNoList = 0;
5621 s++;
5622 while ( *s == ' ' || *s == '\t' ) s++;
5623 }/*if ( *s == '-' || *s == '+' )*/
5624 /*:[17may2006 mt]*/
5625 /*[02feb2006 mt]:*/
5626 if(*s == '"'){/*prevar to store the output is defined*/
5627 prevar=++s;
5628
5629 if ( *s=='$' || chartype[*s] == 0 )for(;*s != '"'; s++)switch(chartype[*s]){
5630 case 10:/*'\0' fits here*/
5631 MesPrint("@Can't finde closing \"");
5632 Terminate(-1);
5633 break;
5634 case 0:case 1: continue;
5635 default:
5636 break;
5637 }
5638 if(*s != '"'){
5639 MesPrint("@Illegal name to store output of external channel");
5640 return(-1);
5641 }
5642 *s='\0';
5643 for(s++; *s == ' ' || *s == '\t'; s++);
5644 }/*if(*s == '"')*/
5645
5646 if(*s != '\0'){
5647 if( chartype[*s] == 1 ){
5648 for(lbuf=0; chartype[*s] == 1 ; s++) { lbuf = 10*lbuf + *s - '0'; }
5649 while ( *s == ' ' || *s == '\t' ) s++;
5650 }
5651 if( (*s!='\0')||(lbuf<0) ){
5652 MesPrint("@Illegal buffer length in fromexternal");
5653 return(-1);
5654 }
5655 }/*if(*s != '\0')*/
5656 /*:[02feb20006 mt]*/
5657 if(getCurrentExternalChannel()!=AX.currentExternalChannel)
5658 /*[08may20006 mt]:*/
5659 /*selectExternalChannel(AX.currentExternalChannel);*/
5660 if(selectExternalChannel(AX.currentExternalChannel)){
5661 MesPrint("@No current external channel");
5662 return(-1);
5663 }
5664 /*:[08may20006 mt]*/
5665
5666 /*[02feb2006 mt]:*/
5667 if(prevar!=0){/*The result must be stored into preprovar*/
5668 UBYTE *buf;
5669 int cc = 0;
5670 if(lbuf == -1){/*Unlimited buffer, everything must be stored*/
5671 int i;
5672 buf=Malloc1( (lbuf=255)+1,"Fromexternal");
5673 /*[18may20006 mt]:*/
5674 /*for(i=0;(cc=getcFromExtChannel())!=EOF;i++){*/
5675 /* May 2006: now getcFromExtChannelOk returns EOF while
5676 getcFromExtChannelFailure returns -2 (see comments in
5677 exctcmd.c):*/
5678 for(i=0;(cc=getcFromExtChannel())>0;i++){
5679 /*:[18may20006 mt]*/
5680 if(i==lbuf){
5681 int j;
5682 UBYTE *tmp=Malloc1( (lbuf*=2)+1,"Fromexternal");
5683 for(j=0;j<i;j++)tmp[j]=buf[j];
5684 M_free(buf,"Fromexternal");
5685 buf=tmp;
5686 }
5687 buf[i]=(UBYTE)(cc);
5688 }/*for(i=0;(cc=getcFromExtChannel())>0;i++)*/
5689 /*[18may20006 mt]:*/
5690 if(cc == -2){
5691 MesPrint("@No current external channel");
5692 return(-1);
5693 }
5694 lbuf=i;
5695 /*:[18may20006 mt]*/
5696 buf[i]='\0';
5697 }else{/*Fixed buffer, only lbuf chars must be stored*/
5698 int i;
5699 buf=Malloc1(lbuf+1,"Fromexternal");
5700 for(i=0; i<lbuf;i++){
5701 /*[18may20006 mt]:*/
5702 /*if( (cc=getcFromExtChannel())==EOF )*/
5703 /* May 2006: now getcFromExtChannelOk returns EOF while
5704 getcFromExtChannelFailure returns -2 (see comments in
5705 exctcmd.c):*/
5706 if( (cc=getcFromExtChannel())<1 )
5707 /*:[18may20006 mt]*/
5708 break;
5709 buf[i]=(UBYTE)(cc);
5710 }
5711 buf[i]='\0';
5712 /*[18may20006 mt]:*/
5713 /*if(cc!=EOF)
5714 while(getcFromExtChannel()!=EOF);*//*Eat the rest*/
5715 /* May 2006: now getcFromExtChannelOk returns EOF while
5716 getcFromExtChannelFailure returns -2 (see comments in
5717 exctcmd.c):*/
5718 if(cc>0)
5719 while(getcFromExtChannel()>0);/*Eat the rest*/
5720 else if(cc == -2){
5721 MesPrint("@No current external channel");
5722 return(-1);
5723 }
5724 /*:[18may20006 mt]*/
5725 }
5726 /*[18may20006 mt]:*/
5727 if(*prevar == '$'){/*Put the answer to the dollar variable*/
5728 int oldNumPotModdollars = NumPotModdollars;
5729 #ifdef WITHMPI
5730 WORD oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
5731 AC.RhsExprInModuleFlag = 0;
5732 #endif
5733 /*Here lbuf is the actual length of buf!*/
5734 /*"prevar=buf'\0'":*/
5735 UBYTE *pbuf=Malloc1(StrLen(prevar)+1+lbuf+1,"Fromexternal to dollar");
5736 UBYTE *c=pbuf;
5737 UBYTE *b=prevar;
5738 while(*b!='\0'){*c++ = *b++;}
5739 *c++='=';
5740 b=buf;
5741 while( (*c++=*b++)!='\0' );
5742 oldpreassignflag = AP.PreAssignFlag;
5743 AP.PreAssignFlag = 1;
5744 if ( ( cc = CompileStatement(pbuf) ) || ( cc = CatchDollar(0) ) ) {
5745 Error1("External channel: can't asign output to dollar variable ",prevar);
5746 }
5747 AP.PreAssignFlag = oldpreassignflag;
5748 NumPotModdollars = oldNumPotModdollars;
5749 #ifdef WITHMPI
5750 AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
5751 #endif
5752 M_free(pbuf,"Fromexternal to dollar");
5753 }else{
5754 cc = PutPreVar(prevar, buf, 0, 1) < 0;
5755 }
5756 /*:[18may20006 mt]*/
5757 M_free(buf,"Fromexternal");
5758 if ( cc ) return(-1);
5759 return(0);
5760 }
5761 /*:[02feb2006 mt]*/
5762 if ( OpenStream(s,EXTERNALCHANNELSTREAM,0,PRENOACTION) == 0 ) return(-1);
5763 /*[17may2006 mt]:*/
5764 AC.NoShowInput = withNoList;
5765 /*:[17may2006 mt]*/
5766 return(0);
5767 #else
5768 Error0("External channel: not implemented on this computer/system");
5769 return(-1);
5770 #endif
5771 }
5772
5773 /*
5774 #] DoFromExternal :
5775 #[ DoToExternal :
5776 #toexetrnal
5777 */
5778
5779 #ifdef WITHEXTERNALCHANNEL
5780
5781 /*A wrapper to writeBufToExtChannel, see the file extcmd.c:*/
WriteToExternalChannel(int handle,UBYTE * buffer,LONG size)5782 LONG WriteToExternalChannel(int handle, UBYTE *buffer, LONG size)
5783 {
5784 /*ATT! handle is not used! Actual output is performed to
5785 the current external channel, see extcmd.c!*/
5786 DUMMYUSE(handle);
5787 if(writeBufToExtChannel((char*)buffer,size))
5788 return(-1);
5789 return(size);
5790 }
5791 #endif /*ifdef WITHEXTERNALCHANNEL*/
5792
DoToExternal(UBYTE * s)5793 int DoToExternal(UBYTE *s)
5794 {
5795 #ifdef WITHEXTERNALCHANNEL
5796 HANDLERS h;
5797 LONG (*OldWrite)(int handle, UBYTE *buffer, LONG size) = WriteFile;
5798 int ret=-1;
5799 #else
5800 DUMMYUSE(s);
5801 #endif
5802 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
5803 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
5804 if ( AP.preError ) return(0);
5805 #ifdef WITHEXTERNALCHANNEL
5806
5807 h.oldsilent=AM.silent;
5808 h.newlogonly = h.oldlogonly = AM.FileOnlyFlag;
5809 h.newhandle = h.oldhandle = AC.LogHandle;
5810 h.oldprinttype = AO.PrintType;
5811
5812 WriteFile=&WriteToExternalChannel;
5813
5814 while ( *s == ' ' || *s == '\t' ) s++;
5815
5816 if(AX.currentExternalChannel==0){
5817 MesPrint("@No current external channel");
5818 goto DoToExternalReady;
5819 }
5820
5821 if(getCurrentExternalChannel()!=AX.currentExternalChannel)
5822 selectExternalChannel(AX.currentExternalChannel);
5823
5824 ret=writeToChannel(EXTERNALCHANNELOUT,s,&h);
5825 DoToExternalReady:
5826 WriteFile=OldWrite;
5827 return(ret);
5828 #else /*ifdef WITHEXTERNALCHANNEL*/
5829 Error0("External channel: not implemented on this computer/system");
5830 return(-1);
5831 #endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5832
5833 }
5834
5835 /*
5836 #] DoToExternal :
5837 #[ defineChannel :
5838 */
5839
defineChannel(UBYTE * s,HANDLERS * h)5840 UBYTE *defineChannel(UBYTE *s, HANDLERS *h)
5841 {
5842 UBYTE *name,*to;
5843
5844 if ( *s != '<' )
5845 return(s);
5846
5847 s++;
5848 name = to = s;
5849 while ( *s && *s != '>' ) {
5850 if ( *s == '\\' ) s++;
5851 *to++ = *s++;
5852 }
5853 if ( *s == 0 ) {
5854 MesPrint("@Improper termination of filename");
5855 return(0);
5856 }
5857 s++;
5858 *to = 0;
5859 if ( *name ) {
5860 h->newhandle = GetChannel((char *)name,0);
5861 h->newlogonly = 1;
5862 }
5863 else if ( AC.LogHandle >= 0 ) {
5864 h->newhandle = AC.LogHandle;
5865 h->newlogonly = 1;
5866 }
5867 return(s);
5868 }
5869
5870 /*
5871 #] defineChannel :
5872 #[ writeToChannel :
5873 */
5874
writeToChannel(int wtype,UBYTE * s,HANDLERS * h)5875 int writeToChannel(int wtype, UBYTE *s, HANDLERS *h)
5876 {
5877 UBYTE *to, *fstring, *ss, *sss, *s1, c, c1;
5878 WORD num, number, nfac;
5879 WORD oldOptimizationLevel;
5880 UBYTE Out[MAXLINELENGTH+14], *stopper;
5881 int nosemi, i;
5882 int plus = 0;
5883
5884 /*
5885 Now determine the format string
5886 */
5887 while ( *s == ',' || *s == ' ' ) s++;
5888 if ( *s != '"' ) {
5889 MesPrint("@No format string present");
5890 return(-1);
5891 }
5892 s++; fstring = to = s;
5893 while ( *s ) {
5894 if ( *s == '\\' ) {
5895 s++;
5896 if ( *s == '\\' ) {
5897 *to++ = *s++;
5898 if ( *s == '\\' ) *to++ = *s++;
5899 }
5900 else if ( *s == '"' ) *to++ = *s++;
5901 else { *to++ = '\\'; *to++ = *s++; }
5902 }
5903 else if ( *s == '"' ) break;
5904 else *to++ = *s++;
5905 }
5906 if ( *s != '"' ) {
5907 MesPrint("@No closing \" in format string");
5908 return(-1);
5909 }
5910 *to = 0; s++;
5911 if ( AC.LineLength > 20 && AC.LineLength <= MAXLINELENGTH ) stopper = Out + AC.LineLength;
5912 else stopper = Out + MAXLINELENGTH;
5913 to = Out;
5914 /*
5915 s points now at the list of objects (if any)
5916 we can start executing the format string.
5917 */
5918 AM.silent = 0;
5919 AC.LogHandle = h->newhandle;
5920 AM.FileOnlyFlag = h->newlogonly;
5921 if ( h->newhandle >= 0 ) {
5922 AO.PrintType |= PRINTLFILE;
5923 }
5924 while ( *fstring ) {
5925 if ( to >= stopper ) {
5926 if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
5927 *to++ = '&';
5928 }
5929 num = to - Out;
5930 WriteString(wtype,Out,num);
5931 to = Out;
5932 if ( AC.OutputMode == FORTRANMODE
5933 || AC.OutputMode == PFORTRANMODE ) {
5934 number = 7;
5935 for ( i = 0; i < number; i++ ) *to++ = ' ';
5936 to[-2] = '&';
5937 }
5938 }
5939 if ( *fstring == '\\' ) {
5940 fstring++;
5941 if ( *fstring == 'n' ) {
5942 num = to - Out;
5943 WriteString(wtype,Out,num);
5944 to = Out;
5945 fstring++;
5946 }
5947 else if ( *fstring == 't' ) { *to++ = '\t'; fstring++; }
5948 else if ( *fstring == 'b' ) { *to++ = '\\'; fstring++; }
5949 else *to++ = *fstring++;
5950 }
5951 else if ( *fstring == '%' ) {
5952 plus = 0;
5953 retry:
5954 fstring++;
5955 if ( *fstring == 'd' ) {
5956 int sign,dig;
5957 number = -1;
5958 donumber:
5959 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
5960 sign = 1;
5961 while ( *s == '+' || *s == '-' ) {
5962 if ( *s == '-' ) sign = -sign;
5963 s++;
5964 }
5965 dig = 0; ss = s; if ( sign < 0 ) { ss--; *ss = '-'; dig++; }
5966 while ( *s >= '0' && *s <= '9' ) { s++; dig++; }
5967 if ( number < 0 ) {
5968 while ( ss < s ) {
5969 if ( to >= stopper ) {
5970 num = to - Out;
5971 WriteString(wtype,Out,num);
5972 to = Out;
5973 }
5974 if ( *ss == '\\' ) ss++;
5975 *to++ = *ss++;
5976 }
5977 }
5978 else {
5979 if ( number < dig ) { dig = number; ss = s - dig; }
5980 while ( number > dig ) {
5981 if ( to >= stopper ) {
5982 num = to - Out;
5983 WriteString(wtype,Out,num);
5984 to = Out;
5985 }
5986 *to++ = ' '; number--;
5987 }
5988 while ( ss < s ) {
5989 if ( to >= stopper ) {
5990 num = to - Out;
5991 WriteString(wtype,Out,num);
5992 to = Out;
5993 }
5994 if ( *ss == '\\' ) ss++;
5995 *to++ = *ss++;
5996 }
5997 }
5998 fstring++;
5999 }
6000 else if ( *fstring == '$' ) {
6001 UBYTE *dolalloc;
6002 number = AO.OutSkip;
6003 dodollar:
6004 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
6005 if ( AC.OutputMode == FORTRANMODE
6006 || AC.OutputMode == PFORTRANMODE ) {
6007 number = 7;
6008 }
6009 if ( *s != '$' ) {
6010 nodollar: MesPrint("@$-variable expected in #write instruction");
6011 AM.FileOnlyFlag = h->oldlogonly;
6012 AC.LogHandle = h->oldhandle;
6013 AO.PrintType = h->oldprinttype;
6014 AM.silent = h->oldsilent;
6015 return(-1);
6016 }
6017 s++; ss = s;
6018 while ( chartype[*s] <= 1 ) s++;
6019 if ( s == ss ) goto nodollar;
6020 c = *s; *s = 0;
6021 num = GetDollar(ss);
6022 if ( num < 0 ) {
6023 MesPrint("@#write instruction: $%s has not been defined",ss);
6024 AM.FileOnlyFlag = h->oldlogonly;
6025 AC.LogHandle = h->oldhandle;
6026 AO.PrintType = h->oldprinttype;
6027 AM.silent = h->oldsilent;
6028 return(-1);
6029 }
6030 *s = c;
6031 if ( *s == '[' ) {
6032 if ( Dollars[num].nfactors <= 0 ) {
6033 *s = 0;
6034 MesPrint("@#write instruction: $%s has not been factorized",ss);
6035 AM.FileOnlyFlag = h->oldlogonly;
6036 AC.LogHandle = h->oldhandle;
6037 AO.PrintType = h->oldprinttype;
6038 AM.silent = h->oldsilent;
6039 return(-1);
6040 }
6041 /*
6042 Now get the number between the []
6043 */
6044 nfac = GetDollarNumber(&s,Dollars+num);
6045
6046 if ( Dollars[num].nfactors == 1 && nfac == 1 ) goto writewhole;
6047
6048 if ( ( dolalloc = WriteDollarFactorToBuffer(num,nfac,0) ) == 0 ) {
6049 AM.FileOnlyFlag = h->oldlogonly;
6050 AC.LogHandle = h->oldhandle;
6051 AO.PrintType = h->oldprinttype;
6052 AM.silent = h->oldsilent;
6053 return(-1);
6054 }
6055 goto writealloc;
6056 }
6057 else if ( *s && *s != ' ' && *s != ',' && *s != '\t' ) {
6058 MesPrint("@#write instruction: illegal characters after $-variable");
6059 AM.FileOnlyFlag = h->oldlogonly;
6060 AC.LogHandle = h->oldhandle;
6061 AO.PrintType = h->oldprinttype;
6062 AM.silent = h->oldsilent;
6063 return(-1);
6064 }
6065 else {
6066 writewhole:
6067 if ( ( dolalloc = WriteDollarToBuffer(num,0) ) == 0 ) {
6068 AM.FileOnlyFlag = h->oldlogonly;
6069 AC.LogHandle = h->oldhandle;
6070 AO.PrintType = h->oldprinttype;
6071 AM.silent = h->oldsilent;
6072 return(-1);
6073 }
6074 else {
6075 writealloc:
6076 ss = dolalloc;
6077 while ( *ss ) {
6078 if ( to >= stopper ) {
6079 if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
6080 *to++ = '&';
6081 }
6082 num = to - Out;
6083 WriteString(wtype,Out,num);
6084 to = Out;
6085 for ( i = 0; i < number; i++ ) *to++ = ' ';
6086 if ( AC.OutputMode == FORTRANMODE
6087 || AC.OutputMode == PFORTRANMODE ) to[-2] = '&';
6088 }
6089 if ( chartype[*ss] > 3 ) { *to++ = *ss++; }
6090 else {
6091 sss = ss; while ( chartype[*ss] <= 3 ) ss++;
6092 if ( ( to + (ss-sss) ) >= stopper ) {
6093 if ( (ss-sss) >= (stopper-Out) ) {
6094 if ( ( to - stopper ) < 10 ) {
6095 if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
6096 *to++ = '&';
6097 }
6098 num = to - Out;
6099 WriteString(wtype,Out,num);
6100 to = Out;
6101 for ( i = 0; i < number; i++ ) *to++ = ' ';
6102 if ( AC.OutputMode == FORTRANMODE
6103 || AC.OutputMode == PFORTRANMODE ) to[-2] = '&';
6104 }
6105 while ( (ss-sss) >= (stopper-Out) ) {
6106 while ( to < stopper-1 ) {
6107 *to++ = *sss++;
6108 }
6109 if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
6110 *to++ = '&';
6111 }
6112 else {
6113 *to++ = '\\';
6114 }
6115 num = to - Out;
6116 WriteString(wtype,Out,num);
6117 to = Out;
6118 if ( AC.OutputMode == FORTRANMODE
6119 || AC.OutputMode == PFORTRANMODE ) {
6120 for ( i = 0; i < number; i++ ) *to++ = ' ';
6121 to[-2] = '&';
6122 }
6123 }
6124 }
6125 else {
6126 if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
6127 *to++ = '&';
6128 }
6129 num = to - Out;
6130 WriteString(wtype,Out,num);
6131 to = Out;
6132 for ( i = 0; i < number; i++ ) *to++ = ' ';
6133 if ( AC.OutputMode == FORTRANMODE
6134 || AC.OutputMode == PFORTRANMODE ) to[-2] = '&';
6135 }
6136 }
6137 while ( sss < ss ) *to++ = *sss++;
6138 }
6139 }
6140 }
6141 M_free(dolalloc,"written dollar");
6142 fstring++;
6143 }
6144 }
6145 else if ( *fstring == 's' ) {
6146 fstring++;
6147 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
6148 if ( *s == '"' ) {
6149 s++; ss = s;
6150 while ( *s ) {
6151 if ( *s == '\\' ) s++;
6152 else if ( *s == '"' ) break;
6153 s++;
6154 }
6155 if ( *s == 0 ) {
6156 MesPrint("@#write instruction: Missing \" in string");
6157 AM.FileOnlyFlag = h->oldlogonly;
6158 AC.LogHandle = h->oldhandle;
6159 AO.PrintType = h->oldprinttype;
6160 AM.silent = h->oldsilent;
6161 return(-1);
6162 }
6163 while ( ss < s ) {
6164 if ( to >= stopper ) {
6165 num = to - Out;
6166 WriteString(wtype,Out,num);
6167 to = Out;
6168 }
6169 if ( *ss == '\\' ) ss++;
6170 *to++ = *ss++;
6171 }
6172 s++;
6173 }
6174 else {
6175 sss = ss = s;
6176 while ( *s && *s != ',' ) {
6177 if ( *s == '\\' ) { s++; sss = s+1; }
6178 s++;
6179 }
6180 while ( s > sss+1 && ( s[-1] == ' ' || s[-1] == '\t' ) ) s--;
6181 while ( ss < s ) {
6182 if ( to >= stopper ) {
6183 num = to - Out;
6184 WriteString(wtype,Out,num);
6185 to = Out;
6186 }
6187 if ( *ss == '\\' ) ss++;
6188 *to++ = *ss++;
6189 }
6190 }
6191 }
6192 else if ( *fstring == 'X' ) {
6193 fstring++;
6194 if ( cbuf[AM.sbufnum].numrhs > 0 ) {
6195 /*
6196 This should be only to the value of AM.oldnumextrasymbols
6197 */
6198 UBYTE *s = GetPreVar(AM.oldnumextrasymbols,0);
6199 WORD x = 0;
6200 while ( *s >= '0' && *s <= '9' ) x = 10*x + *s++ - '0';
6201 if ( x > 0 )
6202 PrintSubtermList(1,x);
6203 else
6204 PrintSubtermList(1,cbuf[AM.sbufnum].numrhs);
6205 }
6206 }
6207 else if ( *fstring == 'O' ) {
6208 number = AO.OutSkip;
6209 dooptim:
6210 fstring++;
6211 /*
6212 First test whether there is an optimization buffer
6213 */
6214 if ( AO.OptimizeResult.code == NULL && AO.OptimizationLevel != 0 ) {
6215 MesPrint("@In #write instruction: no optimization results available!");
6216 return(-1);
6217 }
6218 num = to - Out;
6219 WriteString(wtype,Out,num);
6220 to = Out;
6221 if ( AO.OptimizationLevel != 0 ) {
6222 WORD oldoutskip = AO.OutSkip;
6223 AO.OutSkip = number;
6224 optimize_print_code(0);
6225 AO.OutSkip = oldoutskip;
6226 }
6227 }
6228 else if ( *fstring == 'e' || *fstring == 'E' ) {
6229 if ( *fstring == 'E'
6230 || AC.OutputMode == FORTRANMODE
6231 || AC.OutputMode == PFORTRANMODE ) nosemi = 1;
6232 else nosemi = 0;
6233 fstring++;
6234 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
6235 if ( chartype[*s] != 0 && *s != '[' ) {
6236 noexpr: MesPrint("@expression name expected in #write instruction");
6237 AM.FileOnlyFlag = h->oldlogonly;
6238 AC.LogHandle = h->oldhandle;
6239 AO.PrintType = h->oldprinttype;
6240 AM.silent = h->oldsilent;
6241 return(-1);
6242 }
6243 ss = s;
6244 if ( ( s = SkipAName(ss) ) == 0 || s[-1] == '_' ) goto noexpr;
6245 s1 = s; c = c1 = *s1;
6246 if ( c1 == '(' ) {
6247 SKIPBRA3(s)
6248 if ( *s == ')' ) {
6249 AO.CurBufWrt = s1+1;
6250 c = *s; *s = 0;
6251 }
6252 else {
6253 MesPrint("@Illegal () specifier in expression name in #write");
6254 AM.FileOnlyFlag = h->oldlogonly;
6255 AC.LogHandle = h->oldhandle;
6256 AO.PrintType = h->oldprinttype;
6257 AM.silent = h->oldsilent;
6258 return(-1);
6259 }
6260 }
6261 else AO.CurBufWrt = (UBYTE *)underscore;
6262 *s1 = 0;
6263 num = to - Out;
6264 if ( num > 0 ) WriteUnfinString(wtype,Out,num);
6265 to = Out;
6266 oldOptimizationLevel = AO.OptimizationLevel;
6267 AO.OptimizationLevel = 0;
6268 if ( WriteOne(ss,(int)num,nosemi,plus) < 0 ) {
6269 AM.FileOnlyFlag = h->oldlogonly;
6270 AC.LogHandle = h->oldhandle;
6271 AO.PrintType = h->oldprinttype;
6272 AM.silent = h->oldsilent;
6273 return(-1);
6274 }
6275 AO.OptimizationLevel = oldOptimizationLevel;
6276 *s1 = c1;
6277 if ( s > s1 ) *s++ = c;
6278 }
6279 /*
6280 File content
6281 */
6282 else if ( ( *fstring == 'f' ) || ( *fstring == 'F' ) ) {
6283 LONG n;
6284 while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
6285 ss = s;
6286 while ( *s && *s != ',' ) {
6287 if ( *s == '\\' ) s++;
6288 s++;
6289 }
6290 c = *s; *s = 0;
6291 s1 = LoadInputFile(ss,HEADERFILE);
6292 *s = c;
6293 /*
6294 There should have been a way to pass the file size.
6295 Also there should be conversions for \r\n etc.
6296 */
6297 if ( s1 ) {
6298 ss = s1; while ( *ss ) ss++;
6299 n = ss-s1;
6300 WriteString(wtype,s1,n);
6301 M_free(s1,"copy file");
6302 }
6303 else if ( *fstring == 'F' ) {
6304 *s = 0;
6305 MesPrint("@Error in #write: could not open file %s",ss);
6306 *s = c;
6307 goto ReturnWithError;
6308 }
6309 fstring++;
6310 }
6311 else if ( *fstring == '%' ) {
6312 *to++ = *fstring++;
6313 }
6314 else if ( FG.cTable[*fstring] == 1 ) { /* %#S */
6315 number = 0;
6316 while ( FG.cTable[*fstring] == 1 ) {
6317 number = 10*number + *fstring++ - '0';
6318 }
6319 if ( *fstring == 'O' ) goto dooptim;
6320 else if ( *fstring == 'd' ) goto donumber;
6321 else if ( *fstring == '$' ) goto dodollar;
6322 else if ( *fstring == 'X' || *fstring == 'x' ) {
6323 if ( number > 0 && number <= cbuf[AM.sbufnum].numrhs ) {
6324 UBYTE buffer[80], *out, *old1, *old2, *old3;
6325 WORD *term, first;
6326 if ( *fstring == 'X' ) {
6327 out = StrCopy((UBYTE *)AC.extrasym,buffer);
6328 if ( AC.extrasymbols == 0 ) {
6329 out = NumCopy(number,out);
6330 out = StrCopy((UBYTE *)"_",out);
6331 }
6332 else if ( AC.extrasymbols == 1 ) {
6333 if ( AC.OutputMode == CMODE ) {
6334 out = StrCopy((UBYTE *)"[",out);
6335 out = NumCopy(number,out);
6336 out = StrCopy((UBYTE *)"]",out);
6337 }
6338 else {
6339 out = StrCopy((UBYTE *)"(",out);
6340 out = NumCopy(number,out);
6341 out = StrCopy((UBYTE *)")",out);
6342 }
6343 }
6344 out = StrCopy((UBYTE *)"=",out);
6345 ss = buffer;
6346 while ( ss < out ) {
6347 if ( to >= stopper ) {
6348 num = to - Out;
6349 WriteString(wtype,Out,num);
6350 to = Out;
6351 }
6352 *to++ = *ss++;
6353 }
6354 }
6355 term = cbuf[AM.sbufnum].rhs[number];
6356 first = 1;
6357 if ( *term == 0 ) {
6358 *to++ = '0';
6359 }
6360 else {
6361 old1 = AO.OutFill;
6362 old2 = AO.OutputLine;
6363 old3 = AO.OutStop;
6364 AO.OutFill = to;
6365 AO.OutputLine = Out;
6366 AO.OutStop = Out + AC.LineLength;
6367 while ( *term ) {
6368 if ( WriteInnerTerm(term,first) ) Terminate(-1);
6369 term += *term;
6370 first = 0;
6371 }
6372 to = Out + (AO.OutFill-AO.OutputLine);
6373 AO.OutFill = old1;
6374 AO.OutputLine = old2;
6375 AO.OutStop = old3;
6376 }
6377 }
6378 fstring++;
6379 }
6380 else {
6381 goto IllegControlSequence;
6382 }
6383 }
6384 else if ( *fstring == '+' ) {
6385 plus = 1; goto retry;
6386 }
6387 else if ( *fstring == 0 ) {
6388 *to++ = 0;
6389 }
6390 else {
6391 IllegControlSequence:
6392 MesPrint("@Illegal control sequence in format string in #write instruction");
6393 ReturnWithError:
6394 AM.FileOnlyFlag = h->oldlogonly;
6395 AC.LogHandle = h->oldhandle;
6396 AO.PrintType = h->oldprinttype;
6397 AM.silent = h->oldsilent;
6398 return(-1);
6399 }
6400 }
6401 else {
6402 *to++ = *fstring++;
6403 }
6404 }
6405 /*
6406 Now flush the output
6407 */
6408 num = to - Out;
6409 /*[15apr2004 mt]:*/
6410 if(wtype==EXTERNALCHANNELOUT){
6411 if(num!=0)
6412 WriteUnfinString(wtype,Out,num);
6413 }else
6414 /*:[15apr2004 mt]*/
6415 WriteString(wtype,Out,num);
6416 /*
6417 and restore original parameters
6418 */
6419 AM.FileOnlyFlag = h->oldlogonly;
6420 AC.LogHandle = h->oldhandle;
6421 AO.PrintType = h->oldprinttype;
6422 AM.silent = h->oldsilent;
6423 return(0);
6424 }
6425
6426 /*
6427 #] writeToChannel :
6428 #[ DoFactDollar :
6429
6430 Executes the #factdollar $var
6431 instruction
6432 */
6433
DoFactDollar(UBYTE * s)6434 int DoFactDollar(UBYTE *s)
6435 {
6436 GETIDENTITY
6437 WORD numdollar, *oldworkpointer;
6438
6439 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
6440 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
6441 while ( *s == ' ' || *s == '\t' ) s++;
6442 if ( *s == '$' ) {
6443 if ( GetName(AC.dollarnames,s+1,&numdollar,NOAUTO) != CDOLLAR ) {
6444 MesPrint("@%s is undefined",s);
6445 return(-1);
6446 }
6447 s = SkipAName(s+1);
6448 if ( *s != 0 ) {
6449 MesPrint("@#FactDollar should have a single $variable for its argument");
6450 return(-1);
6451 }
6452 NewSort(BHEAD0);
6453 oldworkpointer = AT.WorkPointer;
6454 if ( DollarFactorize(BHEAD numdollar) ) return(-1);
6455 AT.WorkPointer = oldworkpointer;
6456 LowerSortLevel();
6457 return(0);
6458 }
6459 else if ( ParenthesesTest(s) ) return(-1);
6460 else {
6461 MesPrint("@#FactDollar should have a single $variable for its argument");
6462 return -1;
6463 }
6464 }
6465
6466 /*
6467 #] DoFactDollar :
6468 #[ GetDollarNumber :
6469 */
6470
GetDollarNumber(UBYTE ** inp,DOLLARS d)6471 WORD GetDollarNumber(UBYTE **inp, DOLLARS d)
6472 {
6473 UBYTE *s = *inp, c, *name;
6474 WORD number, nfac, *w;
6475 DOLLARS dd;
6476 s++;
6477 if ( *s == '$' ) {
6478 s++; name = s;
6479 while ( FG.cTable[*s] < 2 ) s++;
6480 c = *s; *s = 0;
6481 if ( GetName(AC.dollarnames,name,&number,NOAUTO) == NAMENOTFOUND ) {
6482 MesPrint("@dollar in #write should have been defined previously");
6483 Terminate(-1);
6484 }
6485 *s = c;
6486 dd = Dollars + number;
6487 if ( c == '[' ) {
6488 *inp = s;
6489 nfac = GetDollarNumber(inp,dd);
6490 s = *inp;
6491 if ( *s != ']' ) {
6492 MesPrint("@Illegal factor for dollar variable");
6493 Terminate(-1);
6494 }
6495 *inp = s+1;
6496 if ( nfac == 0 ) {
6497 if ( dd->nfactors > d->nfactors ) {
6498 TooBig:
6499 MesPrint("@Factor number for dollar variable too large");
6500 Terminate(-1);
6501 }
6502 return(dd->nfactors);
6503 }
6504 w = dd->factors[nfac-1].where;
6505 if ( w == 0 ) {
6506 if ( dd->factors[nfac-1].value > d->nfactors ||
6507 dd->factors[nfac-1].value < 0 ) goto TooBig;
6508 return(dd->factors[nfac-1].value);
6509 }
6510 if ( *w == 4 && w[4] == 0 && w[3] == 3 && w[2] == 1
6511 && w[1] <= d->nfactors ) return(w[1]);
6512 if ( w[*w] == 0 && w[*w-1] == *w-1 ) goto TooBig;
6513 IllNum:
6514 MesPrint("@Illegal factor number for dollar variable");
6515 Terminate(-1);
6516 }
6517 else { /* The dollar should be a number */
6518 if ( dd->type == DOLZERO ) {
6519 return(0);
6520 }
6521 else if ( dd->type == DOLTERMS || dd->type == DOLNUMBER ) {
6522 w = dd->where;
6523 if ( *w == 4 && w[4] == 0 && w[3] == 3 && w[2] == 1
6524 && w[1] <= d->nfactors ) return(w[1]);
6525 if ( w[*w] == 0 && w[*w-1] == *w-1 ) goto TooBig;
6526 goto IllNum;
6527 }
6528 else goto IllNum;
6529 }
6530 }
6531 else if ( FG.cTable[*s] == 1 ) {
6532 WORD x = *s++ - '0';
6533 while ( FG.cTable[*s] == 1 ) {
6534 x = 10*x + *s++ - '0';
6535 if ( x > d->nfactors ) {
6536 MesPrint("@Factor number %d for dollar variable too large",x);
6537 Terminate(-1);
6538 }
6539 }
6540 if ( *s != ']' ) {
6541 MesPrint("@Illegal factor number for dollar variable");
6542 Terminate(-1);
6543 }
6544 s++; *inp = s;
6545 return(x);
6546 }
6547 else {
6548 MesPrint("@Illegal factor indicator for dollar variable");
6549 Terminate(-1);
6550 }
6551 return(-1);
6552 }
6553
6554 /*
6555 #] GetDollarNumber :
6556 #[ DoSetRandom :
6557
6558 Executes the #SetRandom number
6559 */
6560
DoSetRandom(UBYTE * s)6561 int DoSetRandom(UBYTE *s)
6562 {
6563 ULONG x;
6564 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
6565 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
6566 while ( *s == ' ' || *s == '\t' ) s++;
6567 x = 0;
6568 while ( FG.cTable[*s] == 1 ) {
6569 x = 10*x + (*s++-'0');
6570 }
6571 while ( *s == ' ' || *s == '\t' ) s++;
6572 if ( *s == 0 ) {
6573 #ifdef WITHPTHREADS
6574 #ifdef WITHSORTBOTS
6575 int id, totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
6576 #else
6577 int id, totnum = AM.totalnumberofthreads;
6578 #endif
6579 for ( id = 0; id < totnum; id++ ) {
6580 AB[id]->R.wranfseed = x;
6581 if ( AB[id]->R.wranfia ) M_free(AB[id]->R.wranfia,"wranf");
6582 AB[id]->R.wranfia = 0;
6583 }
6584 #else
6585 AR.wranfseed = x;
6586 if ( AR.wranfia ) M_free(AR.wranfia,"wranf");
6587 AR.wranfia = 0;
6588 #endif
6589 return(0);
6590 }
6591 else {
6592 MesPrint("@proper syntax is #SetRandom number");
6593 return(-1);
6594 }
6595 }
6596
6597 /*
6598 #] DoSetRandom :
6599 #[ DoOptimize :
6600
6601 Executes the #Optimize(expr) instruction.
6602 */
6603
DoOptimize(UBYTE * s)6604 int DoOptimize(UBYTE *s)
6605 {
6606 GETIDENTITY
6607 UBYTE *exprname;
6608 WORD numexpr;
6609 int error = 0, i;
6610 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
6611 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
6612 DUMMYUSE(*s)
6613 exprname = s; s = SkipAName(s);
6614 if ( *s != 0 && *s != ';' ) {
6615 MesPrint("@proper syntax is #Optimize,expression");
6616 return(-1);
6617 }
6618 *s = 0;
6619 if ( GetName(AC.exprnames,exprname,&numexpr,NOAUTO) != CEXPRESSION ) {
6620 MesPrint("@%s is not an expression",exprname);
6621 error = 1;
6622 }
6623 else if ( AP.preError == 0 ) {
6624 EXPRESSIONS e = Expressions + numexpr;
6625 POSITION position;
6626 int firstterm;
6627 WORD *term = AT.WorkPointer;
6628 ClearOptimize();
6629 if ( AO.OptimizationLevel == 0 ) return(0);
6630 switch ( e->status ) {
6631 case LOCALEXPRESSION:
6632 case GLOBALEXPRESSION:
6633 break;
6634 default:
6635 MesPrint("@Expression %s is not an active unhidden local or global expression.",exprname);
6636 Terminate(-1);
6637 break;
6638 }
6639 #ifdef WITHMPI
6640 if ( PF.me == MASTER )
6641 #endif
6642 RevertScratch();
6643 for ( i = NumExpressions-1; i >= 0; i-- ) {
6644 AS.OldOnFile[i] = Expressions[i].onfile;
6645 AS.OldNumFactors[i] = Expressions[i].numfactors;
6646 AS.Oldvflags[i] = Expressions[i].vflags;
6647 Expressions[i].vflags &= ~(ISUNMODIFIED|ISZERO);
6648 }
6649 for ( i = 0; i < NumExpressions; i++ ) {
6650 if ( i == numexpr ) {
6651 PutPreVar(AM.oldnumextrasymbols,
6652 GetPreVar((UBYTE *)"EXTRASYMBOLS_",0),0,1);
6653 Optimize(numexpr, 0);
6654 AO.OptimizeResult.nameofexpr = strDup1(exprname,"optimize expression name");
6655 continue;
6656 }
6657 #ifdef WITHMPI
6658 if ( PF.me == MASTER ) {
6659 #endif
6660 e = Expressions + i;
6661 switch ( e->status ) {
6662 case LOCALEXPRESSION:
6663 case SKIPLEXPRESSION:
6664 case DROPLEXPRESSION:
6665 case DROPPEDEXPRESSION:
6666 case GLOBALEXPRESSION:
6667 case SKIPGEXPRESSION:
6668 case DROPGEXPRESSION:
6669 case HIDELEXPRESSION:
6670 case HIDEGEXPRESSION:
6671 case DROPHLEXPRESSION:
6672 case DROPHGEXPRESSION:
6673 case INTOHIDELEXPRESSION:
6674 case INTOHIDEGEXPRESSION:
6675 break;
6676 default:
6677 continue;
6678 }
6679 AR.GetFile = 0;
6680 SetScratch(AR.infile,&(e->onfile));
6681 if ( GetTerm(BHEAD term) <= 0 ) {
6682 MesPrint("@Expression %d has problems reading from scratchfile",i);
6683 Terminate(-1);
6684 }
6685 term[3] = i;
6686 AR.DeferFlag = 0;
6687 SeekScratch(AR.outfile,&position);
6688 e->onfile = position;
6689 *AM.S0->sBuffer = 0; firstterm = -1;
6690 do {
6691 WORD *oldipointer = AR.CompressPointer;
6692 WORD *comprtop = AR.ComprTop;
6693 AR.ComprTop = AM.S0->sTop;
6694 AR.CompressPointer = AM.S0->sBuffer;
6695 if ( firstterm > 0 ) {
6696 if ( PutOut(BHEAD term,&position,AR.outfile,1) < 0 ) goto DoSerr;
6697 }
6698 else if ( firstterm < 0 ) {
6699 if ( PutOut(BHEAD term,&position,AR.outfile,0) < 0 ) goto DoSerr;
6700 firstterm++;
6701 }
6702 else {
6703 if ( PutOut(BHEAD term,&position,AR.outfile,-1) < 0 ) goto DoSerr;
6704 firstterm++;
6705 }
6706 AR.CompressPointer = oldipointer;
6707 AR.ComprTop = comprtop;
6708 } while ( GetTerm(BHEAD term) );
6709 if ( FlushOut(&position,AR.outfile,1) ) {
6710 DoSerr:
6711 MesPrint("@Expression %d has problems writing to scratchfile",i);
6712 Terminate(-1);
6713 }
6714 #ifdef WITHMPI
6715 }
6716 #endif
6717 }
6718 /*
6719 Now some administration and we are done
6720 */
6721 UpdateMaxSize();
6722 }
6723 else {
6724 ClearOptimize();
6725 }
6726 return(error);
6727
6728 }
6729
6730 /*
6731 #] DoOptimize :
6732 #[ DoClearOptimize :
6733
6734 Clears all relevant buffers of the output optimization
6735 */
6736
DoClearOptimize(UBYTE * s)6737 int DoClearOptimize(UBYTE *s)
6738 {
6739 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
6740 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
6741 DUMMYUSE(*s);
6742 return(ClearOptimize());
6743 }
6744
6745 /*
6746 #] DoClearOptimize :
6747 #[ DoSkipExtraSymbols :
6748
6749 Adds the intermediate variables of the previous optimization
6750 to the list of extra symbols, provided it has not yet been erased
6751 by a #clearoptimize
6752 To remove them again one needs to use the 'delete extrasymbols;'
6753 or the 'delete extrasymbols>num;' statement in which num is the
6754 old number of extra symbols.
6755 */
6756
DoSkipExtraSymbols(UBYTE * s)6757 int DoSkipExtraSymbols(UBYTE *s)
6758 {
6759 CBUF *C = cbuf + AM.sbufnum;
6760 WORD tt = 0, j = 0, oldval = AO.OptimizeResult.minvar;
6761 if ( AO.OptimizeResult.code == NULL ) return(0);
6762 if ( AO.OptimizationLevel == 0 ) return(0);
6763 while ( *s == ',' ) s++;
6764 if ( *s == 0 ) {
6765 AO.OptimizeResult.minvar = AO.OptimizeResult.maxvar+1;
6766 }
6767 else {
6768 while ( *s <= '9' && *s >= '0' ) j = 10*j + *s++ - '0';
6769 if ( *s ) {
6770 MesPrint("@Illegal use of #SkipExtraSymbols instruction");
6771 Terminate(-1);
6772 }
6773 AO.OptimizeResult.minvar += j;
6774 if ( AO.OptimizeResult.minvar > AO.OptimizeResult.maxvar )
6775 AO.OptimizeResult.minvar = AO.OptimizeResult.maxvar+1;
6776 }
6777 j = AO.OptimizeResult.minvar - oldval;
6778 while ( j > 0 ) {
6779 AddRHS(AM.sbufnum,1);
6780 AddNtoC(AM.sbufnum,1,&tt,16);
6781 AddToCB(C,0)
6782 InsTree(AM.sbufnum,C->numrhs);
6783 j--;
6784 }
6785 return(0);
6786 }
6787
6788 /*
6789 #] DoSkipExtraSymbols :
6790 #[ DoPreReset :
6791
6792 Does a reset of variables.
6793 Currently only the timer (stopwatch) of `timer_'
6794 */
6795
DoPreReset(UBYTE * s)6796 int DoPreReset(UBYTE *s)
6797 {
6798 UBYTE *ss, c;
6799 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
6800 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
6801 while ( *s == ' ' || *s == '\t' ) s++;
6802 if ( *s == 0 ) {
6803 MesPrint("@proper syntax is #Reset variable");
6804 return(-1);
6805 }
6806 ss = s;
6807 while ( FG.cTable[*s] == 0 ) s++;
6808 c = *s; *s = 0;
6809 if ( ( StrICmp(ss,(UBYTE *)"timer") == 0 )
6810 || ( StrICmp(ss,(UBYTE *)"stopwatch") == 0 ) ) {
6811 *s = c;
6812 AP.StopWatchZero = GetRunningTime();
6813 return(0);
6814 }
6815 else {
6816 *s = c;
6817 MesPrint("@proper syntax is #Reset variable");
6818 return(-1);
6819 }
6820 }
6821
6822 /*
6823 #] DoPreReset :
6824 #[ DoPreAppendPath :
6825 */
6826
DoAddPath(UBYTE * s,int bPrepend)6827 static int DoAddPath(UBYTE *s, int bPrepend)
6828 {
6829 /* NOTE: this doesn't support some file systems, e.g., 0x5c with CP932. */
6830
6831 UBYTE *path, *path_end, *current_dir, *current_dir_end, *NewPath, *t;
6832 int bRelative, n;
6833
6834 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
6835 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
6836
6837 /* Parse the path in the input. */
6838 while ( *s == ' ' || *s == '\t' ) s++; /* skip spaces */
6839 if ( *s == '"' ) { /* the path is given by "..." */
6840 path = ++s;
6841 while ( *s && *s != '"' ) {
6842 if ( SEPARATOR != '\\' && *s == '\\' ) { /* escape character, e.g., "\\\"" */
6843 if ( !s[1] ) goto ImproperPath;
6844 s++;
6845 }
6846 s++;
6847 }
6848 if ( *s != '"' ) goto ImproperPath;
6849 path_end = s++;
6850 }
6851 else {
6852 path = s;
6853 while ( *s && *s != ' ' && *s != '\t' ) {
6854 if ( SEPARATOR != '\\' && *s == '\\' ) { /* escape character, e.g., "\\ " */
6855 if ( !s[1] ) goto ImproperPath;
6856 s++;
6857 }
6858 s++;
6859 }
6860 path_end = s;
6861 }
6862 if ( path == path_end ) goto ImproperPath; /* empty path */
6863 while ( *s == ' ' || *s == '\t' ) s++; /* skip spaces */
6864 if ( *s ) goto ImproperPath; /* extra tokens found */
6865
6866 /* Check if the path is an absolute path. */
6867 bRelative = 1;
6868 if ( path[0] == SEPARATOR ) { /* starts with the directory separator */
6869 bRelative = 0;
6870 }
6871 #ifdef WINDOWS
6872 else if ( chartype[path[0]] == 0 && path[1] == ':' ) { /* starts with (drive letter): */
6873 bRelative = 0;
6874 }
6875 #endif
6876
6877 /* Get the current file directory when a relative path is given. */
6878 if ( bRelative ) {
6879 if ( !AC.CurrentStream ) goto FileNameUnavailable;
6880 if ( AC.CurrentStream->type != FILESTREAM && AC.CurrentStream->type != REVERSEFILESTREAM ) goto FileNameUnavailable;
6881 if ( !AC.CurrentStream->name ) goto FileNameUnavailable;
6882 s = current_dir = current_dir_end = AC.CurrentStream->name;
6883 while ( *s ) {
6884 if ( SEPARATOR != '\\' && *s == '\\' && s[1] ) { /* escape character, e.g., "\\\"" */
6885 s += 2;
6886 continue;
6887 }
6888 if ( *s == SEPARATOR ) {
6889 current_dir_end = s;
6890 }
6891 s++;
6892 }
6893 }
6894 else {
6895 current_dir = current_dir_end = NULL;
6896 }
6897
6898 /* Allocate a buffer for new AM.Path. */
6899 n = path_end - path;
6900 if ( AM.Path ) n += StrLen(AM.Path) + 1;
6901 if ( current_dir != current_dir_end ) n+= current_dir_end - current_dir + 1;
6902 s = NewPath = (UBYTE *)Malloc1(n + 1,"add path");
6903
6904 /* Construct new FORM path. */
6905 if ( bPrepend ) {
6906 if ( current_dir != current_dir_end ) {
6907 t = current_dir;
6908 while ( t != current_dir_end ) *s++ = *t++;
6909 *s++ = SEPARATOR;
6910 }
6911 t = path;
6912 while ( t != path_end ) *s++ = *t++;
6913 if ( AM.Path ) *s++ = PATHSEPARATOR;
6914 }
6915 if ( AM.Path ) {
6916 t = AM.Path;
6917 while ( *t ) *s++ = *t++;
6918 }
6919 if ( !bPrepend ) {
6920 if ( AM.Path ) *s++ = PATHSEPARATOR;
6921 if ( current_dir != current_dir_end ) {
6922 t = current_dir;
6923 while ( t != current_dir_end ) *s++ = *t++;
6924 *s++ = SEPARATOR;
6925 }
6926 t = path;
6927 while ( t != path_end ) *s++ = *t++;
6928 }
6929 *s = '\0';
6930
6931 /* Update AM.Path. */
6932 if ( AM.Path ) M_free(AM.Path,"add path");
6933 AM.Path = NewPath;
6934
6935 return(0);
6936
6937 ImproperPath:
6938 MesPrint("@Improper syntax for %#%sPath", bPrepend ? "Prepend" : "Append");
6939 return(-1);
6940
6941 FileNameUnavailable:
6942 /* This may be improved in future. */
6943 MesPrint("@Sorry, %#%sPath can't resolve the current file name from here", bPrepend ? "Prepend" : "Append");
6944 return(-1);
6945 }
6946
6947 /**
6948 * Appends the given path (absolute or relative to the current file directory)
6949 * to the FORM path.
6950 *
6951 * Syntax:
6952 * #appendpath <path>
6953 */
DoPreAppendPath(UBYTE * s)6954 int DoPreAppendPath(UBYTE *s)
6955 {
6956 return DoAddPath(s, 0);
6957 }
6958
6959 /*
6960 #] DoPreAppendPath :
6961 #[ DoPrePrependPath :
6962 */
6963
6964 /**
6965 * Prepends the given path (absolute or relative to the current file directory)
6966 * to the FORM path.
6967 *
6968 * Syntax:
6969 * #prependpath <path>
6970 */
DoPrePrependPath(UBYTE * s)6971 int DoPrePrependPath(UBYTE *s)
6972 {
6973 return DoAddPath(s, 1);
6974 }
6975
6976 /*
6977 #] DoPrePrependPath :
6978 #[ DoTimeOutAfter :
6979
6980 Executes the #timeoutafter number
6981 */
6982
DoTimeOutAfter(UBYTE * s)6983 int DoTimeOutAfter(UBYTE *s)
6984 {
6985 ULONG x;
6986 if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
6987 if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
6988 while ( *s == ' ' || *s == '\t' ) s++;
6989 x = 0;
6990 while ( FG.cTable[*s] == 1 ) {
6991 x = 10*x + (*s++-'0');
6992 }
6993 while ( *s == ' ' || *s == '\t' ) s++;
6994 if ( *s == 0 ) {
6995 alarm(x);
6996 return(0);
6997 }
6998 else {
6999 MesPrint("@proper syntax is #TimeoutAfter number");
7000 return(-1);
7001 }
7002 }
7003
7004 /*
7005 #] DoTimeOutAfter :
7006 # ] PreProcessor :
7007 */
7008