• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vermaseren / form / 9364948935

04 Jun 2024 09:49AM UTC coverage: 49.979% (-0.02%) from 49.999%
9364948935

Pull #526

github

web-flow
Merge 7062bd769 into 83e3d4185
Pull Request #526: RFC: better debugging

52 of 415 new or added lines in 46 files covered. (12.53%)

32 existing lines in 2 files now uncovered.

41391 of 82816 relevant lines covered (49.98%)

878690.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.66
/sources/pre.c
1
/** @file pre.c
2
 *
3
 *  This is the preprocessor and all its routines.
4
 */
5
/* #[ License : */
6
/*
7
 *   Copyright (C) 1984-2023 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
        ,{"clearflag"    , DoClearUserFlag, 0, 0}
54
        ,{"clearoptimize", DoClearOptimize, 0, 0}
55
        ,{"close"        , DoPreClose     , 0, 0}
56
        ,{"closedictionary", DoPreCloseDictionary,0,0}
57
        ,{"commentchar"  , DoCommentChar  , 0, 0}
58
        ,{"continuedo"  ,  DoContinueDo   , 0, 0}
59
        ,{"create"       , DoPreCreate    , 0, 0}
60
        ,{"debug"        , DoDebug        , 0, 0}
61
        ,{"default"      , DoPreDefault   , 0, 0}
62
        ,{"define"       , DoDefine       , 0, 0}
63
        ,{"do"           , DoDo           , 0, 0}
64
        ,{"else"         , DoElse         , 0, 0}
65
        ,{"elseif"       , DoElseif       , 0, 0}
66
        ,{"enddo"        , DoEnddo        , 0, 0}
67
#ifdef WITHFLOAT
68
    ,{"endfloat"     , DoEndFloat     , 0, 0}
69
#endif
70
        ,{"endif"        , DoEndif        , 0, 0}
71
        ,{"endinside"    , DoEndInside    , 0, 0}
72
        ,{"endnamespace" , DoEndNamespace , 0, 0}
73
        ,{"endprocedure" , DoEndprocedure , 0, 0}
74
        ,{"endswitch"    , DoPreEndSwitch , 0, 0}
75
        ,{"exchange"     , DoPreExchange  , 0, 0}
76
        ,{"external"     , DoExternal     , 0, 0}
77
        ,{"factdollar"   , DoFactDollar   , 0, 0}
78
        ,{"fromexternal" , DoFromExternal , 0, 0}
79
        ,{"if"           , DoIf           , 0, 0}
80
        ,{"ifdef"        , DoIfydef       , 0, 0}
81
        ,{"ifndef"       , DoIfndef       , 0, 0}
82
        ,{"include"      , DoInclude      , 0, 0}
83
        ,{"inside"       , DoInside       , 0, 0}
84
        ,{"message"      , DoMessage      , 0, 0}
85
        ,{"namespace"    , DoNamespace    , 0, 0}
86
        ,{"opendictionary", DoPreOpenDictionary,0,0}
87
        ,{"optimize"     , DoOptimize     , 0, 0}
88
        ,{"pipe"         , DoPipe         , 0, 0}
89
        ,{"preout"       , DoPreOut       , 0, 0}
90
        ,{"prependpath"  , DoPrePrependPath,0, 0}
91
        ,{"printtimes"   , DoPrePrintTimes, 0, 0}
92
        ,{"procedure"    , DoProcedure    , 0, 0}
93
        ,{"procedureextension" , DoPrcExtension   , 0, 0}
94
        ,{"prompt"       , DoPrompt       , 0, 0}
95
        ,{"redefine"     , DoRedefine     , 0, 0}
96
        ,{"remove"       , DoPreRemove    , 0, 0}
97
        ,{"reset"        , DoPreReset     , 0, 0}
98
        ,{"reverseinclude"   , DoReverseInclude   , 0, 0}
99
        ,{"rmexternal"   , DoRmExternal   , 0, 0}
100
        ,{"rmseparator"  , DoPreRmSeparator,0, 0}
101
        ,{"setexternal"  , DoSetExternal  , 0, 0}
102
        ,{"setexternalattr"  , DoSetExternalAttr  , 0, 0}
103
        ,{"setflag"      , DoSetUserFlag  , 0, 0}
104
        ,{"setrandom"    , DoSetRandom    , 0, 0}
105
        ,{"show"         , DoPreShow      , 0, 0}
106
        ,{"skipextrasymbols" , DoSkipExtraSymbols , 0, 0}
107
#ifdef WITHFLOAT
108
    ,{"startfloat"   , DoStartFloat   , 0, 0}
109
#endif
110
        ,{"switch"       , DoPreSwitch    , 0, 0}
111
        ,{"system"       , DoSystem       , 0, 0}
112
        ,{"terminate"    , DoTerminate    , 0, 0}
113
        ,{"timeoutafter" , DoTimeOutAfter , 0, 0}
114
        ,{"toexternal"   , DoToExternal   , 0, 0}
115
        ,{"undefine"     , DoUndefine     , 0, 0}
116
        ,{"use"          , DoUse          , 0, 0}
117
        ,{"usedictionary", DoPreUseDictionary,0,0}
118
        ,{"write"        , DoPreWrite     , 0, 0}
119
};
120

121
/*
122
          #] Includes : 
123
         # [ PreProcessor :
124
                 #[ GetInput :
125

126
                Gets one input character. If we reach the end of a stream
127
                we pop to the previous stream and try again.
128
                If there are no more streams we let this be known.
129
*/
130

131
UBYTE GetInput(VOID)
82,978,330✔
132
{
133
        UBYTE c;
82,978,330✔
134
        while ( AC.CurrentStream ) {
83,341,600✔
135
                c = GetFromStream(AC.CurrentStream);
83,341,600✔
136
                if ( c != ENDOFSTREAM ) {
83,341,600✔
137
#ifdef WITHMPI
138
                        if ( PF.me == MASTER 
9,907,230✔
139
                                 && AC.NoShowInput <= 0
2,476,830✔
140
                                 && AC.CurrentStream->type != PREVARSTREAM )
64,034✔
141
#else
142
                        if ( AC.NoShowInput <= 0 && AC.CurrentStream->type != PREVARSTREAM )
73,071,100✔
143
#endif
144
                                CharOut(c);
264,877✔
145
                        return(c);
82,978,330✔
146
                }
147
                AC.CurrentStream = CloseStream(AC.CurrentStream);
363,058✔
148
                if ( stopdelay && AC.CurrentStream == oldstream ) {
363,058✔
149
                        stopdelay = 0; AP.AllowDelay = 1;
21✔
150
                }
151
        }
152
        return(ENDOFINPUT);
153
}
154

155
/*
156
                 #] GetInput : 
157
                 #[ ClearPushback :
158
*/
159

160
VOID ClearPushback(VOID)
1,776✔
161
{
162
        pushbackchar = 0;
1,776✔
163
}
1,776✔
164

165
/*
166
                 #] ClearPushback : 
167
                 #[ GetChar :
168

169
                Reads one character. If it encounters a quote it immediately
170
                takes the whole preprocessor variable and opens a stream
171
                for it and starts reading the stream.
172
                Note that we have to take special precautions for escaped quotes.
173
                That is why we remember the previous character. We allow the
174
                (dubious?) construction of ending a stream with a backslash and
175
                then using it to escape an object in the parent stream.
176
*/
177

178
UBYTE GetChar(int level)
78,753,680✔
179
{
180
        UBYTE namebuf[MAXPRENAMESIZE+2], c, *s, *t;
78,753,680✔
181
        static UBYTE lastchar, charinbuf = 0;
78,753,680✔
182
        int i, j, raiselow, olddelay;
78,753,680✔
183
        STREAM *stream;
78,753,680✔
184
        if ( level > 0 ) {
78,753,680✔
185
                lastchar = '`';
3,846✔
186
                goto higherlevel;
3,846✔
187
        }
188
        if ( pushbackchar ) { c = pushbackchar; pushbackchar = 0; return(c); }
78,749,880✔
189
        if ( charinbuf ) { c = charinbuf; charinbuf = 0; return(c); }
78,674,010✔
190
        c = GetInput();
78,674,010✔
191
        for(;;) {
79,027,650✔
192
                if ( c == '\\' ) {
79,027,650✔
193
                        charinbuf = GetInput();
217✔
194
                        if ( charinbuf != LINEFEED ) {
217✔
195
                                pushbackchar = charinbuf;
203✔
196
                                charinbuf = 0;
203✔
197
                                break;
203✔
198
                        }
199
                        charinbuf = 0;  /* Escaped linefeed -> skip leading blanks */
14✔
200
                        while ( ( c = GetInput() ) == ' ' || c == '\t' ) {}
525✔
201
                }
202
                else if ( c == '\'' || c == '`' ) {
79,027,430✔
203
                        if ( AP.DelayPrevar == 1 && c == '\'' ) {
349,993✔
204
                                AP.DelayPrevar = 0;
77✔
205
                                break;
77✔
206
                        }
207
                        lastchar = c;
349,916✔
208
higherlevel:
353,762✔
209
                        c = GetInput();
353,762✔
210
                        if ( c == '!' && lastchar == '`' ) {
353,762✔
211
                                if ( stopdelay == 0 ) oldstream = AC.CurrentStream;
21✔
212
                                AP.AllowDelay = 0;
21✔
213
                                stopdelay = 1;
21✔
214
                                c = GetInput();
21✔
215
                        }
216
                        if ( c == '~' && lastchar == '`' ) {
353,762✔
217
                                if ( AP.AllowDelay ) {
2,856✔
218
                                        pushbackchar = c;
77✔
219
                                        c = lastchar;
77✔
220
                                        AP.DelayPrevar = 1;
77✔
221
                                        break;
77✔
222
                                }
223
                        }
224
                        else {
225
                                pushbackchar = c;
350,906✔
226
                        }
227
                        olddelay = AP.DelayPrevar;
353,685✔
228
                        AP.DelayPrevar = 0;
353,685✔
229
                        i = 0; lastchar = 0;
353,685✔
230
                        for (;;) {
758,208✔
231
                                if ( pushbackchar ) { c = pushbackchar; pushbackchar = 0; }
758,208✔
232
                                else { c = GetInput(); }
407,302✔
233
                                if ( c == ENDOFINPUT || ( ( c == '\'' || c == LINEFEED )
758,208✔
234
                                && lastchar != '\\' ) ) {
353,685✔
235
                                        break;
236
                                }
237
                                if ( c == '{' ) { /* Try the preprocessor calculator */
404,523✔
NEW
238
                                        if ( PreCalc() == 0 ) TERMINATE(-1);
×
239
                                        c = GetInput();    /* This is either a { or a number */
×
240
                                        if ( c == '{' ) {
×
241
                                                MesPrint("@Illegal set inside preprocessor variable name");
×
NEW
242
                                                TERMINATE(-1);
×
243
                                        }
244
                                }
245
                                if ( c == '`' && lastchar != '\\' ) {
404,523✔
246
                                        c = GetChar(1);
3,846✔
247
                                        if ( c == ENDOFINPUT || ( ( c == '\'' || c == LINEFEED )
3,846✔
248
                                        && lastchar != '\\' ) ) {
×
249
                                                break;
250
                                        }
251
                                }
252
                                if ( lastchar == '\\' ) { i--; lastchar = 0; }
404,523✔
253
                                else lastchar = c;
404,516✔
254
                                namebuf[i++] = c;
404,523✔
255
                                if ( i > MAXPRENAMESIZE ) {
404,523✔
256
                                        namebuf[i] = 0;
×
257
                                        Error1("Preprocessor variable name too long: ",namebuf);
×
258
                                }
259
                        }
260
                        namebuf[i++] = 0;
353,685✔
261
                        if ( c != '\'' ) {
353,685✔
262
                                Error1("Unmatched quotes for preprocessor variable",namebuf);
×
263
                        }
264
                        AP.DelayPrevar = olddelay;
353,685✔
265
                        if ( namebuf[0] == '$' ) {
353,685✔
266
                                raiselow = PRENOACTION;
779✔
267
                                if ( AP.PreproFlag && *AP.preStart) {
779✔
268
                                        s = EndOfToken(AP.preStart);
304✔
269
                                        c = *s; *s = 0;
304✔
270
                                        if ( ( StrICmp(AP.preStart,(UBYTE *)"ifdef") == 0
304✔
271
                                        || StrICmp(AP.preStart,(UBYTE *)"ifndef") == 0 )
304✔
272
                                        && GetDollar(namebuf+1) < 0 ) {
×
273
                                                *s = c; c = ' ';
×
274
                                                break;
×
275
                                        }
276
                                        *s = c; 
304✔
277
                                }
278
                                else {
279
                                        s = EndOfToken(namebuf+1);
475✔
280
                                        if ( *s == '[' ) { while ( *s ) s++; }
1,165✔
281
                                }
282
                                if ( *s == '-' && s[1] == '-' && s[2] == 0 )
779✔
283
                                        raiselow = PRELOWERAFTER;
284
                                else if ( *s == '+' && s[1] == '+' && s[2] == 0 )
779✔
285
                                        raiselow = PRERAISEAFTER;
×
286
                                c = *s; *s = 0;
779✔
287
                                if ( OpenStream(namebuf+1,DOLLARSTREAM,0,raiselow) == 0 ) {
779✔
288
                                        *s = c;
×
289
                                        MesPrint("@Undefined variable %s used as preprocessor variable",
×
290
                                                namebuf);
NEW
291
                                        TERMINATE(-1);
×
292
                                }
293
                                *s = c;
779✔
294
                        }
295
                        else {
296
                                raiselow = PRENOACTION;
352,906✔
297
                                if ( AP.PreproFlag && *AP.preStart) {
352,906✔
298
                                        s = EndOfToken(AP.preStart);
11,151✔
299
                                        c = *s; *s = 0;
11,151✔
300
                                        if ( ( StrICmp(AP.preStart,(UBYTE *)"ifdef") == 0
11,151✔
301
                                        || StrICmp(AP.preStart,(UBYTE *)"ifndef") == 0 )
11,067✔
302
                                        && GetPreVar(namebuf,WITHOUTERROR) == 0 ) {
98✔
303
                                                *s = c; c = ' ';
70✔
304
                                                break;
70✔
305
                                        }
306
                                        *s = c; 
11,081✔
307
                                }
308
                                s = EndOfToken(namebuf);
352,836✔
309
                                if ( *s == '_' ) s++;
352,836✔
310
                                if ( *s == '-' && s[1] == '-' && s[2] == 0 )
352,836✔
311
                                        raiselow = PRELOWERAFTER;
312
                                else if ( *s == '+' && s[1] == '+' && s[2] == 0 )
352,836✔
313
                                        raiselow = PRERAISEAFTER;
314
                                else if ( *s == '(' && namebuf[i-2] == ')' ) {
352,836✔
315
/*
316
                                        Now count the arguments and separate them by zeroes
317
                                        Check on the ?var construction and if present, reset
318
                                        some comma's.
319
                                        Make the assignments of the variables
320
                                        Run the macro.
321
                                        Undefine the variables
322
*/
323
                                        int nargs = 1;
2,702✔
324
                                        PREVAR *p;
2,702✔
325
                                        size_t p_offset;
2,702✔
326
                                        *s++ = 0; namebuf[i-2] = 0;
2,702✔
327
                                        if ( StrICmp(namebuf,(UBYTE *)"random_") == 0 ) {
2,702✔
328
                                                UBYTE *ranvalue;
×
329
                                                ranvalue = PreRandom(s);
×
330
                                                PutPreVar(namebuf,ranvalue,(UBYTE *)"?a",1);
×
331
                                                M_free(ranvalue,"PreRandom");
×
332
                                                goto dostream;
×
333
                                        }
334
                                        else if ( StrICmp(namebuf,(UBYTE *)"tolower_") == 0 ) {
2,702✔
335
                                                UBYTE *ss = s;
336
                                                while ( *ss ) { *ss = (UBYTE)(tolower(*ss)); ss++; }
×
337
                                                PutPreVar(namebuf,s,(UBYTE *)"?a",1);
×
338
                                                goto dostream;
×
339
                                        }
340
                                        else if ( StrICmp(namebuf,(UBYTE *)"toupper_") == 0 ) {
2,702✔
341
                                                UBYTE *ss = s;
342
                                                while ( *ss ) { *ss = (UBYTE)(toupper(*ss)); ss++; }
×
343
                                                PutPreVar(namebuf,s,(UBYTE *)"?a",1);
×
344
                                                goto dostream;
×
345
                                        }
346
                                        else if ( StrICmp(namebuf,(UBYTE *)"takeleft_") == 0 ) {
2,702✔
347
                                                UBYTE *ss = s;
348
                                                int x = 0, nsize;
×
349
                                                while ( *ss != ',' && *ss ) ss++;
×
350
                                                nsize = ss-s;
×
351
                                                if ( *ss ) {
×
352
                                                        *ss++ = 0;
×
353
                                                        while ( FG.cTable[*ss] == 1 ) x = 10*x + (*ss++ - '0');
×
354
                                                        if ( x > nsize ) x = nsize;
×
355
                                                }
356
                                                else x = 0;
357
                                                PutPreVar(namebuf,s+x,(UBYTE *)"?a",1);
×
358
                                                goto dostream;
×
359
                                        }
360
                                        else if ( StrICmp(namebuf,(UBYTE *)"takeright_") == 0 ) {
2,702✔
361
                                                UBYTE *ss = s;
362
                                                int x = 0, nsize;
×
363
                                                while ( *ss != ',' && *ss ) ss++;
×
364
                                                nsize = ss-s;
×
365
                                                if ( *ss ) {
×
366
                                                        *ss++ = 0;
×
367
                                                        while ( FG.cTable[*ss] == 1 ) x = 10*x + (*ss++ - '0');
×
368
                                                        if ( x > nsize ) x = nsize;
×
369
                                                }
370
                                                else x = 0;
371
                                                x = nsize - x;
×
372
                                                s[x] = 0;
×
373
                                                PutPreVar(namebuf,s,(UBYTE *)"?a",1);
×
374
                                                goto dostream;
×
375
                                        }
376
                                        else if ( StrICmp(namebuf,(UBYTE *)"keepleft_") == 0 ) {
2,702✔
377
                                                UBYTE *ss = s;
378
                                                int x = 0, nsize;
×
379
                                                while ( *ss != ',' && *ss ) ss++;
×
380
                                                nsize = ss-s;
×
381
                                                if ( *ss ) {
×
382
                                                        *ss++ = 0;
×
383
                                                        while ( FG.cTable[*ss] == 1 ) x = 10*x + (*ss++ - '0');
×
384
                                                        if ( x > nsize ) x = nsize;
×
385
                                                }
386
                                                else x = nsize;
387
                                                s[x] = 0;
×
388
                                                PutPreVar(namebuf,s,(UBYTE *)"?a",1);
×
389
                                                goto dostream;
×
390
                                        }
391
                                        else if ( StrICmp(namebuf,(UBYTE *)"keepright_") == 0 ) {
2,702✔
392
                                                UBYTE *ss = s;
393
                                                int x = 0, nsize;
×
394
                                                while ( *ss != ',' && *ss ) ss++;
×
395
                                                nsize = ss-s;
×
396
                                                if ( *ss ) {
×
397
                                                        *ss++ = 0;
×
398
                                                        while ( FG.cTable[*ss] == 1 ) x = 10*x + (*ss++ - '0');
×
399
                                                        if ( x > nsize ) x = nsize;
×
400
                                                }
401
                                                else x = nsize;
402
                                                x = nsize-x;
×
403
                                                PutPreVar(namebuf,s+x,(UBYTE *)"?a",1);
×
404
                                                goto dostream;
×
405
                                        }
406
                                        while ( *s ) {
10,052✔
407
                                                if ( *s == '\\' ) s++;
7,350✔
408
                                                if ( *s == ',' ) { *s = 0; nargs++; }
7,350✔
409
                                                s++;
7,350✔
410
                                        }
411
                                        GetPreVar(namebuf,WITHERROR);
2,702✔
412
                                        p = ThePreVar;
2,702✔
413
                                        if ( p == 0 ) {
2,702✔
414
                                                MesPrint("@Illegal use of arguments in preprocessor variable %s",namebuf);
×
NEW
415
                                                TERMINATE(-1);
×
416
                                        }
417
                                        if ( p->nargs <= 0 || ( p->wildarg == 0 && nargs != p->nargs )
2,702✔
418
                                                || ( p->wildarg > 0 && nargs < p->nargs-1 ) ) {
2,702✔
419
                                                MesPrint("@Arguments of macro %s do not match",namebuf);
×
NEW
420
                                                TERMINATE(-1);
×
421
                                        }
422
                                        if ( p->wildarg > 0 ) {
2,702✔
423
/*
424
                                                Change some zeroes into commas
425
*/
426
                                                s = namebuf;
427
                                                for ( j = 0; j < p->wildarg; j++ ) {
×
428
                                                        while ( *s ) s++;
×
429
                                                        s++;
×
430
                                                }
431
                                                for ( j = 0; j < nargs-p->nargs; j++ ) {
×
432
                                                        while ( *s ) s++;
×
433
                                                        *s++ = ',';
×
434
                                                }
435
                                        }
436
/*
437
                                                Now we can make the assignments
438
*/
439
                                        s = namebuf;
2,702✔
440
                                        while ( *s ) s++;
10,822✔
441
                                        s++;
2,702✔
442
                                        t = p->argnames;
2,702✔
443
                                        p_offset = p - PreVar;
2,702✔
444
                                        for ( j = 0; j < p->nargs; j++ ) {
5,418✔
445
                                                if ( ( nargs == p->nargs-1 ) && ( *t == '?' ) ) {
2,716✔
446
                                                        PutPreVar(t,0,0,0);
×
447
                                                }
448
                                                else {
449
                                                        PutPreVar(t,s,0,0);
2,716✔
450
                                                        while ( *s ) s++;
10,052✔
451
                                                        s++;
2,716✔
452
                                                }
453
                                                p = PreVar + p_offset;
2,716✔
454
                                                while ( *t ) t++;
5,432✔
455
                                                t++;
2,716✔
456
                                        }
457
                                }
458
dostream:;
352,836✔
459
                                if ( ( stream = OpenStream(namebuf,PREVARSTREAM,0,raiselow) ) == 0 ) {
352,836✔
460
/*
461
                                        Eat comma before or after. This is `no value'
462
*/
463
                                }
464
                                else if ( stream->inbuffer == 0 ) {
352,836✔
465
                                        c = GetInput();
×
466
                                        if ( level > 0 && c == '\'' ) return(c);
×
467
                                        goto endofloop;
×
468
                                }
469
                        }
470
                        c = GetInput();
353,615✔
471
                }
472
                else if ( c == '{' ) { /* Try the preprocessor calculator */
78,677,360✔
473
                        if ( PreCalc() == 0 ) TERMINATE(-1);
9,408✔
474
                        c = GetInput();    /* This is either a { or a number */
9,408✔
475
                        break;
9,408✔
476
                }
477
                else break;
478
endofloop:;
479
        }
480
        return(c);        
481
}
482

483
/*
484
                 #] GetChar : 
485
                 #[ CharOut :
486
*/
487

488
VOID CharOut(UBYTE c)
264,877✔
489
{
490
        if ( c == LINEFEED ) {
264,877✔
491
                AM.OutBuffer[AP.InOutBuf++] = c;
13,309✔
492
                WriteString(INPUTOUT,AM.OutBuffer,AP.InOutBuf);
13,309✔
493
                AP.InOutBuf = 0;
13,309✔
494
        }
495
        else {
496
                if ( AP.InOutBuf >= AM.OutBufSize || c == LINEFEED ) {
251,568✔
497
                        WriteString(INPUTOUT,AM.OutBuffer,AP.InOutBuf);
98✔
498
                        AP.InOutBuf = 0;
98✔
499
                }
500
                AM.OutBuffer[AP.InOutBuf++] = c;
251,568✔
501
        }
502
}
264,877✔
503

504
/*
505
                 #] CharOut : 
506
                 #[ UnsetAllowDelay :
507
*/
508

509
VOID UnsetAllowDelay(VOID)
352,836✔
510
{
511
        if ( ThePreVar != 0 ) {
352,836✔
512
                if ( ThePreVar->nargs > 0 ) AP.AllowDelay = 0;
351,961✔
513
        }
514
}
352,836✔
515

516
/*
517
                 #] UnsetAllowDelay : 
518
                 #[ GetPreVar :
519

520
                We use the model of a heap. If the same name has been used more
521
                than once the last definition is used. This gives the impression
522
                of local variables.
523

524
                There are two types: The regular ones and the expression variables.
525
                The last ones are like UNCHANGED_exprname and ZERO_exprname or
526
                UNCHANGED_ and ZERO_.
527
*/
528

529
static UBYTE *yes = (UBYTE *)"1";
530
static UBYTE *no  = (UBYTE *)"0";
531
static UBYTE numintopolynomial[12];
532
#include "vector.h"
533
static Vector(UBYTE, exprstr);  /* Used for numactiveexprs_ and activeexprnames_. */
534

535
UBYTE *GetPreVar(UBYTE *name, int flag)
2,669,614✔
536
{
537
        GETIDENTITY
1,229,941✔
538
        int i, mode;
2,669,614✔
539
        WORD number;
2,669,614✔
540
        UBYTE *t, c = 0, *tt = 0;
2,669,614✔
541
        t = name; while ( *t ) t++;
5,434,532✔
542
        if ( t[-1] == '-' && t[-2] == '-' && t-2 > name && t[-3] != '_' ) {
2,669,614✔
543
                t -= 2; c = *t; *t = 0; tt = t;
×
544
        }
545
        else if ( t[-1] == '+' && t[-2] == '+' && t-2 > name && t[-3] != '_' ) {
2,669,614✔
546
                t -= 2; c = *t; *t = 0; tt = t;
×
547
        }
548
        else if ( StrICmp(name,(UBYTE *)"time_") == 0 ) {
2,669,614✔
549
                UBYTE millibuf[24];
×
550
                LONG millitime, timepart;
×
551
                int timepart1, timepart2;
×
552
                static char timestring[40];
×
553
/*                millitime = TimeCPU(1); */
554
                millitime = GetRunningTime();
×
555
                timepart = millitime%1000;
×
556
                millitime /= 1000;
×
557
                timepart /= 10;
×
558
                timepart1 = timepart / 10;
×
559
                timepart2 = timepart % 10;
×
560
                NumToStr(millibuf,millitime);
×
561
            snprintf(timestring,40,"%s.%1d%1d",millibuf,timepart1,timepart2);
×
562
                return((UBYTE *)timestring);
×
563
        }
564
        else if ( ( StrICmp(name,(UBYTE *)"timer_") == 0 )
2,669,614✔
565
               || ( StrICmp(name,(UBYTE *)"stopwatch_") == 0 ) ) {
2,669,614✔
566
                static char timestring[40];
×
567
            snprintf(timestring,40,"%ld",(GetRunningTime() - AP.StopWatchZero));
×
568
                return((UBYTE *)timestring);
×
569
        }
570
        else if ( StrICmp(name, (UBYTE *)"numactiveexprs_") == 0 ) {
2,669,614✔
571
                /* the number of active expressions */
572
                int n = 0;
573
                for ( i = 0; i < NumExpressions; i++ ) {
140✔
574
                        EXPRESSIONS e = Expressions + i;
112✔
575
                        switch ( e->status ) {
112✔
576
                                case LOCALEXPRESSION:
77✔
577
                                case GLOBALEXPRESSION:
578
                                case UNHIDELEXPRESSION:
579
                                case UNHIDEGEXPRESSION:
580
                                case INTOHIDELEXPRESSION:
581
                                case INTOHIDEGEXPRESSION:
582
                                        n++;
77✔
583
                                        break;
77✔
584
                        }
585
                }
112✔
586
                VectorReserve(exprstr, 41);  /* up to 128-bit */
28✔
587
                LongCopy(n, (char *)VectorPtr(exprstr));
28✔
588
                return VectorPtr(exprstr);
28✔
589
        }
590
        else if ( StrICmp(name, (UBYTE *)"activeexprnames_") == 0 ) {
2,669,580✔
591
                /* the list of active expressions separated by commas */
592
                int j = 0;
49✔
593
                VectorReserve(exprstr, 16);  /* at least 1 character for '\0' */
49✔
594
                for ( i = 0; i < NumExpressions; i++ ) {
210✔
595
                        UBYTE *p, *s;
161✔
596
                        int len, k;
161✔
597
                        EXPRESSIONS e = Expressions + i;
161✔
598
                        switch ( e->status ) {
161✔
599
                                case LOCALEXPRESSION:
133✔
600
                                case GLOBALEXPRESSION:
601
                                case UNHIDELEXPRESSION:
602
                                case UNHIDEGEXPRESSION:
603
                                case INTOHIDELEXPRESSION:
604
                                case INTOHIDEGEXPRESSION:
605
                                        s = AC.exprnames->namebuffer + e->name;
133✔
606
                                        len = StrLen(s);
133✔
607
                                        VectorSize(exprstr) = j;  /* j bytes must be copied in extending the buffer. */
133✔
608
                                        VectorReserve(exprstr, j + len * 2 + 1);
133✔
609
                                        p = VectorPtr(exprstr);
133✔
610
                                        if ( j > 0 ) p[j++] = ',';
133✔
611
                                        for ( k = 0; k < len; k++ ) {
812✔
612
                                                if ( s[k] == ',' || s[k] == '|' ) p[j++] = '\\';
679✔
613
                                                p[j++] = s[k];
679✔
614
                                        }
615
                                        break;
616
                        }
617
                }
161✔
618
                VectorPtr(exprstr)[j] = '\0';
49✔
619
                return VectorPtr(exprstr);
49✔
620
        }
621
        else if ( StrICmp(name, (UBYTE *)"path_") == 0 ) {
2,669,537✔
622
                /* the current FORM path (for debugging both in .c and .frm) */
623
                if ( AM.Path ) {
×
624
                        return(AM.Path);
625
                }
626
                else {
627
                        return((UBYTE *)"");
×
628
                }
629
        }
630
        t = name;
2,669,537✔
631
        while ( *t && *t != '_' ) t++;
5,423,465✔
632
        for ( i = NumPre-1; i >= 0; i-- ) {
5,579,040✔
633
                if ( *t == '_' && ( StrICmp(name,PreVar[i].name) == 0 ) ) {
5,573,720✔
634
                        if ( c ) *tt = c;
66✔
635
                        ThePreVar = PreVar+i;
66✔
636
                        return(PreVar[i].value);
66✔
637
                }
638
                else if ( StrCmp(name,PreVar[i].name) == 0 ) {
5,573,660✔
639
                        if ( c ) *tt = c;
2,664,154✔
640
                        ThePreVar = PreVar+i;
2,664,154✔
641
                        return(PreVar[i].value);
2,664,154✔
642
                }
643
        }
644
        if ( *t == '_' ) {
5,315✔
645
                if ( StrICmp(name,(UBYTE *)"EXTRASYMBOLS_") == 0 ) goto extrashort;
5,245✔
646
                *t = 0;
798✔
647
                if ( StrICmp(name,(UBYTE *)"UNCHANGED") == 0 ) mode = 1;
798✔
648
                else if ( StrICmp(name,(UBYTE *)"ZERO") == 0 ) mode = 0;
798✔
649
                else if ( StrICmp(name,(UBYTE *)"SHOWINPUT") == 0 ) {
×
650
                        *t++ = '_';
×
651
                        if ( c ) *tt = c;
×
652
                        if ( AC.NoShowInput > 0 ) return(no);
×
653
                        else return(yes);
×
654
                }
655
                else if ( StrICmp(name,(UBYTE *)"EXTRASYMBOLS") == 0 ) {
×
656
                        *t++ = '_';
×
657
extrashort:;
4,447✔
658
                        number = cbuf[AM.sbufnum].numrhs;
4,447✔
659
                        t = numintopolynomial;
4,447✔
660
                        NumCopy(number,t);
4,447✔
661
                        return(numintopolynomial);
4,447✔
662
                }
663
                else mode = -1;
664
                *t++ = '_';
798✔
665
                if ( mode >= 0 ) {
798✔
666
                        ThePreVar = 0;
798✔
667
                        if ( *t ) {
798✔
668
                                if ( GetName(AC.exprnames,t,&number,NOAUTO) == CEXPRESSION ) {
791✔
669
                                        if ( c ) *tt = c;
791✔
670
                                        if ( ( Expressions[number].vflags & ( 1 << mode ) ) != 0 )
791✔
671
                                                 return(yes);
784✔
672
                                        else return(no);
7✔
673
                                }
674
                        }
675
                        else {
676
/*
677
                                Here we have to test all active results.
678
                                These are in `negative' so the flags have to be zero.
679
*/
680
                                if ( c ) *tt = c;
7✔
681
                                if ( ( AR.expflags & ( 1 << mode ) ) == 0 ) return(yes);
7✔
682
                                else return(no);
7✔
683
                        }
684
                }
685
        }
686
        if ( ( t = (UBYTE *)(getenv((char *)(name))) ) != 0 ) {
70✔
687
                if ( c ) *tt = c;
×
688
                ThePreVar = 0;
×
689
                return(t);
×
690
        }
691
        if ( c ) *tt = c;
70✔
692
        if ( flag == WITHERROR ) {
70✔
693
                Error1("Undefined preprocessor variable",name);
×
694
        }
695
        return(0);
696
}
697

698
/*
699
                 #] GetPreVar : 
700
                 #[ PutPreVar :
701
*/
702

703
/**
704
 *  Inserts/Updates a preprocessor variable in the name administration.
705
 * 
706
 *  @param   name    Character string with the variable name.
707
 *  @param   value   Character string with a possible value.
708
 *                   Special case: if this argument is zero, then we have no
709
 *                   value. Note: This is different from having an empty
710
 *                   argument! This should only occur when the name starts
711
 *                   with a ?
712
 *  @param   args    Character string with possible arguments.
713
 *  @param   mode    =0: always create a new name entry, =1: try to do a
714
 *                   redefinition if possible.
715
 *  @return          Index of used entry in name list.
716
 */
717
int PutPreVar(UBYTE *name, UBYTE *value, UBYTE *args, int mode)
4,645,129✔
718
{
719
        int i, ii, num = 2, nnum = 2, numargs = 0;
4,645,129✔
720
        UBYTE *s, *t, *u = 0;
4,645,129✔
721
        PREVAR *p;
4,645,129✔
722
        if ( value == 0 && name[0] != '?' ) {
4,645,129✔
723
                MesPrint("@Illegal empty value for preprocessor variable %s",name);
×
NEW
724
                TERMINATE(-1);
×
725
        }
726
        if ( args ) {
4,645,129✔
727
                s = args; num++;
728
                while ( *s ) {
37,366✔
729
                        if ( *s != ' ' && *s != '\t' ) num++;
24,913✔
730
                        s++;
24,913✔
731
                }
732
        }
733
        if ( mode == 1 ) {
4,645,129✔
734
                i = NumPre;
4,583,226✔
735
                while ( --i >= 0 ) {
5,348,535✔
736
                        if ( StrCmp(name,PreVar[i].name) == 0 ) {
5,344,969✔
737
                                u = PreVar[i].name;
4,579,660✔
738
                                break;
4,579,660✔
739
                        }
740
                }
741
        }
742
        else i = -1;
743
        if ( i < 0 ) { p = (PREVAR *)FromList(&AP.PreVarList); ii = p - PreVar; }
4,645,129✔
744
        else         { p = &(PreVar[i]);            ii = i; }
4,579,660✔
745
        if ( value ) {
4,645,129✔
746
                s = value; while ( *s ) { s++; num++; }
9,501,759✔
747
        }
748
        else num = 1;
749
        if ( i >= 0 ) {
4,645,129✔
750
                if ( p->value ) {
4,579,660✔
751
                        s = p->value;
752
                        while ( *s ) { s++; nnum++; }
9,271,770✔
753
                }
754
                else nnum = 1;
755
                if ( nnum >= num ) {
4,579,660✔
756
/*
757
                        We can keep this in place
758
*/
759
                        if ( value && p->value ) {
4,579,222✔
760
                                s = value;
761
                                t = p->value;
762
                                while ( *s ) *t++ = *s++;
9,270,466✔
763
                                *t = 0;
4,579,222✔
764
                        }
765
                        else p->value = 0;
×
766
                        return(i);
4,579,222✔
767
                }
768
        }
769
        s = name;  while ( *s ) { s++; num++; }
681,279✔
770
        t = (UBYTE *)Malloc1(num,"PreVariable");
65,911✔
771
        p->name = t;
65,911✔
772
        s = name;  while ( *s ) *t++ = *s++; *t++ = 0;
681,279✔
773
        if ( value ) {
65,911✔
774
                p->value = t;
65,911✔
775
                s = value; while ( *s ) *t++ = *s++; *t = 0;
231,293✔
776
                if ( AM.atstartup && t[-1] == '\n' ) t[-1] = 0;
65,911✔
777
        }
778
        else p->value = 0;
×
779
        p->wildarg = 0;
65,911✔
780
        if ( args ) {
65,911✔
781
                int first = 1;
12,453✔
782
                t++; p->argnames = t;
12,453✔
783
                s = args;
12,453✔
784
                while ( *s ) {
37,366✔
785
                        if ( *s == ' ' || *s == '\t' ) { s++; continue; }
24,913✔
786
                        if ( *s == ',' ) {
24,913✔
787
                                s++; *t++ = 0; numargs++;
14✔
788
                                while ( *s == ' ' || *s == '\t' ) s++;
14✔
789
                                if ( *s == '?' ) {
14✔
790
                                        if ( p->wildarg > 0 ) {
×
791
                                                Error0("More than one ?var in #define");
×
792
                                        }
793
                                        p->wildarg = numargs;
×
794
                                }
795
                        }
796
                        else if ( *s == '?' && first ) {
24,899✔
797
                                p->wildarg = 1; *t++ = *s++;
12,432✔
798
                        }
799
                        else { *t++ = *s++; }
12,467✔
800
                        first = 0;
801
                }
802
                *t = 0;
12,453✔
803
                numargs++;
12,453✔
804
                p->nargs = numargs;
12,453✔
805
        }
806
        else {
807
                p->nargs = 0;
53,458✔
808
                p->argnames = 0;
53,458✔
809
        }
810
        if ( u ) M_free(u,"replace PreVar value");
65,911✔
811
        return(ii);
812
}
813

814
/*
815
                 #] PutPreVar : 
816
                 #[ PopPreVars :
817
*/
818

819
VOID PopPreVars(int tonumber)
×
820
{
821
        PREVAR *p = &(PreVar[NumPre]);
×
822
        while ( NumPre > tonumber ) {
×
823
                NumPre--; p--;
×
824
                M_free(p->name,"popping PreVar");
×
825
                p->name = p->value = 0;
×
826
        }
827
}
×
828

829
/*
830
                 #] PopPreVars : 
831
                 #[ IniModule :
832
*/
833

834
VOID IniModule(int type)
3,499✔
835
{
836
        GETIDENTITY
1,030✔
837
        WORD **w, i;
3,499✔
838
        CBUF *C = cbuf+AC.cbufnum;
3,499✔
839
        /*[05nov2003 mt]:*/ 
840
#ifdef WITHMPI
841
        /* To prevent
842
         *   (1) FlushOut() and PutOut() on the slaves to send a mess to the master
843
         *       compiling a module,
844
         *   (2) EndSort() called from poly_factorize_expression() on the master
845
         *       waits for the slaves.
846
         */
847
        PF.parallel=0;
1,953✔
848
        /*BTW, this was the bug preventing usage of more than 1 expression!*/
849
#endif
850

851
        AR.BracketOn = 0;
3,499✔
852
        AR.StoreData.dirtyflag = 0;
3,499✔
853
        AC.bracketindexflag = 0;
3,499✔
854
        AT.bracketindexflag = 0;
3,499✔
855

856
/*[06nov2003 mt]:*/
857
#ifdef WITHMPI
858
        /* This flag may be set in the procedure tokenize(). */
859
        AC.RhsExprInModuleFlag = 0;
1,953✔
860
/*[20oct2009 mt]:*/
861
        PF.mkSlaveInfile=0;
1,953✔
862
        PF.slavebuf.PObuffer=NULL;
1,953✔
863
        for(i=0; i<NumExpressions; i++)
8,109✔
864
                Expressions[i].vflags &= ~ISINRHS;
6,156✔
865
/*:[20oct2009 mt]*/
866
#endif
867
/*:[06nov2003 mt]*/
868

869
        /*[19nov2003 mt]:*/
870
        /*The module counter:*/
871
        (AC.CModule)++;
3,499✔
872
        /*:[19nov2003 mt]*/
873

874
        if ( !type ) {
3,499✔
875
                if ( C->rhs ) {
×
876
                        w = C->rhs; i = C->maxrhs;
×
877
                        do { *w++ = 0; } while ( --i > 0 );
×
878
                }
879
                if ( C->lhs ) {
×
880
                        w = C->lhs; i = C->maxlhs;
×
881
                        do { *w++ = 0; } while ( --i > 0 );
×
882
                }
883
        }
884
        C->numlhs = C->numrhs = 0;
3,499✔
885
        ClearTree(AC.cbufnum);
3,499✔
886
        while ( AC.NumLabels > 0 ) {
7,222✔
887
                AC.NumLabels--;
224✔
888
                if ( AC.LabelNames[AC.NumLabels] ) M_free(AC.LabelNames[AC.NumLabels],"LabelName");
224✔
889
        }
890

891
        C->Pointer = C->Buffer;
3,499✔
892

893
        AC.Commercial[0] = 0;
3,499✔
894

895
        AC.IfStack = AC.IfHeap;
3,499✔
896
        AC.arglevel = 0;
3,499✔
897
        AC.termlevel = 0;
3,499✔
898
        AC.IfLevel = 0;
3,499✔
899
        AC.WhileLevel = 0;
3,499✔
900
        AC.RepLevel = 0;
3,499✔
901
        AC.insidelevel = 0;
3,499✔
902
        AC.dolooplevel = 0;
3,499✔
903
        AC.MustTestTable = 0;
3,499✔
904
        AO.PrintType = 0;                                /* Otherwise statistics can get spoiled */
3,499✔
905
        AC.ComDefer = 0;
3,499✔
906
        AC.CollectFun = 0;
3,499✔
907
        AM.S0->PolyWise = 0;
3,499✔
908
        AC.SymChangeFlag = 0;
3,499✔
909
        AP.lhdollarerror = 0;
3,499✔
910
        AR.PolyFun = AC.lPolyFun;
3,499✔
911
        AR.PolyFunInv = AC.lPolyFunInv;
3,499✔
912
        AR.PolyFunType = AC.lPolyFunType;
3,499✔
913
        AR.PolyFunExp = AC.lPolyFunExp;
3,499✔
914
        AR.PolyFunVar = AC.lPolyFunVar;
3,499✔
915
        AR.PolyFunPow = AC.lPolyFunPow;
3,499✔
916
        AC.mparallelflag = AC.parallelflag | AM.hparallelflag;
3,499✔
917
        AC.inparallelflag = 0;
3,499✔
918
        AC.mProcessBucketSize = AC.ProcessBucketSize;
3,499✔
919
        NumPotModdollars = 0;
3,499✔
920
        AC.topolynomialflag = 0;
3,499✔
921
#ifdef WITHPTHREADS
922
        if ( AM.totalnumberofthreads > 1 ) AS.MultiThreaded = 1;
1,030✔
923
        else AS.MultiThreaded = 0;
2✔
924
        for ( i = 1; i < AM.totalnumberofthreads; i++ ) {
4,114✔
925
                AB[i]->T.S0->PolyWise = 0;
3,084✔
926
        }
927
#endif
928
        OpenTemp();
3,499✔
929
}
3,499✔
930

931
/*
932
                 #] IniModule : 
933
                 #[ IniSpecialModule :
934
*/
935

936
VOID IniSpecialModule(int type)
×
937
{
938
        DUMMYUSE(type);
×
939
}
×
940

941
/*
942
                 #] IniSpecialModule : 
943
                 #[ PreProcessor :
944
*/
945

946
VOID PreProcessor(VOID)
1,776✔
947
{
948
        int moduletype = FIRSTMODULE;
1,776✔
949
        int specialtype = 0;
1,776✔
950
        int error1 = 0, error2 = 0, retcode, retval;
1,776✔
951
        UBYTE c, *t, *s;
1,776✔
952
        AP.StopWatchZero = GetRunningTime();
1,776✔
953
        AC.compiletype = 0;
1,776✔
954
        AP.PreContinuation = 0;
1,776✔
955
        AP.PreAssignLevel = 0;
1,776✔
956
        AP.gNumPre = NumPre;
1,776✔
957
        AC.iPointer = AC.iBuffer;
1,776✔
958
        AC.iPointer[0] = 0;
1,776✔
959

960
        if ( AC.CheckpointFlag == -1 ) DoRecovery(&moduletype);
1,776✔
961
        AC.CheckpointStamp = Timer(0);
1,776✔
962

963
        for(;;) {
3,499✔
964
/*                if ( A.StatisticsFlag ) CharOut(LINEFEED); */
965

966
                IniModule(moduletype);
3,499✔
967

968
                /*Re-define preprocessor variable CMODULE_ as a current module number, starting from 1*/
969
                /*The module counter is AC.CModule, it is incremented in IniModule*/
970
                {
971
                        UBYTE buf[24];/*64/Log_2[10] = 19.3, this is enough for any integer*/
3,499✔
972
                        NumToStr(buf,AC.CModule);
3,499✔
973
                        PutPreVar((UBYTE *)"CMODULE_",buf,0,1);
3,499✔
974
                }
975

976
                if ( specialtype ) IniSpecialModule(specialtype);
3,499✔
977

978
                for(;;) {        /* Read a single line/statement */
4,673,187✔
979
                        c = GetChar(0);
4,673,187✔
980
                        if ( c == AP.ComChar ) {  /* This line is commentary */
4,673,187✔
981
                                LoadInstruction(5);
4,373✔
982
                                if ( AC.CurrentStream->FoldName ) {
4,373✔
983
                                        t = AP.preStart;
161✔
984
                                        if ( *t && t[1] && t[2] == '#' && t[3] == ']' ) {
161✔
985
                                                t += 4;
7✔
986
                                                while ( *t == ' ' || *t == '\t' ) t++;
14✔
987
                                                s = AC.CurrentStream->FoldName;
988
                                                while ( *s == *t ) { s++; t++; }
119✔
989
                                                if ( *s == 0 && ( *t == ' ' || *t == '\t'
7✔
990
                                                || *t == ':' ) ) {
×
991
                                                        while ( *t == ' ' || *t == '\t' ) t++;
14✔
992
                                                        if ( *t == ':' ) {
7✔
993
                                                                AC.CurrentStream = CloseStream(AC.CurrentStream);
7✔
994
                                                        }
995
                                                }
996
                                        }
997
                                }
998
                                *AP.preStart = 0;
4,373✔
999
                                continue;
4,373✔
1000
                        }
1001
                        while ( c == ' ' || c == '\t' ) c = GetChar(0);
18,375,999✔
1002
                        if ( c == LINEFEED ) continue;
4,668,813✔
1003
                        if ( c == ENDOFINPUT ) {
4,664,593✔
1004
/*                                CharOut(LINEFEED); */
1005
                                Warning(".end instruction generated");
×
1006
                                moduletype = ENDMODULE; specialtype = 0;
×
1007
                                goto endmodule; /* Fake one */
×
1008
                        }
1009
                        if ( c == '#' ) {
4,664,593✔
1010
                                if ( PreProInstruction() ) { error1++; error2++; AP.preError++; }
4,586,275✔
1011
                                *AP.preStart = 0;
4,586,265✔
1012
                        }
1013
                        else if ( c == '.' ) {
78,328✔
1014
                                if ( ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ||
3,499✔
1015
                                ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) ) {
3,496✔
1016
                                        LoadInstruction(1);
3✔
1017
                                        continue;
3✔
1018
                                }
1019
                                if ( ModuleInstruction(&moduletype,&specialtype) ) { error2++; AP.preError++; }
3,496✔
1020
                                if ( specialtype ) SetSpecialMode(moduletype,specialtype);
3,496✔
1021
                                if ( AP.PreInsideLevel != 0 ) {
3,496✔
1022
                                        MesPrint("@end of module instructions may not be used inside");
×
1023
                                        MesPrint("@the scope of a %#inside %#endinside construction.");
×
NEW
1024
                                        TERMINATE(-1);
×
1025
                                }
1026
                                if ( AC.RepLevel > 0 ) {
3,496✔
1027
                                        MesPrint("&EndRepeat statement(s) missing");
×
1028
                                        error2++; AP.preError++;
×
1029
                                }
1030
                                if ( AC.tablecheck == 0 ) {
3,496✔
1031
                                        AC.tablecheck = 1;
1,614✔
1032
                                        if ( TestTables() ) { error2++; AP.preError++; }
1,614✔
1033
                                }
1034
                                if ( AP.PreContinuation ) {
3,496✔
1035
                                        error1++; error2++;
7✔
1036
                                        MesPrint("&Unfinished statement. Missing ;?");
7✔
1037
                                }
1038
                                if ( moduletype == GLOBALMODULE ) MakeGlobal();
3,496✔
1039
                                else {
1040
endmodule:                        if ( error2 == 0 && AM.qError == 0 ) {
3,496✔
1041
                                                retcode = ExecModule(moduletype);
3,433✔
1042
#ifdef WITHMPI
1043
                                                if(PF.slavebuf.PObuffer!=NULL){
1,917✔
1044
                                                        M_free(PF.slavebuf.PObuffer,"PF inbuf");
147✔
1045
                                                        PF.slavebuf.PObuffer=NULL;
147✔
1046
                                                }
1047
#endif
1048
                                                UpdatePositions();
3,405✔
1049
                                                if ( retcode < 0 ) error1++;
3,405✔
1050
                                                if ( retcode ) { error2++; AP.preError++; }
3,405✔
1051
                                        }
1052
                                        else {
1053
                                                EXPRESSIONS e;
63✔
1054
                                                WORD j;
63✔
1055
                                                for ( j = 0, e = Expressions; j < NumExpressions; j++, e++ ) {
112✔
1056
                                                        if ( e->replace == NEWLYDEFINEDEXPRESSION ) e->replace = REGULAREXPRESSION;
49✔
1057
                                                }
1058
                                        }
1059
                                        switch ( moduletype ) {
3,468✔
1060
                                                case STOREMODULE:
28✔
1061
                                                        if ( ExecStore() ) error1++;
28✔
1062
                                                        break;
1063
                                                case CLEARMODULE:
×
1064
                                                        FullCleanUp();
×
1065
                                                        error1 = error2 = AP.preError = 0;
×
1066
                                                        AM.atstartup = 1;
×
1067
                                                        PutPreVar((UBYTE *)"DATE_",(UBYTE *)MakeDate(),0,1);
×
1068
                                                        AM.atstartup = 0;
×
1069
                                                        if ( AM.resetTimeOnClear ) {
×
1070
#ifdef WITHPTHREADS
1071
                                                                ClearAllThreads();
1072
#endif
1073
                                                                AM.SumTime += TimeCPU(1);
×
1074
                                                                TimeCPU(0);
×
1075
                                                        }
1076
                                                        AP.StopWatchZero = GetRunningTime();
×
1077
                                                        break;
×
1078
                                                case ENDMODULE:
1,745✔
1079
                                                        TERMINATE( -( error1 | error2 ) );
1,745✔
1080
                                        }
1081
                                }
1,723✔
1082
                                AC.tablecheck = 0;
1,723✔
1083
                                AC.compiletype = 0;
1,723✔
1084
                                if ( AC.exprfillwarning > 0 ) {
1,723✔
1085
                                        AC.exprfillwarning = 0;
211✔
1086
                                }
1087
                                if ( AC.CheckpointFlag && error1 == 0 && error2 == 0 ) DoCheckpoint(moduletype);
1,723✔
1088
                                break;  /* start a new module */
1089
                        }
1090
                        else {
1091
                                if ( ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ||
74,829✔
1092
                                ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) ) {
74,683✔
1093
                                        pushbackchar = c;
146✔
1094
                                        LoadInstruction(5);
146✔
1095
                                        continue;
146✔
1096
                                }
1097
                                UngetChar(c);
74,683✔
1098
                                if ( AP.PreContinuation ) {
74,683✔
1099
                                        retval = LoadStatement(OLDSTATEMENT);
42,148✔
1100
                                }
1101
                                else {
1102
                                        AC.CurrentStream->prevline = AC.CurrentStream->linenumber;
32,535✔
1103
                                        retval = LoadStatement(NEWSTATEMENT);
32,535✔
1104
                                }
1105
                                if ( retval < 0 ) {
74,683✔
1106
                                        error1++;
×
1107
                                        if ( retval == -1 ) AP.PreContinuation = 0;
×
1108
                                        else AP.PreContinuation = 1;
×
1109
                                        TryRecover(0);
×
1110
                                }
1111
                                else if ( retval > 0 ) AP.PreContinuation = 0;
74,683✔
1112
                                else AP.PreContinuation = 1;
42,155✔
1113
                                if ( error1 == 0 && !AP.PreContinuation ) {
74,683✔
1114
                                        if ( ( AP.PreDebug & PREPROONLY ) == 0 ) {
32,528✔
1115
                                                int onpmd = NumPotModdollars;
32,528✔
1116
#ifdef WITHMPI
1117
                                                WORD oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
18,433✔
1118
                                                if ( AP.PreAssignFlag ) AC.RhsExprInModuleFlag = 0;
18,433✔
1119
#endif
1120
                                                if ( AP.PreOut || ( AP.PreDebug & DUMPTOCOMPILER )
32,528✔
1121
                                                                == DUMPTOCOMPILER )
1122
                                                                        MesPrint(" %s",AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]);
21✔
1123
                                                retcode = CompileStatement(AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]);
32,528✔
1124
                                                if ( retcode < 0 ) error1++;
32,528✔
1125
                                                if ( retcode ) { error2++; AP.preError++; }
32,528✔
1126
                                                if ( AP.PreAssignFlag ) {
32,528✔
1127
                                                        if ( retcode == 0 ) {
809✔
1128
                                                                if ( ( retcode = CatchDollar(0) ) < 0 ) error1++;
809✔
1129
                                                                else if ( retcode > 0 ) { error2++; AP.preError++; }
809✔
1130
                                                        }
1131
                                                        else CatchDollar(-1);
×
1132
                                                        POPPREASSIGNLEVEL;
809✔
1133
                                                        if ( AP.PreAssignLevel <=0 )
809✔
1134
                                                                AP.PreAssignFlag = 0;
809✔
1135
                                                        NumPotModdollars = onpmd;
809✔
1136
#ifdef WITHMPI
1137
                                                        AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
452✔
1138
#endif
1139
                                                }
1140
                                        }
1141
                                        else {
1142
                                                MesPrint(" %s",AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]);
×
1143
                                        }
1144
                                }
1145
                                else if ( !AP.PreContinuation ) {
42,155✔
1146
                                        if ( AP.PreAssignLevel > 0 ) {
×
1147
                                                POPPREASSIGNLEVEL;
×
1148
                                                if ( AP.PreAssignLevel <=0 )
×
1149
                                                        AP.PreAssignFlag = 0;
×
1150
                                        }
1151
                                }
1152
/*
1153
                                if ( !AP.PreContinuation ) AP.PreAssignFlag = 0;
1154
*/
1155
                        }
1156
                }
1157
        }
1158
}
1159

1160
/*
1161
                 #] PreProcessor : 
1162
                 #[ PreProInstruction :
1163
*/
1164

1165
int PreProInstruction(VOID)
4,586,275✔
1166
{
1167
        UBYTE *s, *t;
4,586,275✔
1168
        KEYWORD *key;
4,586,275✔
1169
        AP.PreproFlag = 1;
4,586,275✔
1170
        AP.preFill = 0;
4,586,275✔
1171
        AP.AllowDelay = 0;
4,586,275✔
1172
        AP.DelayPrevar = 0;
4,586,275✔
1173

1174
        oldmode = 0;
4,586,275✔
1175
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) {
4,586,275✔
1176
                LoadInstruction(3);
×
1177
                if ( ( StrICmp(AP.preStart,(UBYTE *)"case") == 0
×
1178
                || StrICmp(AP.preStart,(UBYTE *)"default") == 0 )
×
1179
                && AP.PreSwitchModes[AP.PreSwitchLevel] == SEARCHINGPRECASE ) {
×
1180
                        LoadInstruction(0);
×
1181
                }
1182
                else if ( StrICmp(AP.preStart,(UBYTE *)"assign ") == 0 ) {}
×
1183
                else { LoadInstruction(1); }
×
1184
        }
1185
        else if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) {
4,586,275✔
1186
                LoadInstruction(3);
2,579✔
1187
                if ( ( StrICmp(AP.preStart,(UBYTE *)"else") == 0
2,579✔
1188
                || StrICmp(AP.preStart,(UBYTE *)"elseif") == 0 )
2,544✔
1189
                && AP.PreIfStack[AP.PreIfLevel] == LOOKINGFORELSE ) {
35✔
1190
                        LoadInstruction(0);
35✔
1191
                }
1192
                else if ( StrICmp(AP.preStart,(UBYTE *)"assign ") == 0 ) {}
2,544✔
1193
                else {
1194
                        LoadInstruction(1);
2,516✔
1195
                }
1196
        }
1197
        else {
1198
                LoadInstruction(0);
4,583,693✔
1199
        }
1200
        AP.PreproFlag = 0;
4,586,275✔
1201
        t = AP.preStart;
4,586,275✔
1202
        if ( *t == '-' ) {
4,586,275✔
1203
                if ( AP.PreSwitchModes[AP.PreSwitchLevel] == EXECUTINGPRESWITCH 
130✔
1204
                        && AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF ) 
130✔
1205
                        AC.NoShowInput = 1;
130✔
1206
        }
1207
        else if ( *t == '+' ) {
4,586,142✔
1208
                if ( AP.PreSwitchModes[AP.PreSwitchLevel] == EXECUTINGPRESWITCH 
×
1209
                        && AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF ) 
×
1210
                        AC.NoShowInput = 0;
×
1211
        }
1212
        else if ( *t == ':' ) {}
4,586,142✔
1213
        else {
1214
retry:;
4,585,958✔
1215
                key = FindKeyWord(t,precommands,sizeof(precommands)/sizeof(KEYWORD));
4,585,958✔
1216
                s = EndOfToken(t);
4,585,958✔
1217
                if ( key == 0 ) {
4,585,958✔
1218
                        if ( *s == ';' ) {
×
1219
                                *s = 0; goto retry;
×
1220
                        }
1221
                        else {
1222
                                *s = 0;
×
1223
                                MesPrint("@Unrecognized preprocessor instruction: %s",t);
×
1224
                                return(-1);
×
1225
                        }
1226
                }
1227
                while ( *s == ' ' || *s == '\t' || *s == ',' ) s++;
6,858,960✔
1228
                t = s;
1229
                while ( *t ) t++;
15,990,926✔
1230
                while ( ( t[-1] == ';' ) && ( t[-2] != '\\' ) ) {
4,586,046✔
1231
                        t--; *t = 0;
84✔
1232
                }
1233
                return((key->func)(s));
4,585,958✔
1234
        }
1235
        return(0);
1236
}
1237

1238
/*
1239
                 #] PreProInstruction : 
1240
                 #[ LoadInstruction :
1241

1242
                0:  preprocessor instruction that may involve matching of brackets
1243
                1:  runs straight to end-of-line
1244
                2:        runs to ;
1245
                3:        only gets one word without `' interpretation.
1246
                5:        with pushbackchar, but inside commentary. -> 1
1247

1248
To be added:
1249
        In define, redefine, call and listed do we may have delayed substitution
1250
        of preprocessor variables.
1251
*/
1252

1253
int LoadInstruction(int mode)
4,597,292✔
1254
{
1255
        UBYTE *s, *sstart, *t, c, cp;
4,597,292✔
1256
        LONG position, fillpos = 0;
4,597,292✔
1257
        int bralevel = 0, parlevel = 0, first = 1;
4,597,292✔
1258
        int quotelevel = 0;
4,597,292✔
1259
        if ( AP.preFill ) {
4,597,292✔
1260
                s = AP.preFill;
2,579✔
1261
                AP.preFill = 0;
2,579✔
1262
                if ( s[1] != LINEFEED && s[1] != ENDOFINPUT ) {
2,579✔
1263
                        s[0] = s[1]; s++;
847✔
1264
                }
1265
                else { oldmode = mode; return(0); }
1,732✔
1266
        }
1267
        else { s = AP.preStart; }
4,594,720✔
1268
        sstart = s; *s = 0;
4,595,574✔
1269
        for(;;) {
48,264,698✔
1270
                if ( ( mode & 1 ) == 1 ) {
48,264,698✔
1271
                        if ( pushbackchar && ( mode == 3 || mode == 5 ) ) {
300,618✔
1272
                                c = pushbackchar; pushbackchar = 0;
146✔
1273
                        }
1274
                        else c = GetInput();
300,472✔
1275
                }
1276
                else {
1277
                        c = GetChar(0);
47,963,958✔
1278
                }
1279

1280
                if ( mode == 2 && c == ';' ) break;
48,264,698✔
1281
                if ( ( mode == 1 || mode == 5 ) && c == LINEFEED ) break;
48,264,698✔
1282
                if ( mode == 3 && FG.cTable[c] != 0 ) {
48,258,822✔
1283
                        if ( c == '$' ) {
2,579✔
1284
                                pushbackchar = '$';
28✔
1285
                                *s++ = 'a'; *s++ = 's'; *s++ = 's'; *s++ = 'i';
28✔
1286
                                *s++ = 'g'; *s++ = 'n'; *s++ = ' '; *s = 0;
28✔
1287
                        }
1288
                        if ( c == '\'' || c == '`' ) { /* we do not expand preprocessor variables */
2,579✔
1289
                                mode = 1;
1290
                        }
1291
                        else {
1292
                                AP.preFill = s; *s++ = 0; *s = c;
2,579✔
1293
                                oldmode = mode;
2,579✔
1294
                                return(0);
2,579✔
1295
                        }
1296
                }
1297
                if ( mode == 0 && first ) {
48,256,250✔
1298
                        if ( c == '$' ) {
4,587,186✔
1299
dodollar:                s = sstart;
809✔
1300
                                *s++ = 'a'; *s++ = 's'; *s++ = 's'; *s++ = 'i';
809✔
1301
                                *s++ = 'g'; *s++ = 'n'; *s = 0;
809✔
1302
                                pushbackchar = c;
809✔
1303
                                oldmode = mode;
809✔
1304
                                return(0);
809✔
1305
                        }
1306
                        if ( c == ' ' || c == '\t' || c == ',' ) {}
4,586,384✔
1307
                        else first = 0;
4,586,384✔
1308
                }
1309
                else if ( mode == 1 && first && c == '$' && oldmode == 3 ) goto dodollar;
43,669,044✔
1310
                if ( c == ENDOFINPUT || ( c == LINEFEED
48,255,498✔
1311
/*                && bralevel == 0  */
1312
                && quotelevel == 0 ) ) {
48,255,498✔
1313
                        if ( mode == 2 && c == ENDOFINPUT ) {
4,586,374✔
1314
                                MesPrint("@Unexpected end of instruction");
×
1315
                                oldmode = mode;
×
1316
                                return(-1);
×
1317
                        }
1318
/*
1319
                        if ( mode == 0 && bralevel ) {
1320
                                MesPrint("@Unmatched brackets");
1321
                                oldmode = mode;
1322
                                return(-1);
1323
                        }
1324
*/
1325
                        if ( mode != 2 ) break;
4,586,374✔
1326
                }
1327
                if ( quotelevel ) {
43,669,044✔
1328
                        if ( c == '\\' ) {
4,538,926✔
1329
                                if ( ( mode == 1 ) || ( mode == 5 ) ) c = GetInput();
126✔
1330
                                else {
1331
                                        c = GetChar(0);
91✔
1332
                                }
1333
                                if ( c == ENDOFINPUT ) {
126✔
1334
                                        MesPrint("@Unmatched \"");
×
1335
                                        if ( mode == 2 && c == ENDOFINPUT ) {
×
1336
                                                MesPrint("@Unexpected end of instruction");
×
1337
                                        }
1338
/*
1339
                                        if ( mode == 0 && bralevel ) {
1340
                                                MesPrint("@Unmatched brackets");
1341
                                        }
1342
*/
1343
                                        oldmode = mode;
×
1344
                                        return(-1);
×
1345
                                }
1346
                                else if ( c == LINEFEED ) {} 
126✔
1347
                                else if ( c == '"' ) { *s++ = '\\'; }
126✔
1348
                                else {
1349
                                        *s++ = '\\';
126✔
1350
                                }
1351
                        }
1352
                        else if ( c == '"' ) {
4,538,794✔
1353
                                quotelevel = 0;
2,264,059✔
1354
                                AP.AllowDelay = 0;
2,264,059✔
1355
                        }
1356
                }
1357
                else if ( c == '\\' ) {
39,130,188✔
1358
                        if ( ( mode == 1 ) || ( mode == 5 ) ) cp = GetInput();
112✔
1359
                        else {
1360
                                cp = GetChar(0);
105✔
1361
                        }
1362
                        if ( cp == LINEFEED ) continue;
112✔
1363
                        if ( mode != 2 || cp != ';' ) *s++ = c;
112✔
1364
                        c = cp;
1365
                }
1366
                else if ( c == '"' ) {
39,129,994✔
1367
/*
1368
                        Now look back in the buffer and determine what the keyword is.
1369
                        If it is define or redefine, put AllowDelay to 1.
1370
*/
1371
                        t = AP.preStart;
2,264,059✔
1372
                        while ( FG.cTable[*t] <= 1 ) t++;
20,371,686✔
1373
                        cp = *t; *t = 0;
2,264,059✔
1374
                        if ( ( StrICmp(AP.preStart,(UBYTE *)"define") == 0 )
2,264,059✔
1375
                                || ( StrICmp(AP.preStart,(UBYTE *)"redefine") == 0 ) ) {
2,263,819✔
1376
                                AP.AllowDelay = 1;
2,263,073✔
1377
                                oldstream = AC.CurrentStream;
2,263,073✔
1378
                        }
1379
                        *t = cp;
2,264,059✔
1380
                        quotelevel = 1;
2,264,059✔
1381
                }
1382
                else if ( quotelevel == 0 && bralevel == 0 && c == '(' ) {
36,865,924✔
1383
                        t = AP.preStart;
1,768✔
1384
                        while ( FG.cTable[*t] <= 1 ) t++;
8,283✔
1385
                        cp = *t; *t = 0;
1,768✔
1386
                        if ( ( parlevel == 0 )
1,768✔
1387
                                 && ( StrICmp(AP.preStart,(UBYTE *)"call") == 0 ) ) {
1,691✔
1388
                                AP.AllowDelay = 1;
406✔
1389
                                oldstream = AC.CurrentStream;
406✔
1390
                        }
1391
                        *t = cp;
1,768✔
1392
                        parlevel++;
1,768✔
1393
                }
1394
                else if ( quotelevel == 0 && bralevel == 0 && c == ')' ) {
36,864,214✔
1395
                        parlevel--;
1,768✔
1396
                }
1397
                else if ( quotelevel == 0 && parlevel == 0 && c == '{' ) {
36,862,394✔
1398
                        t = AP.preStart;
70✔
1399
                        while ( FG.cTable[*t] <= 1 ) t++;
154✔
1400
                        cp = *t; *t = 0;
70✔
1401
                        if ( ( bralevel == 0 )
70✔
1402
                                && ( ( StrICmp(AP.preStart,(UBYTE *)"call") == 0 )
70✔
1403
                                || ( StrICmp(AP.preStart,(UBYTE *)"do") == 0 ) ) ) {
70✔
1404
                                AP.AllowDelay = 1;
42✔
1405
                                oldstream = AC.CurrentStream;
42✔
1406
                        }
1407
                        *t = cp;
70✔
1408
                        bralevel++;
70✔
1409
                }
1410
                else if ( quotelevel == 0 && parlevel == 0 && c == '}' ) {
36,862,334✔
1411
                        bralevel--;
70✔
1412
                        if ( bralevel < 0 ) {
70✔
1413
                                if ( mode != 5 ) {
×
1414
                                        MesPrint("@Unmatched brackets");
×
1415
                                        oldmode = mode;
×
1416
                                        return(-1);
×
1417
                                }
1418
                                bralevel = 0;
1419
                        }
1420
                }
1421
                if ( s >= (AP.preStop-1) ) {
43,669,044✔
1422
                        UBYTE **ppp;
×
1423
                        position = s - AP.preStart;
×
1424
                        if ( AP.preFill ) fillpos = AP.preFill - AP.preStart;
×
1425
                        ppp = &(AP.preStart); /* to avoid a compiler warning */
×
1426
                        if ( DoubleLList((VOID ***)ppp,&AP.pSize,sizeof(UBYTE),
×
1427
                        "instruction buffer") ) { *s = 0; oldmode = mode; return(-1); }
×
1428
                        AP.preStop = AP.preStart + AP.pSize-3;
×
1429
                        s = AP.preStart + position;
×
1430
                        if ( AP.preFill ) AP.preFill = fillpos + AP.preStart;
×
1431
                }
1432
                *s++ = c;
43,669,044✔
1433
        }
1434
        *s = 0;
4,592,180✔
1435
        oldmode = mode;
4,592,180✔
1436
        if ( mode == 0 ) {
4,592,180✔
1437
                if ( ExpandTripleDots(1) < 0 ) return(-1);
4,586,374✔
1438
        }
1439
        return(0);
1440
}
1441

1442
/*
1443
                 #] LoadInstruction : 
1444
                 #[ LoadStatement :
1445

1446
                Puts the current string together in the input buffer.
1447
                Does things like placing comma's where needed and expand ...
1448
                We force a comma after the keyword. Before 8-sep-2009 the program might
1449
                not put a comma if a + or - followed. And then the compiler ate
1450
                the + or - and we needed repair code in the routines that used the
1451
                + or - (Print, modulus, multiply and (a)bracket). This worked but
1452
                the problem was with statements like  Dimension -4; which then would
1453
                be processed as Dimension 4; (JV)
1454
*/
1455

1456
int LoadStatement(int type)
74,683✔
1457
{
1458
        UBYTE *s, c, cp;
74,683✔
1459
        int retval = 0, stringlevel = 0, newstatement = 0;
74,683✔
1460
        if ( type == NEWSTATEMENT ) { AP.eat = 1; newstatement = 1;
74,683✔
1461
                s = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; }
32,535✔
1462
        else { s = AC.iPointer; *s = 0; c = ' '; goto blank; }
42,148✔
1463
        *s = 0;
32,535✔
1464
        for(;;) {
12,312,950✔
1465
                c = GetChar(0);
12,312,950✔
1466
                if ( c == ENDOFINPUT ) { retval = -1; break; }
12,312,950✔
1467
                if ( stringlevel == 0 ) {
12,312,950✔
1468
                        if ( c == LINEFEED ) {
12,257,340✔
1469
                                if ( AP.eat < 0 ) { s--; AP.eat = 0; }
42,155✔
1470
                                retval = 0; break;
1471
                        }
1472
                        if ( c == ';' ) {
12,215,190✔
1473
                                if ( AP.eat < 0 ) { s--; AP.eat = 0; }
32,528✔
1474
                                while ( ( c = GetChar(0) ) == ' ' || c == '\t' ) {}
34,249✔
1475
                                if ( c != LINEFEED ) UngetChar(c);
32,528✔
1476
                                retval = 1;
1477
                                break;
1478
                        }
1479
                }
1480
                if ( c == '\\' ) {
12,238,260✔
1481
                        cp = GetChar(0);
×
1482
                        if ( cp == LINEFEED ) continue;
×
1483
                        *s++ = c;
×
1484
                        c = cp;
×
1485
                }
1486
                if ( c == '"' ) {
12,238,260✔
1487
                        if ( stringlevel == 0 ) stringlevel = 1;
6,216✔
1488
                        else stringlevel = 0;
3,108✔
1489
                        AP.eat = 0;
6,216✔
1490
                }
1491
                else if ( stringlevel == 0 ) {
12,232,050✔
1492
                        if ( c == '\t' ) c = ' ';
12,179,550✔
1493
                        if ( c == ' ' ) {
12,179,530✔
1494
blank:                        if ( newstatement < 0 ) newstatement = 0;
217,147✔
1495
                                if ( AP.eat && ( newstatement == 0 ) ) continue;
217,147✔
1496
                                c = ',';
97,024✔
1497
                                AP.eat = -2;
97,024✔
1498
                                if ( newstatement > 0 ) newstatement = -1;
97,024✔
1499
                        }
1500
                        else if ( chartype[c] <= 3 ) {
12,004,550✔
1501
                                AP.eat = 0;
7,934,600✔
1502
                                if ( newstatement < 0 ) newstatement = 0;
7,934,600✔
1503
                        }
1504
                        else if ( c == ',' ) {
4,069,943✔
1505
                                if ( newstatement > 0 ) {
149,231✔
1506
                                        newstatement = -1;
3,416✔
1507
                                        AP.eat = -2;
3,416✔
1508
                                }
1509
/*                                else if ( AP.eat == -2 ) { s--; } */
1510
                                else if ( AP.eat == -2 ) { AP.eat = 1; continue; }
145,815✔
1511
                                else { goto doall; }
145,808✔
1512
                        }
1513
                        else {
1514
doall:;                        if ( AP.eat < 0 ) {
4,066,526✔
1515
                                        if ( newstatement == 0 ) s--;
71,684✔
1516
                                        else { newstatement = 0; }
1517
                                }
1518
                                else if ( newstatement == 1 ) newstatement = 0;
3,994,842✔
1519
                                AP.eat = 1;
4,066,526✔
1520
                                if ( c == '*' && s > AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel] && s[-1] == '*' ) {
4,066,526✔
1521
                                        s[-1] = '^';
×
1522
                                        continue;
×
1523
                                }
1524
                        }
1525
                }
1526
                if ( s >= AC.iStop ) {
12,160,290✔
1527
                        if ( !AP.iBufError ) {
171✔
1528
                                LONG position = s - AC.iBuffer;
171✔
1529
                                LONG position2 = AC.iPointer - AC.iBuffer;
171✔
1530
                                UBYTE **ppp = &(AC.iBuffer); /* to avoid a compiler warning */
171✔
1531
                                if ( DoubleLList((VOID ***)ppp,&AC.iBufferSize
171✔
1532
                                ,sizeof(UBYTE),"statement buffer") ) {
1533
                                        *s = 0; retval = -1; AP.iBufError = 1;
×
1534
                                }
1535
                                AC.iPointer = AC.iBuffer + position2;
171✔
1536
                                AC.iStop = AC.iBuffer + AC.iBufferSize-2;
171✔
1537
                                s = AC.iBuffer + position;
171✔
1538
                        }
1539
                        if ( AP.iBufError ) {
171✔
1540
                                for(;;){
×
1541
                                        c = GetChar(0);
×
1542
                                        if ( c == ENDOFINPUT ) { retval = -1; break; }
×
1543
                                        if ( c == '"' ) {
×
1544
                                                if ( stringlevel > 0 ) stringlevel = 0;
×
1545
                                                else stringlevel = 1;
×
1546
                                        }
1547
                                        else if ( c == LINEFEED && !stringlevel ) { retval = -2; break; }
×
1548
                                        else if ( c == ';' && !stringlevel ) {
×
1549
                                                while ( ( c = GetChar(0) ) == ' ' || c == '\t' ) {}
×
1550
                                                if ( c != LINEFEED ) UngetChar(c);
×
1551
                                                retval = -1;
1552
                                                break;
1553
                                        }
1554
                                        else if ( c == '\\' ) c = GetChar(0);
×
1555
                                }
1556
                                break;
1557
                        }
1558
                }
1559
                *s++ = c;
12,160,290✔
1560
        }
1561
        AC.iPointer = s;
74,683✔
1562
        *s = 0;
74,683✔
1563
        if ( stringlevel > 0 ) {
74,683✔
1564
                MesPrint("@Unbalanced \". Runaway string");
×
1565
                retval = -1;
×
1566
        }
1567
        if ( retval == 1 ) {
74,683✔
1568
                if ( ExpandTripleDots(0) < 0 ) retval = -1;
32,528✔
1569
        }
1570
        return(retval);
74,683✔
1571
}
1572

1573
/*
1574
                 #] LoadStatement : 
1575
                 #[ ExpandTripleDots :
1576
*/
1577

1578
static inline int IsSignChar(UBYTE c)
149,755✔
1579
{
1580
        return c == '+' || c == '-';
149,755✔
1581
}
1582

1583
static inline int IsAlphanumericChar(UBYTE c)
1,210✔
1584
{
1585
        return FG.cTable[c] == 0 || FG.cTable[c] == 1;
1,210✔
1586
}
1587

1588
static inline int CanParseSignedNumber(const UBYTE *s)
1589
{
1590
        while ( IsSignChar(*s) ) s++;
2,424✔
1591
        return FG.cTable[*s] == 1;
2,324✔
1592
}
1593

1594
int ExpandTripleDots(int par)
4,618,897✔
1595
{
1596
        UBYTE *s, *s1, *s2, *n1, *n2, *t1, *t2, *startp, operator1, operator2, c, cc;
4,618,897✔
1597
        UBYTE *nBuffer, *strngs, *Buffer, *Stop;
4,618,897✔
1598
        LONG withquestion, x1, x2, y1, y2, number, inc, newsize, pow, fullsize;
4,618,897✔
1599
        int i, error = 0, i1 ,i2, ii, *nums = 0;
4,618,897✔
1600

1601
        if ( par == 0 ) {
4,618,897✔
1602
                Buffer = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; Stop = AC.iStop;
32,528✔
1603
        }
1604
        else {
1605
                Buffer = AP.preStart; Stop = AP.preStop;
4,586,374✔
1606
        }
1607
        s = Buffer; while ( *s ) s++;
60,087,180✔
1608
        fullsize = s - Buffer;
4,618,897✔
1609
        if ( fullsize < 7 ) return(error);
4,618,897✔
1610

1611
        s = Buffer+2;
2,299,498✔
1612
        while ( *s ) {
42,307,990✔
1613
                if ( *s != '.' || ( s[-1] != ',' && FG.cTable[s[-1]] != 5 ) )
40,008,400✔
1614
                        { s++; continue; }
40,007,620✔
1615
                if ( s[-1] == '%' || s[-1] == '^' || s[1] != '.' || s[2] != '.' )
795✔
1616
                        { s++; continue; }
14✔
1617
                s1 = s - 2;
781✔
1618
                s += 3;
781✔
1619
                if ( *s != s[-4] && ( *s != '+' || s[-4] != '-' )
781✔
1620
                 && ( *s != '-' || s[-4] != '+' ) ) {
×
1621
                        MesPrint("&Improper operators for ...");
×
1622
                        error = -1;
×
1623
                } 
1624
                operator1 = s[-4];
781✔
1625
                operator2 = *s++;
781✔
1626
                if ( operator1 == ':' ) operator1 = '.';
781✔
1627
                if ( operator2 == ':' ) operator2 = '.';
781✔
1628
/*
1629
                We have now O1...O2 (O stands for operator)
1630
                Full syntax is
1631
                [str]#1[?]O1...O2[str]#2[?]   (Special case)
1632
                in which both strings are identical and if one ? then also the other.
1633
                <pattern1>O1...O2<pattern2>   (General case)
1634
                in which the difference in the patterns is just numerical.
1635
*/
1636
                s2 = s;                        /* the beginning of the second string */
781✔
1637
                if ( *s2 != '<' || *s1 != '>' ) {        /* Special case */
781✔
1638
                        startp = s1+1;
479✔
1639
                        withquestion = ( *s1 == '?' ); s1--;
479✔
1640
                        while ( FG.cTable[*s1] == 1 && s1 >= Buffer ) s1--;
486✔
1641
                        n1 = s1+1;                /* Beginning of first number */ 
479✔
1642
                        if ( FG.cTable[*n1] != 1 ) {
479✔
1643
                                MesPrint("&No first number in ... operator");
×
1644
                                error = -1;
×
1645
                        } 
1646
                        while ( FG.cTable[*s1] <= 1 && s1 >= Buffer ) s1--;
1,119✔
1647
                        s1++;
479✔
1648
/*
1649
                        We have now the first string from s1 to n1, number from n1
1650
*/
1651
                        t1 = s1; t2 = s2;
479✔
1652
                        while ( t1 < n1 && *t1 == *t2 ) { t1++; t2++; }
1,119✔
1653
                        n2 = t2;
479✔
1654
                        if ( FG.cTable[*t2] != 1 ) {
479✔
1655
                                MesPrint("&No second number in ... operator");
×
1656
                                error = -1;
×
1657
                        }
1658
                        x2 = 0;
479✔
1659
                        while ( FG.cTable[*t2] == 1 ) x2 = 10*x2 + *t2++ - '0';
1,241✔
1660
                        x1 = 0;
1661
                        while ( FG.cTable[*t1] == 1 ) x1 = 10*x1 + *t1++ - '0';
965✔
1662
                        if ( withquestion != ( *t2 == '?' ) ) {
479✔
1663
                                MesPrint("&Improper use of ? in ... operator");
×
1664
                                if ( *t2 == '?' ) t2++;
×
1665
                                error = -1;
1666
                        }
1667
                        else if ( withquestion ) t2++;
479✔
1668
                        if ( FG.cTable[*t2] <= 2 ) {
479✔
1669
                                MesPrint("&Illegal object after ... construction");
×
1670
                                error = -1;
×
1671
                        }
1672
                        c = *n1; *n1 = 0; s = t2;
479✔
1673
                        if ( error ) continue;
479✔
1674
/*
1675
                        At this point the syntax has been fulfilled. We have
1676
                        str in s1.
1677
                        x1,x2 are #1,#2
1678
                        operator1,operator2 are the two operators.
1679
                        s points at whatever comes after.
1680
                        Expansion will have to be computed. 
1681
*/
1682
                        if ( x2 < x1 ) { number = x1-x2; inc = -1; y1 = x2; y2 = x1; }
479✔
1683
                        else           { number = x2-x1; inc =  1; y1 = x1; y2 = x2; }
479✔
1684
                        newsize = (number+1)*(n1-s1)                    /* the strings   */
958✔
1685
                                 + number                                            /* the operators */
479✔
1686
                                 +(number+1)*(withquestion?1:0)        /* questionmarks */
479✔
1687
                                 +(number+1);                   /* last digits   */
1688
                        pow = 10;
479✔
1689
                        for ( i = 1; i < 10; i++, pow *= 10 ) {
762✔
1690
                                if ( y1 >= pow )      newsize += number+1;
762✔
1691
                                else if ( y2 >= pow ) newsize += y2-pow+1;
755✔
1692
                                else break;
1693
                        }
1694
                        while ( Buffer+(fullsize+newsize-(s-s1)) >= Stop ) {
605✔
1695
                                LONG strpos = s1-Buffer;
126✔
1696
                                LONG endstr = n1-Buffer;
126✔
1697
                                LONG startq = startp - Buffer;
126✔
1698
                                LONG position = s - Buffer;
126✔
1699
                                UBYTE **ppp;
126✔
1700
                                if ( par == 0 ) {
126✔
1701
                                        LONG position2 = AC.iPointer - AC.iBuffer;
126✔
1702
                                        ppp = &(AC.iBuffer); /* to avoid a compiler warning */
126✔
1703
                                        if ( DoubleLList((VOID ***)ppp,&AC.iBufferSize
126✔
1704
                                                ,sizeof(UBYTE),"statement buffer") ) {
NEW
1705
                                                        TERMINATE(-1);
×
1706
                                        }
1707
                                        AC.iPointer = AC.iBuffer + position2;
126✔
1708
                                        AC.iStop = AC.iBuffer + AC.iBufferSize-2;
126✔
1709
                                        Buffer = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; Stop = AC.iStop;
126✔
1710
                                }
1711
                                else {
1712
                                        LONG fillpos = 0;
×
1713
                                        if ( AP.preFill ) fillpos = AP.preFill - AP.preStart;
×
1714
                                        ppp = &(AP.preStart); /* to avoid a compiler warning */
×
1715
                                        if ( DoubleLList((VOID ***)ppp,&AP.pSize,sizeof(UBYTE),
×
1716
                                                "instruction buffer") ) {
NEW
1717
                                                        TERMINATE(-1);
×
1718
                                        }
1719
                                        AP.preStop = AP.preStart + AP.pSize-3;
×
1720
                                        if ( AP.preFill ) AP.preFill = fillpos + AP.preStart;
×
1721
                                        Buffer = AP.preStart; Stop = AP.preStop;
1722
                                }
1723
                                s  = Buffer + position;
126✔
1724
                                n1 = Buffer + endstr;
126✔
1725
                                s1 = Buffer + strpos;
126✔
1726
                                startp = Buffer + startq;
126✔
1727
                        }
1728
/*
1729
                        We have space for the expansion in the buffer.
1730
                        There are two cases: new size >  old size
1731
                                             old size >= new size
1732
                        Note that whereever we move things, it will be at least startp.
1733
*/
1734
                        if ( newsize > (s-s1) ) {
479✔
1735
                                t2 = Buffer + fullsize;
444✔
1736
                                t1 = t2 + (newsize - (s-s1));
444✔
1737
                                *t1 = 0;
444✔
1738
                                while ( t2 > s ) { *--t1 = *--t2; }
1,242✔
1739
                        }
1740
                        else if ( newsize < (s-s1) ) {
35✔
1741
                                t1 = s1 + newsize; t2 = s; s = t1;
35✔
1742
                                while ( *t2 ) *t1++ = *t2++;
35✔
1743
                                *t1 = 0;
35✔
1744
                        }
1745
                        for ( x1 += inc, t1 = startp; number > 0; number--, x1 += inc ) {
152,026✔
1746
                                *t1++ = operator1;
151,547✔
1747
                                cc = operator1; operator1 = operator2; operator2 = cc;
151,547✔
1748
                                t2 = s1; while ( *t2 ) *t1++ = *t2++;
167,308✔
1749
                                x2 = x1; n2 = t1;
571,268✔
1750
                                do {
571,268✔
1751
                                        *t1++ = '0' + x2 % 10;
571,268✔
1752
                                        x2 /= 10;
571,268✔
1753
                                } while ( x2 );
571,268✔
1754
                                s2 = t1 - 1;
1755
                                while ( s2 > n2 ) { cc = *s2; *s2 = *n2; *n2++ = cc; s2--; }
426,193✔
1756
                                if ( withquestion ) *t1++ = '?';
151,547✔
1757
                        }
1758
                        fullsize += newsize - ( s - s1 );
479✔
1759
                        *n1 = c;
479✔
1760
                }
1761
                else {                /* General case. Find the patterns first */
1762
                        t1 = s1; s1--;
302✔
1763
                        while ( s1 > Buffer ) {
2,147✔
1764
                                if ( *s1 == '<' ) break;
2,147✔
1765
                                s1--;
1,845✔
1766
                        }
1767
                        t2 = s2;
1768
                        while ( *t2 ) {
2,839✔
1769
                                if ( *t2 == '>' ) break;
2,839✔
1770
                                t2++;
2,537✔
1771
                        }
1772
                        if ( *s1 != '<' || *t2 != '>' ) {
302✔
1773
                                MesPrint("&Illegal attempt to use ... operator");
×
1774
                                return(-1);
×
1775
                        }
1776
                        s1++; s2++;                /* Pointers to the patterns */
302✔
1777
                        nums = (int *)Malloc1((t1-s1)*2*(sizeof(int)+sizeof(UBYTE))
302✔
1778
                                                        ,"Expand ...");
1779
                        strngs = (UBYTE *)(nums + 2*(t1-s1));
302✔
1780
                        n1 = s1; n2 = s2; ii = -1; i = 0;
302✔
1781
                        s = strngs;                        
302✔
1782
                        while ( n1 < t1 || n2 < t2 ) {
2,021✔
1783
                                /* Check the next characters can be parsed as numbers including signs. */
1784
                                if ( CanParseSignedNumber(n1) && CanParseSignedNumber(n2) ) {
2,324✔
1785
                                        /*
1786
                                         * Don't allow the cases that one has the sign and the other doesn't,
1787
                                         * and the meaning changes without the sign. For example,
1788
                                         *   <f(1)>+...+<f(3)>       Allowed
1789
                                         *   <f(-2)>+...+<f(2)>      Allowed
1790
                                         *   <f(x-2)>+...+<f(x+2)>   Allowed
1791
                                         *   <f(x-2)>+...+<f(x2)>    Not allowed
1792
                                         */
1793
                                        int sign1 = IsSignChar(*n1);
605✔
1794
                                        int sign2 = IsSignChar(*n2);
605✔
1795
                                        int inword1 = s1 < n1 && IsAlphanumericChar(n1[-1]);
605✔
1796
                                        int inword2 = s2 < n2 && IsAlphanumericChar(n2[-1]);
605✔
1797
                                        if ( ( sign1 ^ sign2 ) && ( inword1 || inword2 ) ) break;  /* Not allowed. */
605✔
1798
                                        if ( sign1 || sign2 ) {
605✔
1799
                                                *s++ = '+';  /* Marker indicating we need the sign. */
56✔
1800
                                        }
1801
                                } else {
1802
                                        /* If they are not numbers, they should be same. */
1803
                                        if ( *n1 == *n2 ) { *s++ = *n1++; n2++; continue; }
1,114✔
1804
                                        else break;
1805
                                }
1806
                                ParseSignedNumber(x1,n1)
1,336✔
1807
                                ParseSignedNumber(x2,n2)
1,726✔
1808
                                if ( x1 == x2 ) {
605✔
1809
                                        if ( s != strngs && ( s[-1] == '+' || s[-1] == '-' ) ) {
105✔
1810
                                                /* We need the sign. */
1811
                                                s--;
14✔
1812
                                                if ( x1 >= 0 ) {
14✔
1813
                                                        *s++ = '+';
7✔
1814
                                                }
1815
                                        }
1816
                                        s = NumCopy(x1, s);
105✔
1817
                                }
1818
                                else {
1819
                                        nums[2*i] = x1; nums[2*i+1] = x2;
500✔
1820
                                        i++; *s++ = 0;
500✔
1821
                                }
1822
                        }
1823
                        if ( n1 < t1 || n2 < t2 ) {
302✔
1824
                                MesPrint("&Improper use of ... operator.");
×
1825
theend:                        M_free(nums,"Expand ...");
×
1826
                                return(-1);
×
1827
                        }
1828
                        *s = 0;
302✔
1829
                        if ( i == 0 ) ii = 0;
302✔
1830
                        else {
1831
                                ii = nums[0] - nums[1];
302✔
1832
                                if ( ii < 0 ) ii = -ii;
302✔
1833
                                for ( x1 = 1; x1 < i; x1++ ) {
500✔
1834
                                        x2 = nums[2*x1]-nums[2*x1+1];
198✔
1835
                                        if ( x2 < 0 ) x2 = -x2;
198✔
1836
                                        if ( x2 != ii ) {
198✔
1837
                                                MesPrint("&Improper synchronization of numbers in ... operator");
×
1838
                                                goto theend;
×
1839
                                        }
1840
                                }
1841
                        }
1842
                        ii++;
302✔
1843
/*
1844
                        We have now proper syntax.
1845
                        There are i+1 strings in strngs and i pairs of numbers
1846
                        in nums. Each time a start value and a finish value.
1847
                        We have ii steps. If ii <= 2, it will fit in the existing
1848
                        allocation. But this is hardly useful.
1849
                        We make a new allocation and copy from the old.
1850
                        Compute space.
1851
*/
1852
                        x2 = s - strngs - i;  /* -1 for end-of-string and +1 for the operator*/
302✔
1853
                        for ( i1 = 0; i1 < i; i1++ ) {
802✔
1854
                                i2 = nums[2*i1];
500✔
1855
                                x1 = nums[2*i1+1];
500✔
1856
                                if ( i2 < 0 ) i2 = -i2;
500✔
1857
                                if ( x1 < 0 ) x1 = -x1;
500✔
1858
                                if ( x1 > i2 ) i2 = x1;
500✔
1859
                                x1 = 2;
1860
                                while ( i2 > 0 ) { i2 /= 10; x1++; }
1,495✔
1861
                                x2 += x1;
500✔
1862
                        }
1863
                        x2 *= ii;        /* Space for the expanded string (a bit more) */
302✔
1864
                        x2 += fullsize;
302✔
1865
                        x2 += 5;                /* This will definitely hold everything */
302✔
1866
                        x2 += sizeof(UBYTE *);
302✔
1867
                        x2 = x2 - (x2 & (sizeof(UBYTE *)-1));
302✔
1868

1869
                        nBuffer = (UBYTE *)Malloc1(x2,"input buffer");
302✔
1870
                        n1 = nBuffer; s = Buffer; s1--;
302✔
1871
                        while ( s < s1 ) *n1++ = *s++;
530,736✔
1872
/*
1873
                        Solution of the special case that no comma was generated
1874
                        due to the presence of < to start the pattern.
1875
                        We get a comma when the word before ends in an alphanumeric
1876
                        character, a _ or a ] and the word inside starts with an
1877
                        alphanumeric character, a [ (or an _ (for future considerations))
1878
*/
1879
                        if ( ( ( n1 > nBuffer ) && ( ( FG.cTable[n1[-1]] <= 1 )
302✔
1880
                        || ( n1[-1] == '_' ) || ( n1[-1] == ']' ) ) ) &&
302✔
1881
                        ( ( FG.cTable[strngs[0]] <= 1 ) || ( strngs[0] == '[' )
×
1882
                         || ( strngs[0] == '_' ) ) ) *n1++ = ',';
×
1883

1884
                        for ( i1 = 0; i1 < ii; i1++ ) {
139,624✔
1885
                                s = strngs; while ( *s ) *n1++ = *s++;
420,636✔
1886
                                for ( i2 = 0; i2 < i; i2++ ) {
286,048✔
1887
                                        if ( n1 > nBuffer && IsSignChar(n1[-1]) ) {
146,726✔
1888
                                                /* We need the sign of counters. */
1889
                                                n1--;
4,844✔
1890
                                                if ( nums[2*i2] >= 0 ) {
4,844✔
1891
                                                        *n1++ = '+';
4,585✔
1892
                                                }
1893
                                        }
1894
                                        n1 = NumCopy((WORD)(nums[2*i2]),n1);
146,726✔
1895
                                        if ( nums[2*i2] > nums[2*i2+1] ) nums[2*i2]--;
146,726✔
1896
                                        else nums[2*i2]++;
146,544✔
1897
                                        s++; while ( *s ) *n1++ = *s++;
295,679✔
1898
                                }
1899
                                if ( ( i1 & 1 ) == 0 ) *n1++ = operator1;
139,322✔
1900
                                else *n1++ = operator2;
69,602✔
1901
                        }
1902
                        n1--;        /* drop the trailing operator */
302✔
1903
                        s = t2 + 1; n2 = n1;
302✔
1904
/*
1905
                        Similar extra comma
1906
*/
1907
                        if ( ( ( ( FG.cTable[n1[-1]] <= 1 )
302✔
1908
                        || ( n1[-1] == '_' ) || ( n1[-1] == ']' ) ) ) &&
117✔
1909
                        ( ( FG.cTable[s[0]] <= 1 ) || ( s[0] == '[' )
199✔
1910
                         || ( s[0] == '_' ) ) ) *n1++ = ',';
199✔
1911

1912
                        while ( *s ) *n1++ = *s++;
46,158✔
1913
                        *n1 = 0;
302✔
1914
                        if ( par == 0 ) {
302✔
1915
                                LONG nnn1 = n1-nBuffer;
302✔
1916
                                LONG nnn2 = n2-nBuffer;
302✔
1917
                                LONG nnn3;
302✔
1918
                                while ( AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel] + x2 >= AC.iStop ) {
391✔
1919
                                        LONG position = s-Buffer;
89✔
1920
                                        LONG position2 = AC.iPointer - AC.iBuffer;
89✔
1921
                                        UBYTE **ppp;
89✔
1922
                                        ppp = &(AC.iBuffer); /* to avoid a compiler warning */
89✔
1923
                                        if ( DoubleLList((VOID ***)ppp,&AC.iBufferSize
89✔
1924
                                                ,sizeof(UBYTE),"statement buffer") ) {
NEW
1925
                                                        TERMINATE(-1);
×
1926
                                        }
1927
                                        AC.iPointer = AC.iBuffer + position2;
89✔
1928
                                        AC.iStop = AC.iBuffer + AC.iBufferSize-2;
89✔
1929
                                        Buffer = AC.iBuffer+AP.PreAssignStack[AP.PreAssignLevel]; Stop = AC.iStop;
89✔
1930
                                        s  = Buffer + position;
89✔
1931
                                }
1932
/*
1933
                                This can be improved. We only have to start from the first term.
1934
*/
1935
                                for ( nnn3 = 0; nnn3 < nnn1; nnn3++ ) Buffer[nnn3] = nBuffer[nnn3];
1,772,116✔
1936
                                Buffer[nnn3] = 0;
302✔
1937
                                n1 = Buffer + nnn1;
302✔
1938
                                n2 = Buffer + nnn2;
302✔
1939
                                M_free(nBuffer,"input buffer");
302✔
1940
                                M_free(nums,"Expand ...");
302✔
1941
                        }
1942
                        else { /* Comes here only inside a real preprocessor instruction */
1943
                                AP.preStop = nBuffer + x2 - 2;
×
1944
                                AP.pSize = x2;
×
1945
                                M_free(AP.preStart,"input buffer");
×
1946
                                M_free(nums,"Expand ...");
×
1947
                                AP.preStart = nBuffer;
×
1948
                                Buffer = AP.preStart; Stop = AP.preStop;
×
1949
                        }
1950
                        fullsize = n1 - Buffer;
302✔
1951
                        s = n2;
302✔
1952
                }
1953
        }
1954
        return(error);
1955
}
1956

1957
/*
1958
                 #] ExpandTripleDots : 
1959
                 #[ FindKeyWord :
1960
*/
1961

1962
KEYWORD *FindKeyWord(UBYTE *theword, KEYWORD *table, int size)
4,589,915✔
1963
{
1964
        int low,med,hi;
4,589,915✔
1965
        UBYTE *s1, *s2;
4,589,915✔
1966
        low = 0;
4,589,915✔
1967
        hi = size-1;
4,589,915✔
1968
        while ( hi >= low ) {
27,525,197✔
1969
                med = (hi+low)/2;
27,525,197✔
1970
                s1 = (UBYTE *)(table[med].name);
27,525,197✔
1971
                s2 = theword;
27,525,197✔
1972
                while ( *s1 && tolower(*s1) == tolower(*s2) ) { s1++; s2++; }
80,263,546✔
1973
                if ( *s1 == 0 &&
27,525,197✔
1974
/*[30apr2004 mt]:*/
1975
/* The bug!:
1976
                                FG.cTable[*s2] != 1 && FG.cTable[*s2] != 2
1977
*/
1978
                                FG.cTable[*s2] != 0 && FG.cTable[*s2] != 1
4,590,055✔
1979
/*                ( *s2 == ' ' || *s2 == '\t' || *s2 == 0 || *s2 == ',' || *s2 == '(' ) */
1980
                         )
1981
                        return(table+med);
1982
                if ( tolower(*s2) > tolower(*s1) ) low = med+1;
22,935,252✔
1983
                else hi = med - 1;
11,495,023✔
1984
        }
1985
        return(0);
1986
}
1987

1988
/*
1989
                 #] FindKeyWord : 
1990
                 #[ FindInKeyWord :
1991
*/
1992

1993
KEYWORD *FindInKeyWord(UBYTE *theword, KEYWORD *table, int size)
×
1994
{
1995
        int i;
×
1996
        UBYTE *s1, *s2;
×
1997
        for ( i = 0; i < size; i++ ) {
×
1998
                s1 = (UBYTE *)(table[i].name);
×
1999
                s2 = theword;
×
2000
                while ( *s1 && tolower(*s1) == tolower(*s2) ) { s1++; s2++; }
×
2001
                if ( *s2 == 0 || *s2 == ' ' || *s2 == ',' || *s2 == '\t' )
×
2002
                        return(table+i);
2003
        }
2004
        return(0);
2005
}
2006

2007
/*
2008
                 #] FindInKeyWord : 
2009
                 #[ TheDefine :
2010
*/
2011

2012
/**
2013
 *  Preprocessor assignment. Possible arguments and values are treated and the
2014
 *  new preprocessor variable is put into the name administration.
2015
 *
2016
 *  @param   s      Pointer to the character string following the preprocessor
2017
 *                  command.
2018
 *  @param   mode   Bitmask. 0-bit clear: always create a new name entry, 0-bit
2019
 *                  set: try to redefine an existing name, 1-bit set: ignore
2020
 *                  preprocessor if/switch status.
2021
 *  @return         zero: no errors, negative number: errors.
2022
 */
2023
int TheDefine(UBYTE *s, int mode)
2,265,757✔
2024
{
2025
        UBYTE *name, *value, *valpoin, *args = 0, c;
2,265,757✔
2026
        if ( ( mode & 2 ) == 0 ) {
2,265,757✔
2027
                if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2,265,757✔
2028
                if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2,265,757✔
2029
        }
2030
        else { mode &= ~2; }
×
2031
        name = s;
2,265,751✔
2032
        if ( chartype[*s] != 0 ) goto illname;
2,265,751✔
2033
        s++;
2,265,751✔
2034
        while ( chartype[*s] <= 1 ) s++;
2,266,405✔
2035
        value = s;
4,528,798✔
2036
        while ( *s == ' ' || *s == '\t' ) s++;
4,528,798✔
2037
        c = *s; *value = 0;
2,265,751✔
2038
        if ( c == 0 ) {
2,265,751✔
2039
                if ( PutPreVar(name,(UBYTE *)"1",0,mode) < 0 ) return(-1);
2,688✔
2040
                return(0);
2,688✔
2041
        }
2042
        if ( c == '(' ) {        /* arguments. scan for correctness */
2,263,067✔
2043
                s++; args = s;
21✔
2044
                for (;;) {
35✔
2045
                        if ( chartype[*s] != 0 ) goto illarg;
35✔
2046
                        s++;
35✔
2047
                        while ( chartype[*s] <= 1 ) s++;
35✔
2048
                        while ( *s == ' ' || *s == '\t' ) s++;
35✔
2049
                        if ( *s == ')' ) break;
35✔
2050
                        if ( *s != ',' ) goto illargs;
14✔
2051
                        s++;
14✔
2052
                        while ( *s == ' ' || *s == '\t' ) s++;
14✔
2053
                }
2054
                *s++ = 0;
21✔
2055
                while ( *s == ' ' || *s == '\t' ) s++;
42✔
2056
                c = *s;
2057
        }
2058
        if ( c == '"' ) {
2,263,067✔
2059
                s++; valpoin = value = s;
2,263,067✔
2060
                while ( *s != '"' ) {
4,526,816✔
2061
                        if ( *s == '\\' ) {
2,263,747✔
2062
                                if ( s[1] == 'n' ) { *valpoin++ = LINEFEED; s += 2; }
×
2063
                                else if ( s[1] == '"' ) { *valpoin++ = '"'; s += 2; }
×
2064
                                else if ( s[1] == 0 ) goto illval;
×
2065
                                else { *valpoin++ = *s++; *valpoin++ = *s++; }
×
2066
                        }
2067
                        else *valpoin++ = *s++;
2,263,747✔
2068
                }
2069
                *valpoin = 0;
2,263,067✔
2070
                if ( PutPreVar(name,value,args,mode) < 0 ) return(-1);
2,263,067✔
2071
        }
2072
        else {
2073
                MesPrint("@Illegal string for preprocessor variable %s. Forgotten double quotes (\") ?",name);
×
2074
                return(-1);
×
2075
        }
2076
        return(0);
2077
illname:;
×
2078
        MesPrint("@Illegally formed name of preprocessor variable");
×
2079
        return(-1);
×
2080
illarg:;
×
2081
        MesPrint("@Illegally formed name of argument of preprocessor definition");
×
2082
        return(-1);
×
2083
illargs:;
×
2084
        MesPrint("@Illegally formed arguments of preprocessor definition");
×
2085
        return(-1);
×
2086
illval:;
×
2087
        MesPrint("@Illegal valpoin for preprocessor variable %s",name);
×
2088
        return(-1);
×
2089
}
2090

2091
/*
2092
                 #] TheDefine : 
2093
                 #[ DoCommentChar :
2094
*/
2095

2096
int DoCommentChar(UBYTE *s)
×
2097
{
2098
        UBYTE c;
×
2099
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
2100
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
2101
        while ( *s == ' ' || *s == '\t' ) s++;
×
2102
        if ( *s == 0 || *s == '\n' ) {
×
2103
                MesPrint("@No valid comment character specified");
×
2104
                return(-1);
×
2105
        }
2106
        c = *s++;
×
2107
        while ( *s == ' ' || *s == '\t' ) s++;
×
2108
        if ( *s != 0 && *s != '\n' ) {
×
2109
                MesPrint("@Comment character should be a single valid character");
×
2110
                return(-1);
×
2111
        }
2112
        AP.ComChar = c;
×
2113
        return(0);
×
2114
}
2115

2116
/*
2117
                 #] DoCommentChar : 
2118
                 #[ DoPreAssign :
2119

2120
                Routine assigns a 'value' to a $variable.
2121
                Syntax: #assign
2122
                        next line(s) a statement of the type
2123
                        $name = expression;
2124
                Note: at the moment of the assign there cannot be an 'open' statement.
2125
*/
2126

2127
int DoPreAssign(UBYTE *s)
837✔
2128
{
2129
        int error = 0;
837✔
2130
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) {
837✔
2131
                return(0);
2132
        }
2133
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) {
837✔
2134
                return(0);
2135
        }
2136
        if ( *s ) {
809✔
2137
                MesPrint("@Illegal characters in %#assign instruction");
×
2138
                error = 1;
×
2139
        }
2140
        PUSHPREASSIGNLEVEL;
809✔
2141
        AP.PreAssignFlag = 1;
809✔
2142
/*
2143
        if ( AP.PreContinuation ) {
2144
                MesPrint("@Assign instructions cannot occur inside statements");
2145
                MesPrint("@Missing ; ?");
2146
                AP.PreContinuation = 0;
2147
                error = 1;
2148
        }
2149
*/
2150
        return(error);
809✔
2151
}
2152

2153
/*
2154
                 #] DoPreAssign : 
2155
                 #[ DoDefine :
2156
*/
2157

2158
int DoDefine(UBYTE *s)
2,924✔
2159
{
2160
        return(TheDefine(s,0));
2,924✔
2161
}
2162

2163
/*
2164
                 #] DoDefine : 
2165
                 #[ DoRedefine :
2166
*/
2167

2168
int DoRedefine(UBYTE *s)
2,262,833✔
2169
{
2170
        return(TheDefine(s,1));
2,262,833✔
2171
}
2172

2173
/*
2174
                 #] DoRedefine : 
2175
                 #[ ClearMacro :
2176

2177
                Undefines the arguments of a macro after its use.
2178
*/
2179

2180
int ClearMacro(UBYTE *name)
352,836✔
2181
{
2182
        int i;
352,836✔
2183
        PREVAR *p;
352,836✔
2184
        UBYTE *s;
352,836✔
2185
        for ( i = NumPre-1, p = &(PreVar[NumPre-1]); i >= 0; i--, p-- ) {
2,074,700✔
2186
                if ( StrCmp(name,p->name) == 0 ) break;
2,073,790✔
2187
        }
2188
        if ( i < 0 ) return(-1);
352,836✔
2189
        if ( p->nargs <= 0 ) return(0);
351,926✔
2190
        s = p->argnames;
2,702✔
2191
        for ( i = 0; i < p->nargs; i++ ) {
5,418✔
2192
                TheUndefine(s);
2,716✔
2193
                while ( *s ) s++;
5,432✔
2194
                s++;
2,716✔
2195
        }
2196
        return(0);
2197
}
2198

2199
/*
2200
                 #] ClearMacro : 
2201
                 #[ TheUndefine :
2202

2203
                There is a complication here. If there are redefine statements
2204
                they will be pointing at the wrong variable if their number is
2205
                greater than the number of the variable we pop.
2206
*/
2207

2208
int TheUndefine(UBYTE *name)
3,260✔
2209
{
2210
        int i, inum, error = 0;
3,260✔
2211
        PREVAR *p;
3,260✔
2212
        for ( i = NumPre-1, p = &(PreVar[NumPre-1]); i >= 0; i--, p-- ) {
5,962✔
2213
                if ( StrCmp(name,p->name) == 0 ) {
5,962✔
2214
                        M_free(p->name,"undefining PreVar");
3,260✔
2215
                        NumPre--;
3,260✔
2216
                        inum = i;
3,260✔
2217
                        while ( i < NumPre ) {
5,962✔
2218
                                p->name  = p[1].name;
2,702✔
2219
                                p->value = p[1].value;
2,702✔
2220
                                p++; i++;
2,702✔
2221
                        }
2222
                        p->name = 0; p->value = 0;
3,260✔
2223
                        {
2224
                                CBUF *CC = cbuf + AC.cbufnum;
3,260✔
2225
                                int j, k;
3,260✔
2226
                                for ( j = 1; j <= CC->numlhs; j++ ) {
26,178✔
2227
                                        if ( CC->lhs[j][0] == TYPEREDEFPRE ) {
22,918✔
2228
                                                if ( CC->lhs[j][2] > inum ) CC->lhs[j][2]--;
×
2229
                                                else if ( CC->lhs[j][2] == inum ) {
×
2230
                                                        for ( k = inum - 1; k >= 0; k-- )
×
2231
                                                                if ( StrCmp(name, PreVar[k].name) == 0 ) break;
×
2232
                                                        if ( k >= 0 ) CC->lhs[j][2] = k;
×
2233
                                                        else {
2234
                                                                MesPrint("@Conflict between undefining a preprocessor variable and a redefine statement");
×
2235
                                                                error = 1;
×
2236
                                                        }
2237
                                                }
2238
                                        }
2239
                                }
2240
#ifdef PARALLELCODE
2241
                                for ( j = 0; j < AC.numpfirstnum; j++ ) {
2,792✔
2242
                                        if ( AC.pfirstnum[j] > inum ) AC.pfirstnum[j]--;
2243
                                        else if ( AC.pfirstnum[j] == inum ) {
2244
                                                for ( k = inum - 1; k >= 0; k-- )
2245
                                                        if ( StrCmp(name, PreVar[k].name) == 0 ) break;
2246
                                                if ( k >= 0 ) AC.pfirstnum[j] = k;
2247
                                        }
2248
                                }
2249
#endif
2250
                        }
2251
                        break;
2252
                }
2253
        }
2254
        return(error);
3,260✔
2255
}
2256

2257
/*
2258
                 #] TheUndefine : 
2259
                 #[ DoUndefine :
2260
*/
2261

2262
int DoUndefine(UBYTE *s)
544✔
2263
{
2264
        UBYTE *name, *t;
544✔
2265
        int error = 0, retval;
544✔
2266
/*
2267
        int i;
2268
        PREVAR *p;
2269
*/
2270
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
544✔
2271
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
544✔
2272
        name = s;
544✔
2273
        if ( chartype[*s] != 0 ) goto illname;
544✔
2274
        s++;
544✔
2275
        while ( chartype[*s] <= 1 ) s++;
999✔
2276
        t = s;
544✔
2277
        if ( *s && *s != ' ' && *s != '\t' ) goto illname;
544✔
2278
        while ( *s == ' ' || *s == '\t' ) s++;
544✔
2279
        if ( *s ) {
544✔
2280
                MesPrint("@Undefine should just have a variable name");
×
2281
                error = -1;
×
2282
        }
2283
        *t = 0;
544✔
2284
        if ( ( retval = TheUndefine(name) ) != 0 ) {
544✔
2285
                if ( error == 0 ) return(retval);
×
2286
                if ( error > 0 ) error = retval;
×
2287
        }
2288
/*
2289
        for ( i = NumPre-1, p = &(PreVar[NumPre-1]); i >= 0; i--, p-- ) {
2290
                if ( StrCmp(name,p->name) == 0 ) {
2291
                        M_free(p->name,"undefining PreVar");
2292
                        NumPre--;
2293
                        while ( i < NumPre ) {
2294
                                p->name  = p[1].name;
2295
                                p->value = p[1].value;
2296
                                p++; i++;
2297
                        }
2298
                        p->name = 0; p->value = 0;
2299
                        break;
2300
                }
2301
        }
2302
*/
2303
        return(error);
2304
illname:;
×
2305
        MesPrint("@Illegally formed name of preprocessor variable");
×
2306
        return(-1);
×
2307
}
2308

2309
/*
2310
                 #] DoUndefine : 
2311
                 #[ DoInclude :
2312
*/
2313

2314
int DoInclude(UBYTE *s) { return(Include(s,FILESTREAM)); }
28✔
2315

2316
/*
2317
                 #] DoInclude : 
2318
                 #[ DoReverseInclude :
2319
*/
2320

2321
int DoReverseInclude(UBYTE *s) { return(Include(s,REVERSEFILESTREAM)); }
×
2322

2323
/*
2324
                 #] DoReverseInclude : 
2325
                 #[ Include :
2326
*/
2327

2328
int Include(UBYTE *s, int type)
28✔
2329
{
2330
        UBYTE *name = s, *fold, *t, c, c1 = 0, c2 = 0, c3 = 0;
28✔
2331
        int str1offset, withnolist = AC.NoShowInput;
28✔
2332
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
28✔
2333
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
28✔
2334
    if ( *s == '-' || *s == '+' ) {
28✔
2335
                if ( *s == '-' ) withnolist = 1;
7✔
2336
                else             withnolist = 0;
×
2337
                s++;
7✔
2338
                while ( *s == ' ' || *s == '\t' ) s++;
14✔
2339
                name = s;
2340
        }
2341
        if ( *s == '"' ) {
28✔
2342
                while ( *s && *s != '"' ) {
×
2343
                        if ( *s == '\\' ) s++;
×
2344
                        s++;
×
2345
                }
2346
                t = s++;
×
2347
        }
2348
        else {
2349
                while ( *s && *s != ' ' && *s != '\t' ) {
238✔
2350
                        if ( *s == '\\' ) s++;
210✔
2351
                        s++;
210✔
2352
                }
2353
                t = s;
28✔
2354
        }
2355
        while ( *s == ' ' || *s == '\t' ) s++;
35✔
2356
        if ( *s == '#' ) {
28✔
2357
                *t = 0;
7✔
2358
                s++;
7✔
2359
                while ( *s == ' ' || *s == '\t' ) s++;
14✔
2360
                fold = s;
7✔
2361
                if ( *s == 0 ) {
7✔
2362
                        MesPrint("@Empty fold name");
×
2363
                        return(-1);
×
2364
                }
2365
continue_fold:
119✔
2366
                while ( *s && *s != ' ' && *s != '\t' ) {
119✔
2367
                        if ( *s == '\\' ) s++;
112✔
2368
                        s++;
112✔
2369
                }
2370
                t = s;
7✔
2371
                while ( *s == ' ' || *s == '\t' ) s++;
7✔
2372
                if ( *s ) {
7✔
2373
                        /*
2374
                         * A non-whitespace character is found. Continue parsing the fold.
2375
                         */
2376
                        goto continue_fold;
×
2377
                }
2378
        }
2379
        else if ( *s == 0 ) {
21✔
2380
                fold = 0;
2381
        }
2382
        else {
2383
                MesPrint("@Improper syntax for file name");
×
2384
                return(-1);
×
2385
        }
2386
        *t = 0;
28✔
2387
        if ( fold ) {
28✔
2388
                fold = strDup1(fold,"foldname");
7✔
2389
        }
2390
/*
2391
        We have the name of the file in 'name' and the fold in 'fold' (or NULL)
2392
*/
2393
        if ( OpenStream(name,type,0,PRENOACTION) == 0 ) {
28✔
2394
                if ( fold ) { M_free(fold,"foldname"); fold = 0; }
×
2395
                return(-1);
×
2396
        }
2397
        if ( fold ) {
28✔
2398
                LONG position = -1;
7✔
2399
                int foldopen = 0;
7✔
2400
                LONG linenum = 0, prevline = 0;
7✔
2401
                name = strDup1(name,"name of include file");
7✔
2402
                AC.CurrentStream->FoldName = strDup1(fold,"name of fold");
7✔
2403
                AC.NoShowInput++;
7✔
2404
                for(;;) {
2,100✔
2405
                        c = GetFromStream(AC.CurrentStream);
2,100✔
2406
                        if ( c == ENDOFSTREAM ) {
2,100✔
2407
                                AC.CurrentStream = CloseStream(AC.CurrentStream);
×
2408
                                goto nofold;
×
2409
                        }
2410
                        if ( c == AP.ComChar ) {
2,100✔
2411
                                str1offset = AC.CurrentStream-AC.Streams;
462✔
2412
                                LoadInstruction(1);
462✔
2413
                                if ( AC.CurrentStream != str1offset+AC.Streams ) {
462✔
2414
                                        c = ENDOFSTREAM;
2415
                                }
2416
                                else {
2417
                                        t = AP.preStart;
462✔
2418
                                        if ( t[2] == '#' && ( ( t[3] == '[' && !foldopen )
462✔
2419
                                        || ( t[3] == ']' && foldopen ) ) ) {
14✔
2420
                                                t += 4;
14✔
2421
                                                while ( *t == ' ' || *t == '\t' ) t++;
28✔
2422
                                                s = AC.CurrentStream->FoldName;
14✔
2423
                                                while ( *s == *t ) { s++; t++; }
238✔
2424
                                                if ( *s == 0 && ( *t == ' ' || *t == '\t'
14✔
2425
                                                || *t == ':' ) ) {
×
2426
                                                        while ( *t == ' ' || *t == '\t' ) t++;
28✔
2427
                                                        if ( *t == ':' ) {
14✔
2428
                                                                if ( foldopen == 0 ) {
14✔
2429
                                                                        foldopen = 1;
7✔
2430
                                                                        position = GetStreamPosition(AC.CurrentStream);
7✔
2431
                                                                        linenum = AC.CurrentStream->linenumber;
7✔
2432
                                                                        prevline = AC.CurrentStream->prevline;
7✔
2433
                                                                        c3 = AC.CurrentStream->isnextchar;
7✔
2434
                                                                        c1 = AC.CurrentStream->nextchar[0];
7✔
2435
                                                                        c2 = AC.CurrentStream->nextchar[1];
7✔
2436
                                                                }
2437
                                                                else {
2438
                                                                        foldopen = 0;
7✔
2439
                                                                        PositionStream(AC.CurrentStream,position);
7✔
2440
                                                                        AC.CurrentStream->linenumber = linenum;
7✔
2441
                                                                        AC.CurrentStream->prevline = prevline;
7✔
2442
                                                                        AC.CurrentStream->eqnum = 1;
7✔
2443
                                                                        AC.NoShowInput--;
7✔
2444
                                                                        AC.CurrentStream->isnextchar = c3;
7✔
2445
                                                                        AC.CurrentStream->nextchar[0] = c1;
7✔
2446
                                                                        AC.CurrentStream->nextchar[1] = c2;
7✔
2447
                                                                        break;
7✔
2448
                                                                }
2449
                                                        }
2450
                                                }
2451
                                        }
2452
                                }
2453
                        }
2454
                        else {
2455
                                while ( c != LINEFEED && c != ENDOFSTREAM ) {
38,451✔
2456
                                        c = GetFromStream(AC.CurrentStream);
36,813✔
2457
                                        if ( c == ENDOFSTREAM ) {
36,813✔
2458
                                                AC.CurrentStream = CloseStream(AC.CurrentStream);
×
2459
                                                break;
×
2460
                                        }
2461
                                }
2462
                        }
2463
                        if ( c == ENDOFSTREAM ) {
2,093✔
2464
nofold:
×
2465
                                MesPrint("@Cannot find fold %s in file %s",fold,name);
×
2466
                                UngetChar(c);
×
2467
                                AC.NoShowInput--;
×
2468
                                M_free(name,"name of include file");
×
NEW
2469
                                TERMINATE(-1);
×
2470
                        }
2471
                }
2472
                M_free(name,"name of include file");
7✔
2473
        }
2474
        AC.NoShowInput = withnolist;
28✔
2475
        if ( fold ) { M_free(fold,"foldname"); fold = 0; }
28✔
2476
        return(0);
2477
}
2478

2479
/*
2480
                 #] Include : 
2481
                 #[ DoPreExchange :
2482

2483
                Exchanges the names of expressions or the contents of dollars
2484
                Syntax:
2485
                        #exchange expr1,expr2
2486
                        #exchange $var1,$var2
2487
*/
2488

2489
int DoPreExchange(UBYTE *s)
×
2490
{
2491
        int error = 0;
×
2492
        UBYTE *s1, *s2;
×
2493
        WORD num1, num2;
×
2494
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
2495
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
2496
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
×
2497
        if ( *s == '$' ) {
×
2498
                s++; s1 = s; while ( FG.cTable[*s] <= 1 ) s++;
×
2499
                if ( *s != ',' && *s != ' ' && *s != '\t' ) goto syntax;
×
2500
                *s++ = 0;
×
2501
                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
2502
                if ( *s != '$' ) goto syntax;
×
2503
                s++; s2 = s; while ( FG.cTable[*s] <= 1 ) s++;
×
2504
                if ( *s != 0 && *s != ';' ) goto syntax;
×
2505
                *s = 0;
×
2506
                if ( ( num1 = GetDollar(s1) ) <= 0 ) {
×
2507
                        MesPrint("@$%s has not been defined (yet)",s1);
×
2508
                        error = 1;
×
2509
                }
2510
                if ( ( num2 = GetDollar(s2) ) <= 0 ) {
×
2511
                        MesPrint("@$%s has not been defined (yet)",s2);
×
2512
                        error = 1;
×
2513
                }
2514
                if ( error == 0 ) {
×
2515
                        ExchangeDollars((int)num1,(int)num2);
×
2516
                }
2517
        }
2518
        else {
2519
                s1 = s; s = SkipAName(s);
×
2520
                if ( *s != ',' && *s != ' ' && *s != '\t' ) goto syntax;
×
2521
                *s++ = 0;
×
2522
                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
2523
                if ( FG.cTable[*s] != 0 && *s != '[' ) goto syntax;
×
2524
                s2 = s; s = SkipAName(s);
×
2525
                if ( *s != 0 && *s != ';' ) goto syntax;
×
2526
                *s = 0;
×
2527
            if ( GetName(AC.exprnames,s1,&num1,NOAUTO) != CEXPRESSION ) {
×
2528
                        MesPrint("@%s is not an expression",s1);
×
2529
                        error = 1;
×
2530
                }
2531
            if ( GetName(AC.exprnames,s2,&num2,NOAUTO) != CEXPRESSION ) {
×
2532
                        MesPrint("@%s is not an expression",s2);
×
2533
                        error = 1;
×
2534
                }
2535
                if ( error == 0 ) {
×
2536
                        ExchangeExpressions((int)num1,(int)num2);
×
2537
                }
2538
        }
2539
        return(error);
2540
syntax:
×
2541
        MesPrint("@Proper syntax: %#exchange expr1,expr2 or %#exchange $var1,$var2");
×
2542
        return(1);
×
2543
}
2544

2545
/*
2546
                 #] DoPreExchange : 
2547
                 #[ DoCall :
2548
*/
2549

2550
int DoCall(UBYTE *s)
465✔
2551
{
2552
        UBYTE *t, *u, *v, *name, c, cp, *args1, *args2, *t1, *t2, *wild = 0;
465✔
2553
        int bratype = 0, wildargs = 0, inwildargs = 0, nwildargs = 0;
465✔
2554
        PROCEDURE *p;
465✔
2555
        int streamoffset;
465✔
2556
        int i, namesize, narg1, narg2, bralevel, numpre;
465✔
2557
        LONG i1, i2;
465✔
2558
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
465✔
2559
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
465✔
2560
/*
2561
        1:        Get the name of the procedure.
2562
        2:        Locate the procedure.
2563
*/
2564
        name = s; s = EndOfToken(s); c = *s; *s = 0;
465✔
2565
        for ( i = NumProcedures-1; i >= 0; i-- ) {
997✔
2566
                if ( StrCmp(Procedures[i].name,name) == 0 ) break;
962✔
2567
        }
2568
        p = (PROCEDURE *)FromList(&AP.ProcList);
465✔
2569
        if ( i < 0 ) {        /* Try to find a file */
465✔
2570
                namesize = 0;
2571
                t = name;
2572
                while ( *t ) { t++; namesize++; }
105✔
2573
                t = AP.procedureExtension;
35✔
2574
                while ( *t ) { t++; namesize++; }
140✔
2575
                t = p->name = (UBYTE *)Malloc1(namesize+2,"procedure");
35✔
2576
                u = name;
35✔
2577
                while ( *u ) *t++ = *u++;
105✔
2578
                *t++ = '.';
35✔
2579
                v = AP.procedureExtension;
35✔
2580
                while ( *v ) *t++ = *v++;
140✔
2581
                *t = 0;
35✔
2582
                p->loadmode = 0;        /* buffer should be freed at end */
35✔
2583
                p->p.buffer = LoadInputFile(p->name,PROCEDUREFILE);
35✔
2584
                if ( p->p.buffer == 0 ) return(-1);
35✔
2585
                t[-4] = 0;
35✔
2586
        }
2587
        else {
2588
                p->p.buffer = Procedures[i].p.buffer;
430✔
2589
                p->name = Procedures[i].name;
430✔
2590
                p->loadmode = 1;
430✔
2591
        }
2592
        t = p->p.buffer;
465✔
2593
        SKIPBLANKS(t)
465✔
2594
        if ( *t++ != '#' ) goto wrongfile;
465✔
2595
        SKIPBLANKS(t)
465✔
2596
        t += 9;
465✔
2597
        SKIPBLANKS(t)
930✔
2598
        u = EndOfToken(t);
465✔
2599
        cp = *u; *u = 0;
465✔
2600
        if ( StrCmp(t,name) != 0 ) goto wrongfile;
465✔
2601
        *u = cp;
465✔
2602
        *s = c;
465✔
2603
/*
2604
        The pointer p points to the contents of the procedure (in memory)
2605
        Now we have to match the arguments. u points to after the name
2606
        in the 'file', s to after the name in the call statement.
2607
*/
2608
        bralevel = narg1 = narg2 = 0; args2 = u;
465✔
2609
        SKIPBLANKS(u)
465✔
2610
        if ( *u == '(' ) {
465✔
2611
                u++; SKIPBLANKS(u)
427✔
2612
                args2 = u;
1,099✔
2613
                while ( *u != ')' ) {
1,099✔
2614
                        if ( *u == '?' ) { wildargs++; u++; nwildargs = narg2+1; }
672✔
2615
                        narg2++; u = EndOfToken(u); SKIPBLANKS(u)
672✔
2616
                        if ( *u == ',' ) { u++; SKIPBLANKS(u) }
672✔
2617
                        else if ( *u != ')' || ( wildargs > 1 ) ) {
322✔
2618
                                MesPrint("@Illegal argument field in procedure %s",p->name);
×
2619
                                return(-1);
×
2620
                        }
2621
                }
2622
        }
2623
        while ( *u != LINEFEED ) u++;
892✔
2624
        SKIPBLANKS(s)
465✔
2625
        args1 = s+1;
465✔
2626
        if ( *s == '(' ) bratype = 1;
465✔
2627
        do {
3,741✔
2628
                if ( *s == '{' && bratype == 0 ) bralevel++;
3,741✔
2629
                else if ( *s == '(' && bratype == 1 ) bralevel++;
3,741✔
2630
                else if ( *s == '}' && bratype == 0 ) {
3,335✔
2631
                        bralevel--;
×
2632
                        if ( bralevel == 0 ) {
×
2633
                                *s = 0; narg1++;
×
2634
                                if ( wildargs && narg1 == nwildargs ) wild = s;
×
2635
                        }
2636
                }
2637
                else if ( *s == ')' && bratype == 1 ) {
3,335✔
2638
                        bralevel--;
406✔
2639
                        if ( bralevel == 0 ) {
406✔
2640
                                *s = 0; narg1++;
406✔
2641
                                if ( wildargs && narg1 == nwildargs ) wild = s;
406✔
2642
                        }
2643
                }
2644
                /*[12dec2003 mt]:*/
2645
                /*else if ( *s == ',' || *s == '|' ) {*/
2646
                else if (set_in(*s,AC.separators)) {/*Function set_in see in
2,929✔
2647
                                                                                                                        file tools.c*/
2648
                /*:[12dec2003 mt]*/
2649
                        *s = 0; narg1++;
364✔
2650
                        if ( wildargs && narg1 == nwildargs ) wild = s;
364✔
2651
                }
2652
                else if ( *s == '\\' ) s++;
2,565✔
2653
                s++;
3,741✔
2654
        } while ( bralevel > 0 );
3,741✔
2655
        if ( wildargs && narg1 >= narg2-1 ) {
465✔
2656
                inwildargs = narg1-narg2+1;
7✔
2657
                if ( inwildargs == 0 ) nwildargs = 0;
7✔
2658
                else {
2659
                        while ( inwildargs > 1 ) {
21✔
2660
                                *wild = ',';
14✔
2661
                                while ( *wild ) wild++;
70✔
2662
                                inwildargs--;
14✔
2663
                        }
2664
                }
2665
        }
2666
        else if ( narg1 != narg2 && ( narg2 != 0 || narg1 != 1 || *args1 != 0 ) ) {
458✔
2667
                MesPrint("@Arguments of procedure %s are not matching",p->name);
×
2668
                return(-1);
×
2669
        }
2670
        numpre = -NumPre-1;        /* For the stream */
465✔
2671
        for ( i = 0; i < narg2; i++ ) {
1,137✔
2672
                t = args2;
672✔
2673
                if ( *t == '?' ) {
672✔
2674
                        args2++;
7✔
2675
                }
2676
                if ( *t == '?' && inwildargs == 0 ) {
672✔
2677
                        args2 = EndOfToken(args2); c = *args2; *args2 = 0;
×
2678
                        if ( PutPreVar(t,(UBYTE *)"",0,0) < 0 ) return(-1);
×
2679
                }
2680
                else {
2681
                        args2 = EndOfToken(args2); c = *args2; *args2 = 0;
672✔
2682
                        t1 = t2 = args1;
672✔
2683
                        while ( *t1 ) {
3,192✔
2684
                                if ( *t1 == '\\' ) t1++;
2,520✔
2685
                                if ( t1 != t2 ) *t2 = *t1;
2,520✔
2686
                                t2++; t1++;
2,520✔
2687
                        }
2688
                        *t2 = 0;
672✔
2689
                        if ( PutPreVar(t,args1,0,0) < 0 ) return(-1);
672✔
2690
                        args1 = t1+1;                  /* Next argument */
672✔
2691
                }
2692
                *args2 = c; SKIPBLANKS(args2)  /* skip to next name */
672✔
2693
                args2++; SKIPBLANKS(args2)
672✔
2694
        }
2695
        streamoffset = AC.CurrentStream - AC.Streams;
465✔
2696
        args1 = AC.CurrentStream->name;
465✔
2697
        AC.CurrentStream->name = p->name;
465✔
2698
        i1 = AC.CurrentStream->linenumber;
465✔
2699
        i2 = AC.CurrentStream->prevline;
465✔
2700
        AC.CurrentStream->prevline   =
465✔
2701
        AC.CurrentStream->linenumber = 2;
465✔
2702
        OpenStream(u+1,PREREADSTREAM3,numpre,PRENOACTION);
465✔
2703
        AC.Streams[streamoffset].name = args1;
465✔
2704
        AC.Streams[streamoffset].linenumber = i1;
465✔
2705
        AC.Streams[streamoffset].prevline   = i2;
465✔
2706
        AddToPreTypes(PRETYPEPROCEDURE);
465✔
2707
        return(0);
465✔
2708
wrongfile:;
×
2709
        if ( i < 0 ) MesPrint("@File %s is not a proper procedure",p->name);
×
2710
        else MesPrint("!!!Internal error with procedure names: %s",name);
×
2711
        return(-1);
2712
}
2713

2714
/*
2715
                 #] DoCall : 
2716
                 #[ DoDebug :
2717
*/
2718

2719
int DoDebug(UBYTE *s)
×
2720
{
2721
        int x;
×
2722
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
2723
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
2724
        NeedNumber(x,s,nonumber)
×
2725
        if ( x < 0 || x >(PREPROONLY
×
2726
                                        | DUMPTOCOMPILER
2727
                                        | DUMPOUTTERMS
2728
                                        | DUMPINTERMS
2729
                                        | DUMPTOSORT
2730
                                        | DUMPTOPARALLEL
2731
#ifdef WITHPTHREADS
2732
                                        | THREADSDEBUG
2733
#endif
2734
                         ) ) goto nonumber;
×
2735
        AP.PreDebug = 0;
×
2736
        if ( ( x & PREPROONLY     ) != 0 ) AP.PreDebug |= PREPROONLY;     /* 1  */
×
2737
        if ( ( x & DUMPTOCOMPILER ) != 0 ) AP.PreDebug |= DUMPTOCOMPILER; /* 2  */
×
2738
        if ( ( x & DUMPOUTTERMS   ) != 0 ) AP.PreDebug |= DUMPOUTTERMS;   /* 4  */
×
2739
        if ( ( x & DUMPINTERMS    ) != 0 ) AP.PreDebug |= DUMPINTERMS;    /* 8  */
×
2740
        if ( ( x & DUMPTOSORT     ) != 0 ) AP.PreDebug |= DUMPTOSORT;     /* 16 */
×
2741
        if ( ( x & DUMPTOPARALLEL ) != 0 ) AP.PreDebug |= DUMPTOPARALLEL; /* 32 */
×
2742
#ifdef WITHPTHREADS
2743
        if ( ( x & THREADSDEBUG   ) != 0 ) AP.PreDebug |= THREADSDEBUG;   /* 64 */
2744
#endif
2745
        return(0);
2746
nonumber:
×
2747
        MesPrint("@Illegal argument for debug instruction");
×
2748
        return(1);
×
2749
}
2750

2751
/*
2752
                 #] DoDebug : 
2753
                 #[ DoTerminate :
2754
*/
2755

2756
int DoTerminate(UBYTE *s)
791✔
2757
{
2758
        int x;
791✔
2759
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
791✔
2760
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
791✔
2761
        if ( *s ) {
×
2762
                NeedNumber(x,s,nonumber)
×
NEW
2763
                TERMINATE(x);
×
2764
        }
2765
        else {
NEW
2766
                TERMINATE(-1);
×
2767
        }
2768
        return(0);
2769
nonumber:
×
2770
        MesPrint("@Illegal argument for terminate instruction");
×
2771
        return(1);
×
2772
}
2773

2774
/*
2775
                 #] DoTerminate : 
2776
                 #[ DoContinueDo :
2777
*/
2778

2779
int DoContinueDo(UBYTE *s)
42✔
2780
{
2781
        DOLOOP *loop;
42✔
2782

2783
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
42✔
2784
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
42✔
2785

2786
        if ( NumDoLoops <= 0 ) {
14✔
2787
                MesPrint("@%#continuedo without %#do");
7✔
2788
                return(1);
7✔
2789
        }
2790

2791
        loop = &(DoLoops[NumDoLoops-1]);
7✔
2792
        AP.NumPreTypes = loop->NumPreTypes+1;
7✔
2793
        AP.PreIfLevel = loop->PreIfLevel;
7✔
2794
        AP.PreSwitchLevel = loop->PreSwitchLevel;
7✔
2795

2796
        return(DoEnddo(s));
7✔
2797
}
2798

2799
/*
2800
                 #] DoContinueDo :
2801
                 #[ DoDo :
2802

2803
                The do loop has three varieties:
2804
                #do i = num1,num2 [,num3]
2805
                #do i = {string1,string2,....,stringn}
2806
                        The | as separator is also allowed for backwards compatibility
2807
                #do i = expression      One by one all terms of the expression
2808
*/
2809

2810
int DoDo(UBYTE *s)
547✔
2811
{
2812
        GETIDENTITY
158✔
2813
        UBYTE *t, c, *u, *uu;
547✔
2814
        DOLOOP *loop;
547✔
2815
        WORD expnum;
547✔
2816
        LONG linenum  = AC.CurrentStream->linenumber;
547✔
2817
        int oldNoShowInput = AC.NoShowInput, i, oldpreassignflag;
547✔
2818

2819
        if ( ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH )
547✔
2820
        || ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ) {
547✔
2821
                if ( PreSkip((UBYTE *)"do",(UBYTE *)"enddo",1) ) return(-1);
×
2822
                return(0);
×
2823
        }
2824

2825
/*
2826
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2827
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2828
*/
2829
        AddToPreTypes(PRETYPEDO);
547✔
2830
 
2831
        loop = (DOLOOP *)FromList(&AP.LoopList);
547✔
2832
        loop->firstdollar = loop->lastdollar = loop->incdollar = -1;
547✔
2833
        loop->NumPreTypes = AP.NumPreTypes-1;
547✔
2834
        loop->PreIfLevel = AP.PreIfLevel;
547✔
2835
        loop->PreSwitchLevel = AP.PreSwitchLevel;
547✔
2836
        AC.NoShowInput = 1;
547✔
2837
        if ( PreLoad(&(loop->p),(UBYTE *)"do",(UBYTE *)"enddo",1,"doloop") ) return(-1);
547✔
2838
        AC.NoShowInput = oldNoShowInput;
547✔
2839
        loop->NoShowInput = AC.NoShowInput;
547✔
2840
/*
2841
        Get now the name. We have to take great care when the name is terminated!
2842
*/
2843
        s = loop->p.buffer + (s - AP.preStart);
547✔
2844
        SKIPBLANKS(s)
1,094✔
2845
        loop->name = s;
547✔
2846
        if ( chartype[*s] != 0 ) goto illname;
547✔
2847
        s++;
547✔
2848
        while ( chartype[*s] <= 1 ) s++;
1,002✔
2849
        t = s;
855✔
2850
        while ( *s == ' ' || *s == '\t' ) s++;
855✔
2851
        if ( *s != '=' ) goto illdo;
547✔
2852
        s++;
547✔
2853
        while ( *s == ' ' || *s == '\t' ) s++;
855✔
2854
        *t = 0;
547✔
2855

2856
        if ( *s == '{' ) {
547✔
2857
                loop->type = LISTEDLOOP;
42✔
2858
                s++; loop->vars = s;
42✔
2859
                loop->lastnum = 0;
42✔
2860
                while ( *s != '}' && *s != 0 ) {
875✔
2861
                        if ( set_in(*s,AC.separators) ) { *s = 0; loop->lastnum++; }
833✔
2862
                        else if ( *s == '\\' ) s++;
644✔
2863
                        s++;
833✔
2864
                }
2865
                if ( *s == 0 ) goto illdo;
42✔
2866
                *s++ = 0;
42✔
2867
                loop->lastnum++;
42✔
2868
                loop->firstnum = 0;
42✔
2869
                loop->contents = s;
42✔
2870
        }
2871
        else if ( *s == '-' || *s == '+' || chartype[*s] == 1 || *s == '$' ) {
505✔
2872
                loop->type = NUMERICALLOOP;
505✔
2873
                t = s;
505✔
2874
                while ( *s && *s != ',' ) s++;
1,038✔
2875
                if ( *s == 0 ) goto illdo;
505✔
2876
                if ( *t == '$' ) {
505✔
2877
                        c = *s; *s = 0;
×
2878
                        if ( GetName(AC.dollarnames,t+1,&loop->firstdollar,NOAUTO) != CDOLLAR ) {
×
2879
                                MesPrint("@%s is undefined in first parameter in %#do instruction",t);
×
2880
                                return(-1);
×
2881
                        }
2882
                        loop->firstnum = DolToLong(BHEAD loop->firstdollar);
×
2883
                        if ( AN.ErrorInDollar ) {
×
2884
                                MesPrint("@%s does not evaluate into a valid loop parameter",t);
×
2885
                                return(-1);
×
2886
                        }
2887
                        *s++ = c;
×
2888
                }
2889
                else {
2890
                        *s = '}';
505✔
2891
                        if ( PreEval(t,&loop->firstnum) == 0 ) goto illdo;
505✔
2892
                        *s++ = ',';
505✔
2893
                }
2894
                t = s;
505✔
2895
                while ( *s && *s != ',' && *s != ';' && *s != LINEFEED ) s++;
1,230✔
2896
                c = *s;
505✔
2897
                if ( *t == '$' ) {
505✔
2898
                        *s = 0;
×
2899
                        if ( GetName(AC.dollarnames,t+1,&loop->lastdollar,NOAUTO) != CDOLLAR ) {
×
2900
                                MesPrint("@%s is undefined in second parameter in %#do instruction",t);
×
2901
                                return(-1);
×
2902
                        }
2903
                        loop->lastnum = DolToLong(BHEAD loop->lastdollar);
×
2904
                        if ( AN.ErrorInDollar ) {
×
2905
                                MesPrint("@%s does not evaluate into a valid loop parameter",t);
×
2906
                                return(-1);
×
2907
                        }
2908
                        *s++ = c;
×
2909
                }
2910
                else {
2911
                        *s = '}';
505✔
2912
                        if ( PreEval(t,&loop->lastnum) == 0 ) goto illdo;
505✔
2913
                        *s++ = c;
505✔
2914
                }
2915
                if ( c == ',' ) {
505✔
2916
                        t = s;
28✔
2917
                        while ( *s && *s != ';' && *s != LINEFEED ) s++;
28✔
2918
                        if ( *t == '$' ) {
14✔
2919
                                c = *s; *s = 0;
×
2920
                                if ( GetName(AC.dollarnames,t+1,&loop->incdollar,NOAUTO) != CDOLLAR ) {
×
2921
                                        MesPrint("@%s is undefined in third parameter in %#do instruction",t);
×
2922
                                        return(-1);
×
2923
                                }
2924
                                loop->incnum = DolToLong(BHEAD loop->incdollar);
×
2925
                                if ( AN.ErrorInDollar ) {
×
2926
                                        MesPrint("@%s does not evaluate into a valid loop parameter",t);
×
2927
                                        return(-1);
×
2928
                                }
2929
                                *s++ = c;
×
2930
                        }
2931
                        else {
2932
                                c = *s; *s = '}';
14✔
2933
                                if ( PreEval(t,&loop->incnum) == 0 ) goto illdo;
14✔
2934
                                *s++ = c;
14✔
2935
                        }
2936
                }
2937
                else loop->incnum = 1;
491✔
2938
                loop->contents = s;
505✔
2939
        }
2940
        else if ( ( chartype[*s] == 0 ) || ( *s == '[' ) ) {
×
2941
                int oldNumPotModdollars = NumPotModdollars;
×
2942
#ifdef WITHMPI
2943
                WORD oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
2944
                AC.RhsExprInModuleFlag = 0;
2945
#endif
2946
                t = s;
×
2947
                if ( ( s = SkipAName(s) ) == 0 ) goto illdo;
×
2948
                c = *s; *s = 0;
×
2949
                if ( GetName(AC.exprnames,t,&expnum,NOAUTO) == CEXPRESSION ) {
×
2950
                        loop->type = ONEEXPRESSION;
×
2951
/*
2952
                        We should remember the expression by name for when it gets
2953
                        renumbered!!! If it gets deleted there will be a crash or at
2954
                        least the loop terminates.
2955
*/        
2956
                        loop->vars = t;
×
2957
                }
2958
                else goto illdo;
×
2959
                if ( c == ',' || c == '\t' || c == ';' ) { s++; }
×
2960
                else if ( c != 0 && c != '\n' ) goto illdo;
×
2961
                while ( *s == ',' || *s == '\t' || *s == ';' ) s++;
×
2962
                if ( *s != 0 && *s != '\n' ) goto illdo;
×
2963
                loop->firstnum = 0;
×
2964
                s++;
×
2965
                loop->contents = s;
×
2966
                loop->incnum = 0;
×
2967
/*
2968
                Next determine size of statement and allocate space
2969
*/
2970
                while ( *t ) t++;
×
2971
                i = t - loop->vars;
×
2972
                t = loop->name;
×
2973
                while ( *t ) { t++; i++; }
×
2974
                i += 4;
×
2975
                loop->dollarname = Malloc1((LONG)i,"do-loop instruction");
×
2976
/*
2977
                Construct the statement
2978
*/
2979
                u = loop->dollarname;
×
2980
                *u++ = '$'; t = loop->name; while ( *t ) *u++ = *t++;
×
2981
                *u++ = '_'; uu = u; *u++ = '='; t = loop->vars;
×
2982
                while ( *t ) *u++ = *t++;
×
2983
                *t = 0; *u = 0;
×
2984
/*
2985
                Compile and put in dollar variable.
2986
                Note that we remember the dollar by name and that this name ends in _
2987
*/
2988
                oldpreassignflag = AP.PreAssignFlag;
×
2989
                AP.PreAssignFlag = 2;
×
2990
        CompileStatement(loop->dollarname);
×
2991
                if ( CatchDollar(0) ) {
×
2992
                        MesPrint("@Cannot load expression in do loop");
×
2993
                        return(-1);
×
2994
                }
2995
                AP.PreAssignFlag = oldpreassignflag;
×
2996
                NumPotModdollars = oldNumPotModdollars;
×
2997
#ifdef WITHMPI
2998
                AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
2999
#endif
3000
                *uu = 0;
×
3001
        }
3002
        else goto illdo; /* Syntax problems */
×
3003
        loop->errorsinloop = 0;
547✔
3004
/*        loop->startlinenumber = linenum+1; 5-oct-2000 One too much? */
3005
        loop->startlinenumber = linenum;
547✔
3006
        PutPreVar(loop->name,(UBYTE *)"0",0,0);                        
547✔
3007
        loop->firstloopcall = 1;
547✔
3008
        return(DoEnddo(s));
547✔
3009
illname:;
×
3010
        MesPrint("@Improper name for do loop variable");
×
3011
        return(-1);
×
3012
illdo:;
×
3013
        MesPrint("@Improper syntax in do loop instruction");
×
3014
        return(-1);
×
3015
}
3016

3017
/*
3018
                 #] DoDo : 
3019
                 #[ DoBreakDo :
3020

3021
                #breakdo [num]
3022
                jumps out of num #do-loops (if there are that many) (default is 1)
3023
*/
3024

3025
int DoBreakDo(UBYTE *s)
×
3026
{
3027
        DOLOOP *loop;
×
3028
        WORD levels;
×
3029

3030
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3031
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
3032

3033
        if ( NumDoLoops <= 0 ) {
×
3034
                MesPrint("@%#breakdo without %#do");
×
3035
                return(1);
×
3036
        }
3037
/*
3038
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEDO ) { MessPreNesting(4); return(-1); }
3039
*/
3040
        while ( *s && ( *s == ',' || *s == ' ' || *s == '\t' ) ) s++;
×
3041
        if ( *s == 0 ) {
×
3042
                levels = 1;
3043
        }
3044
        else if ( FG.cTable[*s] == 1 ) {
×
3045
                levels = 0;
3046
                while ( *s >= '0' && *s <= '9' ) { levels = 10*levels + *s++ - '0'; }
×
3047
                if ( *s != 0 ) goto improper;
×
3048
        }
3049
        else {
3050
improper:
×
3051
                MesPrint("@Improper syntax of %#breakdo instruction");
×
3052
                return(1);
×
3053
        }
3054
        if ( levels > NumDoLoops ) {
×
3055
                MesPrint("@Too many loop levels requested in %#breakdo instruction");
×
NEW
3056
                TERMINATE(-1);
×
3057
        }
3058
        while ( levels > 0 ) {
×
3059
                while ( AC.CurrentStream->type != PREREADSTREAM
×
3060
                  && AC.CurrentStream->type != PREREADSTREAM2
×
3061
                  && AC.CurrentStream->type != PREREADSTREAM3 ) {
×
3062
                        AC.CurrentStream = CloseStream(AC.CurrentStream);
×
3063
                }
3064
                while ( AP.PreTypes[AP.NumPreTypes] != PRETYPEDO
×
3065
                && AP.PreTypes[AP.NumPreTypes] != PRETYPEPROCEDURE ) AP.NumPreTypes--;
×
3066
                if ( AC.CurrentStream->type == PREREADSTREAM3
×
3067
                || AP.PreTypes[AP.NumPreTypes] == PRETYPEPROCEDURE ) {
×
3068
                        MesPrint("@Trying to jump out of a procedure with a %#breakdo instruction");
×
NEW
3069
                        TERMINATE(-1);
×
3070
                }
3071
                loop = &(DoLoops[NumDoLoops-1]);
×
3072
                AP.NumPreTypes = loop->NumPreTypes;
×
3073
                AP.PreIfLevel = loop->PreIfLevel;
×
3074
                AP.PreSwitchLevel = loop->PreSwitchLevel;
×
3075
/*
3076
                AP.NumPreTypes--;
3077
*/
3078
                NumDoLoops--;
×
3079
                DoUndefine(loop->name);
×
3080
                M_free(loop->p.buffer,"loop->p.buffer");
×
3081
                loop->firstloopcall = 0;
×
3082

3083
                AC.CurrentStream = CloseStream(AC.CurrentStream);
×
3084
                levels--;
×
3085
        }
3086
        return(0);
3087
}
3088

3089
/*
3090
                 #] DoBreakDo : 
3091
                 #[ DoElse :
3092
*/
3093

3094
int DoElse(UBYTE *s)
35✔
3095
{
3096
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEIF ) {
35✔
3097
                if ( AP.PreIfLevel <= 0 ) MesPrint("@%#else without corresponding %#if");
×
3098
                else MessPreNesting(1);
×
3099
                return(-1);
×
3100
        }
3101
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
35✔
3102
        while ( *s == ' ' ) s++;
35✔
3103
        if ( tolower(*s) == 'i' && tolower(s[1]) == 'f' && s[2]
35✔
3104
                && FG.cTable[s[2]] > 1 && s[2] != '_' ) {
×
3105
                s += 2;
×
3106
                while ( *s == ' ' ) s++;
×
3107
                return(DoElseif(s));
×
3108
        }
3109
        if ( AP.PreIfLevel <= 0 ) {
35✔
3110
                MesPrint("@%#else without corresponding %#if");
×
3111
                return(-1);
×
3112
        }
3113
        switch ( AP.PreIfStack[AP.PreIfLevel] ) {
35✔
3114
                case EXECUTINGIF:
×
3115
                        AP.PreIfStack[AP.PreIfLevel] = LOOKINGFORENDIF;
×
3116
                        break;
×
3117
                case LOOKINGFORELSE:
35✔
3118
                        AP.PreIfStack[AP.PreIfLevel] = EXECUTINGIF;
35✔
3119
                        break;
35✔
3120
                case LOOKINGFORENDIF:
3121
                        break;
3122
        }
3123
        return(0);
3124
}
3125

3126
/*
3127
                 #] DoElse : 
3128
                 #[ DoElseif :
3129
*/
3130

3131
int DoElseif(UBYTE *s)
×
3132
{
3133
        int condition;
×
3134
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEIF ) {
×
3135
                if ( AP.PreIfLevel <= 0 ) MesPrint("@%#elseif without corresponding %#if");
×
3136
                else MessPreNesting(2);
×
3137
                return(-1);
×
3138
        }
3139
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3140
        if ( AP.PreIfLevel <= 0 ) {
×
3141
                MesPrint("@%#elseif without corresponding %#if");
×
3142
                return(-1);
×
3143
        }
3144
        switch ( AP.PreIfStack[AP.PreIfLevel] ) {
×
3145
                case EXECUTINGIF:
×
3146
                        AP.PreIfStack[AP.PreIfLevel] = LOOKINGFORENDIF;
×
3147
                        break;
×
3148
                case LOOKINGFORELSE:
×
3149
                        if ( ( condition = EvalPreIf(s) ) < 0 ) return(-1);
×
3150
                        AP.PreIfStack[AP.PreIfLevel] = condition;
×
3151
                        break;
×
3152
                case LOOKINGFORENDIF:
3153
                        break;
3154
        }
3155
        return(0);
3156
}
3157

3158
/*
3159
                 #] DoElseif : 
3160
                 #[ DoEnddo :
3161

3162
                At the first call there is no stream yet.
3163
                After that we have to close the stream and start a new one.
3164
*/
3165

3166
int DoEnddo(UBYTE *s)
2,310,287✔
3167
{
3168
        GETIDENTITY
1,127,215✔
3169
        DOLOOP *loop;
2,310,286✔
3170
        UBYTE *t, *tt, *value, numstr[16];
2,310,286✔
3171
        LONG xval;
2,310,286✔
3172
        int xsign, retval;
2,310,286✔
3173
        DUMMYUSE(s);
2,310,286✔
3174
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
2,310,286✔
3175
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
2,310,286✔
3176
/*
3177
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ||
3178
                AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) {
3179
                if ( AP.PreTypes[AP.NumPreTypes] == PRETYPEDO ) AP.NumPreTypes--;
3180
                else { MessPreNesting(3); return(-1); }
3181
                return(0);
3182
        }
3183
*/
3184
        if ( NumDoLoops <= 0 ) {
2,310,286✔
3185
                MesPrint("@%#enddo without %#do");
×
3186
                return(1);
×
3187
        }
3188
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEDO ) { MessPreNesting(4); return(-1); }
2,310,286✔
3189
        loop = &(DoLoops[NumDoLoops-1]);
2,310,286✔
3190
        if ( !loop->firstloopcall ) AC.CurrentStream = CloseStream(AC.CurrentStream);
2,310,286✔
3191

3192
        if ( loop->errorsinloop ) {
2,310,286✔
3193
                MesPrint("++++Errors in Loop");
×
3194
                goto finish;
×
3195
        }
3196
        if ( loop->type == LISTEDLOOP ) {
2,310,286✔
3197
                if ( loop->firstnum >= loop->lastnum ) goto finish;
273✔
3198
                loop->firstnum++;
231✔
3199
                t = value = loop->vars;
231✔
3200
                while ( *value ) value++;
938✔
3201
                value++;
231✔
3202
                loop->vars = value;
231✔
3203
                value = tt = t;
231✔
3204
                while ( *value ) {
875✔
3205
                        if ( *value == '\\' ) value++;
644✔
3206
                        *tt++ = *value++;
644✔
3207
                } 
3208
                *tt = 0;
231✔
3209
                PutPreVar(loop->name,t,0,1);        /* We overwrite the definition */
231✔
3210
        }
3211
        else if ( loop->type == NUMERICALLOOP ) {
2,310,012✔
3212

3213
                if ( !loop->firstloopcall ) {
2,310,012✔
3214
/*
3215
                        Test whether the variable was changed inside the loop into
3216
                        a different numerical value. If so, adjust.
3217
*/
3218
                        t = GetPreVar(loop->name,WITHOUTERROR);
2,309,513✔
3219
                        if ( t ) {
2,309,512✔
3220
                                value = t;
3221
                                xsign = 1;
3222
                                while ( *value && ( *value == ' '
2,309,652✔
3223
                                                || *value == '-' || *value == '+' ) ) {
2,309,652✔
3224
                                        if ( *value == '-' ) xsign = -xsign;
140✔
3225
                                        value++;
140✔
3226
                                }
3227
                                t = value; xval = 0;
4,730,684✔
3228
                                while ( *value >= '0' && *value <= '9' ) xval = 10*xval + *value++ - '0';
4,730,684✔
3229
                                while ( *value && *value == ' ' ) value++;
2,309,512✔
3230
                                if ( *value == 0 ) {
2,309,512✔
3231
/*
3232
                                        Now we may substitute the loopvalue.
3233
*/
3234
                                        if ( xsign < 0 ) xval = -xval;
2,309,511✔
3235
                                        if ( loop->incdollar >= 0 ) {
2,309,511✔
3236
                                                loop->incnum = DolToLong(BHEAD loop->incdollar);
×
3237
                                                if ( AN.ErrorInDollar ) {
×
3238
                                                        MesPrint("@%s does not evaluate into a valid third loop parameter",DOLLARNAME(Dollars,loop->incdollar));
×
3239
                                                        return(-1);
×
3240
                                                }
3241
                                        }
3242
                                        loop->firstnum = xval + loop->incnum;
2,309,511✔
3243
                                }
3244
                        }
3245
                        if ( loop->lastdollar >= 0 ) {
2,309,512✔
3246
                                loop->lastnum = DolToLong(BHEAD loop->lastdollar);
×
3247
                                if ( AN.ErrorInDollar ) {
×
3248
                                        MesPrint("@%s does not evaluate into a valid second loop parameter",DOLLARNAME(Dollars,loop->lastdollar));
×
3249
                                        return(-1);
×
3250
                                }
3251
                        }
3252
                }
3253
                if ( ( loop->incnum > 0 && loop->firstnum > loop->lastnum )
2,310,011✔
3254
                || ( loop->incnum < 0 && loop->firstnum < loop->lastnum ) ) goto finish;
2,310,011✔
3255
                NumToStr(numstr,loop->firstnum);
2,309,513✔
3256
                t = numstr;
2,309,513✔
3257
                loop->firstnum += loop->incnum;
2,309,513✔
3258
                PutPreVar(loop->name,t,0,1);        /* We overwrite the definition */
2,309,513✔
3259
        }
3260
        else if ( loop->type == ONEEXPRESSION ) {
×
3261
/*
3262
                Find the dollar expression
3263
*/
3264
                WORD numdollar = GetDollar(loop->dollarname+1);
×
3265
                DOLLARS d = Dollars + numdollar;
×
3266
                WORD *w, *dw, v, *ww;
×
3267
                if ( (d->where) == 0 ) {
×
3268
                        d->type = DOLUNDEFINED;
×
3269
                        M_free(loop->dollarname,"do-loop instruction");
×
3270
                        goto finish;
×
3271
                }
3272
                w = d->where + loop->incnum;
×
3273
                if ( *w == 0 ) {
×
3274
                        M_free(d->where,"dollar");
×
3275
                        d->where = 0;
×
3276
                        d->type = DOLUNDEFINED;
×
3277
                        M_free(loop->dollarname,"do-loop instruction");
×
3278
                        goto finish;
×
3279
                }
3280
                loop->incnum += *w;
×
3281
/*
3282
                Now the term has to be converted to text.
3283
*/
3284
                ww = w + *w; v = *ww; *ww = 0;
×
3285
                dw = d->where; d->where = w;
×
3286
                t = WriteDollarToBuffer(numdollar,1);
×
3287
                d->where = dw; *ww = v;
×
3288
                PutPreVar(loop->name,t,0,1);        /* We overwrite the definition */
×
3289
                M_free(t,"dollar");
×
3290
        }
3291
        if ( loop->firstloopcall ) OpenStream(loop->contents,PREREADSTREAM2,0,PRENOACTION);
2,309,741✔
3292
        else OpenStream(loop->contents,PREREADSTREAM,0,PRENOACTION);
2,309,195✔
3293
        AC.CurrentStream->prevline   =
2,309,741✔
3294
        AC.CurrentStream->linenumber = loop->startlinenumber;
2,309,741✔
3295
        AC.CurrentStream->eqnum = 0;
2,309,741✔
3296
        loop->firstloopcall = 0;
2,309,741✔
3297
        return(0);
2,309,741✔
3298
finish:;
544✔
3299
        NumDoLoops--;
544✔
3300
        retval = DoUndefine(loop->name);
544✔
3301
        M_free(loop->p.buffer,"loop->p.buffer");
544✔
3302
        loop->firstloopcall = 0;
544✔
3303
        AP.NumPreTypes--;
544✔
3304
        return(retval);
544✔
3305
}
3306

3307
/*
3308
                 #] DoEnddo : 
3309
                 #[ DoEndif :
3310
*/
3311

3312
int DoEndif(UBYTE *s)
955✔
3313
{
3314
        DUMMYUSE(s);
955✔
3315
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEIF ) {
955✔
3316
                if ( AP.PreIfLevel <= 0 ) MesPrint("@%#endif without corresponding %#if");
×
3317
                else MessPreNesting(5);
×
3318
                return(-1);
×
3319
        }
3320
        AP.NumPreTypes--;
955✔
3321
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
955✔
3322
        if ( AP.PreIfLevel <= 0 ) {
955✔
3323
                MesPrint("@%#endif without corresponding %#if");
×
3324
                return(-1);
×
3325
        }
3326
        AP.PreIfLevel--;
955✔
3327
        return(0);
955✔
3328
}
3329

3330
/*
3331
                 #] DoEndif : 
3332
                 #[ DoEndprocedure :
3333

3334
                Action is simple: close the current stream if it is still
3335
                the stream from which the statement came.
3336
                Then pop the current procedure and all its local derivatives.
3337
                if loadmode > 1 the procedure was defined locally.
3338
*/
3339

3340
int DoEndprocedure(UBYTE *s)
462✔
3341
{
3342
        DUMMYUSE(s);
462✔
3343
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEPROCEDURE ) {
462✔
3344
                MessPreNesting(6);
×
3345
                return(-1);
×
3346
        }
3347
        AP.NumPreTypes--;
462✔
3348
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
462✔
3349
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
462✔
3350
        AC.CurrentStream = CloseStream(AC.CurrentStream);
462✔
3351
        do {
462✔
3352
                NumProcedures--;
462✔
3353
                if ( Procedures[NumProcedures].loadmode == 0 ) {
462✔
3354
                        M_free(Procedures[NumProcedures].p.buffer,"procedures buffer");
35✔
3355
                        M_free(Procedures[NumProcedures].name,"procedures name");
35✔
3356
                }
3357
        } while ( Procedures[NumProcedures].loadmode > 1 );
462✔
3358
        return(0);
3359
}
3360

3361
/*
3362
                 #] DoEndprocedure : 
3363
                 #[ DoIf :
3364
*/
3365

3366
int DoIf(UBYTE *s)
864✔
3367
{
3368
        int condition;
864✔
3369
        AddToPreTypes(PRETYPEIF);
864✔
3370
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
864✔
3371
        if ( AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF ) {
864✔
3372
                condition = EvalPreIf(s);
864✔
3373
                if ( condition < 0 ) return(-1);
864✔
3374
        }
3375
        else condition = LOOKINGFORENDIF;
3376
        if ( AP.PreIfLevel+1 >= AP.MaxPreIfLevel ) {
864✔
3377
                int **ppp = &AP.PreIfStack; /* To avoid a compiler warning */
×
3378
                if ( DoubleList((VOID ***)ppp,&AP.MaxPreIfLevel,sizeof(int),
×
3379
                        "PreIfLevels") ) return(-1);
3380
        }
3381
        AP.PreIfStack[++AP.PreIfLevel] = condition;
864✔
3382
        return(0);
864✔
3383
}
3384

3385
/*
3386
                 #] DoIf : 
3387
                 #[ DoIfdef :
3388
*/
3389

3390
int DoIfdef(UBYTE *s, int par)
98✔
3391
{
3392
        int condition;
98✔
3393
        AddToPreTypes(PRETYPEIF);
98✔
3394
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
98✔
3395
        if ( AP.PreIfStack[AP.PreIfLevel] == EXECUTINGIF ) {
98✔
3396
                while ( *s == ' ' || *s == '\t' ) s++;
98✔
3397
                if ( ( *s == 0 ) == ( par == 1 ) ) condition = LOOKINGFORELSE;
98✔
3398
                else                               condition = EXECUTINGIF;
42✔
3399
        }
3400
        else condition = LOOKINGFORENDIF;
3401
        if ( AP.PreIfLevel+1 >= AP.MaxPreIfLevel ) {
98✔
3402
                int **ppp = &AP.PreIfStack; /* to avoid a compiler warning */
×
3403
                if ( DoubleList((VOID ***)ppp,&AP.MaxPreIfLevel,sizeof(int),
×
3404
                        "PreIfLevels") ) return(-1);
3405
        }
3406
        AP.PreIfStack[++AP.PreIfLevel] = condition;
98✔
3407
        return(0);
98✔
3408
}
3409

3410
/*
3411
                 #] DoIfdef : 
3412
                 #[ DoIfydef :
3413
*/
3414

3415
int DoIfydef(UBYTE *s)
84✔
3416
{
3417
        return DoIfdef(s,1);
84✔
3418
}
3419

3420
/*
3421
                 #] DoIfydef : 
3422
                 #[ DoIfndef :
3423
*/
3424

3425
int DoIfndef(UBYTE *s)
14✔
3426
{
3427
        return DoIfdef(s,2);
14✔
3428
}
3429

3430
/*
3431
                 #] DoIfndef : 
3432
                 #[ DoInside :
3433

3434
        #inside $var1,...,$varn
3435
                statements without .sort
3436
        #endinside
3437

3438
        executes the statements on the contents of the $ variables as if they
3439
        are a module. The results are put back in the dollar variables.
3440
        To do this right we need a struct with
3441
                old compiler buffer
3442
                list of numbers of dollars
3443
                length of the list
3444
                length of the array containing the list
3445
        Because we need to compose statements, the statement buffer must be
3446
        empty. This means that we have to test for that. Same at the end. We
3447
        must have a completed statement.
3448
*/
3449

3450
int DoInside(UBYTE *s)
70✔
3451
{
3452
        GETIDENTITY
20✔
3453
        int numdol, error = 0;
70✔
3454
        WORD *nb, newsize, i;
70✔
3455
        UBYTE *name, c;
70✔
3456
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
70✔
3457
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
70✔
3458
        if ( AP.PreInsideLevel != 0 ) {
70✔
3459
                MesPrint("@Illegal nesting of %#inside/%#endinside instructions");
×
3460
                return(-1);
×
3461
        }
3462
/*
3463
        if ( AP.PreContinuation ) {
3464
                error = -1;
3465
                MesPrint("@%#inside cannot be inside a regular statement");
3466
        }
3467
*/
3468
        PUSHPREASSIGNLEVEL
70✔
3469
/*
3470
        Now the dollars to do
3471
*/
3472
        AP.inside.numdollars = 0;
70✔
3473
        for(;;) {
3474
                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
140✔
3475
                if ( *s == 0 ) break;
140✔
3476
                if ( *s != '$' ) {
70✔
3477
                        MesPrint("@%#inside instruction can have only $ variables for parameters");
×
3478
                        return(-1);
×
3479
                }
3480
                s++;
70✔
3481
                name = s;
70✔
3482
                while (chartype[*s] <= 1 ) s++;
280✔
3483
                c = *s; *s = 0;
70✔
3484
                if ( ( numdol = GetDollar(name) ) < 0 ) {
70✔
3485
                        MesPrint("@%#inside: $%s has not (yet) been defined",name);
×
3486
                        *s = c;
×
3487
                        error = -1;
×
3488
                }
3489
                else {
3490
                        *s = c;
70✔
3491
                        if ( AP.inside.numdollars >= AP.inside.size ) {
70✔
3492
                                if ( AP.inside.buffer == 0 ) newsize = 20;
7✔
3493
                                else                         newsize = 2*AP.inside.size;
×
3494
                                nb = (WORD *)Malloc1(newsize*sizeof(WORD),"insidebuffer");
7✔
3495
                                if ( AP.inside.buffer ) {
7✔
3496
                                        for ( i = 0; i < AP.inside.size; i++ ) nb[i] = AP.inside.buffer[i];
×
3497
                                        M_free(AP.inside.buffer,"insidebuffer");
×
3498
                                }
3499
                                AP.inside.buffer = nb;
7✔
3500
                                AP.inside.size = newsize;
7✔
3501
                        }
3502
                        AP.inside.buffer[AP.inside.numdollars++] = numdol;
70✔
3503
                }
3504
        }
3505
/*
3506
        We have to store the configuration of the compiler buffer, so that
3507
        we know where to start executing and how to reset the buffer.
3508
*/
3509
        AP.inside.oldcompiletype = AC.compiletype;
70✔
3510
        AP.inside.oldparallelflag = AC.mparallelflag;
70✔
3511
        AP.inside.oldnumpotmoddollars = NumPotModdollars;
70✔
3512
        AP.inside.oldcbuf = AC.cbufnum;
70✔
3513
        AP.inside.oldrbuf = AM.rbufnum;
70✔
3514
        AP.inside.oldcnumlhs = AR.Cnumlhs, 
70✔
3515
        AddToPreTypes(PRETYPEINSIDE);
70✔
3516
        AP.PreInsideLevel = 1;
70✔
3517
        AC.cbufnum = AP.inside.inscbuf;
70✔
3518
        AM.rbufnum = AP.inside.inscbuf;
70✔
3519
        clearcbuf(AC.cbufnum);
70✔
3520
        AC.compiletype = 0;
70✔
3521
        AC.mparallelflag = PARALLELFLAG;
70✔
3522
#ifdef WITHMPI
3523
        /*
3524
         * We use AC.RhsExprInModuleFlag, PotModdollars, and AC.pfirstnum
3525
         * in order to check (1) whether there are expression names in RHS,
3526
         * (2) which dollar variables can be modified, and (3) which
3527
         * preprocessor variables can be redefined, in #inside.
3528
         * We store the current values of them, and then reset them.
3529
         */
3530
        PF_StoreInsideInfo();
40✔
3531
        AC.RhsExprInModuleFlag = 0;
40✔
3532
        NumPotModdollars = 0;
40✔
3533
        AC.numpfirstnum = 0;
40✔
3534
#endif
3535
        return(error);
70✔
3536
}
3537

3538
/*
3539
                 #] DoInside : 
3540
                 #[ DoEndInside :
3541
*/
3542

3543
int DoEndInside(UBYTE *s)
70✔
3544
{
3545
        GETIDENTITY
20✔
3546
        WORD numdol, *oldworkpointer = AT.WorkPointer, *term, *t, j, i;
70✔
3547
        DOLLARS d, nd;
70✔
3548
        WORD oldbracketon = AR.BracketOn;
70✔
3549
        WORD *oldcompresspointer = AR.CompressPointer;
70✔
3550
        int oldmultithreaded = AS.MultiThreaded;
70✔
3551
        /* int oldmparallelflag = AC.mparallelflag; */
3552
        FILEHANDLE *f;
70✔
3553
#ifdef WITHMPI
3554
        int error = 0;
40✔
3555
#endif
3556
        DUMMYUSE(s);
70✔
3557
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
70✔
3558
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
70✔
3559
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPEINSIDE ) {
70✔
3560
                if ( AP.PreInsideLevel != 1 ) MesPrint("@%#endinside without corresponding %#inside");
×
3561
                else MessPreNesting(11);
×
3562
                return(-1);
×
3563
        }
3564
        AP.NumPreTypes--;
70✔
3565
        if ( AP.PreInsideLevel != 1 ) {
70✔
3566
                MesPrint("@%#endinside without corresponding %#inside");
×
3567
                return(-1);
×
3568
        }
3569
        if ( AP.PreContinuation ) {
70✔
3570
                MesPrint("@%#endinside: previous statement not terminated.");
×
NEW
3571
                TERMINATE(-1);
×
3572
        }
3573
        AC.compiletype = AP.inside.oldcompiletype;
70✔
3574
        AR.Cnumlhs = cbuf[AM.rbufnum].numlhs;
70✔
3575
#ifdef WITHMPI
3576
        /*
3577
         * If the #inside...#endinside contains expressions in RHS, only the master executes it
3578
         * and then broadcasts the result to the all slaves. If not, the all processes execute
3579
         * it and in this case no MPI interactions are needed.
3580
         */
3581
        if ( PF.me == MASTER || !AC.RhsExprInModuleFlag ) {
40✔
3582
#endif
3583
        AR.BracketOn = 0;
70✔
3584
        AS.MultiThreaded = 0;
70✔
3585
        /* AC.mparallelflag = PARALLELFLAG; */
3586
        if ( AR.CompressPointer == 0 ) AR.CompressPointer = AR.CompressBuffer;
70✔
3587
        f = AR.infile; AR.infile = AR.outfile; AR.outfile = f;
70✔
3588
/*
3589
        Now we have to execute the statements on the proper dollars.
3590
*/
3591
        for ( i = 0; i < AP.inside.numdollars; i++ ) {
140✔
3592
                numdol = AP.inside.buffer[i];
70✔
3593
                nd = d = Dollars + numdol;
70✔
3594
                if ( d->type != DOLZERO ) {
70✔
3595
                        if ( d->type != DOLTERMS ) nd = DolToTerms(BHEAD numdol);
70✔
3596
                        term = nd->where;
70✔
3597
                        NewSort(BHEAD0);
70✔
3598
                        NewSort(BHEAD0);
70✔
3599
                        AR.MaxDum = AM.IndDum;
70✔
3600
                        while ( *term ) {
70✔
3601
                                t = oldworkpointer; j = *term;
3602
                                NCOPY(t,term,j);
1,554✔
3603
                                AT.WorkPointer = t;
140✔
3604
                                AN.IndDum = AM.IndDum;
140✔
3605
                                AR.CurDum = ReNumber(BHEAD term);
140✔
3606
                                if ( Generator(BHEAD oldworkpointer,0) ) {
140✔
3607
                                        MesPrint("@Called from %#endinside");
×
3608
                                        MesPrint("@Evaluating variable $%s",DOLLARNAME(Dollars,numdol));
×
3609
                                        TERMINATE(-1);
210✔
3610
                                }
3611
                        }
3612
                        AT.WorkPointer = oldworkpointer;
70✔
3613
                        CleanDollarFactors(d);
70✔
3614
                        if ( d->where ) { M_free(d->where,"dollar contents"); d->where = 0; }
70✔
3615
                        EndSort(BHEAD (WORD *)((VOID *)(&(d->where))),2);
70✔
3616
                        LowerSortLevel();
70✔
3617
                        term = d->where; while ( *term ) term += *term;
210✔
3618
                        d->size = term - d->where;
70✔
3619
                        if ( nd != d ) M_free(nd,"Copy of dollar variable");
70✔
3620
                        if ( d->where[0] == 0 ) {
70✔
3621
                                M_free(d->where,"dollar contents"); d->where = 0;
×
3622
                                d->type = DOLZERO;
×
3623
                        }
3624
                }
3625
        }
3626
#ifdef WITHMPI
3627
        }
3628
        if ( AC.RhsExprInModuleFlag ) {
40✔
3629
                /*
3630
                 * The only master executed the statements in #inside.
3631
                 * We need to broadcast the result to the all slaves.
3632
                 */
3633
                for ( i = 0; i < AP.inside.numdollars; i++ ) {
3634
                        /*
3635
                         * Mark $-variables specified in the #inside instruction as modified
3636
                         * such that they will be broadcast.
3637
                         */
3638
                        AddPotModdollar(AP.inside.buffer[i]);
3639
                }
3640
                /* Now actual broadcast of modified variables. */
3641
                if ( NumPotModdollars > 0 ) {
3642
                        error = PF_BroadcastModifiedDollars();
3643
                        if ( error ) goto cleanup;
3644
                }
3645
                if ( AC.numpfirstnum > 0 ) {
3646
                        error = PF_BroadcastRedefinedPreVars();
3647
                        if ( error ) goto cleanup;
3648
                }
3649
        }
3650
cleanup:
40✔
3651
#endif
3652
        f = AR.infile; AR.infile = AR.outfile; AR.outfile = f;
70✔
3653
        AC.cbufnum = AP.inside.oldcbuf;
70✔
3654
        AM.rbufnum = AP.inside.oldrbuf;
70✔
3655
        AR.Cnumlhs = AP.inside.oldcnumlhs;
70✔
3656
        AR.BracketOn = oldbracketon;
70✔
3657
        AP.PreInsideLevel = 0;
70✔
3658
        AR.CompressPointer = oldcompresspointer;
70✔
3659
        AS.MultiThreaded = oldmultithreaded;
70✔
3660
        AC.mparallelflag = AP.inside.oldparallelflag;
70✔
3661
        NumPotModdollars = AP.inside.oldnumpotmoddollars;
70✔
3662
        POPPREASSIGNLEVEL
70✔
3663
#ifdef WITHMPI
3664
        PF_RestoreInsideInfo();
40✔
3665
        if ( error ) return error;
40✔
3666
#endif
3667
        return(0);
3668
}
3669

3670
/*
3671
                 #] DoEndInside : 
3672
                 #[ DoMessage :
3673
*/
3674

3675
int DoMessage(UBYTE *s)
3,906✔
3676
{
3677
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
3,906✔
3678
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
3,906✔
3679
        while ( *s == ' ' || *s == '\t' ) s++;
3,094✔
3680
        MesPrint("~~~%s",s);
3,094✔
3681
        return(0);
3,094✔
3682
}
3683

3684
/*
3685
                 #] DoMessage : 
3686
                 #[ DoPipe :
3687
*/
3688

3689
int DoPipe(UBYTE *s)
×
3690
{
3691
#ifndef WITHPIPE
3692
        DUMMYUSE(s);
3693
#endif
3694
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3695
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
3696
#ifdef WITHPIPE
3697
        FLUSHCONSOLE;
×
3698
        while ( *s == ' ' || *s == '\t' ) s++;
×
3699
        if ( OpenStream(s,PIPESTREAM,0,PRENOACTION) == 0 ) return(-1);
×
3700
        return(0);
3701
#else
3702
        Error0("Pipes not implemented on this computer/system");
3703
        return(-1);
3704
#endif
3705
}
3706

3707
/*
3708
                 #] DoPipe : 
3709
                 #[ DoPrcExtension :
3710
*/
3711

3712
int DoPrcExtension(UBYTE *s)
×
3713
{
3714
        UBYTE *t, *u, c;
×
3715
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3716
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
3717
        while ( *s == ' ' || *s == '\t' ) s++;
×
3718
        if ( *s == 0 || *s == '\n' ) {
×
3719
                MesPrint("@No valid procedure extension specified");
×
3720
                return(-1);
×
3721
        }
3722
        if ( FG.cTable[*s] != 0 ) {
×
3723
                MesPrint("@Procedure extension should be a string starting with an alphabetic character. No whitespace.");
×
3724
                return(-1);
×
3725
        }
3726
        t = s;
×
3727
        while ( *s && *s != '\n' && *s != ' ' && *s != '\t' ) s++;
×
3728
        u = s;
×
3729
        while ( *s == ' ' || *s == '\t' ) s++;
×
3730
        if ( *s != 0 && *s != '\n' ) {
×
3731
                MesPrint("@Too many parameters in ProcedureExtension instruction");
×
3732
                return(-1);
×
3733
        }
3734
        c = *u; *u = 0;
×
3735
        if ( AP.procedureExtension ) M_free(AP.procedureExtension,"ProcedureExtension");
×
3736
        AP.procedureExtension = strDup1(t,"ProcedureExtension");
×
3737
        *u = c;
×
3738
        return(0);
×
3739
}
3740

3741
/*
3742
                 #] DoPrcExtension : 
3743
                 #[ DoPreOut :
3744
*/
3745

3746
int DoPreOut(UBYTE *s)
7✔
3747
{
3748
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
7✔
3749
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
7✔
3750
        if ( tolower(*s) == 'o' ) {
7✔
3751
                if ( tolower(s[1]) == 'n' && s[2] == 0 ) {
7✔
3752
                        AP.PreOut = 1;
7✔
3753
                        return(0);
7✔
3754
                }
3755
                if ( tolower(s[1]) == 'f' && tolower(s[2]) == 'f' && s[3] == 0 ) {
×
3756
                        AP.PreOut = 0;
×
3757
                        return(0);
×
3758
                }
3759
        }
3760
        MesPrint("@Illegal option in PreOut instruction");
×
3761
        return(-1);
×
3762
}
3763

3764
/*
3765
                 #] DoPreOut : 
3766
                 #[ DoPrePrintTimes :
3767
*/
3768

3769
int DoPrePrintTimes(UBYTE *s)
56✔
3770
{
3771
        DUMMYUSE(s);
56✔
3772
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
56✔
3773
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
56✔
3774
        PrintRunningTime();
56✔
3775
        return(0);
56✔
3776
}
3777

3778
/*
3779
                 #] DoPrePrintTimes : 
3780
                 #[ DoPreAppend :
3781

3782
                Syntax:
3783
                #append <filename>
3784
*/
3785

3786
int DoPreAppend(UBYTE *s)
×
3787
{
3788
        UBYTE *name, *to;
×
3789

3790
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3791
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
3792
        if ( AP.preError ) return(0);
×
3793
        while ( *s == ' ' || *s == '\t' ) s++;
×
3794
/*
3795
        Determine where to write
3796
*/
3797
        if ( *s == '<' ) {
×
3798
                s++;
×
3799
                name = to = s;
×
3800
                while ( *s && *s != '>' ) {
×
3801
                        if ( *s == '\\' ) s++;
×
3802
                        *to++ = *s++;
×
3803
                }
3804
                if ( *s == 0 ) {
×
3805
                        MesPrint("@Improper termination of filename");
×
3806
                        return(-1);
×
3807
                }
3808
                s++;
×
3809
                *to = 0;
×
3810
                if ( *name ) { GetAppendChannel((char *)name); }
×
3811
                else goto improper;
×
3812
        }
3813
        else {
3814
improper:
×
3815
                MesPrint("@Proper syntax is: %#append <filename>");
×
3816
                return(-1);
×
3817
        }
3818
        return(0);
×
3819
}
3820

3821
/*
3822
                 #] DoPreAppend : 
3823
                 #[ DoPreCreate :
3824

3825
                Syntax:
3826
                #create <filename>
3827
*/
3828

3829
int DoPreCreate(UBYTE *s)
×
3830
{
3831
        UBYTE *name, *to;
×
3832

3833
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3834
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
3835
        if ( AP.preError ) return(0);
×
3836
        while ( *s == ' ' || *s == '\t' ) s++;
×
3837
/*
3838
        Determine where to write
3839
*/
3840
        if ( *s == '<' ) {
×
3841
                s++;
×
3842
                name = to = s;
×
3843
                while ( *s && *s != '>' ) {
×
3844
                        if ( *s == '\\' ) s++;
×
3845
                        *to++ = *s++;
×
3846
                }
3847
                if ( *s == 0 ) {
×
3848
                        MesPrint("@Improper termination of filename");
×
3849
                        return(-1);
×
3850
                }
3851
                s++;
×
3852
                *to = 0;
×
3853
                if ( *name ) { GetChannel((char *)name,0); }
×
3854
                else goto improper;
×
3855
        }
3856
        else {
3857
improper:
×
3858
                MesPrint("@Proper syntax is: %#create <filename>");
×
3859
                return(-1);
×
3860
        }
3861
        return(0);
×
3862
}
3863

3864
/*
3865
                 #] DoPreCreate : 
3866
                 #[ DoPreRemove :
3867
*/
3868

3869
int DoPreRemove(UBYTE *s)
×
3870
{
3871
        UBYTE *name, *to;
×
3872
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3873
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
3874
        if ( AP.preError ) return(0);
×
3875
        while ( *s == ' ' || *s == '\t' ) s++;
×
3876
        if ( *s == '<' ) { s++; }
×
3877
        else {
3878
                MesPrint("@Proper syntax is: %#remove <filename>");
×
3879
                return(-1);
×
3880
        }
3881
        name = to = s;
×
3882
        while ( *s && *s != '>' ) {
×
3883
                if ( *s == '\\' ) s++;
×
3884
                *to++ = *s++;
×
3885
        }
3886
        if ( *s == 0 ) {
×
3887
                MesPrint("@Improper filename");
×
3888
                return(-1);
×
3889
        }
3890
        s++;
×
3891
        *to = 0;
×
3892
        CloseChannel((char *)name);
×
3893
        remove((char *)name);
×
3894
        return(0);
×
3895
}
3896

3897
/*
3898
                 #] DoPreRemove : 
3899
                 #[ DoPreClose :
3900
*/
3901

3902
int DoPreClose(UBYTE *s)
×
3903
{
3904
        UBYTE *name, *to;
×
3905
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
3906
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
3907
        if ( AP.preError ) return(0);
×
3908
        while ( *s == ' ' || *s == '\t' ) s++;
×
3909
        if ( *s == '<' ) { s++; }
×
3910
        else {
3911
                MesPrint("@Proper syntax is: %#close <filename>");
×
3912
                return(-1);
×
3913
        }
3914
        name = to = s;
×
3915
        while ( *s && *s != '>' ) {
×
3916
                if ( *s == '\\' ) s++;
×
3917
                *to++ = *s++;
×
3918
        }
3919
        if ( *s == 0 ) {
×
3920
                MesPrint("@Improper filename");
×
3921
                return(-1);
×
3922
        }
3923
        s++;
×
3924
        *to = 0;
×
3925
        return(CloseChannel((char *)name));
×
3926
}
3927

3928
/*
3929
                 #] DoPreClose : 
3930
                 #[ DoPreWrite :
3931

3932
                Syntax:
3933
                #write [<filename>] "formatstring" [,objects]
3934
                The format string can contain the following special objects/codes
3935
                \n  newline
3936
                \t  tab
3937
                \!        if last entry in string: no linefeed at end
3938
                \b        put \ in output
3939
                %$  $-variable (to be found among the objects)
3940
                %e  expression (name to be found among the objects)
3941
                %E  expression without ; (name to be found among the objects)
3942
                %s        string (to be found among the objects) (with or without "")
3943
                %S        subterms (see PrintSubtermList)
3944
*/
3945

3946
int DoPreWrite(UBYTE *s)
469✔
3947
{
3948
        HANDLERS h;
469✔
3949

3950
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
469✔
3951
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
469✔
3952
        if ( AP.preError ) return(0);
469✔
3953

3954
#ifdef WITHMPI
3955
        if ( PF.me != MASTER ) return 0;
268✔
3956
#endif
3957

3958
        h.oldsilent    = AM.silent;
268✔
3959
        h.newlogonly   = h.oldlogonly = AM.FileOnlyFlag;
268✔
3960
        h.newhandle    = h.oldhandle  = AC.LogHandle;
268✔
3961
        h.oldprinttype = AO.PrintType;
268✔
3962
   
3963
        while ( *s == ' ' || *s == '\t' ) s++;
268✔
3964
/*
3965
        Determine where to write
3966
*/
3967
        if( (s=defineChannel(s,&h))==0 ) return(-1);
268✔
3968

3969
        return(writeToChannel(WRITEOUT,s,&h));
268✔
3970
}
3971

3972
/*
3973
                 #] DoPreWrite : 
3974
                 #[ DoProcedure :
3975

3976
                We have to read this procedure into a buffer.
3977
                The only complications are:
3978
                1: we have to seek through the file to do this efficiently
3979
                   the file operations under VMS cannot do this properly
3980
                   (unless we use the proper ANSI structs?)
3981
                   This is the reason why we read whole input files under VMS.
3982
                2: what to do when the same name is used twice.
3983
                Note that we have to do the reading without substitution of
3984
                preprocessor variables.
3985
*/
3986

3987
int DoProcedure(UBYTE *s)
150✔
3988
{
3989
        UBYTE c;
150✔
3990
        PROCEDURE *p;
150✔
3991
        LONG i;
150✔
3992
        if ( ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH )
150✔
3993
        || ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) ) {
150✔
3994
                if ( PreSkip((UBYTE *)"procedure",(UBYTE *)"endprocedure",1) ) return(-1);
×
3995
                return(0);
×
3996
        }
3997
        p = (PROCEDURE *)FromList(&AP.ProcList);
150✔
3998
        if ( PreLoad(&(p->p),(UBYTE *)"procedure",(UBYTE *)"endprocedure"
150✔
3999
                ,1,(char *)"procedure") ) return(-1);
4000

4001
        p->loadmode = 2;
150✔
4002
        s = p->p.buffer + 10;
150✔
4003
        while ( *s == ' ' || *s == LINEFEED ) s++;
300✔
4004
        if ( chartype[*s] ) {
150✔
4005
                MesPrint("@Illegal name for procedure");
×
4006
                return(-1);
×
4007
        }
4008
        p->name = s++;
150✔
4009
        while ( chartype[*s] == 0 || chartype[*s] == 1 ) s++;
1,726✔
4010
        c = *s; *s = 0;
150✔
4011
        p->name = strDup1(p->name,"procedure");
150✔
4012
        *s = c;
150✔
4013
/*
4014
        Check for double names
4015
*/
4016
        for ( i = NumProcedures-2; i >= 0; i-- ) {
367✔
4017
                if ( StrCmp(Procedures[i].name,p->name) == 0 ) {
217✔
4018
                        Error1("Multiple occurrence of procedure name ",p->name);
×
4019
                }
4020
        }
4021
        return(0);
4022
}
4023

4024
/*
4025
                 #] DoProcedure : 
4026
                 #[ DoPreBreak :
4027
*/
4028

4029
int DoPreBreak(UBYTE *s)
×
4030
{
4031
        DUMMYUSE(s);
×
4032
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
4033
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
×
4034
                if ( AP.PreSwitchLevel <= 0 )
×
4035
                         MesPrint("@Break without corresponding Switch");
×
4036
                else MessPreNesting(7);
×
4037
                return(-1);
×
4038
        }
4039
        if ( AP.PreSwitchLevel <= 0 ) {
×
4040
                MesPrint("@Break without corresponding Switch");
×
4041
                return(-1);
×
4042
        }
4043
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] == EXECUTINGPRESWITCH )
×
4044
                AP.PreSwitchModes[AP.PreSwitchLevel] = SEARCHINGPREENDSWITCH;
×
4045
        return(0);
4046
}
4047

4048
/*
4049
                 #] DoPreBreak : 
4050
                 #[ DoPreCase :
4051
*/
4052

4053
int DoPreCase(UBYTE *s)
×
4054
{
4055
        UBYTE *t;
×
4056
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
4057
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
×
4058
                if ( AP.PreSwitchLevel <= 0 )
×
4059
                         MesPrint("@Case without corresponding Switch");
×
4060
                else MessPreNesting(8);
×
4061
                return(-1);
×
4062
        }
4063
        if ( AP.PreSwitchLevel <= 0 ) {
×
4064
                MesPrint("@Case without corresponding Switch");
×
4065
                return(-1);
×
4066
        }
4067
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != SEARCHINGPRECASE ) return(0);
×
4068

4069
        SKIPBLANKS(s)
×
4070
        t = s;
×
4071
        while ( *s ) { if ( *s == '\\' ) s++; s++; }
×
4072
        while ( s > t && ( s[-1] == ' ' || s[-1] == '\t' ) && s[-2] != '\\' ) {
×
4073
                if ( s[-2] == '\\' ) s--;
×
4074
                s--;
×
4075
        }
4076
        if ( *t == '"' && s > t+1 && s[-1] == '"' && s[-2] != '\\' ) {
×
4077
                t++; s--; *s = 0;
×
4078
        }
4079
        else *s = 0;
×
4080
        s = AP.PreSwitchStrings[AP.PreSwitchLevel];
×
4081
        while ( *t == *s && *t ) { s++; t++; }
×
4082
        if ( *t || *s ) return(0);        /* case did not match */
×
4083
        AP.PreSwitchModes[AP.PreSwitchLevel] = EXECUTINGPRESWITCH;
×
4084
        return(0);
×
4085
}
4086

4087
/*
4088
                 #] DoPreCase : 
4089
                 #[ DoPreDefault :
4090
*/
4091

4092
int DoPreDefault(UBYTE *s)
×
4093
{
4094
        DUMMYUSE(s);
×
4095
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
4096
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
×
4097
                if ( AP.PreSwitchLevel <= 0 )
×
4098
                         MesPrint("@Default without corresponding Switch");
×
4099
                else MessPreNesting(9);
×
4100
                return(-1);
×
4101
        }
4102
        if ( AP.PreSwitchLevel <= 0 ) {
×
4103
                MesPrint("@Default without corresponding Switch");
×
4104
                return(-1);
×
4105
        }
4106
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != SEARCHINGPRECASE ) return(0);
×
4107
        AP.PreSwitchModes[AP.PreSwitchLevel] = EXECUTINGPRESWITCH;
×
4108
        return(0);
×
4109
}
4110

4111
/*
4112
                 #] DoPreDefault : 
4113
                 #[ DoPreEndSwitch :
4114
*/
4115

4116
int DoPreEndSwitch(UBYTE *s)
×
4117
{
4118
        DUMMYUSE(s);
×
4119
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
4120
        if ( AP.PreTypes[AP.NumPreTypes] != PRETYPESWITCH ) {
×
4121
                if ( AP.PreSwitchLevel <= 0 )
×
4122
                         MesPrint("@EndSwitch without corresponding Switch");
×
4123
                else MessPreNesting(10);
×
4124
                return(-1);
×
4125
        }
4126
        AP.NumPreTypes--;
×
4127
        if ( AP.PreSwitchLevel <= 0 ) {
×
4128
                MesPrint("@EndSwitch without corresponding Switch");
×
4129
                return(-1);
×
4130
        }
4131
        M_free(AP.PreSwitchStrings[AP.PreSwitchLevel--],"pre switch string");
×
4132
        return(0);
×
4133
}
4134

4135
/*
4136
                 #] DoPreEndSwitch : 
4137
                 #[ DoPreSwitch :
4138

4139
                There should be a string after this.
4140
                We have to store it somewhere.
4141
*/
4142

4143
int DoPreSwitch(UBYTE *s)
×
4144
{
4145
        UBYTE *t, *switchstring, **newstrings;
×
4146
        int newnum, i, *newmodes;
×
4147
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
4148
        SKIPBLANKS(s)
×
4149
        t = s;
×
4150
        while ( *s ) { if ( *s == '\\' ) s++; s++; }
×
4151
        while ( s > t && ( s[-1] == ' ' || s[-1] == '\t' ) && s[-2] != '\\' ) {
×
4152
                if ( s[-2] == '\\' ) s--;
×
4153
                s--;
×
4154
        }
4155
        if ( *t == '"' && s > t+1 && s[-1] == '"' && s[-2] != '\\' ) {
×
4156
                t++; s--; *s = 0;
×
4157
        }
4158
        else *s = 0;
×
4159
        switchstring = (UBYTE *)Malloc1((s-t)+1,"case string");
×
4160
        s = switchstring;
×
4161
        while ( *t ) {
×
4162
                if ( *t == '\\' ) t++;
×
4163
                *s++ = *t++;
×
4164
        }
4165
        *s = 0;
×
4166
        if ( AP.PreSwitchLevel >= AP.NumPreSwitchStrings ) {
×
4167
                newnum = 2*AP.NumPreSwitchStrings;
×
4168
                newstrings = (UBYTE **)Malloc1(sizeof(UBYTE *)*(newnum+1),"case strings");
×
4169
                newmodes   = (int *)Malloc1(sizeof(int)*(newnum+1),"case strings");
×
4170
                for ( i = 0; i < AP.NumPreSwitchStrings; i++ )
×
4171
                        newstrings[i] = AP.PreSwitchStrings[i];
×
4172
                M_free(AP.PreSwitchStrings,"AP.PreSwitchStrings");
×
4173
                for ( i = 0; i <= AP.NumPreSwitchStrings; i++ )
×
4174
                        newmodes[i] = AP.PreSwitchModes[i];
×
4175
                M_free(AP.PreSwitchModes,"AP.PreSwitchModes");
×
4176
                AP.PreSwitchStrings = newstrings;
×
4177
                AP.PreSwitchModes   = newmodes;
×
4178
                AP.NumPreSwitchStrings = newnum;
×
4179
        }
4180
        AP.PreSwitchStrings[++AP.PreSwitchLevel] = switchstring;
×
4181
        if ( ( AP.PreSwitchLevel > 1 )
×
4182
         && ( AP.PreSwitchModes[AP.PreSwitchLevel-1] != EXECUTINGPRESWITCH ) )
×
4183
                AP.PreSwitchModes[AP.PreSwitchLevel] = SEARCHINGPREENDSWITCH;
×
4184
        else
4185
                AP.PreSwitchModes[AP.PreSwitchLevel] = SEARCHINGPRECASE;
×
4186
        AddToPreTypes(PRETYPESWITCH);
×
4187
        return(0);
×
4188
}
4189

4190
/*
4191
                 #] DoPreSwitch : 
4192
                 #[ DoPreShow :
4193

4194
                Print the contents of the preprocessor variables
4195
*/
4196

4197
int DoPreShow(UBYTE *s)
×
4198
{
4199
        int i;
×
4200
        UBYTE *name, c;
×
4201
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
4202
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
4203
        while ( *s == ' ' || *s == '\t' ) s++;
×
4204
        if ( *s == 0 ) {
×
4205
                MesPrint("%#The preprocessor variables:");
×
4206
                for ( i = 0; i < NumPre; i++ ) {
×
4207
                        MesPrint("%d: %s = \"%s\"",i,PreVar[i].name,PreVar[i].value);
×
4208
                }
4209
        }
4210
        else {
4211
                while ( *s ) {
×
4212
                        name = s; while ( *s && *s != ' ' && *s != '\t' && *s != ',' ) s++;
×
4213
                        c = *s; *s = 0;
×
4214
                        for ( i = 0; i < NumPre; i++ ) {
×
4215
                                if ( StrCmp(PreVar[i].name,name) == 0 )
×
4216
                                        MesPrint("%d: %s = \"%s\"",i,PreVar[i].name,PreVar[i].value);
×
4217
                        }
4218
                        *s = c;
×
4219
                        while ( *s == ' ' || *s == '\t' ) s++;
×
4220
                }
4221
        }
4222
        return(0);
4223
}
4224

4225
/*
4226
                 #] DoPreShow : 
4227
                 #[ DoSystem :
4228
*/
4229

4230
/*
4231
 * A macro for translating the contents of `x' into a string after expanding.
4232
 */
4233
#define STRINGIFY(x)  STRINGIFY__(x)
4234
#define STRINGIFY__(x) #x
4235

4236
int DoSystem(UBYTE *s)
×
4237
{
4238
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
4239
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
4240
        if ( AP.preError ) return(0);
×
4241
#ifdef WITHSYSTEM
4242
        FLUSHCONSOLE;
×
4243
        while ( *s == ' ' || *s == '\t' ) s++;
×
4244
        if ( *s == '-' && s[1] == 'e' ) {
×
4245
                LONG err;
×
4246
                UBYTE str[24];
×
4247
                s += 2;
×
4248
                if ( *s != ' ' ) {
×
4249
                        MesPrint("@Syntax error in #system command.");
×
4250
                        return(-1);
×
4251
                }
4252
                while ( *s == ' ' || *s == '\t' ) s++;
×
4253
                err = system((char *)s);
×
4254
                NumToStr(str,err);
×
4255
                PutPreVar((UBYTE *)"SYSTEMERROR_",str,0,1);
×
4256
        }
4257
        else if ( system((char *)s) ) {
×
4258
                MesPrint("@System call returned with error condition");
×
NEW
4259
                TERMINATE(-1);
×
4260
        }
4261
        return(0);
4262
#else
4263
        Error0("External programs not implemented on this computer/system");
4264
        return(-1);
4265
#endif
4266
}
4267

4268
/*
4269
                 #] DoSystem : 
4270
                 #[ PreLoad :
4271

4272
                Loads a loop or procedure into a special buffer.
4273
                Note: The current instruction is already in the preStart buffer
4274
*/
4275

4276
int PreLoad(PRELOAD *p, UBYTE *start, UBYTE *stop, int mode, char *message)
697✔
4277
{
4278
        UBYTE *s, *t, *top, *newbuffer, c;
697✔
4279
        LONG i, ppsize, linenum = AC.CurrentStream->linenumber;
697✔
4280
        int size1, size2, level, com=0, last=1, strng = 0;
697✔
4281
        p->size = AP.pSize;
697✔
4282
        p->buffer = (UBYTE *)Malloc1(p->size+1,message);
697✔
4283
        top = p->buffer + p->size - 2;
697✔
4284
        t = p->buffer; *t++ = '#';
697✔
4285
        s = start; size1 = size2 = 0;
697✔
4286
        while ( *s ) { s++; size1++; }
3,141✔
4287
        s = stop; while ( *s ) { s++; size2++; }
5,232✔
4288
        s = AP.preStart; while ( *s ) *t++ = *s++; *t++ = LINEFEED;
11,935✔
4289
        level = 1;
697✔
4290
        i = 100;
697✔
4291
        for (;;) {
2,823,319✔
4292
                c = GetInput();
2,823,319✔
4293
                if ( c == ENDOFINPUT ) {
2,823,319✔
4294
                        MesPrint("@Missing %#%s, Should match line %l",stop,linenum);
×
4295
                        return(-1);
×
4296
                }
4297
                if ( c == AP.ComChar && last == 1 ) com = 1;
2,823,319✔
4298
                if ( c == LINEFEED ) { last = 1; com = 0; }
2,823,319✔
4299
                else last = 0;
2,816,191✔
4300

4301
                if ( ( c == '"' ) && ( com == 0 ) ) { strng ^= 1; }
2,823,319✔
4302

4303
                if ( ( c == '#' ) && ( com == 0 ) ) i = 0;
2,823,319✔
4304
                else i++;
2,821,575✔
4305

4306
                if ( t >= top ) {
2,823,319✔
4307
                        ppsize = t - p->buffer;
623✔
4308
                        p->size *= 2;
623✔
4309
                        newbuffer = (UBYTE *)Malloc1(p->size,message);
623✔
4310
                        t = newbuffer; s = p->buffer;
623✔
4311
                        while ( --ppsize >= 0 ) *t++ = *s++;
4,124,559✔
4312
                        M_free(p->buffer,"loading do loop");
623✔
4313
                        p->buffer = newbuffer;
623✔
4314
                        top = p->buffer + p->size - 2;
623✔
4315
                }
4316
                *t++ = c;
2,823,319✔
4317
                if ( strng == 0 ) {
2,823,319✔
4318
                  if ( ( i == size2 ) && ( com == 0 ) ) {
2,816,880✔
4319
                        *t = 0;
1,627✔
4320
                        if ( StrICmp(t-size2,(UBYTE *)(stop)) == 0 ) {
1,627✔
4321
                                while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
753✔
4322
                                level--;
753✔
4323
                                if ( level <= 0 ) break;
753✔
4324
                                if ( c == ENDOFINPUT ) Error1("Missing #",stop);
56✔
4325
                                *t++ = LINEFEED; *t = 0; last = 1;
56✔
4326
                        }
4327
                  }
4328
                  if ( ( i == size1 ) && mode && ( com == 0 ) ) {
2,816,185✔
4329
                        *t = 0;
1,665✔
4330
                        if ( StrICmp(t-size1,(UBYTE *)(start)) == 0 ) {
1,665✔
4331
/*
4332
                                while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
4333
                                if ( c == ENDOFINPUT ) Error1("Missing #",stop);
4334
*/
4335
                                level++;
56✔
4336
                        }
4337
                  }
4338
                  if ( i == 1 && t[-2] == LINEFEED ) {
2,816,185✔
4339
                        if ( c == '-' )      AC.NoShowInput = 1;
×
4340
                        else if ( c == '+' ) AC.NoShowInput = 0;
×
4341
                  }
4342
                }
4343
        }
4344
        *t++ = LINEFEED;
697✔
4345
        *t = 0;
697✔
4346
        return(0);
697✔
4347
}
4348

4349
/*
4350
                 #] PreLoad : 
4351
                 #[ PreSkip :
4352

4353
                Skips a loop or procedure.
4354
                Note: The current instruction is already in the preStart buffer
4355
*/
4356

4357
#define SKIPBUFSIZE 20
4358

4359
int PreSkip(UBYTE *start, UBYTE *stop, int mode)
×
4360
{
4361
        UBYTE *s, *t, buffer[SKIPBUFSIZE+2], c;
×
4362
        LONG i, linenum = AC.CurrentStream->linenumber;
×
4363
        int size1, size2, level, com=0, last=1;
×
4364

4365
        t = buffer; *t++ = '#';
×
4366
        s = start; size1 = size2 = 0;
×
4367
        while ( *s ) { s++; size1++; }
×
4368
        s = stop; while ( *s ) { s++; size2++; }
×
4369
        level = 1;
4370
        i = 0;
4371
        for (;;) {
×
4372
                c = GetInput();
×
4373
                if ( c == ENDOFINPUT ) {
×
4374
                        MesPrint("@Missing %#%s, Should match line %l",stop,linenum);
×
4375
                        return(-1);
×
4376
                }
4377
                if ( c == AP.ComChar && last == 1 ) com = 1;
×
4378
                if ( c == LINEFEED ) { last = 1; com = 0; i = 0; t = buffer; }
×
4379
                else last = 0;
×
4380
                if ( ( c == '#' ) && ( com == 0 ) ) { i = 0; t = buffer; }
×
4381
                else i++;
×
4382

4383
                if ( i < SKIPBUFSIZE ) *t++ = c;
×
4384
                if ( ( i == size2 ) && ( com == 0 ) ) {
×
4385
                        *t = 0;
×
4386
                        if ( StrICmp(t-size2,(UBYTE *)(stop)) == 0 ) {
×
4387
                                while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
×
4388
                                level--;
×
4389
                                if ( level <= 0 ) {
×
4390
                                        pushbackchar = LINEFEED;
×
4391
                                        break;
×
4392
                                }
4393
                                if ( c == ENDOFINPUT ) Error1("Missing #",stop);
×
4394
                                i = 0; t = buffer;
4395
                        }
4396
                }
4397
                if ( ( i == size1 ) && mode && ( com == 0 ) ) {
×
4398
                        *t = 0;
×
4399
                        if ( StrICmp(t-size1,(UBYTE *)(start)) == 0 ) {
×
4400
                                while ( ( c = GetInput() ) != LINEFEED && c != ENDOFINPUT ) {}
×
4401
                                level++;
×
4402
                                i = 0; t = buffer;
×
4403
                        }
4404
                }
4405
        }
4406
        return(0);
×
4407
}
4408

4409
/*
4410
                 #] PreSkip : 
4411
                 #[ StartPrepro :
4412
*/
4413

4414
VOID StartPrepro(VOID)
1,776✔
4415
{
4416
        int **ppp;
1,776✔
4417
        AP.MaxPreIfLevel = 2;
1,776✔
4418
        ppp = &AP.PreIfStack;
1,776✔
4419
        if ( DoubleList((VOID ***)ppp,&AP.MaxPreIfLevel,sizeof(int),
1,776✔
NEW
4420
                        "PreIfLevels") ) TERMINATE(-1);
×
4421
        AP.PreIfLevel = 0; AP.PreIfStack[0] = EXECUTINGIF;
1,776✔
4422

4423
        AP.NumPreSwitchStrings = 10;
1,776✔
4424
        AP.PreSwitchStrings = (UBYTE **)Malloc1(sizeof(UBYTE *)*
1,776✔
4425
                                                                (AP.NumPreSwitchStrings+1),"case strings");
4426
        AP.PreSwitchModes   = (int *)Malloc1(sizeof(int)*
3,552✔
4427
                                                                (AP.NumPreSwitchStrings+1),"case strings");
1,776✔
4428
        AP.PreSwitchModes[0] = EXECUTINGPRESWITCH;
1,776✔
4429
        AP.PreSwitchLevel = 0;
1,776✔
4430
}
1,776✔
4431

4432
/*
4433
                 #] StartPrepro : 
4434
                 #[ EvalPreIf :
4435

4436
                Evaluates the condition in an if instruction.
4437
                The return value is EXECUTINGIF if the condition is true.
4438
                If it is false the returnvalue is LOOKINGFORELSE.
4439
                An error gives a return value of -1
4440
*/
4441

4442
int EvalPreIf(UBYTE *s)
864✔
4443
{
4444
        UBYTE *t, *u;
864✔
4445
        int val;
864✔
4446
        t = s;
864✔
4447
        while ( *t ) t++;
6,096✔
4448
        *t++ = ')';
864✔
4449
        *t = 0;
864✔
4450
        if ( ( u = PreIfEval(s,&val) ) == 0 ) return(-1);
864✔
4451
        if ( u < t ) {
864✔
4452
                MesPrint("@Unmatched parentheses in condition");
×
4453
                return(-1);
×
4454
        }
4455
        if ( val ) return(EXECUTINGIF);
864✔
4456
        else       return(LOOKINGFORELSE);
857✔
4457
}
4458

4459
/*
4460
                 #] EvalPreIf : 
4461
                 #[ PreIfEval :
4462

4463
                Used for recursions in the evaluation of a preprocessor if-condition.
4464
                It determines whether the contents of () is true or false
4465
                (or in error).
4466
                The return value is the address of the first character after the
4467
                closing parenthesis or null if there is an error.
4468
                In value we find true(1) or false(0)
4469
                We enter after the opening parenthesis.
4470
                There are levels:
4471
                        0: orlevel:  a || b
4472
                        1: andlevel: a && b
4473
                        2: eqlevel:  a == b or a != b or a = b
4474
                        3: cmplevel: a > b or a >= b or a < b or a <= b or a >~ b etc
4475
*/
4476

4477
UBYTE *PreIfEval(UBYTE *s, int *value)
864✔
4478
{
4479
        int orlevel = 0, andlevel = 0, eqlevel = 0, cmplevel = 0;
864✔
4480
        int type, val;
864✔
4481
        LONG val2;
864✔
4482
        int ortype, orval, cmptype, cmpval, eqtype, eqval, andtype, andval;
864✔
4483
        UBYTE *t, *eqt, *cmpt, c;
864✔
4484
        int eqop, cmpop;
864✔
4485
        ortype = orval = cmptype = cmpval = eqtype = eqval = andtype = andval = 0;
864✔
4486
        eqop = cmpop = 0;
864✔
4487
        eqt = cmpt = 0;
864✔
4488
        *value = 0;
864✔
4489
        while ( *s != ')' ) {
1,718✔
4490
                while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
2,572✔
4491
                t = s;
1,718✔
4492
                s = pParseObject(s,&type,&val2);
1,718✔
4493
                if ( s == 0 ) return(0);
1,718✔
4494
                val = val2;
1,718✔
4495
                c = *s;
1,718✔
4496
                *s++ = 0;    /* in case the object is a string without " */
1,718✔
4497
                while ( c == ' ' || c == '\t' || c == '\n' || c == '\r' ) {
1,718✔
4498
                        c = *s; *s++ = 0;
×
4499
                }
4500
                if ( *t == '"' ) t++;
1,718✔
4501
                switch(c) {
1,718✔
4502
                        case '|':
×
4503
                                if ( *s != '|' ) goto illoper;
×
4504
                                s++;
×
4505
                                /* fall through */
4506
                        case ')':
864✔
4507
                                if ( cmplevel ) {
864✔
4508
                                        if ( type == 0 || cmptype == 0 ) goto illobject;
28✔
4509
                                        val = PreCmp(type,val,t,cmptype,cmpval,cmpt,cmpop);
28✔
4510
                                        type = 0;
28✔
4511
                                        cmplevel = 0;
28✔
4512
                                }
4513
                                if ( eqlevel ) {
864✔
4514
                                        val = PreEq(type,val,t,eqtype,eqval,eqt,eqop);
826✔
4515
                                        type = 0;
826✔
4516
                                        eqlevel = 0;
826✔
4517
                                }
4518
                                if ( andlevel ) {
864✔
4519
                                        if ( andtype != 0 || type != 0 ) goto illobject;
×
4520
                                        val &= andval;
×
4521
                                        andlevel = 0;
×
4522
                                }
4523
                                if ( orlevel ) {
864✔
4524
                                        if ( ortype != 0 || type != 0 ) goto illobject;
×
4525
                                        val |= orval;
×
4526
                                }
4527
                                if ( c == ')' ) {
864✔
4528
                                        *value = val;
864✔
4529
                                        return(s);
864✔
4530
                                }
4531
                                orlevel = 1;
×
4532
                                orval = val;
×
4533
                                ortype = type;
×
4534
                                break;
×
4535
                        case '&':
×
4536
                                if ( *s != '&' ) goto illoper;
×
4537
                                s++;
×
4538
                                if ( cmplevel ) {
×
4539
                                        if ( type == 0 || cmptype == 0 ) goto illobject;
×
4540
                                        val = PreCmp(type,val,t,cmptype,cmpval,cmpt,cmpop);
×
4541
                                        type = 0;
×
4542
                                        cmplevel = 0;
×
4543
                                }
4544
                                if ( eqlevel ) {
×
4545
                                        val = PreEq(type,val,t,eqtype,eqval,eqt,eqop);
×
4546
                                        type = 0;
×
4547
                                        eqlevel = 0;
×
4548
                                }
4549
                                if ( andlevel ) {
×
4550
                                        if ( andtype != 0 || type != 0 ) goto illobject;
×
4551
                                        val &= andval;
×
4552
                                }
4553
                                andlevel = 1;
×
4554
                                andval = val;
×
4555
                                andtype = type;
×
4556
                                break;
×
4557
                        case '!':
826✔
4558
                        case '=':
4559
                                if ( eqlevel ) goto illorder;
826✔
4560
                                if ( cmplevel ) {
826✔
4561
                                        if ( type == 0 || cmptype == 0 ) goto illobject;
×
4562
                                        val = PreCmp(type,val,t,cmptype,cmpval,cmpt,cmpop);
×
4563
                                        type = 0;
×
4564
                                        cmplevel = 0;
×
4565
                                }
4566
                                if ( c == '!' && *s != '=' ) goto illoper;
826✔
4567
                                if ( *s == '=' ) s++;
826✔
4568
                                if ( c == '!' ) eqop = 1;
826✔
4569
                                else eqop = 0;
826✔
4570
                                eqlevel = 1; eqt = t; eqval = val; eqtype = type;
826✔
4571
                                break;
826✔
4572
                        case '>':
28✔
4573
                        case '<':
4574
                                if ( cmplevel ) goto illorder;
28✔
4575
                                if ( c == '<' ) cmpop = -1;
28✔
4576
                                else            cmpop = 1;
×
4577
                                cmplevel = 1; cmpt = t; cmpval = val; cmptype = type;
28✔
4578
                                if ( *s == '=' ) {
28✔
4579
                                        s++;
28✔
4580
                                        if ( *s == '~' ) { s++; cmpop *= 4; }
28✔
4581
                                        else cmpop *= 2;
28✔
4582
                                }
4583
                                else if ( *s == '~' ) { s++; cmpop *= 3; }
×
4584
                                break;
4585
                        default:
×
4586
                                goto illoper;
×
4587
                }
4588
        }
4589
        return(s);
4590
illorder:
×
4591
        MesPrint("@illegal order of operators");
×
4592
        return(0);
×
4593
illobject:
×
4594
        MesPrint("@illegal object for this operator");
×
4595
        return(0);
×
4596
illoper:
×
4597
        MesPrint("@illegal operator");
×
4598
        return(0);
×
4599
}
4600

4601
/*
4602
                 #] PreIfEval : 
4603
                 #[ PreCmp :
4604
*/
4605

4606
int PreCmp(int type, int val, UBYTE *t, int type2, int val2, UBYTE *t2, int cmpop)
28✔
4607
{
4608
        if ( type == 2 || type2 == 2 || cmpop < -2 || cmpop > 2 ) {
28✔
4609
                if ( cmpop < 0 && cmpop > -3 ) cmpop -= 2;
×
4610
                if ( cmpop > 0 && cmpop <  3 ) cmpop += 2;
×
4611
                     if ( cmpop ==  3 ) val = StrCmp(t2,t) >  0;
×
4612
                else if ( cmpop ==  4 ) val = StrCmp(t2,t) >= 0;
×
4613
                else if ( cmpop == -3 ) val = StrCmp(t2,t) <  0; 
×
4614
                else if ( cmpop == -4 ) val = StrCmp(t2,t) <= 0; 
×
4615
        }
4616
        else {
4617
                     if ( cmpop ==  1 ) val = ( val2 >  val );
28✔
4618
                else if ( cmpop ==  2 ) val = ( val2 >= val );
28✔
4619
                else if ( cmpop == -1 ) val = ( val2 <  val );
28✔
4620
                else if ( cmpop == -2 ) val = ( val2 <= val );
28✔
4621
        }
4622
        return(val);
28✔
4623
}
4624

4625
/*
4626
                 #] PreCmp : 
4627
                 #[ PreEq :
4628
*/
4629

4630
int PreEq(int type, int val, UBYTE *t, int type2, int val2, UBYTE *t2, int eqop)
826✔
4631
{
4632
        UBYTE str[20];
826✔
4633
        if ( type == 2 || type2 == 2 ) {
826✔
4634
                if ( type  != 2 ) { NumToStr(str,val ); t  = str; }
7✔
4635
                if ( type2 != 2 ) { NumToStr(str,val2); t2 = str; }
7✔
4636
                if ( eqop == 1 ) val = StrCmp(t,t2) != 0;
7✔
4637
                else             val = StrCmp(t,t2) == 0;
7✔
4638
        }
4639
        else {
4640
                if ( eqop ) val = val != val2;
819✔
4641
                else        val = val == val2;
819✔
4642
        }
4643
        return(val);
826✔
4644
}
4645

4646
/*
4647
                 #] PreEq : 
4648
                 #[ pParseObject :
4649

4650
                Parses a preprocessor object. We can have:
4651
                1: a number  (type = 1)
4652
                2: a string  (type = 2)
4653
                3: an expression between parentheses (type = 0)
4654
                4: a special function (type = 3)
4655
                If the object is not a number, an expression or a special operator
4656
                we try to interpret it as a string.
4657
*/
4658

4659
UBYTE *pParseObject(UBYTE *s, int *type, LONG *val2)
1,718✔
4660
{
4661
        UBYTE *t, c;
1,718✔
4662
        int sign, val = 0;
1,718✔
4663
        LONG x;
1,718✔
4664
        while ( *s == ' ' || *s == '\t' ) s++;
1,718✔
4665
        if ( *s == '(' ) {
1,718✔
4666
                s++;
×
4667
                while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
×
4668
                s = PreIfEval(s,&val);
×
4669
                *type = 0;
×
4670
                *val2 = val;
×
4671
                return(s);
×
4672
        }
4673
        else if ( *s == '$' && s[1] == '(' ) {
1,718✔
4674
                s += 2;
×
4675
                while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
×
4676
                s = PreIfDollarEval(s,&val);
×
4677
                *type = 0; *val2 = val;
×
4678
                return(s);
×
4679
        }
4680
        if ( *s == 0 ) {
1,718✔
4681
illend:
×
4682
                MesPrint("@illegal end of condition");
×
4683
                return(0);
×
4684
        }
4685
        if ( *s == '"' ) {
1,718✔
4686
                s++;
14✔
4687
                while ( *s && *s != '"' ) {
91✔
4688
                        if ( *s == '\\' ) s++;
77✔
4689
                        s++;
77✔
4690
                }
4691
                if ( *s == 0 ) goto illend;
14✔
4692
                else *s = 0;
14✔
4693
                *type = 2;
14✔
4694
                s++;
14✔
4695

4696
                while ( *s == ' ' || *s == '\t' || *s == '\n' || *s == '\r' ) s++;
21✔
4697

4698
                return(s);
4699
        }
4700
        t = s; sign = 1; x = 0;
1,704✔
4701
        if ( chartype[*t] == 0 ) {        /* Special operators and strings without "" */
1,704✔
4702
                do { t++; } while ( chartype[*t] <= 1 );
×
4703
                if ( *t == '(' ) {
×
4704
                        WORD ttype;
×
4705
                        c = *t; *t = 0;
×
4706
                        if ( StrICmp(s,(UBYTE *)"termsin") == 0 ) {
×
4707
                                UBYTE *tt;
4708
                                WORD numdol, numexp;
4709
                                ttype = 0;
4710
together:
×
4711
                                *t++ = c;
×
4712
                                while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
×
4713
                                if ( *t == '$' ) {
×
4714
                                        t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
×
4715
                                        c = *tt; *tt = 0;
×
4716
                                        if ( ( numdol = GetDollar(t) ) > 0 ) {
×
4717
                                                *tt = c;
×
4718
                                                if ( ttype == 1 ) {
×
4719
                                                        x = SizeOfDollar(numdol);
×
4720
                                                }
4721
                                                else {
4722
                                                        x = TermsInDollar(numdol);
×
4723
                                                }
4724
                                        }
4725
                                        else {
4726
                                                MesPrint("@$%s has not (yet) been defined",t);
×
4727
                                                *tt = c;
×
NEW
4728
                                                TERMINATE(-1);
×
4729
                                        }
4730
                                }
4731
                                else {
4732
                                        tt = SkipAName(t);
×
4733
                                        c = *tt; *tt = 0;
×
4734
                                        if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) {
×
4735
                                                MesPrint("@%s has not (yet) been defined",t);
×
4736
                                                *tt = c;
×
NEW
4737
                                                TERMINATE(-1);
×
4738
                                        }
4739
                                        else {
4740
                                                *tt = c;
×
4741
                                                if ( ttype == 1 ) {
×
4742
                                                        x = SizeOfExpression(numexp);
×
4743
                                                }
4744
                                                else {
4745
                                                        x = TermsInExpression(numexp);
×
4746
                                                }
4747
                                        }
4748
                                }
4749
                                while ( *tt == ' ' || *tt == '\t'
×
4750
                                                 || *tt == '\n' || *tt == '\r' ) tt++;
×
4751
                                if ( *tt != ')' ) {
×
4752
                                        MesPrint("@Improper use of terms($var) or terms(expr)");
×
NEW
4753
                                        TERMINATE(-1);
×
4754
                                }
4755
                                *type = 3;
×
4756
                                s = tt+1;
×
4757
                                *val2 = x;
×
4758
                                return(s);
×
4759
                        }
4760
                        else if ( StrICmp(s,(UBYTE *)"sizeof") == 0 ) {
×
4761
                                ttype = 1;
×
4762
                                goto together;
×
4763
                        }
4764
                        else if ( StrICmp(s,(UBYTE *)"exists") == 0 ) {
×
4765
                                UBYTE *tt;
×
4766
                                WORD numdol, numexp;
×
4767
                                *t++ = c;
×
4768
                                while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
×
4769
                                if ( *t == '$' ) {
×
4770
                                        t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
×
4771
                                        c = *tt; *tt = 0;
×
4772
                                        if ( ( numdol = GetDollar(t) ) >= 0 ) { x = 1; }
×
4773
                                        else                                  { x = 0; }
×
4774
                                        *tt = c;
×
4775
                                }
4776
                                else if ( *t == '"' ) {        /* see whether a file exists */
×
4777
/*                                        UBYTE *name, *oldname; */
4778
                                        t++; tt = t;
×
4779
                                        for (;;) {
×
4780
                                                if ( *tt == '\\' ) tt++;
×
4781
                                                else if ( *tt == '"' ) break;
×
4782
                                                tt++;
×
4783
                                        }
4784
                                        c = *tt; *tt = 0;
×
4785
/*
4786
                                        Try to open the file. If possible, return 1.
4787
                                        Afterwards close it.
4788
                                        We do have to run through the FORMPATH. Hence we use LocateFile.
4789
                                        This routine may change the name to the full name.
4790

4791
                                        oldname = name = strDup1(t,"name in exists");
4792
                                        x = LocateFile(&name,-1);
4793
*/
4794
                                        x = OpenFile((char *)t);
×
4795
                                        if ( x >= 0 ) {
×
4796
                                                CloseFile(x);
×
4797
                                                x = 1;
×
4798
/*
4799
                                                if ( name != oldname ) M_free(name,"name from LocateFile");
4800
*/
4801
                                        }
4802
                                        else x = 0;
4803
/*
4804
                                        M_free(oldname,"name in exists");
4805
*/
4806
                                        *tt++ = c;
×
4807
                                }
4808
                                else {
4809
                                        tt = SkipAName(t);
×
4810
                                        c = *tt; *tt = 0;
×
4811
                                        if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) { x = 0; }
×
4812
                                        else { x = 1; }
×
4813
                                        *tt = c;
×
4814
                                } 
4815
                                while ( *tt == ' ' || *tt == '\t'
×
4816
                                                 || *tt == '\n' || *tt == '\r' ) tt++;
×
4817
                                if ( *tt != ')' ) {
×
4818
                                        MesPrint("@Improper use of exists($var) or exists(expr)");
×
NEW
4819
                                        TERMINATE(-1);
×
4820
                                }
4821
                                *type = 3;
×
4822
                                s = tt+1;
×
4823
                                *val2 = x;
×
4824
                                return(s);
×
4825
                        }
4826
                        else if ( StrICmp(s,(UBYTE *)"isnumerical") == 0 ) {
×
4827
                                GETIDENTITY
4828
                                UBYTE *tt;
×
4829
                                WORD numdol, numexp;
×
4830
                                *t++ = c;
×
4831
                                while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
×
4832
                                if ( *t == '$' ) {
×
4833
                                        t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
×
4834
                                        c = *tt; *tt = 0;
×
4835
                                        if ( ( numdol = GetDollar(t) ) < 0 ) {
×
4836
                                                MesPrint("@$ variable in isnumerical(%s) does not exist",t);
×
NEW
4837
                                                TERMINATE(-1);
×
4838
                                        }
4839
                                        x = DolToLong(BHEAD numdol);
×
4840
                                        if ( AN.ErrorInDollar ) {
×
4841
                                                DOLLARS d = Dollars + numdol;
×
4842
                                                x = 0;
×
4843
                                                if ( d->type == DOLNUMBER || d->type == DOLTERMS ) {
×
4844
                                                        if ( d->where[0] == 0 ) x = 1;
×
4845
                                                        else if ( d->where[d->where[0]] == 0 ) {
×
4846
                                                                if ( ABS(d->where[d->where[0]-1]) == d->where[0]-1 )
×
4847
                                                                        x = 1;
×
4848
                                                        }
4849
                                                }
4850
                                        }
4851
                                        else x = 1;
4852
                                        *tt = c;
×
4853
                                }
4854
                                else {
4855
                                        tt = SkipAName(t);
×
4856
                                        c = *tt; *tt = 0;
×
4857
                                        if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) {
×
4858
                                                MesPrint("@expression in isnumerical(%s) does not exist",t);
×
NEW
4859
                                                TERMINATE(-1);
×
4860
                                        }
4861
                                        x = TermsInExpression(numexp);
×
4862
                                        if ( x != 1 ) x = 0;
×
4863
                                        else {
4864
                                                WORD *term = AT.WorkPointer;
×
4865
                                                if ( GetFirstTerm(term,numexp) < 0 ) {
×
4866
                                                        MesPrint("@error reading expression in isnumerical(%s)",t);
×
NEW
4867
                                                        TERMINATE(-1);
×
4868
                                                }
4869
                                                if ( *term == ABS(term[*term-1])+1 ) x = 1;
×
4870
                                                else                                 x = 0;
×
4871
                                        }
4872
                                        *tt = c;
×
4873
                                } 
4874
                                while ( *tt == ' ' || *tt == '\t'
×
4875
                                                 || *tt == '\n' || *tt == '\r' ) tt++;
×
4876
                                if ( *tt != ')' ) {
×
4877
                                        MesPrint("@Improper use of isnumerical($var) or numerical(expr)");
×
NEW
4878
                                        TERMINATE(-1);
×
4879
                                }
4880
                                *type = 3;
×
4881
                                s = tt+1;
×
4882
                                *val2 = x;
×
4883
                                return(s);
×
4884
                        }
4885
                        else if ( StrICmp(s,(UBYTE *)("maxpowerof")) == 0 ) {
×
4886
                                UBYTE *tt;
×
4887
                                WORD numsym;
×
4888
                                int stype;
×
4889
                                *t++ = c;
×
4890
                                while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
×
4891
                                tt = SkipAName(t);
×
4892
                                c = *tt; *tt = 0;
×
4893
                                if ( ( stype = GetName(AC.varnames,t,&numsym,NOAUTO) ) == NAMENOTFOUND ) {
×
4894
                                        MesPrint("@%s has not (yet) been defined",t);
×
4895
                                        *tt = c;
×
NEW
4896
                                        TERMINATE(-1);
×
4897
                                }
4898
                                else if ( stype != CSYMBOL ) {
×
4899
                                        MesPrint("@%s should be a symbol",t);
×
4900
                                        *tt = c;
×
NEW
4901
                                        TERMINATE(-1);
×
4902
                                }
4903
                                else {
4904
                                        *tt = c;
×
4905
                                        x = symbols[numsym].maxpower;
×
4906
                                }
4907
                                while ( *tt == ' ' || *tt == '\t'
×
4908
                                                 || *tt == '\n' || *tt == '\r' ) tt++;
×
4909
                                if ( *tt != ')' ) {
×
4910
                                        MesPrint("@Improper use of maxpowerof(symbol)");
×
NEW
4911
                                        TERMINATE(-1);
×
4912
                                }
4913
                                *type = 3;
×
4914
                                s = tt+1;
×
4915
                                *val2 = x;
×
4916
                                return(s);
×
4917
                        }
4918
                        else if ( StrICmp(s,(UBYTE *)("minpowerof")) == 0 ) {
×
4919
                                UBYTE *tt;
×
4920
                                WORD numsym;
×
4921
                                int stype;
×
4922
                                *t++ = c;
×
4923
                                while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
×
4924
                                tt = SkipAName(t);
×
4925
                                c = *tt; *tt = 0;
×
4926
                                if ( ( stype = GetName(AC.varnames,t,&numsym,NOAUTO) ) == NAMENOTFOUND ) {
×
4927
                                        MesPrint("@%s has not (yet) been defined",t);
×
4928
                                        *tt = c;
×
NEW
4929
                                        TERMINATE(-1);
×
4930
                                }
4931
                                else if ( stype != CSYMBOL ) {
×
4932
                                        MesPrint("@%s should be a symbol",t);
×
4933
                                        *tt = c;
×
NEW
4934
                                        TERMINATE(-1);
×
4935
                                }
4936
                                else {
4937
                                        *tt = c;
×
4938
                                        x = symbols[numsym].minpower;
×
4939
                                }
4940
                                while ( *tt == ' ' || *tt == '\t'
×
4941
                                                 || *tt == '\n' || *tt == '\r' ) tt++;
×
4942
                                if ( *tt != ')' ) {
×
4943
                                        MesPrint("@Improper use of minpowerof(symbol)");
×
NEW
4944
                                        TERMINATE(-1);
×
4945
                                }
4946
                                *type = 3;
×
4947
                                s = tt+1;
×
4948
                                *val2 = x;
×
4949
                                return(s);
×
4950
                        }
4951
                        else if ( StrICmp(s,(UBYTE *)"isfactorized") == 0 ) {
×
4952
                                UBYTE *tt;
×
4953
                                WORD numdol, numexp;
×
4954
                                *t++ = c;
×
4955
                                while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
×
4956
                                if ( *t == '$' ) {
×
4957
                                        t++; tt = t; while (chartype[*tt] <= 1 ) tt++;
×
4958
                                        c = *tt; *tt = 0;
×
4959
                                        if ( ( numdol = GetDollar(t) ) > 0 ) {
×
4960
                                                if ( Dollars[numdol].factors != 0 ) x = 1;
×
4961
                                                else x = 0;
×
4962
                                        }
4963
                                        else {
4964
                                                MesPrint("@ %s should be the name of an expression or a $ variable",t-1);
×
NEW
4965
                                                TERMINATE(-1);
×
4966
                                        }
4967
                                        *tt = c;
×
4968
                                }
4969
                                else {
4970
                                        tt = SkipAName(t);
×
4971
                                        c = *tt; *tt = 0;
×
4972
                                        if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) {
×
4973
                                                MesPrint("@ %s should be the name of an expression or a $ variable",t);
×
NEW
4974
                                                TERMINATE(-1);
×
4975
                                        }
4976
                                        else {
4977
                                                if ( ( Expressions[numexp].vflags & ISFACTORIZED ) != 0 ) x = 1;
×
4978
                                                else x = 0;
×
4979
                                        }
4980
                                        *tt = c;
×
4981
                                } 
4982
                                while ( *tt == ' ' || *tt == '\t'
×
4983
                                                 || *tt == '\n' || *tt == '\r' ) tt++;
×
4984
                                if ( *tt != ')' ) {
×
4985
                                        MesPrint("@Improper use of isfactorized($var) or isfactorized(expr)");
×
NEW
4986
                                        TERMINATE(-1);
×
4987
                                }
4988
                                *type = 3;
×
4989
                                s = tt+1;
×
4990
                                *val2 = x;
×
4991
                                return(s);
×
4992
                        }
4993
                        else if ( StrICmp(s,(UBYTE *)"isdefined") == 0 ) {
×
4994
                                UBYTE *tt;
×
4995
                                *t++ = c;
×
4996
                                while ( *t == ' ' || *t == '\t' || *t == '\n' || *t == '\r' ) t++;
×
4997
                                tt = SkipAName(t);
×
4998
                                c = *tt; *tt = 0;
×
4999
                                if ( GetPreVar(t,WITHOUTERROR) != 0 ) x = 1;
×
5000
                                else x = 0;
×
5001
                                *tt = c;
×
5002
                                while ( *tt == ' ' || *tt == '\t'
×
5003
                                                 || *tt == '\n' || *tt == '\r' ) tt++;
×
5004
                                if ( *tt != ')' ) {
×
5005
                                        MesPrint("@Improper use of isdefined(var)");
×
NEW
5006
                                        TERMINATE(-1);
×
5007
                                }
5008
                                *type = 3;
×
5009
                                s = tt+1;
×
5010
                                *val2 = x;
×
5011
                                return(s);
×
5012
                        }
5013
                        else if ( StrICmp(s,(UBYTE *)"flag") == 0 ) {
×
5014
                                UBYTE *tt;
×
5015
                                WORD x = 0, numexp;
×
5016
                                {
5017
                                *t++ = c;
×
5018
                                while ( *t == ' ' || *t == '\t' ) t++;
×
5019
                                if ( FG.cTable[*t] != 1 ) goto flagerror;
×
5020
                                while ( FG.cTable[*t] == 1 ) x = 10*x + (*t++ - '0');
×
5021
                                if ( x < 1 || x > BITSINWORD ) {
×
5022
                                        MesPrint("@Illegal number %d for flag in flag condition",x);
×
5023
                                        goto flagerror;
×
5024
                                }
5025
                                while ( *t == ' ' || *t == '\t' ) t++;
×
5026
                                if ( *t != ',' ) goto flagerror;
×
5027
                                t++;
×
5028
                                while ( *t == ' ' || *t == '\t' ) t++;
×
5029
                                tt = SkipAName(t);
×
5030
                                c = *tt; *tt = 0;
×
5031
                                if ( GetName(AC.exprnames,t,&numexp,NOAUTO) == NAMENOTFOUND ) {
×
5032
                                        MesPrint("@ %s should be the name of an expression",t);
×
5033
                                        goto flagerror;
×
5034
                                }
5035
                                *tt = c;
×
5036
                                while ( *t == ' ' || *t == '\t' ) t++;
×
5037
                                if ( *tt != ')' ) {
×
5038
flagerror:
×
5039
                                        MesPrint("@Improper use of flag(num,expr)");
×
NEW
5040
                                        TERMINATE(-1);
×
5041
                                        return(0);
×
5042
                                }
5043
                                if ( ( Expressions[numexp].uflags & ( 1 << (x-1) ) ) != 0 )
×
5044
                                        *val2 = 1;
×
5045
                                else *val2 = 0;
×
5046
                                *type = 3;
×
5047
                                s = tt+1;
×
5048
                                return(s);
×
5049
                                }
5050
                        }
5051
                        else *t = c;
×
5052
                }
5053
                else if ( *t == '=' || *t == '<' || *t == '>' || *t == '!'
×
5054
                || *t == ')' || *t == ' ' || *t == '\t' || *t == 0 || *t == '\n' ) {
×
5055
                        *val2 = 0;
×
5056
                        *type = 2;
×
5057
                        return(t);
×
5058
                }
5059
                else {
5060
                        MesPrint("@Illegal use of string in preprocessor condition: %s",s);
×
NEW
5061
                        TERMINATE(-1);
×
5062
                }
5063
        }
5064
        while ( *t == '-' || *t == '+' || *t == ' ' || *t == '\t' ) {
1,704✔
5065
                if ( *t == '-' ) sign = -sign;
×
5066
                t++;
×
5067
        }
5068
        while ( chartype[*t] == 1 ) { x = 10*x + *t++ - '0'; }
3,415✔
5069
        while ( *t == ' ' || *t == '\t' ) t++;
2,551✔
5070
        if ( chartype[*t] == 8 || *t == ')' || *t == '=' || *t == 0 ) {
1,704✔
5071
                *val2 = sign > 0 ? x: -x;
1,704✔
5072
                *type = 1;
1,704✔
5073
                return(t);
1,704✔
5074
        }
5075
        while ( chartype[*t] != 8 && *t != ')' && *t != '=' && *t ) t++;
×
5076
        while ( ( t > s ) && ( t[-1] == ' ' || t[-1] == '\t' ) ) t--;
×
5077
        *type = 2;
×
5078
        *val2 = val;
×
5079
        return(t);
×
5080
}
5081

5082
/*
5083
                 #] pParseObject : 
5084
                 #[ PreCalc :
5085
 
5086
                To be called when a { is encountered.
5087
                Action: read first till matching }. This is to be stored.
5088
                Next we look whether this is a set or whether it can be
5089
                evaluated. If it is a set we consider it as a new stream.
5090
                The stream will have to be deallocated when read completely.
5091
                If it is to be evaluated we do that and put the result in
5092
                a stream.
5093
*/
5094

5095
UBYTE *PreCalc(VOID)
9,408✔
5096
{
5097
        UBYTE *buff, *s = 0, *t, *newb, c;
9,408✔
5098
        int size, i, n, parlevel = 0, bralevel = 0;
9,408✔
5099
        LONG answer;
9,408✔
5100
        ULONG uanswer;
9,408✔
5101
        size = n = 0;
9,408✔
5102
        buff = 0; c = '{';
9,408✔
5103
        for (;;) {
58,107✔
5104
                if ( n >= size ) {
58,107✔
5105
                        if ( size == 0 ) size = 72;
9,408✔
5106
                        else size *= 2;
×
5107
                        if ( ( newb = (UBYTE *)Malloc1(size+2,"{}") ) == 0 ) return(0);
9,408✔
5108
                        s = newb;
9,408✔
5109
                        if ( buff ) {
9,408✔
5110
                                i = n;
5111
                                t = buff;
5112
                                NCOPYB(s,t,i);
×
5113
                                M_free(buff,"pre calc buffer");
×
5114
                        }
5115
                        else s = newb;
5116
                        buff = newb;
5117
                }
5118
                *s++ = c; n++;
58,107✔
5119
                c = GetChar(0);
58,107✔
5120
                if ( c == 0 ) {
58,107✔
5121
                        Error0("Unmatched {}");
×
5122
                        M_free(buff,"precalc buffer");
×
5123
                        return(0);
×
5124
                }
5125
                else if ( c == '{' ) { bralevel++; }
58,107✔
5126
                else if ( c == '}' ) {
58,107✔
5127
                        if ( --bralevel < 0 ) { *s++ = c; *s = 0; break; }
7,154✔
5128
                }
5129
                else if ( c == '(' ) { parlevel++; }
50,953✔
5130
                else if ( c == ')' ) {
50,946✔
5131
                        if ( --parlevel < 0 ) { *s++ = c; *s = 0; goto setstring; }
7✔
5132
                }
5133
                else if ( chartype[c] != 1 && chartype[c] != 5
50,939✔
5134
                && chartype[c] != 6 && c != '!' && c != '&'
2,261✔
5135
                && c != '|' && c != '\\' ) { *s++ = c; *s = 0; goto setstring; }
2,261✔
5136
        }
5137
        if ( parlevel > 0 ) goto setstring;
7,154✔
5138
/*
5139
        Try now to evaluate the string.
5140
        If it works, copy the resulting value back into buff as a string.
5141
*/
5142
        answer = 0;
7,154✔
5143
        if ( PreEval(buff+1,&answer) == 0 ) goto setstring;
7,154✔
5144
        t = buff + size;
7,154✔
5145
        s = buff;
7,154✔
5146
        if ( answer < 0 ) { *s++ = '-'; }
7,154✔
5147
        uanswer = LongAbs(answer);
7,154✔
5148
        n = 0;
5149
        do {
21,462✔
5150
                *--t = ( uanswer % 10 ) + '0';
21,462✔
5151
                uanswer /= 10;
21,462✔
5152
                n++;
21,462✔
5153
        } while ( uanswer > 0 );
21,462✔
5154
        NCOPYB(s,t,n);
28,616✔
5155
        *s = 0;
7,154✔
5156
setstring:;
9,408✔
5157
/*
5158
        Open a stream that contains the current string.
5159
        Mark it to be removed after termination.
5160
*/
5161
        if ( OpenStream(buff,PRECALCSTREAM,0,PRENOACTION) == 0 ) return(0);
9,408✔
5162
        return(buff);
5163
}
5164

5165
/*
5166
                 #] PreCalc : 
5167
                 #[ PreEval :
5168

5169
                Operations are:
5170
                +, -, *, /, %, &, |, ^, !,  ^% (postfix 2log), ^/ (postfix sqrt)
5171
*/
5172

5173
UBYTE *PreEval(UBYTE *s, LONG *x)
8,185✔
5174
{
5175
        LONG y, z, a;
8,185✔
5176
        int tobemultiplied, tobeadded = 1, expsign, i;
8,185✔
5177
        UBYTE *t;
8,185✔
5178
        *x = 0; a = 1;
8,185✔
5179
        while ( *s == ' ' || *s == '\t' ) s++;
8,185✔
5180
        for(;;){
15,283✔
5181
                if ( *s == '+' || *s == '-' ) {
15,283✔
5182
                        if ( *s == '-' ) tobeadded = -1;
7,238✔
5183
                        else tobeadded = 1;
7,091✔
5184
                        s++;
7,238✔
5185
                        while ( *s == '-' || *s == '+' || *s == ' ' || *s == '\t' ) {
7,343✔
5186
                                if ( *s == '-' ) tobeadded = -tobeadded;
105✔
5187
                                s++;
105✔
5188
                        }
5189
                }
5190
                tobemultiplied = 0;
15,283✔
5191
                for(;;){
28✔
5192
                        while ( *s == ' ' || *s == '\t' ) s++;
15,311✔
5193
                        if ( *s <= '9' && *s >= '0' ) {
15,311✔
5194
                                ULONG uy;
5195
                                ParseNumber(uy,s)
57,778✔
5196
                                y = uy;  /* may cause an implementation-defined behaviour */
15,304✔
5197
                        }
5198
                        else if ( *s == '(' || *s == '{' ) {
7✔
5199
                                if ( ( t = PreEval(s+1,&y) ) == 0 ) return(0);
7✔
5200
                                s = t;
5201
                        }
5202
                        else return(0);
5203
                        while ( *s == ' ' || *s == '\t' ) s++;
15,311✔
5204
                        expsign = 1;
5205
                        while ( *s == '^' || *s == '!' ) {
15,325✔
5206
                                s++;
14✔
5207
                                if ( s[-1] == '!' ) {   /* factorial of course */
14✔
5208
                                        while ( *s == ' ' || *s == '\t' ) s++;
×
5209
                                        if ( y < 0 ) {
×
5210
                                                MesPrint("@Negative value in preprocessor factorial: %l",y);
×
5211
                                                return(0);
×
5212
                                        }
5213
                                        else if ( y == 0 ) y = 1;
×
5214
                                        else if ( y > 1 ) {
×
5215
                                                z = y-1;
×
5216
                                                while ( z > 0 ) { y = y*z; z--; }
×
5217
                                        }
5218
                                        continue;
×
5219
                                }
5220
                                else if ( *s == '%' ) {        /* ^% is postfix 2log */
14✔
5221
                                        s++;
×
5222
                                        while ( *s == ' ' || *s == '\t' ) s++;
×
5223
                                        z = y;
×
5224
                                        if ( z <= 0 ) {
×
5225
                                                MesPrint("@Illegal value in preprocessor logarithm: %l",z);
×
5226
                                                return(0);
×
5227
                                        }
5228
                                        y = 0; z >>= 1;
×
5229
                                        while ( z ) { y++; z >>= 1; }
×
5230
                                        continue;
×
5231
                                }
5232
                                else if ( *s == '/' ) { /* ^/ is postfix sqrt */
14✔
5233
                                        LONG yy, zz;
×
5234
                                        s++;
×
5235
                                        while ( *s == ' ' || *s == '\t' ) s++;
×
5236
                                        z = y;
×
5237
                                        if ( z <= 0 ) {
×
5238
                                                MesPrint("@Illegal value in preprocessor square root: %l",z);
×
5239
                                                return(0);
×
5240
                                        }
5241
                                        if ( z > 8 ) {                /* Very crude integer square root */
×
5242
                                                zz = z;
×
5243
                                                yy = 0; zz >>= 1;
×
5244
                                                while ( zz ) { yy++; zz >>= 1; }
×
5245
                                                zz = z >> (yy/2); i = 10; y = 0;
×
5246
                                                do { 
×
5247
                                                        yy = zz/2 + z/(2*zz); i--;
×
5248
                                                        if ( y == yy ) break;
×
5249
                                                        y = zz; zz = yy;
×
5250
                                                } while ( y != yy && i > 0 );
×
5251
                                                while ( y*y < z ) y++;
×
5252
                                                while ( y*y > z ) y--;
×
5253
                                        }
5254
                                        else if ( z >= 4 ) y = 2;
×
5255
                                        else if ( z == 0 ) y = 0;
×
5256
                                        else y = 1;
×
5257
                                        continue;
×
5258
                                }
5259
                                while ( *s == ' ' || *s == '\t' ) s++;
14✔
5260
                                while ( *s == '-' || *s == '+' || *s == ' ' || *s == '\t' ) {
14✔
5261
                                        if ( *s == '-' ) expsign = -expsign;
×
5262
                                }
5263
                                if ( *s <= '9' && *s >= '0' ) {
14✔
5264
                                        ParseNumber(z,s)
35✔
5265
                                }
5266
                                else if ( *s == '(' || *s == '{' ) {
×
5267
                                        if ( ( t = PreEval(s+1,&z) ) == 0 ) return(0);
×
5268
                                        s = t;
5269
                                }
5270
                                else return(0);
5271
                                while ( *s == ' ' || *s == '\t' ) s++;
14✔
5272
                                y = iexp(y,(int)z);
14✔
5273
                        }
5274
                        if ( tobemultiplied == 0 ) {
15,311✔
5275
                                if ( expsign < 0 ) a = 1/y;
15,283✔
5276
                                else a = y;
15,283✔
5277
                        }
5278
                        else {
5279
                                if ( tobemultiplied > 2 && expsign != 1 ) {
28✔
5280
                                        MesPrint("&Incorrect use of ^ with & or |. Use brackets!");
×
NEW
5281
                                        TERMINATE(-1);
×
5282
                                }
5283
                                tobemultiplied *= expsign;
28✔
5284
                                if ( tobemultiplied == 1 ) a *= y;
28✔
5285
                                else if ( tobemultiplied == 3 ) a &= y;
×
5286
                                else if ( tobemultiplied == 4 ) a |= y;
×
5287
                                else {
5288
                                        if ( y == 0 || tobemultiplied == -2 ) {
×
5289
                                                MesPrint("@Division by zero in preprocessor calculator");
×
NEW
5290
                                                TERMINATE(-1);
×
5291
                                        }
5292
                                        if ( tobemultiplied == 2 ) a %= y;
×
5293
                                        else a /= y;
×
5294
                                }
5295
                        }
5296
                        if ( *s == '%' ) tobemultiplied = 2;
15,311✔
5297
                        else if ( *s == '*' ) tobemultiplied = 1;
15,311✔
5298
                        else if ( *s == '/' ) tobemultiplied = -1;
15,283✔
5299
                        else if ( *s == '&' ) tobemultiplied = 3;
15,283✔
5300
                        else if ( *s == '|' ) tobemultiplied = 4;
15,283✔
5301
                        else {
5302
                                ULONG ux, ua;
15,283✔
5303
                                ux = *x;
15,283✔
5304
                                ua = a;
15,283✔
5305
                                if ( tobeadded >= 0 ) ux += ua;
15,283✔
5306
                                else ux -= ua;
84✔
5307
                                *x = ULongToLong(ux);
15,283✔
5308
                                if ( *s == ')' || *s == '}' ) return(s+1);
15,283✔
5309
                                else if ( *s == '-' || *s == '+' ) { tobeadded = 1; break; }
7,098✔
5310
                                else return(0);
5311
                        }
5312
                        s++;
28✔
5313
                }
5314
        }
5315
/*        return(0); */
5316
}
5317

5318
/*
5319
                 #] PreEval : 
5320
                 #[ AddToPreTypes :
5321
*/
5322

5323
void AddToPreTypes(int type)
2,044✔
5324
{
5325
        if ( AP.NumPreTypes >= AP.MaxPreTypes ) {
2,044✔
5326
                int i, *newlist = (int *)Malloc1(sizeof(int)*(2*AP.MaxPreTypes+1)
×
5327
                                                ,"preprocessor type lists");
5328
                for ( i = 0; i <= AP.MaxPreTypes; i++ ) newlist[i] = AP.PreTypes[i];
×
5329
                M_free(AP.PreTypes,"preprocessor type lists");
×
5330
                AP.PreTypes = newlist;
×
5331
                AP.MaxPreTypes = 2*AP.MaxPreTypes;
×
5332
        }
5333
        AP.PreTypes[++AP.NumPreTypes] = type;
2,044✔
5334
}
2,044✔
5335

5336
/*
5337
                 #] AddToPreTypes : 
5338
                 #[ MessPreNesting :
5339
*/
5340

5341
void MessPreNesting(int par)
×
5342
{
5343
        MesPrint("@(%d)Illegal nesting of %#if, %#do, %#procedure and/or %#switch",par);
×
5344
}
×
5345

5346
/*
5347
                 #] MessPreNesting : 
5348
                 #[ DoPreAddSeparator :
5349

5350
                Preprocessor directives "addseparator" and "rmseparator" add/remove 
5351
                separator characters used to separate function arguments. 
5352
                Example:
5353

5354
                        #define QQ "a|g|a"
5355
                        #addseparator %
5356
                        *Comma must be quoted!:
5357
                        #rmseparator ","
5358
                        #rmseparator |
5359
                        #call H(a,a%`QQ')
5360

5361
                Characters ' ', '\t' and '"' are ignored!
5362
*/
5363

5364
int DoPreAddSeparator(UBYTE *s)
×
5365
{
5366
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
5367
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
5368
        for(;*s != '\0';s++){
×
5369
                while ( *s == ' ' || *s == '\t' || *s == '"') s++;
×
5370
                /* Todo: 
5371
                if ( set_in(*s,invalidseparators) ) {
5372
                        MesPrint("@Invalid separator specified");
5373
                        return(-1);
5374
                }
5375
                */
5376
                set_set(*s,AC.separators);
×
5377
        }
5378
        return(0);
5379
}
5380

5381
/*
5382
                 #] DoPreAddSeparator : 
5383
                 #[ DoPreRmSeparator :
5384

5385
                See commentary with DoPreAddSeparator
5386

5387
                Characters ' ', '\t' and '"' are ignored!
5388
*/
5389
int DoPreRmSeparator(UBYTE *s)
×
5390
{
5391
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
5392
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
5393
        for(;*s != '\0';s++){
×
5394
                while ( *s == ' ' || *s == '\t' || *s == '"') s++;
×
5395
                set_del(*s,AC.separators);
×
5396
        }
5397
        return(0);
5398
}
5399

5400
/*
5401
                 #] DoPreRmSeparator : 
5402
                 #[ DoExternal:
5403

5404
                #external ["prevar"] command
5405
*/
5406
int DoExternal(UBYTE *s)
14✔
5407
{ 
5408
#ifdef WITHEXTERNALCHANNEL
5409
        UBYTE *prevar=0;
14✔
5410
        int externalD= 0;
14✔
5411
#else
5412
        DUMMYUSE(s);
5413
#endif
5414
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
14✔
5415
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
14✔
5416
        if ( AP.preError ) return(0);
14✔
5417

5418
#ifdef WITHEXTERNALCHANNEL
5419
        while ( *s == ' ' || *s == '\t' ) s++;
14✔
5420
        if(*s == '"'){/*prevar to store the descriptor is defined*/
14✔
5421
                prevar=++s;
14✔
5422

5423
                if ( chartype[*s] == 0 )for(;*s != '"'; s++)switch(chartype[*s]){
42✔
5424
                        case 10:/*'\0' fits here*/
×
5425
                                MesPrint("@Can't finde closing \"");
×
NEW
5426
                                TERMINATE(-1);
×
5427
                        case 0:case 1: continue;
28✔
5428
                        default:
5429
                                break;
5430
                }
5431
                if(*s != '"'){
14✔
5432
                                MesPrint("@Illegal name of preprocessor variable to store external channel");
×
5433
                                return(-1);
×
5434
      }
5435
      *s='\0';
14✔
5436
                for(s++; *s == ' ' || *s == '\t'; s++);
28✔
5437
        }
5438

5439
        if(*s == '\0'){
14✔
5440
                MesPrint("@Illegal external command");
×
5441
                return(-1);
×
5442
        }
5443
        /*here s is a command*/
5444
   /*See the file extcmd.c*/
5445
        /*[08may2006 mt]:*/
5446
        externalD=openExternalChannel(
14✔
5447
                                s,
5448
                                 AX.daemonize,
5449
                                AX.shellname,
5450
                                AX.stderrname);
5451
        /*:[08may2006 mt]*/
5452
        if(externalD<1){/*error?*/
14✔
5453
                /*Not quite correct - terminate the program on error:*/
5454
                Error1("Can't start external program",s);
×
5455
                return(-1);
×
5456
        }
5457
   /*Now external command runs.*/
5458
   
5459
   if(prevar){/*Store the external channel descriptor in the provided variable:*/
14✔
5460
                UBYTE buf[21];/* 64/Log_2[10] = 19.3, so this is enough forever...*/
14✔
5461
                NumToStr(buf,externalD);
14✔
5462
                if ( PutPreVar(prevar,buf,0,1) < 0 ) return(-1);
14✔
5463
        }
5464

5465
        AX.currentExternalChannel=externalD;
14✔
5466
        /*[08may2006 mt]:*/
5467
        if(AX.currentPrompt!=0){/*Change default terminator*/
14✔
5468
                if(setTerminatorForExternalChannel(  (char *)AX.currentPrompt)){
×
5469
                        MesPrint("@Prompt is too long");
×
5470
                        return(-1);
×
5471
                }
5472
        }
5473
        setKillModeForExternalChannel(AX.killSignal,AX.killWholeGroup);
14✔
5474
        /*:[08may2006 mt]*/
5475
        return(0);
14✔
5476
#else /*ifdef WITHEXTERNALCHANNEL*/
5477
        Error0("External channel: not implemented on this computer/system");
5478
        return(-1);
5479
#endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5480
}
5481

5482
/*
5483
                 #] DoExternal: 
5484
                 #[ DoPrompt:
5485
                        #prompt string
5486
*/
5487

5488
int DoPrompt(UBYTE *s)
14✔
5489
{
5490
#ifndef WITHEXTERNALCHANNEL
5491
        DUMMYUSE(s);
5492
#endif
5493
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
14✔
5494
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
14✔
5495

5496
#ifdef WITHEXTERNALCHANNEL
5497
        while ( *s == ' ' || *s == '\t' ) s++;
14✔
5498
        if ( AX.currentPrompt )
14✔
5499
                        M_free(AX.currentPrompt,"external channel prompt");
7✔
5500
        if ( *s == '\0' )
14✔
5501
                AX.currentPrompt = (UBYTE *)strDup1((UBYTE *)"","external channel prompt");
7✔
5502
        else
5503
                AX.currentPrompt = strDup1(s,"external channel prompt");
7✔
5504
        if(  setTerminatorForExternalChannel( (char *)AX.currentPrompt) > 0  ){
14✔
5505
                MesPrint("@Prompt is too long");
×
5506
                return(-1);
×
5507
        }
5508
        /*else: if 0, ok; if -1, there is no current channel-ok, just prompt is stored.*/
5509
        return(0);
5510
#else /*ifdef WITHEXTERNALCHANNEL*/
5511
        Error0("External channel: not implemented on this computer/system");
5512
        return(-1);
5513
#endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5514
}
5515
/*
5516
                 #] DoPrompt: 
5517
                 #[ DoSetExternal:
5518
                        #setexternal n
5519
*/
5520

5521
int DoSetExternal(UBYTE *s)
21✔
5522
{
5523
#ifdef WITHEXTERNALCHANNEL
5524
        int n=0;
21✔
5525
#else
5526
        DUMMYUSE(s);
5527
#endif
5528
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
21✔
5529
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
21✔
5530
        if ( AP.preError ) return(0);
21✔
5531

5532
#ifdef WITHEXTERNALCHANNEL
5533
        while ( *s == ' ' || *s == '\t' ) s++;
21✔
5534
        while ( chartype[*s] == 1 ) { n = 10*n + *s++ - '0'; }
42✔
5535
        while ( *s == ' ' || *s == '\t' ) s++;
21✔
5536
        if(*s!='\0'){
21✔
5537
                MesPrint("@setexternal: number expected");
×
5538
                return(-1);
×
5539
        }
5540
        if(selectExternalChannel(n)<0){
21✔
5541
                MesPrint("@setexternal: invalid number");
×
5542
                return(-1);
×
5543
        }
5544
        AX.currentExternalChannel=n;
21✔
5545
        return(0);
21✔
5546
#else /*ifdef WITHEXTERNALCHANNEL*/
5547
        Error0("External channel: not implemented on this computer/system");
5548
        return(-1);
5549
#endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5550
}
5551
/*
5552
                 #] DoSetExternal: 
5553
                 #[ DoSetExternalAttr:
5554
*/
5555

5556
static FORM_INLINE UBYTE *pickupword(UBYTE *s)
×
5557
{
5558

5559
        for(;*s>' ';s++)switch(*s){
×
5560
                case '=':
5561
                case ',':
5562
                case ';':
5563
                        return(s);
5564
        }/*for(;*s>' ';s++)switch(*s)*/
5565
        return(s);
5566
}
5567
/*Returns 0 if the first string (case insensitively) equal to
5568
  the beginning of the second string (of length n):
5569
*/
5570
static inline int strINCmp(UBYTE *a, UBYTE *b, int n)
×
5571
{
5572
        for(;n>0;n--)if(tolower(*a++)!=tolower(*b++))
×
5573
                return(1);
5574
        return(*a != '\0');
×
5575
}
5576

5577
#define KILL "kill"
5578
#define KILLALL "killall"
5579
#define DAEMON "daemon"
5580
#define SHELL "shell"
5581
#define STDERR "stderr"
5582

5583
#define TRUE_EXPR "true"
5584
#define FALSE_EXPR "false"
5585
#define NOSHELL "noshell"
5586
#define TERMINAL "terminal"
5587

5588
/*
5589
        Expects comma-separated list of pairs name=value
5590
*/
5591
int DoSetExternalAttr(UBYTE *s)
×
5592
{
5593
#ifdef WITHEXTERNALCHANNEL
5594
        int lnam,lval;
×
5595
        UBYTE *nam,*val;
×
5596
#else
5597
        DUMMYUSE(s);
5598
#endif
5599
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
5600
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
5601
        if ( AP.preError ) return(0);
×
5602

5603
#ifdef WITHEXTERNALCHANNEL
5604
        do{
5605
                /*Read the name:*/
5606
                while ( *s == ' ' || *s == '\t' ) s++;
×
5607
                s=pickupword(nam=s);
×
5608
                lnam=s-nam;
×
5609
                while ( *s == ' ' || *s == '\t' ) s++;
×
5610
                if(*s++!='='){
×
5611
                        MesPrint("@External channel:'=' expected instead of %s",s-1);
×
5612
                        return(-1);
×
5613
                }
5614
                /*Read the value:*/
5615
                while ( *s == ' ' || *s == '\t' ) s++;
×
5616
                val=s;
×
5617

5618
                for(;;){
×
5619
                        UBYTE *m;
×
5620
                        s=pickupword(s);
×
5621
                        m=s;
×
5622
                        while ( *s == ' ' || *s == '\t' ) s++;
×
5623
         if( (*s == ',')||(*s == '\n')||(*s == ';')||(*s == '\0') ){
×
5624
                                s=m;
×
5625
                                break;
×
5626
                        }
5627
                }/*for(;;)*/
5628

5629
                lval=s-val;
×
5630
                while ( *s == ' ' || *s == '\t' ) s++;
×
5631

5632
                if(strINCmp((UBYTE *)SHELL,nam,lnam)==0){
×
5633
                        if(AX.shellname!=NULL)
×
5634
                                M_free(AX.shellname,"external channel shellname");
×
5635
                        if(strINCmp((UBYTE *)NOSHELL,val,lval)==0)
×
5636
                                AX.shellname=NULL;
×
5637
                        else{
5638
                                UBYTE *ch,*b;
×
5639
                                b=ch=AX.shellname=Malloc1(lval+1,"external channel shellname");
×
5640
                                while(ch-b<lval)
×
5641
                                        *ch++=*val++;
×
5642
                                *ch='\0';
×
5643
                        }
5644
                }else if(strINCmp((UBYTE *)DAEMON,nam,lnam)==0){
×
5645
                        if(strINCmp((UBYTE *)TRUE_EXPR,val,lval)==0)
×
5646
                                AX.daemonize = 1;
×
5647
                        else if(strINCmp((UBYTE *)FALSE_EXPR,val,lval)==0)
×
5648
                                AX.daemonize = 0;
×
5649
                        else{
5650
                                MesPrint("@External channel:true or false expected for %s",DAEMON);
×
5651
                                return(-1);
×
5652
                        }
5653
                }else        if(strINCmp((UBYTE *)KILLALL,nam,lnam)==0){
×
5654
                        if(strINCmp((UBYTE *)TRUE_EXPR,val,lval)==0)
×
5655
                                AX.killWholeGroup = 1;
×
5656
                        else if(strINCmp((UBYTE *)FALSE_EXPR,val,lval)==0)
×
5657
                                AX.killWholeGroup = 0;
×
5658
                        else{
5659
                                MesPrint("@External channel: true or false expected for %s",KILLALL);
×
5660
                                return(-1);
×
5661
                        }
5662
                }else        if(strINCmp((UBYTE *)KILL,nam,lnam)==0){
×
5663
                        int i,n=0;
5664
                        for(i=0;i<lval;i++)
×
5665
                                if( *val>='0' && *val<= '9' )
×
5666
                                        n = 10*n + *val++  - '0';
×
5667
                                else{
5668
                                        MesPrint("@External channel: number expected for %s",KILL);
×
5669
                                        return(-1);
×
5670
                                }
5671
                                AX.killSignal=n;
×
5672
                }else        if(strINCmp((UBYTE *)STDERR,nam,lnam)==0){
×
5673
                        if( AX.stderrname != NULL ) {
×
5674
                                M_free(AX.stderrname,"external channel stderrname");
×
5675
                        }
5676
                        if(strINCmp((UBYTE *)TERMINAL,val,lval)==0)
×
5677
                                AX.stderrname = NULL;
×
5678
                        else{
5679
                                UBYTE *ch,*b;
×
5680
                                b=ch=AX.stderrname=Malloc1(lval+1,"external channel stderrname");
×
5681
                                while(ch-b<lval)
×
5682
                                        *ch++=*val++;
×
5683
                                *ch='\0';
×
5684
                        }
5685
                }else{
5686
                        nam[lnam+1]='\0';
×
5687
                        MesPrint("@External channel: unrecognized attribute",nam);
×
5688
                        return(-1);
×
5689
                }
5690
        }while(*s++ == ',');
×
5691
        if(  (*(s-1)>' ')&&(*(s-1)!=';')  ){
×
5692
                MesPrint("@External channel: syntax error: %s",s-1);
×
5693
                return(-1);
×
5694
        }
5695
   return(0);
5696
#else /*ifdef WITHEXTERNALCHANNEL*/
5697
        Error0("External channel: not implemented on this computer/system");
5698
        return(-1);
5699
#endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5700
}
5701
/*
5702
                 #] DoSetExternalAttr: 
5703
                 #[ DoRmExternal:
5704
                        #rmexternal [n] (if 0, close all)
5705
*/
5706

5707
int DoRmExternal(UBYTE *s)
14✔
5708
{
5709
#ifdef WITHEXTERNALCHANNEL
5710
        int n = -1;
14✔
5711
#else
5712
        DUMMYUSE(s);
5713
#endif
5714
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
14✔
5715
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
14✔
5716
        if ( AP.preError ) return(0);
14✔
5717

5718
#ifdef WITHEXTERNALCHANNEL
5719
        while ( *s == ' ' || *s == '\t' ) s++;
14✔
5720
        if( chartype[*s] == 1 ){
14✔
5721
                for(n=0; chartype[*s] == 1 ; s++) { n = 10*n + *s - '0'; }
28✔
5722
                while ( *s == ' ' || *s == '\t' ) s++;
14✔
5723
        }
5724
        if(*s!='\0'){
14✔
5725
                MesPrint("@rmexternal: invalid number");
×
5726
                return(-1);
×
5727
        }
5728
        switch(n){
14✔
5729
                case 0:/*Close all opened channels*/
×
5730
                        closeAllExternalChannels();
×
5731
                        AX.currentExternalChannel=0;
×
5732
                        /*Do not clean AX.currentPrompt!*/
5733
                        return(0);
×
5734
                case -1:/*number is not specified - try current*/
×
5735
                        n=AX.currentExternalChannel;
×
5736
                        /* fall through */
5737
                default:
14✔
5738
                        closeExternalChannel(n);/*No reaction for possible error*/
14✔
5739
        }
5740
        if (n == AX.currentExternalChannel)/*cleaned up by closeExternalChannel()*/
14✔
5741
                AX.currentExternalChannel=0;
7✔
5742
        return(0);
5743
#else /*ifdef WITHEXTERNALCHANNEL*/
5744
        Error0("External channel: not implemented on this computer/system");
5745
        return(-1);
5746
#endif /*ifdef WITHEXTERNALCHANNEL ... else*/
5747

5748
}
5749
/*
5750
                 #] DoRmExternal: 
5751
                 #[ DoFromExternal :
5752
                                #fromexternal 
5753
                                        is used to read the text from the running external
5754
                                        program, the syntax is similar to the #include
5755
                                        directive.
5756
                                #fromexternal "varname"
5757
                                        is used to read the text from the running external
5758
                                        program into the preprocessor variable varname.
5759
                                        directive.
5760
                                #fromexternal "varname" maxlength
5761
                                        is used to read the text from the running external
5762
                                        program into the preprocessor variable varname.
5763
                                        directive. Only first maxlength characters are 
5764
                                        stored.
5765

5766
                                        FORM continues to read the running external
5767
                                        program output until the external program outputs a
5768
                                        prompt.
5769

5770
*/
5771

5772
int DoFromExternal(UBYTE *s)
14✔
5773
{
5774
#ifdef WITHEXTERNALCHANNEL
5775
        UBYTE *prevar=0; 
14✔
5776
        int lbuf=-1;
14✔
5777
        int withNoList=AC.NoShowInput;
14✔
5778
        int oldpreassignflag;
14✔
5779
#else
5780
        DUMMYUSE(s);
5781
#endif
5782
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
14✔
5783
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
14✔
5784
        if ( AP.preError ) return(0);
14✔
5785
#ifdef WITHEXTERNALCHANNEL
5786
        
5787
        FLUSHCONSOLE;
14✔
5788

5789
        while ( *s == ' ' || *s == '\t' ) s++;
14✔
5790
        /*[17may2006 mt]:*/
5791
        if ( *s == '-' || *s == '+' ) {
14✔
5792
                if ( *s == '-' )
×
5793
                        withNoList = 1;
5794
                else
5795
                        withNoList = 0;
×
5796
                s++;
×
5797
                while ( *s == ' ' || *s == '\t' ) s++;
×
5798
        }/*if ( *s == '-' || *s == '+' )*/
5799
        /*:[17may2006 mt]*/
5800
        /*[02feb2006 mt]:*/
5801
        if(*s == '"'){/*prevar to store the output is defined*/
14✔
5802
                prevar=++s;
×
5803

5804
                if ( *s=='$' || chartype[*s] == 0 )for(;*s != '"'; s++)switch(chartype[*s]){
×
5805
                        case 10:/*'\0' fits here*/
×
5806
                                MesPrint("@Can't finde closing \"");
×
NEW
5807
                                TERMINATE(-1);
×
5808
                        case 0:case 1: continue;
×
5809
                        default:
5810
                                break;
5811
                }
5812
                if(*s != '"'){
×
5813
                                MesPrint("@Illegal name to store output of external channel");
×
5814
                                return(-1);
×
5815
      }
5816
      *s='\0';
×
5817
                for(s++; *s == ' ' || *s == '\t'; s++);
×
5818
        }/*if(*s == '"')*/
5819

5820
        if(*s != '\0'){
14✔
5821
                if( chartype[*s] == 1 ){
×
5822
                        for(lbuf=0; chartype[*s] == 1 ; s++) { lbuf = 10*lbuf + *s - '0'; }
×
5823
                        while ( *s == ' ' || *s == '\t' ) s++;
×
5824
                }
5825
                if( (*s!='\0')||(lbuf<0) ){
×
5826
                        MesPrint("@Illegal buffer length in fromexternal");
×
5827
                        return(-1);
×
5828
                }
5829
        }/*if(*s != '\0')*/
5830
        /*:[02feb20006 mt]*/
5831
        if(getCurrentExternalChannel()!=AX.currentExternalChannel)
14✔
5832
                /*[08may20006 mt]:*/
5833
                /*selectExternalChannel(AX.currentExternalChannel);*/
5834
                if(selectExternalChannel(AX.currentExternalChannel)){
×
5835
                        MesPrint("@No current external channel");
×
5836
                        return(-1);
×
5837
                }
5838
                /*:[08may20006 mt]*/
5839

5840
        /*[02feb2006 mt]:*/
5841
        if(prevar!=0){/*The result must be stored into preprovar*/
14✔
5842
      UBYTE *buf;
×
5843
                int cc = 0;
×
5844
                if(lbuf == -1){/*Unlimited buffer, everything must be stored*/
×
5845
                        int i;
×
5846
                        buf=Malloc1( (lbuf=255)+1,"Fromexternal");
×
5847
                        /*[18may20006 mt]:*/
5848
                        /*for(i=0;(cc=getcFromExtChannel())!=EOF;i++){*/
5849
                        /* May 2006: now getcFromExtChannelOk returns EOF while 
5850
                                getcFromExtChannelFailure returns -2 (see comments in 
5851
                                exctcmd.c):*/
5852
                        for(i=0;(cc=getcFromExtChannel())>0;i++){
×
5853
                        /*:[18may20006 mt]*/
5854
                                if(i==lbuf){
×
5855
                                        int j;
×
5856
                                        UBYTE *tmp=Malloc1( (lbuf*=2)+1,"Fromexternal");
×
5857
                                        for(j=0;j<i;j++)tmp[j]=buf[j];
×
5858
                                        M_free(buf,"Fromexternal");
×
5859
                                        buf=tmp;
×
5860
                                }
5861
                                buf[i]=(UBYTE)(cc);
×
5862
                        }/*for(i=0;(cc=getcFromExtChannel())>0;i++)*/
5863
                        /*[18may20006 mt]:*/
5864
         if(cc == -2){
×
5865
                                MesPrint("@No current external channel");
×
5866
                                return(-1);
×
5867
                        }
5868
                        lbuf=i;
×
5869
                        /*:[18may20006 mt]*/
5870
                        buf[i]='\0';
×
5871
                }else{/*Fixed buffer, only lbuf chars must be stored*/
5872
                        int i;
×
5873
                        buf=Malloc1(lbuf+1,"Fromexternal");
×
5874
                        for(i=0; i<lbuf;i++){
×
5875
                        /*[18may20006 mt]:*/
5876
                                /*if( (cc=getcFromExtChannel())==EOF )*/
5877
                                /* May 2006: now getcFromExtChannelOk returns EOF while 
5878
                                        getcFromExtChannelFailure returns -2 (see comments in 
5879
                                        exctcmd.c):*/
5880
                                if( (cc=getcFromExtChannel())<1 )
×
5881
                        /*:[18may20006 mt]*/
5882
                                        break;
5883
                                buf[i]=(UBYTE)(cc);
×
5884
                        }
5885
                        buf[i]='\0';
×
5886
                        /*[18may20006 mt]:*/
5887
                        /*if(cc!=EOF)
5888
                                while(getcFromExtChannel()!=EOF);*//*Eat the rest*/
5889
                        /* May 2006: now getcFromExtChannelOk returns EOF while 
5890
                                getcFromExtChannelFailure returns -2 (see comments in 
5891
                                exctcmd.c):*/
5892
                        if(cc>0)
×
5893
                                while(getcFromExtChannel()>0);/*Eat the rest*/
×
5894
                        else if(cc == -2){
×
5895
                                MesPrint("@No current external channel");
×
5896
                                return(-1);
×
5897
                        }
5898
                        /*:[18may20006 mt]*/
5899
                }
5900
                /*[18may20006 mt]:*/
5901
                if(*prevar == '$'){/*Put the answer to the dollar variable*/
×
5902
                        int oldNumPotModdollars = NumPotModdollars;
×
5903
#ifdef WITHMPI
5904
                        WORD oldRhsExprInModuleFlag = AC.RhsExprInModuleFlag;
5905
                        AC.RhsExprInModuleFlag = 0;
5906
#endif
5907
                        /*Here lbuf is the actual length of buf!*/
5908
                        /*"prevar=buf'\0'":*/
5909
                        UBYTE *pbuf=Malloc1(StrLen(prevar)+1+lbuf+1,"Fromexternal to dollar");
×
5910
                        UBYTE *c=pbuf;
×
5911
                        UBYTE *b=prevar;
×
5912
                        while(*b!='\0'){*c++ = *b++;}
×
5913
                        *c++='=';
×
5914
                        b=buf;
×
5915
                        while(  (*c++=*b++)!='\0'  );
×
5916
                        oldpreassignflag = AP.PreAssignFlag;
×
5917
                        AP.PreAssignFlag = 1;
×
5918
                        if ( ( cc = CompileStatement(pbuf) ) || ( cc = CatchDollar(0) ) ) {
×
5919
                                Error1("External channel: can't asign output to dollar variable ",prevar);
×
5920
                        }
5921
                        AP.PreAssignFlag = oldpreassignflag;
×
5922
                        NumPotModdollars = oldNumPotModdollars;
×
5923
#ifdef WITHMPI
5924
                        AC.RhsExprInModuleFlag = oldRhsExprInModuleFlag;
5925
#endif
5926
                        M_free(pbuf,"Fromexternal to dollar");
×
5927
                }else{
5928
                        cc = PutPreVar(prevar, buf, 0, 1) < 0;
×
5929
                }
5930
                /*:[18may20006 mt]*/
5931
                M_free(buf,"Fromexternal");
×
5932
                if ( cc ) return(-1);
×
5933
                return(0);
×
5934
        }
5935
        /*:[02feb2006 mt]*/
5936
        if ( OpenStream(s,EXTERNALCHANNELSTREAM,0,PRENOACTION) == 0 ) return(-1);
14✔
5937
        /*[17may2006 mt]:*/
5938
        AC.NoShowInput = withNoList;
14✔
5939
        /*:[17may2006 mt]*/
5940
        return(0);
14✔
5941
#else
5942
        Error0("External channel: not implemented on this computer/system");
5943
        return(-1);
5944
#endif
5945
}
5946

5947
/*
5948
                 #] DoFromExternal : 
5949
                 #[ DoToExternal :
5950
                        #toexetrnal
5951
*/
5952

5953
#ifdef WITHEXTERNALCHANNEL
5954

5955
/*A wrapper to writeBufToExtChannel, see the file extcmd.c:*/
5956
LONG WriteToExternalChannel(int handle, UBYTE *buffer, LONG size)
28✔
5957
{
5958
        /*ATT! handle is not used! Actual output is performed to
5959
                 the current external channel, see extcmd.c!*/
5960
        DUMMYUSE(handle);
28✔
5961
        if(writeBufToExtChannel((char*)buffer,size))
28✔
5962
                return(-1);
×
5963
        return(size);
5964
}
5965
#endif /*ifdef WITHEXTERNALCHANNEL*/
5966

5967
int DoToExternal(UBYTE *s)
14✔
5968
{
5969
#ifdef WITHEXTERNALCHANNEL
5970
   HANDLERS h;
14✔
5971
   LONG        (*OldWrite)(int handle, UBYTE *buffer, LONG size) = WriteFile;
14✔
5972
        int ret=-1;
14✔
5973
#else
5974
        DUMMYUSE(s);
5975
#endif
5976
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
14✔
5977
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
14✔
5978
        if ( AP.preError ) return(0);
14✔
5979
#ifdef WITHEXTERNALCHANNEL
5980

5981
        h.oldsilent=AM.silent;
14✔
5982
        h.newlogonly = h.oldlogonly = AM.FileOnlyFlag;
14✔
5983
        h.newhandle = h.oldhandle = AC.LogHandle;
14✔
5984
        h.oldprinttype = AO.PrintType;
14✔
5985

5986
        WriteFile=&WriteToExternalChannel;
14✔
5987

5988
        while ( *s == ' ' || *s == '\t' ) s++;
14✔
5989

5990
        if(AX.currentExternalChannel==0){
14✔
5991
                MesPrint("@No current external channel");
×
5992
                goto DoToExternalReady;
×
5993
        }
5994

5995
        if(getCurrentExternalChannel()!=AX.currentExternalChannel)
14✔
5996
                selectExternalChannel(AX.currentExternalChannel);
×
5997

5998
        ret=writeToChannel(EXTERNALCHANNELOUT,s,&h);
14✔
5999
        DoToExternalReady:
14✔
6000
                WriteFile=OldWrite;
14✔
6001
                return(ret);
14✔
6002
#else /*ifdef WITHEXTERNALCHANNEL*/
6003
        Error0("External channel: not implemented on this computer/system");
6004
        return(-1);
6005
#endif /*ifdef WITHEXTERNALCHANNEL ... else*/
6006

6007
}
6008

6009
/*
6010
                 #] DoToExternal : 
6011
                 #[ defineChannel :
6012
*/
6013
 
6014
UBYTE *defineChannel(UBYTE *s, HANDLERS *h)
268✔
6015
{
6016
        UBYTE *name,*to;
268✔
6017

6018
        if ( *s != '<' )
268✔
6019
                return(s);
6020

6021
        s++;
136✔
6022
        name = to = s;
136✔
6023
        while ( *s && *s != '>' ) {
740✔
6024
                if ( *s == '\\' ) s++;
604✔
6025
                *to++ = *s++;
604✔
6026
        }
6027
        if ( *s == 0 ) {
136✔
6028
                MesPrint("@Improper termination of filename");
×
6029
                return(0);
×
6030
        }
6031
        s++;
136✔
6032
        *to = 0;
136✔
6033
        if ( *name ) {
136✔
6034
                h->newhandle = GetChannel((char *)name,0);
116✔
6035
                h->newlogonly = 1;
116✔
6036
        }
6037
        else if ( AC.LogHandle >= 0 ) {
20✔
6038
                h->newhandle = AC.LogHandle;
×
6039
                h->newlogonly = 1;
×
6040
        }
6041
        return(s);        
6042
}
6043

6044
/*
6045
                 #] defineChannel : 
6046
                 #[ writeToChannel :
6047
*/
6048
 
6049
int writeToChannel(int wtype, UBYTE *s, HANDLERS *h)
282✔
6050
{
6051
        UBYTE *to, *fstring, *ss, *sss, *s1, c, c1;
282✔
6052
        WORD  num, number, nfac;
282✔
6053
        WORD oldOptimizationLevel;
282✔
6054
        UBYTE Out[MAXLINELENGTH+14], *stopper;
282✔
6055
        int nosemi, i;
282✔
6056
        int plus = 0;
282✔
6057

6058
/*
6059
        Now determine the format string
6060
*/
6061
        while ( *s == ',' || *s == ' ' ) s++;
418✔
6062
        if ( *s != '"' ) {
282✔
6063
                MesPrint("@No format string present");
×
6064
                return(-1);
×
6065
        }
6066
        s++; fstring = to = s;
282✔
6067
        while ( *s ) {
4,271✔
6068
                if ( *s == '\\' ) {
4,271✔
6069
                        s++;
40✔
6070
                        if ( *s == '\\' ) {
40✔
6071
                                *to++ = *s++;
8✔
6072
                                if ( *s == '\\' ) *to++ = *s++;
8✔
6073
                        }
6074
                        else if ( *s == '"' ) *to++ = *s++;
32✔
6075
                        else { *to++ = '\\'; *to++ = *s++; }
32✔
6076
                }
6077
                else if ( *s == '"' ) break;
4,231✔
6078
                else *to++ = *s++;
3,949✔
6079
        }
6080
        if ( *s != '"' ) {
282✔
6081
                MesPrint("@No closing \" in format string");
×
6082
                return(-1);
×
6083
        }
6084
        *to = 0; s++;
282✔
6085
        if ( AC.LineLength > 20 && AC.LineLength <= MAXLINELENGTH ) stopper = Out + AC.LineLength;
282✔
6086
        else stopper = Out + MAXLINELENGTH;
6087
        to = Out;
282✔
6088
/*
6089
        s points now at the list of objects (if any)
6090
        we can start executing the format string.
6091
*/
6092
        AM.silent = 0;
282✔
6093
        AC.LogHandle = h->newhandle;
282✔
6094
        AM.FileOnlyFlag = h->newlogonly;
282✔
6095
        if ( h->newhandle >= 0 ) {
282✔
6096
                AO.PrintType |= PRINTLFILE;
116✔
6097
        }
6098
        while ( *fstring ) {
4,119✔
6099
                if ( to >= stopper ) {
3,837✔
6100
                        if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
×
6101
                                *to++ = '&';
×
6102
                        }
6103
                        num = to - Out;
×
6104
                        WriteString(wtype,Out,num);
×
6105
                        to = Out;
×
6106
                        if ( AC.OutputMode == FORTRANMODE
×
6107
                         || AC.OutputMode == PFORTRANMODE ) {
×
6108
                                number = 7;
×
6109
                                for ( i = 0; i < number; i++ ) *to++ = ' ';
×
6110
                                to[-2] = '&';
×
6111
                        }
6112
                }
6113
                if ( *fstring == '\\' ) {
3,837✔
6114
                        fstring++;
40✔
6115
                        if ( *fstring == 'n' ) {
40✔
6116
                                num = to - Out;
40✔
6117
                                WriteString(wtype,Out,num);
40✔
6118
                                to = Out;
40✔
6119
                                fstring++;
40✔
6120
                        }
6121
                        else if ( *fstring == 't' ) { *to++ = '\t'; fstring++; }
×
6122
                        else if ( *fstring == 'b' ) { *to++ = '\\'; fstring++; }
×
6123
                        else *to++ = *fstring++;
×
6124
                }
6125
                else if ( *fstring == '%' ) {
3,797✔
6126
                        plus = 0;
6127
retry:
192✔
6128
                        fstring++;
192✔
6129
                        if ( *fstring == 'd' ) {
192✔
6130
                                int sign,dig;
6131
                                number = -1;
×
6132
donumber:
×
6133
                                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
6134
                                sign = 1;
6135
                                while ( *s == '+' || *s == '-' ) {
×
6136
                                        if ( *s == '-' ) sign = -sign;
×
6137
                                        s++;
×
6138
                                }
6139
                                dig = 0; ss = s; if ( sign < 0 ) { ss--; *ss = '-'; dig++; }
×
6140
                                while ( *s >= '0' && *s <= '9' ) { s++; dig++; }
×
6141
                                if ( number < 0 ) {
×
6142
                                        while ( ss < s ) {
×
6143
                                                if ( to >= stopper ) {
×
6144
                                                        num = to - Out;
×
6145
                                                        WriteString(wtype,Out,num);
×
6146
                                                        to = Out;
×
6147
                                                }
6148
                                                if ( *ss == '\\' ) ss++;
×
6149
                                                *to++ = *ss++;
×
6150
                                        }
6151
                                }
6152
                                else {
6153
                                        if ( number < dig ) { dig = number; ss = s - dig; }
×
6154
                                        while ( number > dig ) {
×
6155
                                                if ( to >= stopper ) {
×
6156
                                                        num = to - Out;
×
6157
                                                        WriteString(wtype,Out,num);
×
6158
                                                        to = Out;
×
6159
                                                }
6160
                                                *to++ = ' '; number--;
×
6161
                                        }
6162
                                        while ( ss < s ) {
×
6163
                                                if ( to >= stopper ) {
×
6164
                                                        num = to - Out;
×
6165
                                                        WriteString(wtype,Out,num);
×
6166
                                                        to = Out;
×
6167
                                                }
6168
                                                if ( *ss == '\\' ) ss++;
×
6169
                                                *to++ = *ss++;
×
6170
                                        }
6171
                                }
6172
                                fstring++;
×
6173
                        }
6174
                        else if ( *fstring == '$' ) {
192✔
6175
                                UBYTE *dolalloc;
64✔
6176
                                number = AO.OutSkip;
64✔
6177
dodollar:
64✔
6178
                                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
176✔
6179
                                if ( AC.OutputMode == FORTRANMODE
64✔
6180
                                 || AC.OutputMode == PFORTRANMODE ) {
64✔
6181
                                        number = 7;
×
6182
                                }
6183
                                if ( *s != '$' ) {
64✔
6184
nodollar:                        MesPrint("@$-variable expected in #write instruction");
×
6185
                                        AM.FileOnlyFlag = h->oldlogonly;
×
6186
                                        AC.LogHandle = h->oldhandle;
×
6187
                                        AO.PrintType = h->oldprinttype;
×
6188
                                        AM.silent = h->oldsilent;
×
6189
                                        return(-1);
×
6190
                                }
6191
                                s++; ss = s;
64✔
6192
                                while ( chartype[*s] <= 1 ) s++;
140✔
6193
                                if ( s == ss ) goto nodollar;
64✔
6194
                                c = *s; *s = 0;
64✔
6195
                                num = GetDollar(ss);
64✔
6196
                                if ( num < 0 ) {
64✔
6197
                                        MesPrint("@#write instruction: $%s has not been defined",ss);
×
6198
                                        AM.FileOnlyFlag = h->oldlogonly;
×
6199
                                        AC.LogHandle = h->oldhandle;
×
6200
                                        AO.PrintType = h->oldprinttype;
×
6201
                                        AM.silent = h->oldsilent;
×
6202
                                        return(-1);
×
6203
                                }
6204
                                *s = c;
64✔
6205
                                if ( *s == '[' ) {
64✔
6206
                                        if ( Dollars[num].nfactors <= 0 ) {
48✔
6207
                                                *s = 0;
×
6208
                                                MesPrint("@#write instruction: $%s has not been factorized",ss);
×
6209
                                                AM.FileOnlyFlag = h->oldlogonly;
×
6210
                                                AC.LogHandle = h->oldhandle;
×
6211
                                                AO.PrintType = h->oldprinttype;
×
6212
                                                AM.silent = h->oldsilent;
×
6213
                                                return(-1);
×
6214
                                        }
6215
/*
6216
                                        Now get the number between the []
6217
*/
6218
                                        nfac = GetDollarNumber(&s,Dollars+num);
48✔
6219

6220
                                        if ( Dollars[num].nfactors == 1 && nfac == 1 ) goto writewhole;
48✔
6221

6222
                                        if ( ( dolalloc = WriteDollarFactorToBuffer(num,nfac,0) ) == 0 ) {
48✔
6223
                                                AM.FileOnlyFlag = h->oldlogonly;
×
6224
                                                AC.LogHandle = h->oldhandle;
×
6225
                                                AO.PrintType = h->oldprinttype;
×
6226
                                                AM.silent = h->oldsilent;
×
6227
                                                return(-1);
×
6228
                                        }
6229
                                        goto writealloc;
48✔
6230
                                }
6231
                                else if ( *s && *s != ' ' && *s != ',' && *s != '\t' ) {
16✔
6232
                                        MesPrint("@#write instruction: illegal characters after $-variable");
×
6233
                                        AM.FileOnlyFlag = h->oldlogonly;
×
6234
                                        AC.LogHandle = h->oldhandle;
×
6235
                                        AO.PrintType = h->oldprinttype;
×
6236
                                        AM.silent = h->oldsilent;
×
6237
                                        return(-1);
×
6238
                                }
6239
                                else {
6240
writewhole:
16✔
6241
                                  if ( ( dolalloc = WriteDollarToBuffer(num,0) ) == 0 ) {
16✔
6242
                                        AM.FileOnlyFlag = h->oldlogonly;
×
6243
                                        AC.LogHandle = h->oldhandle;
×
6244
                                        AO.PrintType = h->oldprinttype;
×
6245
                                        AM.silent = h->oldsilent;
×
6246
                                        return(-1);
×
6247
                                  }
6248
                                  else {
6249
writealloc:
16✔
6250
                                        ss = dolalloc;
64✔
6251
                                        while ( *ss ) {
408✔
6252
                                                if ( to >= stopper ) {
344✔
6253
                                                        if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
×
6254
                                                                *to++ = '&';
×
6255
                                                        }
6256
                                                        num = to - Out;
×
6257
                                                        WriteString(wtype,Out,num);
×
6258
                                                        to = Out;
×
6259
                                                        for ( i = 0; i < number; i++ ) *to++ = ' ';
×
6260
                                                        if ( AC.OutputMode == FORTRANMODE
×
6261
                                                         || AC.OutputMode == PFORTRANMODE ) to[-2] = '&';
×
6262
                                                }
6263
                                                if ( chartype[*ss] > 3 ) { *to++ = *ss++; }
344✔
6264
                                                else {
6265
                                                        sss = ss; while ( chartype[*ss] <= 3 ) ss++;
404✔
6266
                                                        if ( ( to + (ss-sss) ) >= stopper ) {
184✔
6267
                                                                if ( (ss-sss) >= (stopper-Out) ) {
×
6268
                                                                        if ( ( to - stopper ) < 10 ) {
×
6269
                                                                                if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
×
6270
                                                                                        *to++ = '&';
×
6271
                                                                                }
6272
                                                                                num = to - Out;
×
6273
                                                                                WriteString(wtype,Out,num);
×
6274
                                                                                to = Out;
×
6275
                                                                                for ( i = 0; i < number; i++ ) *to++ = ' ';
×
6276
                                                                                if ( AC.OutputMode == FORTRANMODE
×
6277
                                                                                 || AC.OutputMode == PFORTRANMODE ) to[-2] = '&';
×
6278
                                                                        }
6279
                                                                        while ( (ss-sss) >= (stopper-Out) ) {
×
6280
                                                                                while ( to < stopper-1 ) {
×
6281
                                                                                        *to++ = *sss++;
×
6282
                                                                                }
6283
                                                                                if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
×
6284
                                                                                        *to++ = '&';
×
6285
                                                                                }
6286
                                                                                else {
6287
                                                                                        *to++ = '\\';
×
6288
                                                                                }
6289
                                                                                num = to - Out;
×
6290
                                                                                WriteString(wtype,Out,num);
×
6291
                                                                                to = Out;
×
6292
                                                                                if ( AC.OutputMode == FORTRANMODE
×
6293
                                                                                 || AC.OutputMode == PFORTRANMODE ) {
×
6294
                                                                                        for ( i = 0; i < number; i++ ) *to++ = ' ';
×
6295
                                                                                        to[-2] = '&';
×
6296
                                                                                }
6297
                                                                        }
6298
                                                                }
6299
                                                                else {
6300
                                                                        if ( AC.OutputMode == FORTRANMODE && AC.IsFortran90 == ISFORTRAN90 ) {
×
6301
                                                                                *to++ = '&';
×
6302
                                                                        }
6303
                                                                        num = to - Out;
×
6304
                                                                        WriteString(wtype,Out,num);
×
6305
                                                                        to = Out;
×
6306
                                                                        for ( i = 0; i < number; i++ ) *to++ = ' ';
×
6307
                                                                        if ( AC.OutputMode == FORTRANMODE
×
6308
                                                                         || AC.OutputMode == PFORTRANMODE ) to[-2] = '&';
×
6309
                                                                }
6310
                                                        }
6311
                                                        while ( sss < ss ) *to++ = *sss++;
404✔
6312
                                                }
6313
                                        }
6314
                                  }
6315
                                  M_free(dolalloc,"written dollar");
64✔
6316
                                  fstring++;
64✔
6317
                                }
6318
                        }
6319
                        else if ( *fstring == 's' ) {
128✔
6320
                                fstring++;
4✔
6321
                                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
8✔
6322
                                if ( *s == '"' ) {
4✔
6323
                                        s++; ss = s;
4✔
6324
                                        while ( *s ) {
36✔
6325
                                                if ( *s == '\\' ) s++;
36✔
6326
                                                else if ( *s == '"' ) break;
36✔
6327
                                                s++;
32✔
6328
                                        }
6329
                                        if ( *s == 0 ) {
4✔
6330
                                                MesPrint("@#write instruction: Missing \" in string");
×
6331
                                                AM.FileOnlyFlag = h->oldlogonly;
×
6332
                                                AC.LogHandle = h->oldhandle;
×
6333
                                                AO.PrintType = h->oldprinttype;
×
6334
                                                AM.silent = h->oldsilent;
×
6335
                                                return(-1);
×
6336
                                        }
6337
                                        while ( ss < s ) {
36✔
6338
                                                if ( to >= stopper ) {
32✔
6339
                                                        num = to - Out;
×
6340
                                                        WriteString(wtype,Out,num);
×
6341
                                                        to = Out;
×
6342
                                                }
6343
                                                if ( *ss == '\\' ) ss++;
32✔
6344
                                                *to++ = *ss++;
32✔
6345
                                        }
6346
                                        s++;
4✔
6347
                                }
6348
                                else {
6349
                                        sss = ss = s;
×
6350
                                        while ( *s && *s != ',' ) {
×
6351
                                                if ( *s == '\\' ) { s++; sss = s+1; }
×
6352
                                                s++;
×
6353
                                        }
6354
                                        while ( s > sss+1 && ( s[-1] == ' ' || s[-1] == '\t' ) ) s--;
×
6355
                                        while ( ss < s ) {
×
6356
                                                if ( to >= stopper ) {
×
6357
                                                        num = to - Out;
×
6358
                                                        WriteString(wtype,Out,num);
×
6359
                                                        to = Out;
×
6360
                                                }
6361
                                                if ( *ss == '\\' ) ss++;
×
6362
                                                *to++ = *ss++;
×
6363
                                        }
6364
                                }
6365
                        }
6366
                        else if ( *fstring == 'X' ) {
124✔
6367
                                fstring++;
4✔
6368
                                if ( cbuf[AM.sbufnum].numrhs > 0 ) {
4✔
6369
/*
6370
                                        This should be only to the value of AM.oldnumextrasymbols
6371
*/
6372
                                        UBYTE *s = GetPreVar(AM.oldnumextrasymbols,0);
4✔
6373
                                        WORD x = 0;
4✔
6374
                                        while ( *s >= '0' && *s <= '9' ) x = 10*x + *s++ - '0';
8✔
6375
                                        if ( x > 0 )
4✔
6376
                                                PrintSubtermList(1,x);
4✔
6377
                                        else
6378
                                                PrintSubtermList(1,cbuf[AM.sbufnum].numrhs);
×
6379
                                }
6380
                        }
6381
                        else if ( *fstring == 'O' ) {
120✔
6382
                                number = AO.OutSkip;
8✔
6383
dooptim:
8✔
6384
                                fstring++;
8✔
6385
/*
6386
                                First test whether there is an optimization buffer
6387
*/
6388
                                if ( AO.OptimizeResult.code == NULL && AO.OptimizationLevel != 0 ) {
8✔
6389
                                        MesPrint("@In #write instruction: no optimization results available!");
×
6390
                                        return(-1);
×
6391
                                }
6392
                                num = to - Out;
8✔
6393
                                WriteString(wtype,Out,num);
8✔
6394
                                to = Out;
8✔
6395
                                if ( AO.OptimizationLevel != 0 ) {
8✔
6396
                                        WORD oldoutskip = AO.OutSkip;
8✔
6397
                                        AO.OutSkip = number;
8✔
6398
                                        optimize_print_code(0);
8✔
6399
                                        AO.OutSkip = oldoutskip;
8✔
6400
                                }
6401
                        }
6402
                        else if ( *fstring == 'e' || *fstring == 'E' ) {
112✔
6403
                                if ( *fstring == 'E'
64✔
6404
                                        || AC.OutputMode == FORTRANMODE
20✔
6405
                                        || AC.OutputMode == PFORTRANMODE ) nosemi = 1;
8✔
6406
                                else nosemi = 0;
8✔
6407
                                fstring++;
64✔
6408
                                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
172✔
6409
                                if ( chartype[*s] != 0 && *s != '[' ) {
64✔
6410
noexpr:                                MesPrint("@expression name expected in #write instruction");
×
6411
                                        AM.FileOnlyFlag = h->oldlogonly;
×
6412
                                        AC.LogHandle = h->oldhandle;
×
6413
                                        AO.PrintType = h->oldprinttype;
×
6414
                                        AM.silent = h->oldsilent;
×
6415
                                        return(-1);
×
6416
                                }
6417
                                ss = s;
64✔
6418
                                if ( ( s = SkipAName(ss) ) == 0 || s[-1] == '_' ) goto noexpr;
64✔
6419
                                s1 = s; c = c1 = *s1;
64✔
6420
                                if ( c1 == '(' ) {
64✔
6421
                                        SKIPBRA3(s)
16✔
6422
                                        if ( *s == ')' ) {
4✔
6423
                                                AO.CurBufWrt = s1+1;
4✔
6424
                                                c = *s; *s = 0;
4✔
6425
                                        }
6426
                                        else {
6427
                                                MesPrint("@Illegal () specifier in expression name in #write");
×
6428
                                                AM.FileOnlyFlag = h->oldlogonly;
×
6429
                                                AC.LogHandle = h->oldhandle;
×
6430
                                                AO.PrintType = h->oldprinttype;
×
6431
                                                AM.silent = h->oldsilent;
×
6432
                                                return(-1);
×
6433
                                        }
6434
                                }
6435
                                else AO.CurBufWrt = (UBYTE *)underscore;
60✔
6436
                                *s1 = 0;
64✔
6437
                                num = to - Out;
64✔
6438
                                if ( num > 0 ) WriteUnfinString(wtype,Out,num);
64✔
6439
                                to = Out;
64✔
6440
                                oldOptimizationLevel = AO.OptimizationLevel;
64✔
6441
                                AO.OptimizationLevel = 0;
64✔
6442
                                if ( WriteOne(ss,(int)num,nosemi,plus) < 0 ) {
64✔
6443
                                        AM.FileOnlyFlag = h->oldlogonly;
×
6444
                                        AC.LogHandle = h->oldhandle;
×
6445
                                        AO.PrintType = h->oldprinttype;
×
6446
                                        AM.silent = h->oldsilent;
×
6447
                                        return(-1);
×
6448
                                }
6449
                                AO.OptimizationLevel = oldOptimizationLevel;
64✔
6450
                                *s1 = c1;
64✔
6451
                                if ( s > s1 ) *s++ = c;
64✔
6452
                        }
6453
/*
6454
                        File content
6455
*/
6456
                        else if ( ( *fstring == 'f' ) || ( *fstring == 'F' ) ) {
48✔
6457
                                LONG n;
6458
                                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
6459
                                ss = s;
×
6460
                                while ( *s && *s != ',' ) {
×
6461
                                        if ( *s == '\\' ) s++;
×
6462
                                        s++;
×
6463
                                }
6464
                                c = *s; *s = 0;
×
6465
                                s1 = LoadInputFile(ss,HEADERFILE);
×
6466
                                *s = c;
×
6467
/*
6468
                                There should have been a way to pass the file size.
6469
                                Also there should be conversions for \r\n etc.
6470
*/
6471
                                if ( s1 ) {
×
6472
                                        ss = s1; while ( *ss ) ss++;
×
6473
                                        n = ss-s1;
×
6474
                                        WriteString(wtype,s1,n);
×
6475
                                        M_free(s1,"copy file");
×
6476
                                }
6477
                                else if ( *fstring == 'F' ) {
×
6478
                                        *s = 0;
×
6479
                                        MesPrint("@Error in #write: could not open file %s",ss);
×
6480
                                        *s = c;
×
6481
                                        goto ReturnWithError;
×
6482
                                }
6483
                                fstring++;
×
6484
                        }
6485
                        else if ( *fstring == '%' ) {
48✔
6486
                                *to++ = *fstring++;
×
6487
                        }
6488
                        else if ( FG.cTable[*fstring] == 1 ) {  /* %#S */
48✔
6489
                                number = 0;
6490
                                while ( FG.cTable[*fstring] == 1 ) {
×
6491
                                        number = 10*number + *fstring++ - '0';
×
6492
                                }
6493
                                if ( *fstring == 'O' ) goto dooptim;
×
6494
                                else if ( *fstring == 'd' ) goto donumber;
×
6495
                                else if ( *fstring == '$' ) goto dodollar;
×
6496
                                else if ( *fstring == 't' ) {        /* `tab' position */
×
6497
                                        if ( number < (WORD)(stopper-Out) ) {
×
6498
                                                while ( (WORD)(to-Out) < number ) *to++ = ' ';
×
6499
                                        }
6500
                                        fstring++;
×
6501
                                }
6502
                                else if ( *fstring == 'X' || *fstring == 'x' ) {
×
6503
                                        if ( number > 0 && number <= cbuf[AM.sbufnum].numrhs ) {
×
6504
                                                UBYTE buffer[80], *out, *old1, *old2, *old3;
×
6505
                                                WORD *term, first;
×
6506
                                                if ( *fstring == 'X' ) {
×
6507
                                                        out = StrCopy((UBYTE *)AC.extrasym,buffer);
×
6508
                                                        if ( AC.extrasymbols == 0 ) {
×
6509
                                                                out = NumCopy(number,out);
×
6510
                                                                out = StrCopy((UBYTE *)"_",out);
×
6511
                                                        }
6512
                                                        else if ( AC.extrasymbols == 1 ) {
×
6513
                                                                if ( AC.OutputMode == CMODE ) {
×
6514
                                                                        out = StrCopy((UBYTE *)"[",out);
×
6515
                                                                        out = NumCopy(number,out);
×
6516
                                                                        out = StrCopy((UBYTE *)"]",out);
×
6517
                                                                }
6518
                                                                else {
6519
                                                                        out = StrCopy((UBYTE *)"(",out);
×
6520
                                                                        out = NumCopy(number,out);
×
6521
                                                                        out = StrCopy((UBYTE *)")",out);
×
6522
                                                                }
6523
                                                        }
6524
                                                        out = StrCopy((UBYTE *)"=",out);
×
6525
                                                        ss = buffer;
×
6526
                                                        while ( ss < out ) {
×
6527
                                                                if ( to >= stopper ) {
×
6528
                                                                        num = to - Out;
×
6529
                                                                        WriteString(wtype,Out,num);
×
6530
                                                                        to = Out;
×
6531
                                                                }
6532
                                                                *to++ = *ss++;
×
6533
                                                        }
6534
                                                }
6535
                                                term = cbuf[AM.sbufnum].rhs[number];
×
6536
                                                first = 1;
×
6537
                                                if ( *term == 0 ) {
×
6538
                                                        *to++ = '0';
×
6539
                                                }
6540
                                                else {
6541
                                                        old1 = AO.OutFill;
×
6542
                                                        old2 = AO.OutputLine;
×
6543
                                                        old3 = AO.OutStop;
×
6544
                                                        AO.OutFill = to;
×
6545
                                                        AO.OutputLine = Out;
×
6546
                                                        AO.OutStop = Out + AC.LineLength;
×
6547
                                                        while ( *term ) {
×
NEW
6548
                                                                if ( WriteInnerTerm(term,first) ) TERMINATE(-1);
×
6549
                                                                term += *term;
×
6550
                                                                first = 0;
×
6551
                                                        }
6552
                                                        to = Out + (AO.OutFill-AO.OutputLine);
×
6553
                                                        AO.OutFill = old1;
×
6554
                                                        AO.OutputLine = old2;
×
6555
                                                        AO.OutStop = old3;
×
6556
                                                }
6557
                                        }
6558
                                        fstring++;
×
6559
                                }
6560
                                else {
6561
                                        goto IllegControlSequence;
×
6562
                                }
6563
                        }
6564
                        else if ( *fstring == '+' ) {
48✔
6565
                                plus = 1; goto retry;
×
6566
                        }
6567
                        else if ( *fstring == 0 ) {
48✔
6568
                                *to++ = 0;
48✔
6569
                        }
6570
                        else {
6571
IllegControlSequence:
×
6572
                                MesPrint("@Illegal control sequence in format string in #write instruction");
×
6573
ReturnWithError:
×
6574
                                AM.FileOnlyFlag = h->oldlogonly;
×
6575
                                AC.LogHandle = h->oldhandle;
×
6576
                                AO.PrintType = h->oldprinttype;
×
6577
                                AM.silent = h->oldsilent;
×
6578
                                return(-1);
×
6579
                        }
6580
                }
6581
                else {
6582
                        *to++ = *fstring++;
3,605✔
6583
                }
6584
        }
6585
/*
6586
        Now flush the output
6587
*/
6588
        num = to - Out;
282✔
6589
        /*[15apr2004 mt]:*/
6590
        if(wtype==EXTERNALCHANNELOUT){
282✔
6591
                if(num!=0)
14✔
6592
                        WriteUnfinString(wtype,Out,num);
×
6593
        }else
6594
        /*:[15apr2004 mt]*/
6595
        WriteString(wtype,Out,num);
268✔
6596
/*
6597
        and restore original parameters
6598
*/
6599
        AM.FileOnlyFlag = h->oldlogonly;
282✔
6600
        AC.LogHandle = h->oldhandle;
282✔
6601
        AO.PrintType = h->oldprinttype;
282✔
6602
        AM.silent = h->oldsilent;
282✔
6603
        return(0);
282✔
6604
}
6605

6606
/*
6607
                 #] writeToChannel : 
6608
                 #[ DoFactDollar :
6609

6610
                Executes the #factdollar $var
6611
                      instruction
6612
*/
6613

6614
int DoFactDollar(UBYTE *s)
59✔
6615
{
6616
        GETIDENTITY
18✔
6617
        WORD numdollar, *oldworkpointer;
59✔
6618

6619
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
59✔
6620
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
59✔
6621
        while ( *s == ' ' || *s == '\t' ) s++;
59✔
6622
        if ( *s == '$' ) {
59✔
6623
                if ( GetName(AC.dollarnames,s+1,&numdollar,NOAUTO) != CDOLLAR ) {
59✔
6624
                        MesPrint("@%s is undefined",s);
×
6625
                        return(-1);
×
6626
                }
6627
                s = SkipAName(s+1);
59✔
6628
                if ( *s != 0 ) {
59✔
6629
                        MesPrint("@#FactDollar should have a single $variable for its argument");
×
6630
                        return(-1);
×
6631
                }
6632
                NewSort(BHEAD0);
59✔
6633
                oldworkpointer = AT.WorkPointer;
59✔
6634
                if ( DollarFactorize(BHEAD numdollar) ) return(-1);
59✔
6635
                AT.WorkPointer = oldworkpointer;
59✔
6636
                LowerSortLevel();
59✔
6637
                return(0);
59✔
6638
        }
6639
        else if ( ParenthesesTest(s) ) return(-1);
×
6640
        else {
6641
                MesPrint("@#FactDollar should have a single $variable for its argument");
×
6642
                return -1;
×
6643
        }
6644
}
6645

6646
/*
6647
                 #] DoFactDollar : 
6648
                 #[ GetDollarNumber :
6649
*/
6650

6651
WORD GetDollarNumber(UBYTE **inp, DOLLARS d)
48✔
6652
{
6653
        UBYTE *s = *inp, c, *name;
48✔
6654
        WORD number, nfac, *w;
48✔
6655
        DOLLARS dd;
48✔
6656
        s++;
48✔
6657
        if ( *s == '$' ) {
48✔
6658
                s++; name = s;
×
6659
                while ( FG.cTable[*s] < 2 ) s++;
×
6660
                c = *s; *s = 0;
×
6661
                if ( GetName(AC.dollarnames,name,&number,NOAUTO) == NAMENOTFOUND ) {
×
6662
                        MesPrint("@dollar in #write should have been defined previously");
×
NEW
6663
                        TERMINATE(-1);
×
6664
                }
6665
                *s = c;
×
6666
                dd = Dollars + number;
×
6667
                if ( c == '[' ) {
×
6668
                        *inp = s;
×
6669
                        nfac = GetDollarNumber(inp,dd);
×
6670
                        s = *inp;
×
6671
                        if ( *s != ']' ) {
×
6672
                                MesPrint("@Illegal factor for dollar variable");
×
NEW
6673
                                TERMINATE(-1);
×
6674
                        }
6675
                        *inp = s+1;
×
6676
                        if ( nfac == 0 ) {
×
6677
                                if ( dd->nfactors > d->nfactors ) {
×
6678
TooBig:
×
6679
                                        MesPrint("@Factor number for dollar variable too large");
×
NEW
6680
                                        TERMINATE(-1);
×
6681
                                }
6682
                                return(dd->nfactors);
×
6683
                        }
6684
                        w = dd->factors[nfac-1].where;
×
6685
                        if ( w == 0 ) {
×
6686
                                if ( dd->factors[nfac-1].value > d->nfactors ||
×
6687
                                     dd->factors[nfac-1].value < 0 ) goto TooBig;
×
6688
                                return(dd->factors[nfac-1].value);
6689
                        }
6690
                        if ( *w == 4 && w[4] == 0 && w[3] == 3 && w[2] == 1
×
6691
                          && w[1] <= d->nfactors ) return(w[1]);
×
6692
                        if ( w[*w] == 0 && w[*w-1] == *w-1 ) goto TooBig;
×
6693
IllNum:
×
6694
                        MesPrint("@Illegal factor number for dollar variable");
×
NEW
6695
                        TERMINATE(-1);
×
6696
                }
6697
                else {        /* The dollar should be a number */
6698
                        if ( dd->type == DOLZERO ) {
×
6699
                                return(0);
6700
                        }
6701
                        else if ( dd->type == DOLTERMS || dd->type == DOLNUMBER ) {
×
6702
                                w = dd->where;
×
6703
                                if ( *w == 4 && w[4] == 0 && w[3] == 3 && w[2] == 1
×
6704
                                  && w[1] <= d->nfactors ) return(w[1]);
×
6705
                                if ( w[*w] == 0 && w[*w-1] == *w-1 ) goto TooBig;
×
6706
                                goto IllNum;
×
6707
                        }
6708
                        else goto IllNum;
×
6709
                }
6710
        }
6711
        else if ( FG.cTable[*s] == 1 ) {
48✔
6712
                WORD x = *s++ - '0';
48✔
6713
                while ( FG.cTable[*s] == 1 ) {
48✔
6714
                        x = 10*x + *s++ - '0';
×
6715
                        if ( x > d->nfactors ) {
×
6716
                                MesPrint("@Factor number %d for dollar variable too large",x);
×
6717
                                TERMINATE(-1);
48✔
6718
                        }
6719
                }
6720
                if ( *s != ']' ) {
48✔
6721
                        MesPrint("@Illegal factor number for dollar variable");
×
NEW
6722
                        TERMINATE(-1);
×
6723
                }
6724
                s++; *inp = s;
48✔
6725
                return(x);
48✔
6726
        }
6727
        else {
6728
                MesPrint("@Illegal factor indicator for dollar variable");
×
NEW
6729
                TERMINATE(-1);
×
6730
        }
6731
        return(-1);
6732
}
6733

6734
/*
6735
                 #] GetDollarNumber : 
6736
                 #[ DoSetRandom :
6737

6738
                Executes the #SetRandom number
6739
*/
6740

6741
int DoSetRandom(UBYTE *s)
×
6742
{
6743
        ULONG x;
×
6744
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
6745
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
6746
        while ( *s == ' ' || *s == '\t' ) s++;
×
6747
        x = 0;
6748
        while ( FG.cTable[*s] == 1 ) {
×
6749
                x = 10*x + (*s++-'0');
×
6750
        }
6751
        while ( *s == ' ' || *s == '\t' ) s++;
×
6752
        if ( *s  == 0 ) {
×
6753
#ifdef WITHPTHREADS
6754
#ifdef WITHSORTBOTS
6755
                int id, totnum = MaX(2*AM.totalnumberofthreads-3,AM.totalnumberofthreads);
6756
#else
6757
                int id, totnum = AM.totalnumberofthreads;
6758
#endif
6759
                for ( id = 0; id < totnum; id++ ) {
6760
                        AB[id]->R.wranfseed = x;
6761
                        if ( AB[id]->R.wranfia ) M_free(AB[id]->R.wranfia,"wranf");
6762
                        AB[id]->R.wranfia = 0;
6763
                }
6764
#else
6765
                AR.wranfseed = x;
6766
                if ( AR.wranfia ) M_free(AR.wranfia,"wranf");
6767
                AR.wranfia = 0;
6768
#endif
6769
                return(0);
6770
        }
6771
        else {
6772
                MesPrint("@proper syntax is #SetRandom number");
×
6773
                return(-1);
×
6774
        }
6775
}
6776

6777
/*
6778
                 #] DoSetRandom : 
6779
                 #[ DoOptimize :
6780

6781
                Executes the #Optimize(expr) instruction.
6782
*/
6783

6784
int DoOptimize(UBYTE *s)
35✔
6785
{
6786
        GETIDENTITY
10✔
6787
        UBYTE *exprname;
35✔
6788
        WORD numexpr;
35✔
6789
        int error = 0, i;
35✔
6790
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
35✔
6791
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
35✔
6792
        DUMMYUSE(*s)
35✔
6793
        exprname = s; s = SkipAName(s);
35✔
6794
        if ( *s != 0 && *s != ';' ) {
35✔
6795
                MesPrint("@proper syntax is #Optimize,expression");
×
6796
                return(-1);
×
6797
        }
6798
        *s = 0;
35✔
6799
    if ( GetName(AC.exprnames,exprname,&numexpr,NOAUTO) != CEXPRESSION ) {
35✔
6800
                MesPrint("@%s is not an expression",exprname);
×
6801
                error = 1;
×
6802
        }
6803
        else if ( AP.preError == 0 ) {
35✔
6804
                EXPRESSIONS e = Expressions + numexpr;
35✔
6805
                POSITION position;
35✔
6806
                int firstterm;
35✔
6807
                WORD *term = AT.WorkPointer;
35✔
6808
                ClearOptimize();
35✔
6809
                if ( AO.OptimizationLevel == 0 ) return(0);
35✔
6810
                switch ( e->status ) {
35✔
6811
                        case LOCALEXPRESSION:
6812
                        case GLOBALEXPRESSION:
6813
                                break;
6814
                        default:
×
6815
                                MesPrint("@Expression %s is not an active unhidden local or global expression.",exprname);
×
NEW
6816
                                TERMINATE(-1);
×
6817
                                break;
×
6818
                }
6819
#ifdef WITHMPI
6820
                if ( PF.me == MASTER )
20✔
6821
#endif
6822
                RevertScratch();
20✔
6823
                for ( i = NumExpressions-1; i >= 0; i-- ) {
77✔
6824
                        AS.OldOnFile[i] = Expressions[i].onfile;
42✔
6825
                        AS.OldNumFactors[i] = Expressions[i].numfactors;
42✔
6826
                        AS.Oldvflags[i] = Expressions[i].vflags;
42✔
6827
                        Expressions[i].vflags &= ~(ISUNMODIFIED|ISZERO);
42✔
6828
                }
6829
                for ( i = 0; i < NumExpressions; i++ ) {
77✔
6830
                        if ( i == numexpr ) {
42✔
6831
                                PutPreVar(AM.oldnumextrasymbols,
35✔
6832
                                                GetPreVar((UBYTE *)"EXTRASYMBOLS_",0),0,1);
6833
                                Optimize(numexpr, 0);
35✔
6834
                                AO.OptimizeResult.nameofexpr = strDup1(exprname,"optimize expression name");
35✔
6835
                                continue;
35✔
6836
                        }
6837
#ifdef WITHMPI
6838
                        if ( PF.me == MASTER ) {
4✔
6839
#endif
6840
                        e = Expressions + i;
4✔
6841
                        switch ( e->status ) {
4✔
6842
                                case LOCALEXPRESSION:
6843
                                case SKIPLEXPRESSION:
6844
                                case DROPLEXPRESSION:
6845
                                case DROPPEDEXPRESSION:
6846
                                case GLOBALEXPRESSION:
6847
                                case SKIPGEXPRESSION:
6848
                                case DROPGEXPRESSION:
6849
                                case HIDELEXPRESSION:
6850
                                case HIDEGEXPRESSION:
6851
                                case DROPHLEXPRESSION:
6852
                                case DROPHGEXPRESSION:
6853
                                case INTOHIDELEXPRESSION:
6854
                                case INTOHIDEGEXPRESSION:
6855
                                        break;
4✔
6856
                                default:
×
6857
                                        continue;
×
6858
                        }
6859
                        AR.GetFile = 0;
4✔
6860
                        SetScratch(AR.infile,&(e->onfile));
4✔
6861
                        if ( GetTerm(BHEAD term) <= 0 ) {
4✔
6862
                                MesPrint("@Expression %d has problems reading from scratchfile",i);
×
NEW
6863
                                TERMINATE(-1);
×
6864
                        }
6865
                        term[3] = i;
4✔
6866
                        AR.DeferFlag = 0;
4✔
6867
                        SeekScratch(AR.outfile,&position);
4✔
6868
                        e->onfile = position;
4✔
6869
                        *AM.S0->sBuffer = 0; firstterm = -1;
4✔
6870
                        do {
36✔
6871
                                WORD *oldipointer = AR.CompressPointer;
36✔
6872
                                WORD *comprtop = AR.ComprTop;
36✔
6873
                                AR.ComprTop = AM.S0->sTop;
36✔
6874
                                AR.CompressPointer = AM.S0->sBuffer;
36✔
6875
                                if ( firstterm > 0 ) {
36✔
6876
                                        if ( PutOut(BHEAD term,&position,AR.outfile,1) < 0 ) goto DoSerr;
28✔
6877
                                }
6878
                                else if ( firstterm < 0 ) {
8✔
6879
                                        if ( PutOut(BHEAD term,&position,AR.outfile,0) < 0 ) goto DoSerr;
4✔
6880
                                        firstterm++;
4✔
6881
                                }
6882
                                else {
6883
                                        if ( PutOut(BHEAD term,&position,AR.outfile,-1) < 0 ) goto DoSerr;
4✔
6884
                                        firstterm++;
4✔
6885
                                }
6886
                                AR.CompressPointer = oldipointer;
36✔
6887
                                AR.ComprTop = comprtop;
36✔
6888
                        } while ( GetTerm(BHEAD term) );
36✔
6889
                        if ( FlushOut(&position,AR.outfile,1) ) {
4✔
6890
DoSerr:
×
6891
                                MesPrint("@Expression %d has problems writing to scratchfile",i);
×
6892
                                TERMINATE(-1);
42✔
6893
                        }
6894
#ifdef WITHMPI
6895
                        }
6896
#endif
6897
                }
6898
/*
6899
                Now some administration and we are done
6900
*/
6901
                UpdateMaxSize();
35✔
6902
        }
6903
        else {
6904
                ClearOptimize();
×
6905
        }
6906
        return(error);
6907
        
6908
}
6909

6910
/*
6911
                 #] DoOptimize : 
6912
                 #[ DoClearOptimize :
6913

6914
                Clears all relevant buffers of the output optimization
6915
*/
6916

6917
int DoClearOptimize(UBYTE *s)
7✔
6918
{
6919
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
7✔
6920
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
7✔
6921
        DUMMYUSE(*s);
7✔
6922
        return(ClearOptimize());
7✔
6923
}
6924

6925
/*
6926
                 #] DoClearOptimize : 
6927
                 #[ DoSkipExtraSymbols :
6928

6929
                Adds the intermediate variables of the previous optimization
6930
                to the list of extra symbols, provided it has not yet been erased
6931
                by a #clearoptimize
6932
                To remove them again one needs to use the 'delete extrasymbols;'
6933
                or the 'delete extrasymbols>num;' statement in which num is the
6934
                old number of extra symbols.
6935
*/
6936

6937
int DoSkipExtraSymbols(UBYTE *s)
×
6938
{
6939
        CBUF *C = cbuf + AM.sbufnum;
×
6940
        WORD tt = 0, j = 0, oldval = AO.OptimizeResult.minvar;
×
6941
        if ( AO.OptimizeResult.code == NULL ) return(0);
×
6942
        if ( AO.OptimizationLevel == 0 ) return(0);
×
6943
        while ( *s == ',' ) s++;
×
6944
        if ( *s == 0 ) {
×
6945
                AO.OptimizeResult.minvar = AO.OptimizeResult.maxvar+1;
×
6946
        }
6947
        else {
6948
                while ( *s <= '9' && *s >= '0' ) j = 10*j + *s++ - '0';
×
6949
                if ( *s ) {
×
6950
                        MesPrint("@Illegal use of #SkipExtraSymbols instruction");
×
NEW
6951
                        TERMINATE(-1);
×
6952
                }
6953
                AO.OptimizeResult.minvar += j;
×
6954
                if ( AO.OptimizeResult.minvar > AO.OptimizeResult.maxvar )
×
6955
                        AO.OptimizeResult.minvar = AO.OptimizeResult.maxvar+1;
×
6956
        }
6957
        j = AO.OptimizeResult.minvar - oldval;
×
6958
        while ( j > 0 ) {
×
6959
                AddRHS(AM.sbufnum,1);
×
6960
                AddNtoC(AM.sbufnum,1,&tt,16);
×
6961
                AddToCB(C,0)
×
6962
                InsTree(AM.sbufnum,C->numrhs);
×
6963
                j--;
×
6964
        }
6965
        return(0);
6966
}
6967

6968
/*
6969
                 #] DoSkipExtraSymbols : 
6970
                 #[ DoPreReset :
6971

6972
                Does a reset of variables.
6973
                Currently only the timer (stopwatch) of `timer_'
6974
*/
6975

6976
int DoPreReset(UBYTE *s)
×
6977
{
6978
        UBYTE *ss, c;
×
6979
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
6980
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
6981
        while ( *s == ' ' || *s == '\t' ) s++;
×
6982
        if ( *s == 0 ) {
×
6983
                MesPrint("@proper syntax is #Reset variable");
×
6984
                return(-1);
×
6985
        }
6986
        ss = s;
×
6987
        while ( FG.cTable[*s] == 0 ) s++;
×
6988
        c = *s; *s = 0;
×
6989
        if ( ( StrICmp(ss,(UBYTE *)"timer") == 0 )
×
6990
          || ( StrICmp(ss,(UBYTE *)"stopwatch") == 0 ) ) {
×
6991
                *s = c;
×
6992
                AP.StopWatchZero = GetRunningTime();
×
6993
                return(0);
×
6994
        }
6995
        else {
6996
                *s = c;
×
6997
                MesPrint("@proper syntax is #Reset variable");
×
6998
                return(-1);
×
6999
        }
7000
}
7001

7002
/*
7003
                 #] DoPreReset : 
7004
                 #[ DoPreAppendPath :
7005
*/
7006

7007
static int DoAddPath(UBYTE *s, int bPrepend)
21✔
7008
{
7009
        /* NOTE: this doesn't support some file systems, e.g., 0x5c with CP932. */
7010

7011
        UBYTE *path, *path_end, *current_dir, *current_dir_end, *NewPath, *t;
21✔
7012
        int bRelative, n;
21✔
7013

7014
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
21✔
7015
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
21✔
7016

7017
        /* Parse the path in the input. */
7018
        while ( *s == ' ' || *s == '\t' ) s++;  /* skip spaces */
21✔
7019
        if ( *s == '"' ) {  /* the path is given by "..." */
21✔
7020
                path = ++s;
×
7021
                while ( *s && *s != '"' ) {
×
7022
                        if ( SEPARATOR != '\\' && *s == '\\' ) {  /* escape character, e.g., "\\\"" */
×
7023
                                if ( !s[1] ) goto ImproperPath;
×
7024
                                s++;
×
7025
                        }
7026
                        s++;
×
7027
                }
7028
                if ( *s != '"' ) goto ImproperPath;
×
7029
                path_end = s++;
×
7030
        }
7031
        else {
7032
                path = s;
84✔
7033
                while ( *s && *s != ' ' && *s != '\t' ) {
84✔
7034
                        if ( SEPARATOR != '\\' && *s == '\\' ) {  /* escape character, e.g., "\\ " */
63✔
7035
                                if ( !s[1] ) goto ImproperPath;
×
7036
                                s++;
×
7037
                        }
7038
                        s++;
63✔
7039
                }
7040
                path_end = s;
7041
        }
7042
        if ( path == path_end ) goto ImproperPath;  /* empty path */
21✔
7043
        while ( *s == ' ' || *s == '\t' ) s++;  /* skip spaces */
21✔
7044
        if ( *s ) goto ImproperPath;  /* extra tokens found */
21✔
7045

7046
        /* Check if the path is an absolute path. */
7047
        bRelative = 1;
21✔
7048
        if ( path[0] == SEPARATOR ) {  /* starts with the directory separator */
21✔
7049
                bRelative = 0;
7050
        }
7051
#ifdef WINDOWS
7052
        else if ( chartype[path[0]] == 0 && path[1] == ':' ) {  /* starts with (drive letter): */
7053
                bRelative = 0;
7054
        }
7055
#endif
7056

7057
        /* Get the current file directory when a relative path is given. */
7058
        if ( bRelative ) {
21✔
7059
                if ( !AC.CurrentStream ) goto FileNameUnavailable;
21✔
7060
                if ( AC.CurrentStream->type != FILESTREAM && AC.CurrentStream->type != REVERSEFILESTREAM ) goto FileNameUnavailable;
21✔
7061
                if ( !AC.CurrentStream->name ) goto FileNameUnavailable;
21✔
7062
                s = current_dir = current_dir_end = AC.CurrentStream->name;
231✔
7063
                while ( *s ) {
231✔
7064
                        if ( SEPARATOR != '\\' && *s == '\\' && s[1] ) {  /* escape character, e.g., "\\\"" */
210✔
7065
                                s += 2;
×
7066
                                continue;
×
7067
                        }
7068
                        if ( *s == SEPARATOR ) {
210✔
7069
                                current_dir_end = s;
21✔
7070
                        }
7071
                        s++;
210✔
7072
                }
7073
        }
7074
        else {
7075
                current_dir = current_dir_end = NULL;
7076
        }
7077

7078
        /* Allocate a buffer for new AM.Path. */
7079
        n = path_end - path;
21✔
7080
        if ( AM.Path ) n += StrLen(AM.Path) + 1;
21✔
7081
        if ( current_dir != current_dir_end ) n+= current_dir_end - current_dir + 1;
21✔
7082
        s = NewPath = (UBYTE *)Malloc1(n + 1,"add path");
21✔
7083

7084
        /* Construct new FORM path. */
7085
        if ( bPrepend ) {
21✔
7086
                if ( current_dir != current_dir_end ) {
14✔
7087
                        t = current_dir;
7088
                        while ( t != current_dir_end ) *s++ = *t++;
56✔
7089
                        *s++ = SEPARATOR;
14✔
7090
                }
7091
                t = path;
7092
                while ( t != path_end ) *s++ = *t++;
56✔
7093
                if ( AM.Path ) *s++ = PATHSEPARATOR;
14✔
7094
        }
7095
        if ( AM.Path ) {
21✔
7096
                t = AM.Path;
7097
                while ( *t ) *s++ = *t++;
350✔
7098
        }
7099
        if ( !bPrepend ) {
21✔
7100
                if ( AM.Path ) *s++ = PATHSEPARATOR;
7✔
7101
                if ( current_dir != current_dir_end ) {
7✔
7102
                        t = current_dir;
7103
                        while ( t != current_dir_end ) *s++ = *t++;
28✔
7104
                        *s++ = SEPARATOR;
7✔
7105
                }
7106
                t = path;
7107
                while ( t != path_end ) *s++ = *t++;
28✔
7108
        }
7109
        *s = '\0';
21✔
7110

7111
        /* Update AM.Path. */
7112
        if ( AM.Path ) M_free(AM.Path,"add path");
21✔
7113
        AM.Path = NewPath;
21✔
7114

7115
        return(0);
21✔
7116

7117
ImproperPath:
×
7118
        MesPrint("@Improper syntax for %#%sPath", bPrepend ? "Prepend" : "Append");
×
7119
        return(-1);
×
7120

7121
FileNameUnavailable:
×
7122
        /* This may be improved in future. */
7123
        MesPrint("@Sorry, %#%sPath can't resolve the current file name from here", bPrepend ? "Prepend" : "Append");
×
7124
        return(-1);
×
7125
}
7126

7127
/**
7128
 * Appends the given path (absolute or relative to the current file directory)
7129
 * to the FORM path.
7130
 *
7131
 * Syntax:
7132
 *   #appendpath <path>
7133
 */
7134
int DoPreAppendPath(UBYTE *s)
7✔
7135
{
7136
        return DoAddPath(s, 0);
7✔
7137
}
7138

7139
/*
7140
                 #] DoPreAppendPath : 
7141
                 #[ DoPrePrependPath :
7142
*/
7143

7144
/**
7145
 * Prepends the given path (absolute or relative to the current file directory)
7146
 * to the FORM path.
7147
 *
7148
 * Syntax:
7149
 *   #prependpath <path>
7150
 */
7151
int DoPrePrependPath(UBYTE *s)
14✔
7152
{
7153
        return DoAddPath(s, 1);
14✔
7154
}
7155

7156
/*
7157
                 #] DoPrePrependPath : 
7158
                 #[ DoTimeOutAfter :
7159

7160
                Executes the #timeoutafter number
7161
*/
7162

7163
int DoTimeOutAfter(UBYTE *s)
17✔
7164
{
7165
#ifdef WITH_ALARM
7166
        ULONG x;
17✔
7167
#else
7168
        DUMMYUSE(s);
7169
#endif
7170
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
17✔
7171
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
17✔
7172
#ifdef WITH_ALARM
7173
        while ( *s == ' ' || *s == '\t' ) s++;
17✔
7174
        x = 0;
7175
        while ( FG.cTable[*s] == 1 ) {
55✔
7176
                x = 10*x + (*s++-'0');
38✔
7177
        }
7178
        while ( *s == ' ' || *s == '\t' ) s++;
17✔
7179
        if ( *s  == 0 ) {
17✔
7180
                alarm(x);
17✔
7181
                return(0);
17✔
7182
        }
7183
        else {
7184
                MesPrint("@proper syntax is #TimeoutAfter number");
×
7185
                return(-1);
×
7186
        }
7187
#else
7188
        Error0("#timeoutafter not implemented on this computer/system");
7189
        return(-1);
7190
#endif
7191
}
7192

7193
/*
7194
                 #] DoTimeOutAfter : 
7195
                 #[ DoNamespace :
7196

7197
                Syntax:
7198
                        #Namespace name
7199
                                .....
7200
                        #use variables
7201
                                .....
7202
                        #EndNamespace
7203
                Effect:
7204
                        All variables/expressions defined inside the range of the
7205
                        namespace get name_ prepended.
7206
                        This holds also for $-variables, names of procedures and 
7207
                        names of files.
7208
                Namespaces can be used in a nested way. cf this_is_deep_x
7209
                A leading _ takes the role of what is super:: in some other languages.
7210
                Remarks:
7211
                        Names of preprocessor variables are excluded!
7212
                        Names of built in objects are excluded! (like sum_, d_ etc.)
7213
*/
7214

7215
int DoNamespace(UBYTE *s)
×
7216
{
7217
        UBYTE *s1, *s2, c;
×
7218
        NAMESPACE *namespace;
×
7219
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
7220
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
7221
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
×
7222
        if ( FG.cTable[*s] != 0 ) {
×
7223
                MesPrint("@Illegal name in #namespace instruction: %s",s);
×
7224
                return(-1);
×
7225
        }
7226
        s1 = s;
7227
        while ( FG.cTable[*s1] <= 1 ) s1++;
×
7228
        s2 = s1;
7229
        while ( *s2 == ' ' || *s2 == ',' || *s2 == '\t' ) s2++;
×
7230
        if ( *s2 != 0 ) {
×
7231
                MesPrint("@A #namespace instruction can only have one name with only alphanumeric characters.");
×
7232
                return(-1);
×
7233
        }
7234
        c = *s1; *s1 = 0;
×
7235
/*
7236
        Now we have the name and the statement is legal.
7237
        We can proceed creating the namespace and its use tree.
7238
*/
7239
        namespace = (NAMESPACE *)Malloc1(sizeof(NAMESPACE),"namespace");
×
7240
        namespace->name = strDup1(s,"namespace_name");
×
7241
        namespace->usenames = MakeNameTree();
×
7242
        if ( AP.firstnamespace == 0 ) {
×
7243
                namespace->previous = 0;
×
7244
                namespace->next = 0;
×
7245
                AP.firstnamespace = namespace;
×
7246
                AP.lastnamespace = namespace;
×
7247
        }
7248
        else {
7249
                AP.lastnamespace->next = namespace;
×
7250
                namespace->next = 0;
×
7251
                namespace->previous = AP.lastnamespace;
×
7252
                AP.lastnamespace = namespace;
×
7253
        }
7254
        *s1 = c;
×
7255
        return(0);
×
7256
}
7257

7258
/*
7259
                 #] DoNamespace : 
7260
                 #[ DoEndNamespace :
7261
*/
7262

7263
int DoEndNamespace(UBYTE *s)
×
7264
{
7265
        NAMESPACE *namespace;
×
7266
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
7267
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
7268
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
×
7269
        if ( *s != 0 ) {
×
7270
                MesPrint("@Illegal #endnamespace instruction");
×
7271
                return(-1);
×
7272
        }
7273
        namespace = AP.lastnamespace;
×
7274
        AP.lastnamespace = namespace->previous;
×
7275
        M_free(namespace->name,"namespace_name");
×
7276
        FreeNameTree(namespace->usenames);
×
7277
        M_free(namespace,"namespace");
×
7278
        return(0);
×
7279
}
7280

7281
/*
7282
                 #] DoEndNamespace : 
7283
                 #[ SkipName :
7284
*/
7285

7286
UBYTE *SkipName(UBYTE *s)
35✔
7287
{
7288
        UBYTE *t = s, *s1, c;
35✔
7289
        int num = 0, block = 0;
35✔
7290
        if ( *s == '[' ) {
35✔
7291
straight:
×
7292
                SKIPBRA1(s)
×
7293
                if ( *s == 0 ) {
×
7294
                        MesPrint("&Illegal name: '%s'",t);
×
7295
                        return(0);
×
7296
                }
7297
                s++; s1 = s;
×
7298
                while ( FG.cTable[*s] <= 1 || *s == '_' ) s++;
×
7299
                if ( s1 != s ) goto witherror;
×
7300
        }
7301
        else if ( *s == '$' ) {
35✔
7302
                s++;
×
7303
                while ( *s == '_' ) { s++; num++; }
×
7304
                block = 1;
7305
                while ( FG.cTable[*s] <= 1 || *s == '_' ) {
×
7306
                        if ( FG.cTable[*s] != 0 && block == 1 ) {
×
7307
blocked:
×
7308
                                MesPrint("&Illegally formed name: %s",t);
×
7309
                                return(0);
×
7310
                        }
7311
                        if ( *s == '_' ) { num++; block = 1; }
×
7312
                        else block = 0;
7313
                        s++;
×
7314
                }
7315
                if ( s[-1] == '_' && num > 1 ) goto built;
×
7316
        }
7317
        else if ( FG.cTable[*s] == 0 ) {
35✔
7318
regular:
35✔
7319
                while ( FG.cTable[*s] <= 1 || *s == '_' ) {
126✔
7320
                        if ( FG.cTable[*s] != 0 && block == 1 ) goto blocked;
91✔
7321
                        if ( *s == '_' ) { block = 1; num++; }
91✔
7322
                        else block = 0;
7323
                        s++;
91✔
7324
                }
7325
                if ( *s == '[' ) goto straight;
35✔
7326
                if ( s[-1] == '_' && num > 1 ) {
35✔
7327
built:
×
7328
                        c = *s; *s = 0;
×
7329
                        MesPrint("&Built in objects cannot be part of namespaces: %s",t);
×
7330
                        *s = c;
×
7331
                        return(0);
×
7332
                }
7333
        }
7334
        else if ( *s == '_' ) {
×
7335
                while ( *s == '_' ) { s++; num++; }
×
7336
                if ( FG.cTable[*s] == 0 ) { block = 0; goto regular; }
×
7337
                goto witherror;
×
7338
        }
7339
        else if ( *s == '@' ) {
×
7340
                s++; block = 1;
×
7341
                if ( *s == '_' || FG.cTable[*s] == 1 ) {
×
7342
                        MesPrint("@Illegally formed name: %s",s-1);
×
7343
                }
7344
                goto regular;
×
7345
        }
7346
        else if ( *s == '#' ) {        /* name of a procedure */
×
7347
                s++;
×
7348
                while ( *s == '_' ) { s++; num++; }
×
7349
                block = 1;
7350
                while ( FG.cTable[*s] <= 1 || *s == '_' ) {
×
7351
                        if ( FG.cTable[*s] != 0 && block == 1 ) goto blocked;
×
7352
                        if ( *s == '_' ) { num++; block = 1; }
×
7353
                        else block = 0;
7354
                        s++;
×
7355
                }
7356
                if ( s[-1] == '_' ) {
×
7357
witherror:
×
7358
                        c = *s; *s = 0;
×
7359
                        MesPrint("&Illegally formed name: %s",t);
×
7360
                        *s = c;
×
7361
                        return(0);
×
7362
                }
7363
        }
7364
        else if ( *s == '<' ) {        /* name of a file. Can be anything (more or less) */
×
7365
                s++;
×
7366
                while ( *s && *s != '>' ) s++;
×
7367
                if ( *s != '>' ) goto witherror;
×
7368
                s++;
×
7369
        }
7370
        return(s);
7371
}
7372

7373
/*
7374
                 #] SkipName : 
7375
                 #[ ConstructName :
7376

7377
                Routine gets a 'raw' name and modifies it if the namespace
7378
                settings ask for it. It puts the new name in a buffer that
7379
                may be expanded if the names become rather long.
7380
                Note that eventually that name needs to be copied, because
7381
                we do not allocate new buffers for each name.
7382

7383
                type tells what kind of name we look for
7384
*/
7385

7386
UBYTE *ConstructName(UBYTE *s,UBYTE type)
7✔
7387
{
7388
        int len;
7✔
7389
        UBYTE *t, *u;
7✔
7390
        WORD number;
7✔
7391
        NAMESPACE *namespace;
7✔
7392
        if ( AP.lastnamespace == 0 ) return(s);
7✔
7393
        if ( *s == '@' ) return(s+1);
×
7394
        if ( GetName(AP.lastnamespace->usenames,s,&number,NOAUTO) !=
×
7395
                        NAMENOTFOUND ) return(s);
7396
/*
7397
        Now the real stuff
7398
        First we have to compute the size of the new name.
7399
*/
7400
        len = StrLen(s) + 1;
×
7401
        namespace = AP.firstnamespace;
×
7402
        while ( namespace ) {
×
7403
                len += StrLen(namespace->name)+1;
×
7404
                namespace = namespace->previous;
×
7405
        }
7406
        if ( len > AP.fullnamesize ) {
×
7407
                while ( len > AP.fullnamesize ) AP.fullnamesize *= 2;
×
7408
                M_free(AP.fullname,"AP.fullname");
×
7409
                AP.fullname = (UBYTE *)Malloc1(AP.fullnamesize*sizeof(UBYTE *),"AP.fullname");
×
7410
        }
7411
        namespace = AP.firstnamespace;
×
7412
        t = AP.fullname;
×
7413
        switch ( type ) {
×
7414
                case ' ':
7415
                case 0:
7416
                        while ( namespace ) {
×
7417
                                u = namespace->name;
×
7418
                                while ( *u ) *t++ = *u++;
×
7419
                                *t++ = '_';
×
7420
                                namespace = namespace->previous;
×
7421
                        }
7422
                        while ( *s ) *t++ = *s++;
×
7423
                        *t = 0;
×
7424
                        break;
×
7425
                case '$':
×
7426
                case '#':
7427
                        *t++ = type;
×
7428
                        while ( namespace ) {
×
7429
                                u = namespace->name;
×
7430
                                while ( *u ) *t++ = *u++;
×
7431
                                *t++ = '_';
×
7432
                                namespace = namespace->previous;
×
7433
                        }
7434
                        if ( type == '$' ) s++;
×
7435
                        while ( *s ) *t++ = *s++;
×
7436
                        *t = 0;
×
7437
                        break;
×
7438
                case '<':
7439
                        while ( namespace ) {
×
7440
                                u = namespace->name;
×
7441
                                while ( *u ) *t++ = *u++;
×
7442
                                *t++ = '_';
×
7443
                                namespace = namespace->previous;
×
7444
                        }
7445
                        s++;
×
7446
                        while ( *s ) *t++ = *s++;
×
7447
                        t--;  /* strip the '>' */
×
7448
                        *t = 0;
×
7449
                        break;
×
7450
                default:
×
7451
                        MesPrint("&Unrecognized datatype in ConstructName");
×
7452
                        *t = 0;
×
7453
                        break;
×
7454
        }
7455
        return(AP.fullname);
×
7456
}
7457

7458
/*
7459
                 #] ConstructName : 
7460
                 #[ DoUse :
7461

7462
                Routine makes (inside the confines of the current namespace)
7463
                a list of variables that are excluded from the namespace.
7464
                Once the namespace is ended, the list is removed.
7465
                The list can include names of variables, dollars and procedures.
7466
                Preprocessor variables are excluded from the namespace. Their
7467
                inclusion would be too complicated for the input streams.
7468
                Note that the preprocessor variables that are arguments in a #do
7469
                or in a procedure are on a stack and should not cause problems.
7470
                Names of variables can be just that.
7471
                Names of $-variables are also straightforward.
7472
                Names of procedures should be preceeded by a # character.
7473
                Names of files (like in #include) should be enclosed by <>.
7474
                The names are stored in a balanced tree. Each namespace may have
7475
                its own tree. The toplevel (no namespace) does not allow a #use.
7476
*/
7477

7478
int DoUse(UBYTE *s)
×
7479
{
7480
        NAMESPACE *namespace;
×
7481
        UBYTE *t, c;
×
7482
        int number;
×
7483
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
7484
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
7485
        if ( AP.lastnamespace == 0 ) {
×
7486
                MesPrint("@It is not allowed to use #use outside the scope of a namespace.");
×
7487
                return(-1);
×
7488
        }
7489
        namespace = AP.lastnamespace;
×
7490
        while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
×
7491
        while ( *s ) {
×
7492
                t = s;
×
7493
                if ( ( s = SkipName(t) ) == 0 ) return(-1);
×
7494
                if ( s == t ) {
×
7495
                        MesPrint("@Unrecognized object in #use instruction: %s",t);
×
7496
                        return(-1);
×
7497
                }
7498
                c = *s; *s = 0;
×
7499
/*
7500
                In usenames we only need the names to know whether they are 'protected'.
7501
                We need to keep the $, # and <> to avoid potential double names.
7502
*/
7503
                AddName(namespace->usenames,t,0,0,&number);
×
7504
                *s = c;
×
7505
                while ( *s == ' ' || *s == ',' || *s == '\t' ) s++;
×
7506
        }
7507
        return(0);
7508
}
7509

7510
/*
7511
                 #] DoUse : 
7512
                 #[ UserFlags :
7513
 
7514
        Syntax:
7515
                #ClearFlag number(s),expression(s)
7516
                #ClearFlag number(s)
7517
                #ClearFlag expression(s)
7518
                #ClearFlag
7519
                #SetFlag number(s),expression(s)
7520
                #SetFlag number(s)
7521
                #SetFlag expression(s)
7522
                #SetFlag
7523
                par == 0: Clear, par == 1: Set.
7524
*/
7525

7526
int UserFlags(UBYTE *s,int par)
×
7527
{
7528
        int mask = 0, error = 0, i;
×
7529
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
7530
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
7531
        while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
7532
        if ( *s == 0 ) {        /* Treat all flags in all active expressions */
×
7533
allexpr:
×
7534
                for ( i = 0; i < NumExpressions; i++ ) {
×
7535
                        switch ( Expressions[i].status ) {
×
7536
                                case UNHIDELEXPRESSION:
×
7537
                                case UNHIDEGEXPRESSION:
7538
                                case INTOHIDELEXPRESSION:
7539
                                case INTOHIDEGEXPRESSION:
7540
                                case LOCALEXPRESSION:
7541
                                case GLOBALEXPRESSION:
7542
                                case SKIPLEXPRESSION:
7543
                                case SKIPGEXPRESSION:
7544
                                case HIDELEXPRESSION:
7545
                                case HIDEGEXPRESSION:
7546
                                        if ( par == 1 ) Expressions[i].uflags |= ~mask;
×
7547
                                        else            Expressions[i].uflags &= mask;
×
7548
                                        break;
7549
                                case DROPPEDEXPRESSION:
7550
                                case DROPLEXPRESSION:
7551
                                case DROPGEXPRESSION:
7552
                                case DROPHLEXPRESSION:
7553
                                case DROPHGEXPRESSION:
7554
                                case STOREDEXPRESSION:
7555
                                case HIDDENLEXPRESSION:
7556
                                case HIDDENGEXPRESSION:
7557
                                case SPECTATOREXPRESSION:
7558
                                default:
7559
                                        break;
7560
                        }
7561
                }
7562
        }
7563
        else if ( FG.cTable[*s] == 1 ) {
×
7564
                mask = (int)WORDMASK;
7565
                while ( FG.cTable[*s] == 1 ) {
×
7566
                        int x = 0;
7567
                        while ( FG.cTable[*s] == 1 ) { x = 10*x + (*s++-'0'); }
×
7568
                        if ( x < 1 || x > BITSINWORD ) {
×
7569
                                MesPrint("@Illegal number %d for flag in #...Flag instruction",x);
×
7570
                                return(1);
×
7571
                        }
7572
                        mask ^= (1<<(x-1));
×
7573
                        while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
7574
                }
7575
                if ( *s == 0 ) goto allexpr;
×
7576
        }
7577
        else {        /* Clear all flags in all expressions that are specified */
7578
                mask = (int)WORDMASK;
×
7579
        }
7580
        while ( *s ) { /* now read the expressions */
×
7581
                UBYTE *s1, c;
×
7582
                WORD num1;
×
7583
                if ( FG.cTable[*s] != 0 && *s != '[' ) goto syntax;
×
7584
                s1 = s; s = SkipAName(s);
×
7585
                c = *s; *s = 0;
×
7586
            if ( GetName(AC.exprnames,s1,&num1,NOAUTO) != CEXPRESSION ) {
×
7587
                        MesPrint("@%s is not an active expression",s1);
×
7588
                        error = 1;
×
7589
                        return(error);
×
7590
                }
7591
                switch ( Expressions[num1].status ) {
×
7592
                        case UNHIDELEXPRESSION:
×
7593
                        case UNHIDEGEXPRESSION:
7594
                        case INTOHIDELEXPRESSION:
7595
                        case INTOHIDEGEXPRESSION:
7596
                        case LOCALEXPRESSION:
7597
                        case GLOBALEXPRESSION:
7598
                        case SKIPLEXPRESSION:
7599
                        case SKIPGEXPRESSION:
7600
                        case HIDELEXPRESSION:
7601
                        case HIDEGEXPRESSION:
7602
                                if ( par == 1 ) Expressions[num1].uflags |= ~mask;
×
7603
                                else            Expressions[num1].uflags &= mask;
×
7604
                                break;
7605
                        case DROPPEDEXPRESSION:
×
7606
                        case DROPLEXPRESSION:
7607
                        case DROPGEXPRESSION:
7608
                        case DROPHLEXPRESSION:
7609
                        case DROPHGEXPRESSION:
7610
                        case STOREDEXPRESSION:
7611
                        case HIDDENLEXPRESSION:
7612
                        case HIDDENGEXPRESSION:
7613
                        case SPECTATOREXPRESSION:
7614
                        default:
7615
                                MesPrint("@%s is not an active expression",s1);
×
7616
                                error = 1;
×
7617
                                break;
×
7618
                }
7619
                *s = c;
×
7620
                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
7621
        }
7622
        return(error);
7623
syntax:
×
7624
        MesPrint("@Illegal name in #...Flag instruction.");
×
7625
        return(1);
×
7626
}
7627

7628
/*
7629
                 #] UserFlags : 
7630
                 #[ DoClearUserFlag :
7631
*/
7632

7633
int DoClearUserFlag(UBYTE *s)
×
7634
{
7635
        return(UserFlags(s,0));
×
7636
}
7637

7638
/*
7639
                 #] DoClearUserFlag : 
7640
                 #[ DoSetUserFlag :
7641
*/
7642

7643
int DoSetUserFlag(UBYTE *s)
×
7644
{
7645
        return(UserFlags(s,1));
×
7646
}
7647

7648
/*
7649
                 #] DoSetUserFlag : 
7650
                 #[ DoStartFloat :
7651

7652
                If there is a number follwing, it will be the new default precision.
7653
                If float has been started before, the old one will be removed first.
7654
                If there are two numbers, the second one is the maximum weight for
7655
                MZV's.
7656
*/
7657
#ifdef WITHFLOAT
7658

7659
int DoStartFloat(UBYTE *s)
×
7660
{
7661
        GETIDENTITY
7662
        int error = 0;
×
7663
        LONG x;
×
7664
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
7665
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
7666
        if ( AR.PolyFun != 0 ) {
×
7667
                MesPrint("@Simultaneous use of Poly(Rat)Fun and float_ is not allowed.");
×
7668
                error = 1;
×
7669
        }
7670
        if ( AC.ncmod != 0 ) {
×
7671
                MesPrint("@Simultaneous use of floating point and modulus arithmetic makes no sense.");
×
7672
                error = 1;
×
7673
        }
7674
        while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
7675
        if ( *s >= '0' && *s <= '9' ) {
×
7676
                x = 0;
7677
                do {
×
7678
                        x = 10*x + (*s++-'0');
×
7679
                } while ( *s >= '0' && *s <= '9' );
×
7680
                AC.tDefaultPrecision = x;
×
7681
                while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
7682
                if ( *s >= '0' && *s <= '9' ) {
×
7683
                        x = 0;
7684
                        do {
×
7685
                                x = 10*x + (*s++ - '0');
×
7686
                        } while ( *s >= '0' && *s <= '9' );
×
7687
                        AC.tMaxWeight = x;
×
7688
                        while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
7689
                }
7690
                else {
7691
                        AC.tMaxWeight = 0;
×
7692
                }
7693
                if ( *s ) goto IllPar;
×
7694
        }
7695
        else if ( *s != 0 ) {
×
7696
IllPar:
×
7697
                MesPrint("@Illegal parameter in %#StartFloat instruction: %s ",s);
×
7698
                error = 1;
×
7699
        }
7700
        if ( error == 0 ) {
×
7701
                if ( AC.tDefaultPrecision && ( AC.tDefaultPrecision != AC.DefaultPrecision
×
7702
                || AT.aux_ == 0 ) ) {
×
7703
                        AC.DefaultPrecision = AC.tDefaultPrecision;
×
7704
                        AC.tDefaultPrecision = 0;
×
7705
                }
7706
                if ( AC.tMaxWeight && ( AC.tMaxWeight != AC.MaxWeight
×
7707
                || AT.aux_ == 0 ) ) {
×
7708
                        AC.MaxWeight = AC.tMaxWeight;
×
7709
                        AC.tMaxWeight = 0;
×
7710
                }
7711
                SetupMPFTables();
×
7712
                if ( AC.MaxWeight > 0 ) SetupMZVTables();
×
7713
                SetfFloatPrecision(AC.DefaultPrecision);
×
7714
        }
7715
        else {
7716
                AC.tDefaultPrecision = 0;
×
7717
                AC.tMaxWeight = 0;
×
7718
        }
7719
        return(error);
7720
}
7721

7722
#endif
7723
/*
7724
                 #] DoStartFloat : 
7725
                 #[ DoEndFloat :
7726
*/
7727
#ifdef WITHFLOAT
7728

7729
int DoEndFloat(UBYTE *s)
×
7730
{
7731
        int error = 0;
×
7732
        if ( AP.PreSwitchModes[AP.PreSwitchLevel] != EXECUTINGPRESWITCH ) return(0);
×
7733
        if ( AP.PreIfStack[AP.PreIfLevel] != EXECUTINGIF ) return(0);
×
7734
        while ( *s == ',' || *s == ' ' || *s == '\t' ) s++;
×
7735
        if ( *s != 0 ) {
×
7736
                MesPrint("@Illegal parameter in %#EndFloat instruction: %s ",s);
×
7737
                error = 1;
×
7738
        }
7739
        if ( error == 0 ) {
×
7740
                ClearfFloat();
×
7741
                ClearMZVTables();
×
7742
        }
7743
        return(error);
7744
}
7745

7746
#endif
7747
/*
7748
                 #] DoEndFloat : 
7749
         # ] PreProcessor :
7750
*/
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc