Deleted Added
full compact
eval.c (7004) eval.c (7896)
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Ozan Yigit at York University.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93";
39#endif /* not lint */
40
41/*
42 * eval.c
43 * Facility: m4 macro processor
44 * by: oz
45 */
46
47#include <sys/types.h>
48#include <errno.h>
49#include <unistd.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include "mdef.h"
54#include "stdd.h"
55#include "extern.h"
56#include "pathnames.h"
57
58/*
59 * eval - evaluate built-in macros.
60 * argc - number of elements in argv.
61 * argv - element vector :
62 * argv[0] = definition of a user
63 * macro or nil if built-in.
64 * argv[1] = name of the macro or
65 * built-in.
66 * argv[2] = parameters to user-defined
67 * . macro or built-in.
68 * .
69 *
70 * Note that the minimum value for argc is 3. A call in the form
71 * of macro-or-builtin() will result in:
72 * argv[0] = nullstr
73 * argv[1] = macro-or-builtin
74 * argv[2] = nullstr
75 */
76
77void
78eval(argv, argc, td)
79register char *argv[];
80register int argc;
81register int td;
82{
83 register int c, n;
84 static int sysval = 0;
85
86#ifdef DEBUG
87 printf("argc = %d\n", argc);
88 for (n = 0; n < argc; n++)
89 printf("argv[%d] = %s\n", n, argv[n]);
90#endif
91 /*
92 * if argc == 3 and argv[2] is null, then we
93 * have macro-or-builtin() type call. We adjust
94 * argc to avoid further checking..
95 */
96 if (argc == 3 && !*(argv[2]))
97 argc--;
98
99 switch (td & ~STATIC) {
100
101 case DEFITYPE:
102 if (argc > 2)
103 dodefine(argv[2], (argc > 3) ? argv[3] : null);
104 break;
105
106 case PUSDTYPE:
107 if (argc > 2)
108 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
109 break;
110
111 case DUMPTYPE:
112 dodump(argv, argc);
113 break;
114
115 case EXPRTYPE:
116 /*
117 * doexpr - evaluate arithmetic
118 * expression
119 */
120 if (argc > 2)
121 pbnum(expr(argv[2]));
122 break;
123
124 case IFELTYPE:
125 if (argc > 4)
126 doifelse(argv, argc);
127 break;
128
129 case IFDFTYPE:
130 /*
131 * doifdef - select one of two
132 * alternatives based on the existence of
133 * another definition
134 */
135 if (argc > 3) {
136 if (lookup(argv[2]) != nil)
137 pbstr(argv[3]);
138 else if (argc > 4)
139 pbstr(argv[4]);
140 }
141 break;
142
143 case LENGTYPE:
144 /*
145 * dolen - find the length of the
146 * argument
147 */
148 if (argc > 2)
149 pbnum((argc > 2) ? strlen(argv[2]) : 0);
150 break;
151
152 case INCRTYPE:
153 /*
154 * doincr - increment the value of the
155 * argument
156 */
157 if (argc > 2)
158 pbnum(atoi(argv[2]) + 1);
159 break;
160
161 case DECRTYPE:
162 /*
163 * dodecr - decrement the value of the
164 * argument
165 */
166 if (argc > 2)
167 pbnum(atoi(argv[2]) - 1);
168 break;
169
170 case SYSCTYPE:
171 /*
172 * dosys - execute system command
173 */
174 /* Make sure m4 output is NOT interrupted */
175 fflush(stdout);
176 fflush(stderr);
177 if (argc > 2)
178 sysval = system(argv[2]);
179 break;
180
181 case SYSVTYPE:
182 /*
183 * dosysval - return value of the last
184 * system call.
185 *
186 */
187 pbnum(sysval);
188 break;
189
190 case INCLTYPE:
191 if (argc > 2)
192 if (!doincl(argv[2]))
193 oops("%s: %s", argv[2], strerror(errno));
194 break;
195
196 case SINCTYPE:
197 if (argc > 2)
198 (void) doincl(argv[2]);
199 break;
200#ifdef EXTENDED
201 case PASTTYPE:
202 if (argc > 2)
203 if (!dopaste(argv[2]))
204 oops("%s: %s", argv[2], strerror(errno));
205 break;
206
207 case SPASTYPE:
208 if (argc > 2)
209 (void) dopaste(argv[2]);
210 break;
211#endif
212 case CHNQTYPE:
213 dochq(argv, argc);
214 break;
215
216 case CHNCTYPE:
217 dochc(argv, argc);
218 break;
219
220 case SUBSTYPE:
221 /*
222 * dosub - select substring
223 *
224 */
225 if (argc > 3)
226 dosub(argv, argc);
227 break;
228
229 case SHIFTYPE:
230 /*
231 * doshift - push back all arguments
232 * except the first one (i.e. skip
233 * argv[2])
234 */
235 if (argc > 3) {
236 for (n = argc - 1; n > 3; n--) {
237 putback(rquote);
238 pbstr(argv[n]);
239 putback(lquote);
240 putback(',');
241 }
242 putback(rquote);
243 pbstr(argv[3]);
244 putback(lquote);
245 }
246 break;
247
248 case DIVRTYPE:
249 if (argc > 2 && (n = atoi(argv[2])) != 0)
250 dodiv(n);
251 else {
252 active = stdout;
253 oindex = 0;
254 }
255 break;
256
257 case UNDVTYPE:
258 doundiv(argv, argc);
259 break;
260
261 case DIVNTYPE:
262 /*
263 * dodivnum - return the number of
264 * current output diversion
265 */
266 pbnum(oindex);
267 break;
268
269 case UNDFTYPE:
270 /*
271 * doundefine - undefine a previously
272 * defined macro(s) or m4 keyword(s).
273 */
274 if (argc > 2)
275 for (n = 2; n < argc; n++)
276 remhash(argv[n], ALL);
277 break;
278
279 case POPDTYPE:
280 /*
281 * dopopdef - remove the topmost
282 * definitions of macro(s) or m4
283 * keyword(s).
284 */
285 if (argc > 2)
286 for (n = 2; n < argc; n++)
287 remhash(argv[n], TOP);
288 break;
289
290 case MKTMTYPE:
291 /*
292 * dotemp - create a temporary file
293 */
294 if (argc > 2)
295 pbstr(mktemp(argv[2]));
296 break;
297
298 case TRNLTYPE:
299 /*
300 * dotranslit - replace all characters in
301 * the source string that appears in the
302 * "from" string with the corresponding
303 * characters in the "to" string.
304 */
305 if (argc > 3) {
306 char temp[MAXTOK];
307 if (argc > 4)
308 map(temp, argv[2], argv[3], argv[4]);
309 else
310 map(temp, argv[2], argv[3], null);
311 pbstr(temp);
312 }
313 else if (argc > 2)
314 pbstr(argv[2]);
315 break;
316
317 case INDXTYPE:
318 /*
319 * doindex - find the index of the second
320 * argument string in the first argument
321 * string. -1 if not present.
322 */
323 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
324 break;
325
326 case ERRPTYPE:
327 /*
328 * doerrp - print the arguments to stderr
329 * file
330 */
331 if (argc > 2) {
332 for (n = 2; n < argc; n++)
333 fprintf(stderr, "%s ", argv[n]);
334 fprintf(stderr, "\n");
335 }
336 break;
337
338 case DNLNTYPE:
339 /*
340 * dodnl - eat-up-to and including
341 * newline
342 */
343 while ((c = gpbc()) != '\n' && c != EOF)
344 ;
345 break;
346
347 case M4WRTYPE:
348 /*
349 * dom4wrap - set up for
350 * wrap-up/wind-down activity
351 */
352 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
353 break;
354
355 case EXITTYPE:
356 /*
357 * doexit - immediate exit from m4.
358 */
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Ozan Yigit at York University.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char sccsid[] = "@(#)eval.c 8.1 (Berkeley) 6/6/93";
39#endif /* not lint */
40
41/*
42 * eval.c
43 * Facility: m4 macro processor
44 * by: oz
45 */
46
47#include <sys/types.h>
48#include <errno.h>
49#include <unistd.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include "mdef.h"
54#include "stdd.h"
55#include "extern.h"
56#include "pathnames.h"
57
58/*
59 * eval - evaluate built-in macros.
60 * argc - number of elements in argv.
61 * argv - element vector :
62 * argv[0] = definition of a user
63 * macro or nil if built-in.
64 * argv[1] = name of the macro or
65 * built-in.
66 * argv[2] = parameters to user-defined
67 * . macro or built-in.
68 * .
69 *
70 * Note that the minimum value for argc is 3. A call in the form
71 * of macro-or-builtin() will result in:
72 * argv[0] = nullstr
73 * argv[1] = macro-or-builtin
74 * argv[2] = nullstr
75 */
76
77void
78eval(argv, argc, td)
79register char *argv[];
80register int argc;
81register int td;
82{
83 register int c, n;
84 static int sysval = 0;
85
86#ifdef DEBUG
87 printf("argc = %d\n", argc);
88 for (n = 0; n < argc; n++)
89 printf("argv[%d] = %s\n", n, argv[n]);
90#endif
91 /*
92 * if argc == 3 and argv[2] is null, then we
93 * have macro-or-builtin() type call. We adjust
94 * argc to avoid further checking..
95 */
96 if (argc == 3 && !*(argv[2]))
97 argc--;
98
99 switch (td & ~STATIC) {
100
101 case DEFITYPE:
102 if (argc > 2)
103 dodefine(argv[2], (argc > 3) ? argv[3] : null);
104 break;
105
106 case PUSDTYPE:
107 if (argc > 2)
108 dopushdef(argv[2], (argc > 3) ? argv[3] : null);
109 break;
110
111 case DUMPTYPE:
112 dodump(argv, argc);
113 break;
114
115 case EXPRTYPE:
116 /*
117 * doexpr - evaluate arithmetic
118 * expression
119 */
120 if (argc > 2)
121 pbnum(expr(argv[2]));
122 break;
123
124 case IFELTYPE:
125 if (argc > 4)
126 doifelse(argv, argc);
127 break;
128
129 case IFDFTYPE:
130 /*
131 * doifdef - select one of two
132 * alternatives based on the existence of
133 * another definition
134 */
135 if (argc > 3) {
136 if (lookup(argv[2]) != nil)
137 pbstr(argv[3]);
138 else if (argc > 4)
139 pbstr(argv[4]);
140 }
141 break;
142
143 case LENGTYPE:
144 /*
145 * dolen - find the length of the
146 * argument
147 */
148 if (argc > 2)
149 pbnum((argc > 2) ? strlen(argv[2]) : 0);
150 break;
151
152 case INCRTYPE:
153 /*
154 * doincr - increment the value of the
155 * argument
156 */
157 if (argc > 2)
158 pbnum(atoi(argv[2]) + 1);
159 break;
160
161 case DECRTYPE:
162 /*
163 * dodecr - decrement the value of the
164 * argument
165 */
166 if (argc > 2)
167 pbnum(atoi(argv[2]) - 1);
168 break;
169
170 case SYSCTYPE:
171 /*
172 * dosys - execute system command
173 */
174 /* Make sure m4 output is NOT interrupted */
175 fflush(stdout);
176 fflush(stderr);
177 if (argc > 2)
178 sysval = system(argv[2]);
179 break;
180
181 case SYSVTYPE:
182 /*
183 * dosysval - return value of the last
184 * system call.
185 *
186 */
187 pbnum(sysval);
188 break;
189
190 case INCLTYPE:
191 if (argc > 2)
192 if (!doincl(argv[2]))
193 oops("%s: %s", argv[2], strerror(errno));
194 break;
195
196 case SINCTYPE:
197 if (argc > 2)
198 (void) doincl(argv[2]);
199 break;
200#ifdef EXTENDED
201 case PASTTYPE:
202 if (argc > 2)
203 if (!dopaste(argv[2]))
204 oops("%s: %s", argv[2], strerror(errno));
205 break;
206
207 case SPASTYPE:
208 if (argc > 2)
209 (void) dopaste(argv[2]);
210 break;
211#endif
212 case CHNQTYPE:
213 dochq(argv, argc);
214 break;
215
216 case CHNCTYPE:
217 dochc(argv, argc);
218 break;
219
220 case SUBSTYPE:
221 /*
222 * dosub - select substring
223 *
224 */
225 if (argc > 3)
226 dosub(argv, argc);
227 break;
228
229 case SHIFTYPE:
230 /*
231 * doshift - push back all arguments
232 * except the first one (i.e. skip
233 * argv[2])
234 */
235 if (argc > 3) {
236 for (n = argc - 1; n > 3; n--) {
237 putback(rquote);
238 pbstr(argv[n]);
239 putback(lquote);
240 putback(',');
241 }
242 putback(rquote);
243 pbstr(argv[3]);
244 putback(lquote);
245 }
246 break;
247
248 case DIVRTYPE:
249 if (argc > 2 && (n = atoi(argv[2])) != 0)
250 dodiv(n);
251 else {
252 active = stdout;
253 oindex = 0;
254 }
255 break;
256
257 case UNDVTYPE:
258 doundiv(argv, argc);
259 break;
260
261 case DIVNTYPE:
262 /*
263 * dodivnum - return the number of
264 * current output diversion
265 */
266 pbnum(oindex);
267 break;
268
269 case UNDFTYPE:
270 /*
271 * doundefine - undefine a previously
272 * defined macro(s) or m4 keyword(s).
273 */
274 if (argc > 2)
275 for (n = 2; n < argc; n++)
276 remhash(argv[n], ALL);
277 break;
278
279 case POPDTYPE:
280 /*
281 * dopopdef - remove the topmost
282 * definitions of macro(s) or m4
283 * keyword(s).
284 */
285 if (argc > 2)
286 for (n = 2; n < argc; n++)
287 remhash(argv[n], TOP);
288 break;
289
290 case MKTMTYPE:
291 /*
292 * dotemp - create a temporary file
293 */
294 if (argc > 2)
295 pbstr(mktemp(argv[2]));
296 break;
297
298 case TRNLTYPE:
299 /*
300 * dotranslit - replace all characters in
301 * the source string that appears in the
302 * "from" string with the corresponding
303 * characters in the "to" string.
304 */
305 if (argc > 3) {
306 char temp[MAXTOK];
307 if (argc > 4)
308 map(temp, argv[2], argv[3], argv[4]);
309 else
310 map(temp, argv[2], argv[3], null);
311 pbstr(temp);
312 }
313 else if (argc > 2)
314 pbstr(argv[2]);
315 break;
316
317 case INDXTYPE:
318 /*
319 * doindex - find the index of the second
320 * argument string in the first argument
321 * string. -1 if not present.
322 */
323 pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
324 break;
325
326 case ERRPTYPE:
327 /*
328 * doerrp - print the arguments to stderr
329 * file
330 */
331 if (argc > 2) {
332 for (n = 2; n < argc; n++)
333 fprintf(stderr, "%s ", argv[n]);
334 fprintf(stderr, "\n");
335 }
336 break;
337
338 case DNLNTYPE:
339 /*
340 * dodnl - eat-up-to and including
341 * newline
342 */
343 while ((c = gpbc()) != '\n' && c != EOF)
344 ;
345 break;
346
347 case M4WRTYPE:
348 /*
349 * dom4wrap - set up for
350 * wrap-up/wind-down activity
351 */
352 m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
353 break;
354
355 case EXITTYPE:
356 /*
357 * doexit - immediate exit from m4.
358 */
359 killdiv();
359 exit((argc > 2) ? atoi(argv[2]) : 0);
360 break;
361
362 case DEFNTYPE:
363 if (argc > 2)
364 for (n = 2; n < argc; n++)
365 dodefn(argv[n]);
366 break;
367
368 default:
369 oops("%s: major botch.", "eval");
370 break;
371 }
372}
373
374char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
375
376/*
377 * expand - user-defined macro expansion
378 */
379void
380expand(argv, argc)
381register char *argv[];
382register int argc;
383{
384 register unsigned char *t;
385 register unsigned char *p;
386 register int n;
387 register int argno;
388
389 t = argv[0]; /* defn string as a whole */
390 p = t;
391 while (*p)
392 p++;
393 p--; /* last character of defn */
394 while (p > t) {
395 if (*(p - 1) != ARGFLAG)
396 putback(*p);
397 else {
398 switch (*p) {
399
400 case '#':
401 pbnum(argc - 2);
402 break;
403 case '0':
404 case '1':
405 case '2':
406 case '3':
407 case '4':
408 case '5':
409 case '6':
410 case '7':
411 case '8':
412 case '9':
413 if ((argno = *p - '0') < argc - 1)
414 pbstr(argv[argno + 1]);
415 break;
416 case '*':
417 for (n = argc - 1; n > 2; n--) {
418 pbstr(argv[n]);
419 putback(',');
420 }
421 pbstr(argv[2]);
422 break;
423 default:
424 putback(*p);
425 putback('$');
426 break;
427 }
428 p--;
429 }
430 p--;
431 }
432 if (p == t) /* do last character */
433 putback(*p);
434}
435
436/*
437 * dodefine - install definition in the table
438 */
439void
440dodefine(name, defn)
441register char *name;
442register char *defn;
443{
444 register ndptr p;
445
446 if (!*name)
447 oops("null definition.");
448 if (STREQ(name, defn))
449 oops("%s: recursive definition.", name);
450 if ((p = lookup(name)) == nil)
451 p = addent(name);
452 else if (p->defn != null)
453 free((char *) p->defn);
454 if (!*defn)
455 p->defn = null;
456 else
457 p->defn = xstrdup(defn);
458 p->type = MACRTYPE;
459}
460
461/*
462 * dodefn - push back a quoted definition of
463 * the given name.
464 */
465void
466dodefn(name)
467char *name;
468{
469 register ndptr p;
470
471 if ((p = lookup(name)) != nil && p->defn != null) {
472 putback(rquote);
473 pbstr(p->defn);
474 putback(lquote);
475 }
476}
477
478/*
479 * dopushdef - install a definition in the hash table
480 * without removing a previous definition. Since
481 * each new entry is entered in *front* of the
482 * hash bucket, it hides a previous definition from
483 * lookup.
484 */
485void
486dopushdef(name, defn)
487register char *name;
488register char *defn;
489{
490 register ndptr p;
491
492 if (!*name)
493 oops("null definition");
494 if (STREQ(name, defn))
495 oops("%s: recursive definition.", name);
496 p = addent(name);
497 if (!*defn)
498 p->defn = null;
499 else
500 p->defn = xstrdup(defn);
501 p->type = MACRTYPE;
502}
503
504/*
505 * dodumpdef - dump the specified definitions in the hash
506 * table to stderr. If nothing is specified, the entire
507 * hash table is dumped.
508 */
509void
510dodump(argv, argc)
511register char *argv[];
512register int argc;
513{
514 register int n;
515 ndptr p;
516
517 if (argc > 2) {
518 for (n = 2; n < argc; n++)
519 if ((p = lookup(argv[n])) != nil)
520 fprintf(stderr, dumpfmt, p->name,
521 p->defn);
522 }
523 else {
524 for (n = 0; n < HASHSIZE; n++)
525 for (p = hashtab[n]; p != nil; p = p->nxtptr)
526 fprintf(stderr, dumpfmt, p->name,
527 p->defn);
528 }
529}
530
531/*
532 * doifelse - select one of two alternatives - loop.
533 */
534void
535doifelse(argv, argc)
536register char *argv[];
537register int argc;
538{
539 cycle {
540 if (STREQ(argv[2], argv[3]))
541 pbstr(argv[4]);
542 else if (argc == 6)
543 pbstr(argv[5]);
544 else if (argc > 6) {
545 argv += 3;
546 argc -= 3;
547 continue;
548 }
549 break;
550 }
551}
552
553/*
554 * doinclude - include a given file.
555 */
556int
557doincl(ifile)
558char *ifile;
559{
560 if (ilevel + 1 == MAXINP)
561 oops("too many include files.");
562 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
563 ilevel++;
564 bbase[ilevel] = bufbase = bp;
565 return (1);
566 }
567 else
568 return (0);
569}
570
571#ifdef EXTENDED
572/*
573 * dopaste - include a given file without any
574 * macro processing.
575 */
576int
577dopaste(pfile)
578char *pfile;
579{
580 FILE *pf;
581 register int c;
582
583 if ((pf = fopen(pfile, "r")) != NULL) {
584 while ((c = getc(pf)) != EOF)
585 putc(c, active);
586 (void) fclose(pf);
587 return (1);
588 }
589 else
590 return (0);
591}
592#endif
593
594/*
595 * dochq - change quote characters
596 */
597void
598dochq(argv, argc)
599register char *argv[];
600register int argc;
601{
602 if (argc > 2) {
603 if (*argv[2])
604 lquote = *argv[2];
605 if (argc > 3) {
606 if (*argv[3])
607 rquote = *argv[3];
608 }
609 else
610 rquote = lquote;
611 }
612 else {
613 lquote = LQUOTE;
614 rquote = RQUOTE;
615 }
616}
617
618/*
619 * dochc - change comment characters
620 */
621void
622dochc(argv, argc)
623register char *argv[];
624register int argc;
625{
626 if (argc > 2) {
627 if (*argv[2])
628 scommt = *argv[2];
629 if (argc > 3) {
630 if (*argv[3])
631 ecommt = *argv[3];
632 }
633 else
634 ecommt = ECOMMT;
635 }
636 else {
637 scommt = SCOMMT;
638 ecommt = ECOMMT;
639 }
640}
641
642/*
643 * dodivert - divert the output to a temporary file
644 */
645void
646dodiv(n)
647register int n;
648{
649 if (n < 0 || n >= MAXOUT)
650 n = 0; /* bitbucket */
651 if (outfile[n] == NULL) {
652 m4temp[UNIQUE] = n + '0';
653 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
654 oops("%s: cannot divert.", m4temp);
655 }
656 oindex = n;
657 active = outfile[n];
658}
659
660/*
661 * doundivert - undivert a specified output, or all
662 * other outputs, in numerical order.
663 */
664void
665doundiv(argv, argc)
666register char *argv[];
667register int argc;
668{
669 register int ind;
670 register int n;
671
672 if (argc > 2) {
673 for (ind = 2; ind < argc; ind++) {
674 n = atoi(argv[ind]);
675 if (n > 0 && n < MAXOUT && outfile[n] != NULL)
676 getdiv(n);
677
678 }
679 }
680 else
681 for (n = 1; n < MAXOUT; n++)
682 if (outfile[n] != NULL)
683 getdiv(n);
684}
685
686/*
687 * dosub - select substring
688 */
689void
690dosub(argv, argc)
691register char *argv[];
692register int argc;
693{
694 register unsigned char *ap, *fc, *k;
695 register int nc;
696
697 if (argc < 5)
698 nc = MAXTOK;
699 else
700#ifdef EXPR
701 nc = expr(argv[4]);
702#else
703 nc = atoi(argv[4]);
704#endif
705 ap = argv[2]; /* target string */
706#ifdef EXPR
707 fc = ap + expr(argv[3]); /* first char */
708#else
709 fc = ap + atoi(argv[3]); /* first char */
710#endif
711 if (fc >= ap && fc < ap + strlen(ap))
712 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
713 putback(*k);
714}
715
716/*
717 * map:
718 * map every character of s1 that is specified in from
719 * into s3 and replace in s. (source s1 remains untouched)
720 *
721 * This is a standard implementation of map(s,from,to) function of ICON
722 * language. Within mapvec, we replace every character of "from" with
723 * the corresponding character in "to". If "to" is shorter than "from",
724 * than the corresponding entries are null, which means that those
725 * characters dissapear altogether. Furthermore, imagine
726 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
727 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
728 * ultimately maps to `*'. In order to achieve this effect in an efficient
729 * manner (i.e. without multiple passes over the destination string), we
730 * loop over mapvec, starting with the initial source character. if the
731 * character value (dch) in this location is different than the source
732 * character (sch), sch becomes dch, once again to index into mapvec, until
733 * the character value stabilizes (i.e. sch = dch, in other words
734 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
735 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
736 * end, we restore mapvec* back to normal where mapvec[n] == n for
737 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
738 * about 5 times faster than any algorithm that makes multiple passes over
739 * destination string.
740 */
741void
742map(dest, src, from, to)
743register char *dest;
744register char *src;
745register char *from;
746register char *to;
747{
748 register char *tmp;
749 register char sch, dch;
750 static char mapvec[128] = {
751 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
752 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
753 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
754 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
755 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
756 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
757 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
758 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
759 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
760 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
761 120, 121, 122, 123, 124, 125, 126, 127
762 };
763
764 if (*src) {
765 tmp = from;
766 /*
767 * create a mapping between "from" and
768 * "to"
769 */
770 while (*from)
771 mapvec[*from++] = (*to) ? *to++ : (char) 0;
772
773 while (*src) {
774 sch = *src++;
775 dch = mapvec[sch];
776 while (dch != sch) {
777 sch = dch;
778 dch = mapvec[sch];
779 }
780 if (*dest = dch)
781 dest++;
782 }
783 /*
784 * restore all the changed characters
785 */
786 while (*tmp) {
787 mapvec[*tmp] = *tmp;
788 tmp++;
789 }
790 }
791 *dest = (char) 0;
792}
360 exit((argc > 2) ? atoi(argv[2]) : 0);
361 break;
362
363 case DEFNTYPE:
364 if (argc > 2)
365 for (n = 2; n < argc; n++)
366 dodefn(argv[n]);
367 break;
368
369 default:
370 oops("%s: major botch.", "eval");
371 break;
372 }
373}
374
375char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
376
377/*
378 * expand - user-defined macro expansion
379 */
380void
381expand(argv, argc)
382register char *argv[];
383register int argc;
384{
385 register unsigned char *t;
386 register unsigned char *p;
387 register int n;
388 register int argno;
389
390 t = argv[0]; /* defn string as a whole */
391 p = t;
392 while (*p)
393 p++;
394 p--; /* last character of defn */
395 while (p > t) {
396 if (*(p - 1) != ARGFLAG)
397 putback(*p);
398 else {
399 switch (*p) {
400
401 case '#':
402 pbnum(argc - 2);
403 break;
404 case '0':
405 case '1':
406 case '2':
407 case '3':
408 case '4':
409 case '5':
410 case '6':
411 case '7':
412 case '8':
413 case '9':
414 if ((argno = *p - '0') < argc - 1)
415 pbstr(argv[argno + 1]);
416 break;
417 case '*':
418 for (n = argc - 1; n > 2; n--) {
419 pbstr(argv[n]);
420 putback(',');
421 }
422 pbstr(argv[2]);
423 break;
424 default:
425 putback(*p);
426 putback('$');
427 break;
428 }
429 p--;
430 }
431 p--;
432 }
433 if (p == t) /* do last character */
434 putback(*p);
435}
436
437/*
438 * dodefine - install definition in the table
439 */
440void
441dodefine(name, defn)
442register char *name;
443register char *defn;
444{
445 register ndptr p;
446
447 if (!*name)
448 oops("null definition.");
449 if (STREQ(name, defn))
450 oops("%s: recursive definition.", name);
451 if ((p = lookup(name)) == nil)
452 p = addent(name);
453 else if (p->defn != null)
454 free((char *) p->defn);
455 if (!*defn)
456 p->defn = null;
457 else
458 p->defn = xstrdup(defn);
459 p->type = MACRTYPE;
460}
461
462/*
463 * dodefn - push back a quoted definition of
464 * the given name.
465 */
466void
467dodefn(name)
468char *name;
469{
470 register ndptr p;
471
472 if ((p = lookup(name)) != nil && p->defn != null) {
473 putback(rquote);
474 pbstr(p->defn);
475 putback(lquote);
476 }
477}
478
479/*
480 * dopushdef - install a definition in the hash table
481 * without removing a previous definition. Since
482 * each new entry is entered in *front* of the
483 * hash bucket, it hides a previous definition from
484 * lookup.
485 */
486void
487dopushdef(name, defn)
488register char *name;
489register char *defn;
490{
491 register ndptr p;
492
493 if (!*name)
494 oops("null definition");
495 if (STREQ(name, defn))
496 oops("%s: recursive definition.", name);
497 p = addent(name);
498 if (!*defn)
499 p->defn = null;
500 else
501 p->defn = xstrdup(defn);
502 p->type = MACRTYPE;
503}
504
505/*
506 * dodumpdef - dump the specified definitions in the hash
507 * table to stderr. If nothing is specified, the entire
508 * hash table is dumped.
509 */
510void
511dodump(argv, argc)
512register char *argv[];
513register int argc;
514{
515 register int n;
516 ndptr p;
517
518 if (argc > 2) {
519 for (n = 2; n < argc; n++)
520 if ((p = lookup(argv[n])) != nil)
521 fprintf(stderr, dumpfmt, p->name,
522 p->defn);
523 }
524 else {
525 for (n = 0; n < HASHSIZE; n++)
526 for (p = hashtab[n]; p != nil; p = p->nxtptr)
527 fprintf(stderr, dumpfmt, p->name,
528 p->defn);
529 }
530}
531
532/*
533 * doifelse - select one of two alternatives - loop.
534 */
535void
536doifelse(argv, argc)
537register char *argv[];
538register int argc;
539{
540 cycle {
541 if (STREQ(argv[2], argv[3]))
542 pbstr(argv[4]);
543 else if (argc == 6)
544 pbstr(argv[5]);
545 else if (argc > 6) {
546 argv += 3;
547 argc -= 3;
548 continue;
549 }
550 break;
551 }
552}
553
554/*
555 * doinclude - include a given file.
556 */
557int
558doincl(ifile)
559char *ifile;
560{
561 if (ilevel + 1 == MAXINP)
562 oops("too many include files.");
563 if ((infile[ilevel + 1] = fopen(ifile, "r")) != NULL) {
564 ilevel++;
565 bbase[ilevel] = bufbase = bp;
566 return (1);
567 }
568 else
569 return (0);
570}
571
572#ifdef EXTENDED
573/*
574 * dopaste - include a given file without any
575 * macro processing.
576 */
577int
578dopaste(pfile)
579char *pfile;
580{
581 FILE *pf;
582 register int c;
583
584 if ((pf = fopen(pfile, "r")) != NULL) {
585 while ((c = getc(pf)) != EOF)
586 putc(c, active);
587 (void) fclose(pf);
588 return (1);
589 }
590 else
591 return (0);
592}
593#endif
594
595/*
596 * dochq - change quote characters
597 */
598void
599dochq(argv, argc)
600register char *argv[];
601register int argc;
602{
603 if (argc > 2) {
604 if (*argv[2])
605 lquote = *argv[2];
606 if (argc > 3) {
607 if (*argv[3])
608 rquote = *argv[3];
609 }
610 else
611 rquote = lquote;
612 }
613 else {
614 lquote = LQUOTE;
615 rquote = RQUOTE;
616 }
617}
618
619/*
620 * dochc - change comment characters
621 */
622void
623dochc(argv, argc)
624register char *argv[];
625register int argc;
626{
627 if (argc > 2) {
628 if (*argv[2])
629 scommt = *argv[2];
630 if (argc > 3) {
631 if (*argv[3])
632 ecommt = *argv[3];
633 }
634 else
635 ecommt = ECOMMT;
636 }
637 else {
638 scommt = SCOMMT;
639 ecommt = ECOMMT;
640 }
641}
642
643/*
644 * dodivert - divert the output to a temporary file
645 */
646void
647dodiv(n)
648register int n;
649{
650 if (n < 0 || n >= MAXOUT)
651 n = 0; /* bitbucket */
652 if (outfile[n] == NULL) {
653 m4temp[UNIQUE] = n + '0';
654 if ((outfile[n] = fopen(m4temp, "w")) == NULL)
655 oops("%s: cannot divert.", m4temp);
656 }
657 oindex = n;
658 active = outfile[n];
659}
660
661/*
662 * doundivert - undivert a specified output, or all
663 * other outputs, in numerical order.
664 */
665void
666doundiv(argv, argc)
667register char *argv[];
668register int argc;
669{
670 register int ind;
671 register int n;
672
673 if (argc > 2) {
674 for (ind = 2; ind < argc; ind++) {
675 n = atoi(argv[ind]);
676 if (n > 0 && n < MAXOUT && outfile[n] != NULL)
677 getdiv(n);
678
679 }
680 }
681 else
682 for (n = 1; n < MAXOUT; n++)
683 if (outfile[n] != NULL)
684 getdiv(n);
685}
686
687/*
688 * dosub - select substring
689 */
690void
691dosub(argv, argc)
692register char *argv[];
693register int argc;
694{
695 register unsigned char *ap, *fc, *k;
696 register int nc;
697
698 if (argc < 5)
699 nc = MAXTOK;
700 else
701#ifdef EXPR
702 nc = expr(argv[4]);
703#else
704 nc = atoi(argv[4]);
705#endif
706 ap = argv[2]; /* target string */
707#ifdef EXPR
708 fc = ap + expr(argv[3]); /* first char */
709#else
710 fc = ap + atoi(argv[3]); /* first char */
711#endif
712 if (fc >= ap && fc < ap + strlen(ap))
713 for (k = fc + min(nc, strlen(fc)) - 1; k >= fc; k--)
714 putback(*k);
715}
716
717/*
718 * map:
719 * map every character of s1 that is specified in from
720 * into s3 and replace in s. (source s1 remains untouched)
721 *
722 * This is a standard implementation of map(s,from,to) function of ICON
723 * language. Within mapvec, we replace every character of "from" with
724 * the corresponding character in "to". If "to" is shorter than "from",
725 * than the corresponding entries are null, which means that those
726 * characters dissapear altogether. Furthermore, imagine
727 * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
728 * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
729 * ultimately maps to `*'. In order to achieve this effect in an efficient
730 * manner (i.e. without multiple passes over the destination string), we
731 * loop over mapvec, starting with the initial source character. if the
732 * character value (dch) in this location is different than the source
733 * character (sch), sch becomes dch, once again to index into mapvec, until
734 * the character value stabilizes (i.e. sch = dch, in other words
735 * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
736 * character, it will stabilize, since mapvec[0] == 0 at all times. At the
737 * end, we restore mapvec* back to normal where mapvec[n] == n for
738 * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
739 * about 5 times faster than any algorithm that makes multiple passes over
740 * destination string.
741 */
742void
743map(dest, src, from, to)
744register char *dest;
745register char *src;
746register char *from;
747register char *to;
748{
749 register char *tmp;
750 register char sch, dch;
751 static char mapvec[128] = {
752 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
753 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
754 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
755 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
756 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
757 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
758 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
759 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
760 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
761 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
762 120, 121, 122, 123, 124, 125, 126, 127
763 };
764
765 if (*src) {
766 tmp = from;
767 /*
768 * create a mapping between "from" and
769 * "to"
770 */
771 while (*from)
772 mapvec[*from++] = (*to) ? *to++ : (char) 0;
773
774 while (*src) {
775 sch = *src++;
776 dch = mapvec[sch];
777 while (dch != sch) {
778 sch = dch;
779 dch = mapvec[sch];
780 }
781 if (*dest = dch)
782 dest++;
783 }
784 /*
785 * restore all the changed characters
786 */
787 while (*tmp) {
788 mapvec[*tmp] = *tmp;
789 tmp++;
790 }
791 }
792 *dest = (char) 0;
793}