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