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