eval.c revision 1.17 1 1.17 agc /* $NetBSD: eval.c,v 1.17 2003/08/07 11:14:30 agc Exp $ */
2 1.14 tv /* $OpenBSD: eval.c,v 1.41 2001/10/10 23:25:31 espie Exp $ */
3 1.4 tls
4 1.1 cgd /*
5 1.2 glass * Copyright (c) 1989, 1993
6 1.2 glass * The Regents of the University of California. All rights reserved.
7 1.1 cgd *
8 1.1 cgd * This code is derived from software contributed to Berkeley by
9 1.2 glass * Ozan Yigit at York University.
10 1.1 cgd *
11 1.1 cgd * Redistribution and use in source and binary forms, with or without
12 1.1 cgd * modification, are permitted provided that the following conditions
13 1.1 cgd * are met:
14 1.1 cgd * 1. Redistributions of source code must retain the above copyright
15 1.1 cgd * notice, this list of conditions and the following disclaimer.
16 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 cgd * notice, this list of conditions and the following disclaimer in the
18 1.1 cgd * documentation and/or other materials provided with the distribution.
19 1.17 agc * 3. Neither the name of the University nor the names of its contributors
20 1.1 cgd * may be used to endorse or promote products derived from this software
21 1.1 cgd * without specific prior written permission.
22 1.1 cgd *
23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 cgd * SUCH DAMAGE.
34 1.1 cgd */
35 1.1 cgd
36 1.10 lukem #include <sys/cdefs.h>
37 1.16 tv #if defined(__RCSID) && !defined(lint)
38 1.4 tls #if 0
39 1.4 tls static char sccsid[] = "@(#)eval.c 8.2 (Berkeley) 4/27/95";
40 1.4 tls #else
41 1.17 agc __RCSID("$NetBSD: eval.c,v 1.17 2003/08/07 11:14:30 agc Exp $");
42 1.4 tls #endif
43 1.1 cgd #endif /* not lint */
44 1.1 cgd
45 1.1 cgd /*
46 1.1 cgd * eval.c
47 1.1 cgd * Facility: m4 macro processor
48 1.1 cgd * by: oz
49 1.1 cgd */
50 1.1 cgd
51 1.2 glass #include <sys/types.h>
52 1.2 glass #include <errno.h>
53 1.14 tv #include <fcntl.h>
54 1.1 cgd #include <stdio.h>
55 1.1 cgd #include <stdlib.h>
56 1.14 tv #include <stddef.h>
57 1.1 cgd #include <string.h>
58 1.1 cgd #include "mdef.h"
59 1.2 glass #include "stdd.h"
60 1.2 glass #include "extern.h"
61 1.2 glass #include "pathnames.h"
62 1.1 cgd
63 1.14 tv #define BUILTIN_MARKER "__builtin_"
64 1.14 tv
65 1.14 tv static void dodefn __P((const char *));
66 1.14 tv static void dopushdef __P((const char *, const char *));
67 1.14 tv static void dodump __P((const char *[], int));
68 1.14 tv static void dotrace __P((const char *[], int, int));
69 1.14 tv static void doifelse __P((const char *[], int));
70 1.14 tv static int doincl __P((const char *));
71 1.14 tv static int dopaste __P((const char *));
72 1.14 tv static void gnu_dochq __P((const char *[], int));
73 1.14 tv static void dochq __P((const char *[], int));
74 1.14 tv static void gnu_dochc __P((const char *[], int));
75 1.14 tv static void dochc __P((const char *[], int));
76 1.14 tv static void dodiv __P((int));
77 1.14 tv static void doundiv __P((const char *[], int));
78 1.14 tv static void dosub __P((const char *[], int));
79 1.14 tv static void map __P((char *, const char *, const char *, const char *));
80 1.14 tv static const char *handledash __P((char *, char *, const char *));
81 1.14 tv static void expand_builtin __P((const char *[], int, int));
82 1.14 tv static void expand_macro __P((const char *[], int));
83 1.14 tv static void dump_one_def __P((ndptr));
84 1.14 tv
85 1.14 tv unsigned long expansion_id;
86 1.14 tv
87 1.1 cgd /*
88 1.14 tv * eval - eval all macros and builtins calls
89 1.1 cgd * argc - number of elements in argv.
90 1.1 cgd * argv - element vector :
91 1.1 cgd * argv[0] = definition of a user
92 1.1 cgd * macro or nil if built-in.
93 1.1 cgd * argv[1] = name of the macro or
94 1.1 cgd * built-in.
95 1.1 cgd * argv[2] = parameters to user-defined
96 1.1 cgd * . macro or built-in.
97 1.1 cgd * .
98 1.1 cgd *
99 1.14 tv * A call in the form of macro-or-builtin() will result in:
100 1.1 cgd * argv[0] = nullstr
101 1.1 cgd * argv[1] = macro-or-builtin
102 1.1 cgd * argv[2] = nullstr
103 1.14 tv *
104 1.14 tv * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin
105 1.1 cgd */
106 1.14 tv void
107 1.14 tv eval(argv, argc, td)
108 1.14 tv const char *argv[];
109 1.14 tv int argc;
110 1.14 tv int td;
111 1.14 tv {
112 1.14 tv ssize_t mark = -1;
113 1.1 cgd
114 1.14 tv expansion_id++;
115 1.14 tv if (td & RECDEF)
116 1.14 tv errx(1, "%s at line %lu: expanding recursive definition for %s",
117 1.14 tv CURRENT_NAME, CURRENT_LINE, argv[1]);
118 1.14 tv if (traced_macros && is_traced(argv[1]))
119 1.14 tv mark = trace(argv, argc, infile+ilevel);
120 1.14 tv if (td == MACRTYPE)
121 1.14 tv expand_macro(argv, argc);
122 1.14 tv else
123 1.14 tv expand_builtin(argv, argc, td);
124 1.14 tv if (mark != -1)
125 1.14 tv finish_trace(mark);
126 1.14 tv }
127 1.14 tv
128 1.14 tv /*
129 1.14 tv * expand_builtin - evaluate built-in macros.
130 1.14 tv */
131 1.2 glass void
132 1.14 tv expand_builtin(argv, argc, td)
133 1.14 tv const char *argv[];
134 1.10 lukem int argc;
135 1.10 lukem int td;
136 1.1 cgd {
137 1.10 lukem int c, n;
138 1.14 tv int ac;
139 1.2 glass static int sysval = 0;
140 1.1 cgd
141 1.1 cgd #ifdef DEBUG
142 1.1 cgd printf("argc = %d\n", argc);
143 1.1 cgd for (n = 0; n < argc; n++)
144 1.1 cgd printf("argv[%d] = %s\n", n, argv[n]);
145 1.1 cgd #endif
146 1.14 tv
147 1.2 glass /*
148 1.2 glass * if argc == 3 and argv[2] is null, then we
149 1.2 glass * have macro-or-builtin() type call. We adjust
150 1.2 glass * argc to avoid further checking..
151 1.2 glass */
152 1.14 tv ac = argc;
153 1.14 tv
154 1.1 cgd if (argc == 3 && !*(argv[2]))
155 1.1 cgd argc--;
156 1.1 cgd
157 1.14 tv switch (td & TYPEMASK) {
158 1.1 cgd
159 1.1 cgd case DEFITYPE:
160 1.1 cgd if (argc > 2)
161 1.1 cgd dodefine(argv[2], (argc > 3) ? argv[3] : null);
162 1.1 cgd break;
163 1.1 cgd
164 1.1 cgd case PUSDTYPE:
165 1.1 cgd if (argc > 2)
166 1.1 cgd dopushdef(argv[2], (argc > 3) ? argv[3] : null);
167 1.1 cgd break;
168 1.1 cgd
169 1.1 cgd case DUMPTYPE:
170 1.1 cgd dodump(argv, argc);
171 1.1 cgd break;
172 1.1 cgd
173 1.14 tv case TRACEONTYPE:
174 1.14 tv dotrace(argv, argc, 1);
175 1.14 tv break;
176 1.14 tv
177 1.14 tv case TRACEOFFTYPE:
178 1.14 tv dotrace(argv, argc, 0);
179 1.14 tv break;
180 1.14 tv
181 1.1 cgd case EXPRTYPE:
182 1.2 glass /*
183 1.2 glass * doexpr - evaluate arithmetic
184 1.2 glass * expression
185 1.2 glass */
186 1.1 cgd if (argc > 2)
187 1.1 cgd pbnum(expr(argv[2]));
188 1.1 cgd break;
189 1.1 cgd
190 1.1 cgd case IFELTYPE:
191 1.1 cgd if (argc > 4)
192 1.1 cgd doifelse(argv, argc);
193 1.1 cgd break;
194 1.1 cgd
195 1.1 cgd case IFDFTYPE:
196 1.2 glass /*
197 1.2 glass * doifdef - select one of two
198 1.2 glass * alternatives based on the existence of
199 1.2 glass * another definition
200 1.2 glass */
201 1.1 cgd if (argc > 3) {
202 1.1 cgd if (lookup(argv[2]) != nil)
203 1.1 cgd pbstr(argv[3]);
204 1.1 cgd else if (argc > 4)
205 1.1 cgd pbstr(argv[4]);
206 1.1 cgd }
207 1.1 cgd break;
208 1.1 cgd
209 1.1 cgd case LENGTYPE:
210 1.2 glass /*
211 1.2 glass * dolen - find the length of the
212 1.2 glass * argument
213 1.2 glass */
214 1.14 tv pbnum((argc > 2) ? strlen(argv[2]) : 0);
215 1.1 cgd break;
216 1.1 cgd
217 1.1 cgd case INCRTYPE:
218 1.2 glass /*
219 1.2 glass * doincr - increment the value of the
220 1.2 glass * argument
221 1.2 glass */
222 1.1 cgd if (argc > 2)
223 1.1 cgd pbnum(atoi(argv[2]) + 1);
224 1.1 cgd break;
225 1.1 cgd
226 1.1 cgd case DECRTYPE:
227 1.2 glass /*
228 1.2 glass * dodecr - decrement the value of the
229 1.2 glass * argument
230 1.2 glass */
231 1.1 cgd if (argc > 2)
232 1.1 cgd pbnum(atoi(argv[2]) - 1);
233 1.1 cgd break;
234 1.1 cgd
235 1.1 cgd case SYSCTYPE:
236 1.2 glass /*
237 1.2 glass * dosys - execute system command
238 1.2 glass */
239 1.1 cgd if (argc > 2)
240 1.1 cgd sysval = system(argv[2]);
241 1.1 cgd break;
242 1.1 cgd
243 1.1 cgd case SYSVTYPE:
244 1.2 glass /*
245 1.2 glass * dosysval - return value of the last
246 1.2 glass * system call.
247 1.2 glass *
248 1.2 glass */
249 1.1 cgd pbnum(sysval);
250 1.1 cgd break;
251 1.1 cgd
252 1.14 tv case ESYSCMDTYPE:
253 1.14 tv if (argc > 2)
254 1.14 tv doesyscmd(argv[2]);
255 1.14 tv break;
256 1.1 cgd case INCLTYPE:
257 1.1 cgd if (argc > 2)
258 1.2 glass if (!doincl(argv[2]))
259 1.14 tv err(1, "%s at line %lu: include(%s)",
260 1.14 tv CURRENT_NAME, CURRENT_LINE, argv[2]);
261 1.1 cgd break;
262 1.1 cgd
263 1.1 cgd case SINCTYPE:
264 1.1 cgd if (argc > 2)
265 1.1 cgd (void) doincl(argv[2]);
266 1.1 cgd break;
267 1.1 cgd #ifdef EXTENDED
268 1.1 cgd case PASTTYPE:
269 1.1 cgd if (argc > 2)
270 1.2 glass if (!dopaste(argv[2]))
271 1.14 tv err(1, "%s at line %lu: paste(%s)",
272 1.14 tv CURRENT_NAME, CURRENT_LINE, argv[2]);
273 1.1 cgd break;
274 1.1 cgd
275 1.1 cgd case SPASTYPE:
276 1.1 cgd if (argc > 2)
277 1.1 cgd (void) dopaste(argv[2]);
278 1.1 cgd break;
279 1.1 cgd #endif
280 1.1 cgd case CHNQTYPE:
281 1.14 tv if (mimic_gnu)
282 1.14 tv gnu_dochq(argv, ac);
283 1.14 tv else
284 1.14 tv dochq(argv, argc);
285 1.1 cgd break;
286 1.1 cgd
287 1.1 cgd case CHNCTYPE:
288 1.14 tv if (mimic_gnu)
289 1.14 tv gnu_dochc(argv, ac);
290 1.14 tv else
291 1.14 tv dochc(argv, argc);
292 1.1 cgd break;
293 1.1 cgd
294 1.1 cgd case SUBSTYPE:
295 1.2 glass /*
296 1.2 glass * dosub - select substring
297 1.2 glass *
298 1.2 glass */
299 1.1 cgd if (argc > 3)
300 1.2 glass dosub(argv, argc);
301 1.1 cgd break;
302 1.1 cgd
303 1.1 cgd case SHIFTYPE:
304 1.2 glass /*
305 1.2 glass * doshift - push back all arguments
306 1.2 glass * except the first one (i.e. skip
307 1.2 glass * argv[2])
308 1.2 glass */
309 1.1 cgd if (argc > 3) {
310 1.2 glass for (n = argc - 1; n > 3; n--) {
311 1.9 cgd pbstr(rquote);
312 1.1 cgd pbstr(argv[n]);
313 1.9 cgd pbstr(lquote);
314 1.7 pk putback(COMMA);
315 1.1 cgd }
316 1.9 cgd pbstr(rquote);
317 1.1 cgd pbstr(argv[3]);
318 1.9 cgd pbstr(lquote);
319 1.1 cgd }
320 1.1 cgd break;
321 1.1 cgd
322 1.1 cgd case DIVRTYPE:
323 1.1 cgd if (argc > 2 && (n = atoi(argv[2])) != 0)
324 1.1 cgd dodiv(n);
325 1.1 cgd else {
326 1.1 cgd active = stdout;
327 1.1 cgd oindex = 0;
328 1.1 cgd }
329 1.1 cgd break;
330 1.1 cgd
331 1.1 cgd case UNDVTYPE:
332 1.1 cgd doundiv(argv, argc);
333 1.1 cgd break;
334 1.1 cgd
335 1.1 cgd case DIVNTYPE:
336 1.2 glass /*
337 1.2 glass * dodivnum - return the number of
338 1.2 glass * current output diversion
339 1.2 glass */
340 1.1 cgd pbnum(oindex);
341 1.1 cgd break;
342 1.1 cgd
343 1.1 cgd case UNDFTYPE:
344 1.2 glass /*
345 1.2 glass * doundefine - undefine a previously
346 1.2 glass * defined macro(s) or m4 keyword(s).
347 1.2 glass */
348 1.1 cgd if (argc > 2)
349 1.1 cgd for (n = 2; n < argc; n++)
350 1.1 cgd remhash(argv[n], ALL);
351 1.1 cgd break;
352 1.1 cgd
353 1.1 cgd case POPDTYPE:
354 1.2 glass /*
355 1.2 glass * dopopdef - remove the topmost
356 1.2 glass * definitions of macro(s) or m4
357 1.2 glass * keyword(s).
358 1.2 glass */
359 1.1 cgd if (argc > 2)
360 1.1 cgd for (n = 2; n < argc; n++)
361 1.1 cgd remhash(argv[n], TOP);
362 1.1 cgd break;
363 1.1 cgd
364 1.1 cgd case MKTMTYPE:
365 1.2 glass /*
366 1.2 glass * dotemp - create a temporary file
367 1.2 glass */
368 1.11 mrg if (argc > 2) {
369 1.11 mrg int fd;
370 1.14 tv char *temp;
371 1.11 mrg
372 1.14 tv temp = xstrdup(argv[2]);
373 1.14 tv
374 1.14 tv fd = mkstemp(temp);
375 1.11 mrg if (fd == -1)
376 1.14 tv err(1,
377 1.14 tv "%s at line %lu: couldn't make temp file %s",
378 1.14 tv CURRENT_NAME, CURRENT_LINE, argv[2]);
379 1.11 mrg close(fd);
380 1.14 tv pbstr(temp);
381 1.14 tv free(temp);
382 1.11 mrg }
383 1.1 cgd break;
384 1.1 cgd
385 1.1 cgd case TRNLTYPE:
386 1.2 glass /*
387 1.2 glass * dotranslit - replace all characters in
388 1.2 glass * the source string that appears in the
389 1.2 glass * "from" string with the corresponding
390 1.2 glass * characters in the "to" string.
391 1.2 glass */
392 1.1 cgd if (argc > 3) {
393 1.14 tv char temp[STRSPMAX+1];
394 1.1 cgd if (argc > 4)
395 1.1 cgd map(temp, argv[2], argv[3], argv[4]);
396 1.1 cgd else
397 1.1 cgd map(temp, argv[2], argv[3], null);
398 1.1 cgd pbstr(temp);
399 1.14 tv } else if (argc > 2)
400 1.1 cgd pbstr(argv[2]);
401 1.1 cgd break;
402 1.1 cgd
403 1.1 cgd case INDXTYPE:
404 1.2 glass /*
405 1.2 glass * doindex - find the index of the second
406 1.2 glass * argument string in the first argument
407 1.2 glass * string. -1 if not present.
408 1.2 glass */
409 1.1 cgd pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
410 1.1 cgd break;
411 1.1 cgd
412 1.1 cgd case ERRPTYPE:
413 1.2 glass /*
414 1.2 glass * doerrp - print the arguments to stderr
415 1.2 glass * file
416 1.2 glass */
417 1.1 cgd if (argc > 2) {
418 1.1 cgd for (n = 2; n < argc; n++)
419 1.2 glass fprintf(stderr, "%s ", argv[n]);
420 1.1 cgd fprintf(stderr, "\n");
421 1.1 cgd }
422 1.1 cgd break;
423 1.1 cgd
424 1.1 cgd case DNLNTYPE:
425 1.2 glass /*
426 1.2 glass * dodnl - eat-up-to and including
427 1.2 glass * newline
428 1.2 glass */
429 1.1 cgd while ((c = gpbc()) != '\n' && c != EOF)
430 1.1 cgd ;
431 1.1 cgd break;
432 1.1 cgd
433 1.1 cgd case M4WRTYPE:
434 1.2 glass /*
435 1.2 glass * dom4wrap - set up for
436 1.2 glass * wrap-up/wind-down activity
437 1.2 glass */
438 1.2 glass m4wraps = (argc > 2) ? xstrdup(argv[2]) : null;
439 1.1 cgd break;
440 1.1 cgd
441 1.1 cgd case EXITTYPE:
442 1.2 glass /*
443 1.2 glass * doexit - immediate exit from m4.
444 1.2 glass */
445 1.3 mycroft killdiv();
446 1.1 cgd exit((argc > 2) ? atoi(argv[2]) : 0);
447 1.1 cgd break;
448 1.1 cgd
449 1.1 cgd case DEFNTYPE:
450 1.1 cgd if (argc > 2)
451 1.1 cgd for (n = 2; n < argc; n++)
452 1.1 cgd dodefn(argv[n]);
453 1.1 cgd break;
454 1.1 cgd
455 1.14 tv case INDIRTYPE: /* Indirect call */
456 1.14 tv if (argc > 2)
457 1.14 tv doindir(argv, argc);
458 1.14 tv break;
459 1.14 tv
460 1.14 tv case BUILTINTYPE: /* Builtins only */
461 1.14 tv if (argc > 2)
462 1.14 tv dobuiltin(argv, argc);
463 1.14 tv break;
464 1.14 tv
465 1.14 tv case PATSTYPE:
466 1.14 tv if (argc > 2)
467 1.14 tv dopatsubst(argv, argc);
468 1.14 tv break;
469 1.14 tv case REGEXPTYPE:
470 1.14 tv if (argc > 2)
471 1.14 tv doregexp(argv, argc);
472 1.14 tv break;
473 1.14 tv case LINETYPE:
474 1.14 tv doprintlineno(infile+ilevel);
475 1.14 tv break;
476 1.14 tv case FILENAMETYPE:
477 1.14 tv doprintfilename(infile+ilevel);
478 1.14 tv break;
479 1.14 tv case SELFTYPE:
480 1.14 tv pbstr(rquote);
481 1.14 tv pbstr(argv[1]);
482 1.14 tv pbstr(lquote);
483 1.14 tv break;
484 1.1 cgd default:
485 1.14 tv errx(1, "%s at line %lu: eval: major botch.",
486 1.14 tv CURRENT_NAME, CURRENT_LINE);
487 1.1 cgd break;
488 1.1 cgd }
489 1.2 glass }
490 1.2 glass
491 1.2 glass /*
492 1.14 tv * expand_macro - user-defined macro expansion
493 1.2 glass */
494 1.2 glass void
495 1.14 tv expand_macro(argv, argc)
496 1.14 tv const char *argv[];
497 1.10 lukem int argc;
498 1.2 glass {
499 1.14 tv const char *t;
500 1.14 tv const char *p;
501 1.10 lukem int n;
502 1.10 lukem int argno;
503 1.2 glass
504 1.2 glass t = argv[0]; /* defn string as a whole */
505 1.2 glass p = t;
506 1.2 glass while (*p)
507 1.2 glass p++;
508 1.2 glass p--; /* last character of defn */
509 1.2 glass while (p > t) {
510 1.2 glass if (*(p - 1) != ARGFLAG)
511 1.14 tv PUTBACK(*p);
512 1.2 glass else {
513 1.2 glass switch (*p) {
514 1.2 glass
515 1.2 glass case '#':
516 1.2 glass pbnum(argc - 2);
517 1.2 glass break;
518 1.2 glass case '0':
519 1.2 glass case '1':
520 1.2 glass case '2':
521 1.2 glass case '3':
522 1.2 glass case '4':
523 1.2 glass case '5':
524 1.2 glass case '6':
525 1.2 glass case '7':
526 1.2 glass case '8':
527 1.2 glass case '9':
528 1.2 glass if ((argno = *p - '0') < argc - 1)
529 1.2 glass pbstr(argv[argno + 1]);
530 1.2 glass break;
531 1.2 glass case '*':
532 1.14 tv if (argc > 2) {
533 1.14 tv for (n = argc - 1; n > 2; n--) {
534 1.14 tv pbstr(argv[n]);
535 1.14 tv putback(COMMA);
536 1.14 tv }
537 1.14 tv pbstr(argv[2]);
538 1.14 tv }
539 1.2 glass break;
540 1.14 tv case '@':
541 1.14 tv if (argc > 2) {
542 1.14 tv for (n = argc - 1; n > 2; n--) {
543 1.14 tv pbstr(rquote);
544 1.14 tv pbstr(argv[n]);
545 1.14 tv pbstr(lquote);
546 1.14 tv putback(COMMA);
547 1.14 tv }
548 1.13 jdolecek pbstr(rquote);
549 1.14 tv pbstr(argv[2]);
550 1.13 jdolecek pbstr(lquote);
551 1.13 jdolecek }
552 1.14 tv break;
553 1.2 glass default:
554 1.14 tv PUTBACK(*p);
555 1.14 tv PUTBACK('$');
556 1.2 glass break;
557 1.2 glass }
558 1.2 glass p--;
559 1.2 glass }
560 1.2 glass p--;
561 1.2 glass }
562 1.2 glass if (p == t) /* do last character */
563 1.14 tv PUTBACK(*p);
564 1.2 glass }
565 1.2 glass
566 1.2 glass /*
567 1.2 glass * dodefine - install definition in the table
568 1.2 glass */
569 1.2 glass void
570 1.2 glass dodefine(name, defn)
571 1.14 tv const char *name;
572 1.14 tv const char *defn;
573 1.2 glass {
574 1.10 lukem ndptr p;
575 1.14 tv int n;
576 1.2 glass
577 1.2 glass if (!*name)
578 1.14 tv errx(1, "%s at line %lu: null definition.", CURRENT_NAME,
579 1.14 tv CURRENT_LINE);
580 1.2 glass if ((p = lookup(name)) == nil)
581 1.2 glass p = addent(name);
582 1.2 glass else if (p->defn != null)
583 1.2 glass free((char *) p->defn);
584 1.14 tv if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) {
585 1.14 tv n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1);
586 1.14 tv if (n != -1) {
587 1.14 tv p->type = n & TYPEMASK;
588 1.14 tv if ((n & NOARGS) == 0)
589 1.14 tv p->type |= NEEDARGS;
590 1.14 tv p->defn = null;
591 1.14 tv return;
592 1.14 tv }
593 1.14 tv }
594 1.2 glass if (!*defn)
595 1.2 glass p->defn = null;
596 1.2 glass else
597 1.2 glass p->defn = xstrdup(defn);
598 1.2 glass p->type = MACRTYPE;
599 1.14 tv if (STREQ(name, defn))
600 1.14 tv p->type |= RECDEF;
601 1.2 glass }
602 1.2 glass
603 1.2 glass /*
604 1.2 glass * dodefn - push back a quoted definition of
605 1.2 glass * the given name.
606 1.2 glass */
607 1.14 tv static void
608 1.2 glass dodefn(name)
609 1.14 tv const char *name;
610 1.2 glass {
611 1.10 lukem ndptr p;
612 1.14 tv const char *real;
613 1.2 glass
614 1.14 tv if ((p = lookup(name)) != nil) {
615 1.14 tv if (p->defn != null) {
616 1.14 tv pbstr(rquote);
617 1.14 tv pbstr(p->defn);
618 1.14 tv pbstr(lquote);
619 1.14 tv } else if ((real = builtin_realname(p->type)) != NULL) {
620 1.14 tv pbstr(real);
621 1.14 tv pbstr(BUILTIN_MARKER);
622 1.14 tv }
623 1.2 glass }
624 1.2 glass }
625 1.2 glass
626 1.2 glass /*
627 1.2 glass * dopushdef - install a definition in the hash table
628 1.2 glass * without removing a previous definition. Since
629 1.2 glass * each new entry is entered in *front* of the
630 1.2 glass * hash bucket, it hides a previous definition from
631 1.2 glass * lookup.
632 1.2 glass */
633 1.14 tv static void
634 1.2 glass dopushdef(name, defn)
635 1.14 tv const char *name;
636 1.14 tv const char *defn;
637 1.2 glass {
638 1.10 lukem ndptr p;
639 1.2 glass
640 1.2 glass if (!*name)
641 1.14 tv errx(1, "%s at line %lu: null definition", CURRENT_NAME,
642 1.14 tv CURRENT_LINE);
643 1.2 glass p = addent(name);
644 1.2 glass if (!*defn)
645 1.2 glass p->defn = null;
646 1.2 glass else
647 1.2 glass p->defn = xstrdup(defn);
648 1.2 glass p->type = MACRTYPE;
649 1.14 tv if (STREQ(name, defn))
650 1.14 tv p->type |= RECDEF;
651 1.14 tv }
652 1.14 tv
653 1.14 tv /*
654 1.14 tv * dump_one_def - dump the specified definition.
655 1.14 tv */
656 1.14 tv static void
657 1.14 tv dump_one_def(p)
658 1.14 tv ndptr p;
659 1.14 tv {
660 1.14 tv const char *real;
661 1.14 tv
662 1.14 tv if (mimic_gnu) {
663 1.14 tv if ((p->type & TYPEMASK) == MACRTYPE)
664 1.14 tv fprintf(traceout, "%s:\t%s\n", p->name, p->defn);
665 1.14 tv else {
666 1.14 tv real = builtin_realname(p->type);
667 1.14 tv if (real == NULL)
668 1.14 tv real = null;
669 1.14 tv fprintf(traceout, "%s:\t<%s>\n", p->name, real);
670 1.14 tv }
671 1.14 tv } else
672 1.14 tv fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn);
673 1.2 glass }
674 1.2 glass
675 1.2 glass /*
676 1.2 glass * dodumpdef - dump the specified definitions in the hash
677 1.2 glass * table to stderr. If nothing is specified, the entire
678 1.2 glass * hash table is dumped.
679 1.2 glass */
680 1.14 tv static void
681 1.2 glass dodump(argv, argc)
682 1.14 tv const char *argv[];
683 1.10 lukem int argc;
684 1.2 glass {
685 1.10 lukem int n;
686 1.2 glass ndptr p;
687 1.2 glass
688 1.2 glass if (argc > 2) {
689 1.2 glass for (n = 2; n < argc; n++)
690 1.2 glass if ((p = lookup(argv[n])) != nil)
691 1.14 tv dump_one_def(p);
692 1.14 tv } else {
693 1.2 glass for (n = 0; n < HASHSIZE; n++)
694 1.2 glass for (p = hashtab[n]; p != nil; p = p->nxtptr)
695 1.14 tv dump_one_def(p);
696 1.2 glass }
697 1.2 glass }
698 1.2 glass
699 1.2 glass /*
700 1.14 tv * dotrace - mark some macros as traced/untraced depending upon on.
701 1.14 tv */
702 1.14 tv static void
703 1.14 tv dotrace(argv, argc, on)
704 1.14 tv const char *argv[];
705 1.14 tv int argc;
706 1.14 tv int on;
707 1.14 tv {
708 1.14 tv int n;
709 1.14 tv
710 1.14 tv if (argc > 2) {
711 1.14 tv for (n = 2; n < argc; n++)
712 1.14 tv mark_traced(argv[n], on);
713 1.14 tv } else
714 1.14 tv mark_traced(NULL, on);
715 1.14 tv }
716 1.14 tv
717 1.14 tv /*
718 1.2 glass * doifelse - select one of two alternatives - loop.
719 1.2 glass */
720 1.14 tv static void
721 1.2 glass doifelse(argv, argc)
722 1.14 tv const char *argv[];
723 1.10 lukem int argc;
724 1.2 glass {
725 1.2 glass cycle {
726 1.2 glass if (STREQ(argv[2], argv[3]))
727 1.2 glass pbstr(argv[4]);
728 1.2 glass else if (argc == 6)
729 1.2 glass pbstr(argv[5]);
730 1.2 glass else if (argc > 6) {
731 1.2 glass argv += 3;
732 1.2 glass argc -= 3;
733 1.2 glass continue;
734 1.2 glass }
735 1.2 glass break;
736 1.2 glass }
737 1.2 glass }
738 1.2 glass
739 1.2 glass /*
740 1.2 glass * doinclude - include a given file.
741 1.2 glass */
742 1.14 tv static int
743 1.2 glass doincl(ifile)
744 1.14 tv const char *ifile;
745 1.2 glass {
746 1.2 glass if (ilevel + 1 == MAXINP)
747 1.14 tv errx(1, "%s at line %lu: too many include files.",
748 1.14 tv CURRENT_NAME, CURRENT_LINE);
749 1.14 tv if (fopen_trypath(infile+ilevel+1, ifile) != NULL) {
750 1.2 glass ilevel++;
751 1.2 glass bbase[ilevel] = bufbase = bp;
752 1.2 glass return (1);
753 1.14 tv } else
754 1.2 glass return (0);
755 1.2 glass }
756 1.2 glass
757 1.2 glass #ifdef EXTENDED
758 1.2 glass /*
759 1.2 glass * dopaste - include a given file without any
760 1.2 glass * macro processing.
761 1.2 glass */
762 1.14 tv static int
763 1.2 glass dopaste(pfile)
764 1.14 tv const char *pfile;
765 1.2 glass {
766 1.2 glass FILE *pf;
767 1.10 lukem int c;
768 1.2 glass
769 1.2 glass if ((pf = fopen(pfile, "r")) != NULL) {
770 1.2 glass while ((c = getc(pf)) != EOF)
771 1.2 glass putc(c, active);
772 1.2 glass (void) fclose(pf);
773 1.2 glass return (1);
774 1.14 tv } else
775 1.2 glass return (0);
776 1.2 glass }
777 1.2 glass #endif
778 1.2 glass
779 1.14 tv static void
780 1.14 tv gnu_dochq(argv, ac)
781 1.14 tv const char *argv[];
782 1.14 tv int ac;
783 1.14 tv {
784 1.14 tv /* In gnu-m4 mode, the only way to restore quotes is to have no
785 1.14 tv * arguments at all. */
786 1.14 tv if (ac == 2) {
787 1.14 tv lquote[0] = LQUOTE, lquote[1] = EOS;
788 1.14 tv rquote[0] = RQUOTE, rquote[1] = EOS;
789 1.14 tv } else {
790 1.14 tv strlcpy(lquote, argv[2], sizeof(lquote));
791 1.14 tv if(ac > 3)
792 1.14 tv strlcpy(rquote, argv[3], sizeof(rquote));
793 1.14 tv else
794 1.14 tv rquote[0] = EOS;
795 1.14 tv }
796 1.14 tv }
797 1.14 tv
798 1.2 glass /*
799 1.2 glass * dochq - change quote characters
800 1.2 glass */
801 1.14 tv static void
802 1.2 glass dochq(argv, argc)
803 1.14 tv const char *argv[];
804 1.10 lukem int argc;
805 1.2 glass {
806 1.2 glass if (argc > 2) {
807 1.2 glass if (*argv[2])
808 1.14 tv strlcpy(lquote, argv[2], sizeof(lquote));
809 1.14 tv else {
810 1.14 tv lquote[0] = LQUOTE;
811 1.14 tv lquote[1] = EOS;
812 1.14 tv }
813 1.2 glass if (argc > 3) {
814 1.2 glass if (*argv[3])
815 1.14 tv strlcpy(rquote, argv[3], sizeof(rquote));
816 1.14 tv } else
817 1.5 pk strcpy(rquote, lquote);
818 1.14 tv } else {
819 1.14 tv lquote[0] = LQUOTE, lquote[1] = EOS;
820 1.14 tv rquote[0] = RQUOTE, rquote[1] = EOS;
821 1.2 glass }
822 1.14 tv }
823 1.14 tv
824 1.14 tv static void
825 1.14 tv gnu_dochc(argv, ac)
826 1.14 tv const char *argv[];
827 1.14 tv int ac;
828 1.14 tv {
829 1.14 tv /* In gnu-m4 mode, no arguments mean no comment
830 1.14 tv * arguments at all. */
831 1.14 tv if (ac == 2) {
832 1.14 tv scommt[0] = EOS;
833 1.14 tv ecommt[0] = EOS;
834 1.14 tv } else {
835 1.14 tv if (*argv[2])
836 1.14 tv strlcpy(scommt, argv[2], sizeof(scommt));
837 1.14 tv else
838 1.14 tv scommt[0] = SCOMMT, scommt[1] = EOS;
839 1.14 tv if(ac > 3 && *argv[3])
840 1.14 tv strlcpy(ecommt, argv[3], sizeof(ecommt));
841 1.14 tv else
842 1.14 tv ecommt[0] = ECOMMT, ecommt[1] = EOS;
843 1.2 glass }
844 1.2 glass }
845 1.2 glass /*
846 1.2 glass * dochc - change comment characters
847 1.2 glass */
848 1.14 tv static void
849 1.2 glass dochc(argv, argc)
850 1.14 tv const char *argv[];
851 1.10 lukem int argc;
852 1.2 glass {
853 1.2 glass if (argc > 2) {
854 1.2 glass if (*argv[2])
855 1.14 tv strlcpy(scommt, argv[2], sizeof(scommt));
856 1.2 glass if (argc > 3) {
857 1.2 glass if (*argv[3])
858 1.14 tv strlcpy(ecommt, argv[3], sizeof(ecommt));
859 1.2 glass }
860 1.2 glass else
861 1.14 tv ecommt[0] = ECOMMT, ecommt[1] = EOS;
862 1.2 glass }
863 1.2 glass else {
864 1.14 tv scommt[0] = SCOMMT, scommt[1] = EOS;
865 1.14 tv ecommt[0] = ECOMMT, ecommt[1] = EOS;
866 1.2 glass }
867 1.2 glass }
868 1.2 glass
869 1.2 glass /*
870 1.2 glass * dodivert - divert the output to a temporary file
871 1.2 glass */
872 1.14 tv static void
873 1.2 glass dodiv(n)
874 1.10 lukem int n;
875 1.2 glass {
876 1.14 tv int fd;
877 1.9 cgd
878 1.14 tv oindex = n;
879 1.14 tv if (n >= maxout) {
880 1.14 tv if (mimic_gnu)
881 1.14 tv resizedivs(n + 10);
882 1.14 tv else
883 1.14 tv n = 0; /* bitbucket */
884 1.14 tv }
885 1.9 cgd
886 1.14 tv if (n < 0)
887 1.14 tv n = 0; /* bitbucket */
888 1.14 tv if (outfile[n] == NULL) {
889 1.14 tv char fname[] = _PATH_DIVNAME;
890 1.14 tv
891 1.14 tv if ((fd = mkstemp(fname)) < 0 ||
892 1.14 tv (outfile[n] = fdopen(fd, "w+")) == NULL)
893 1.14 tv err(1, "%s: cannot divert", fname);
894 1.14 tv if (unlink(fname) == -1)
895 1.14 tv err(1, "%s: cannot unlink", fname);
896 1.2 glass }
897 1.14 tv active = outfile[n];
898 1.2 glass }
899 1.2 glass
900 1.2 glass /*
901 1.2 glass * doundivert - undivert a specified output, or all
902 1.2 glass * other outputs, in numerical order.
903 1.2 glass */
904 1.14 tv static void
905 1.2 glass doundiv(argv, argc)
906 1.14 tv const char *argv[];
907 1.10 lukem int argc;
908 1.2 glass {
909 1.10 lukem int ind;
910 1.10 lukem int n;
911 1.2 glass
912 1.2 glass if (argc > 2) {
913 1.2 glass for (ind = 2; ind < argc; ind++) {
914 1.2 glass n = atoi(argv[ind]);
915 1.14 tv if (n > 0 && n < maxout && outfile[n] != NULL)
916 1.2 glass getdiv(n);
917 1.2 glass
918 1.2 glass }
919 1.2 glass }
920 1.2 glass else
921 1.14 tv for (n = 1; n < maxout; n++)
922 1.2 glass if (outfile[n] != NULL)
923 1.2 glass getdiv(n);
924 1.2 glass }
925 1.2 glass
926 1.2 glass /*
927 1.2 glass * dosub - select substring
928 1.2 glass */
929 1.14 tv static void
930 1.2 glass dosub(argv, argc)
931 1.14 tv const char *argv[];
932 1.10 lukem int argc;
933 1.2 glass {
934 1.14 tv const char *ap, *fc, *k;
935 1.10 lukem int nc;
936 1.2 glass
937 1.14 tv ap = argv[2]; /* target string */
938 1.2 glass #ifdef EXPR
939 1.14 tv fc = ap + expr(argv[3]); /* first char */
940 1.2 glass #else
941 1.14 tv fc = ap + atoi(argv[3]); /* first char */
942 1.2 glass #endif
943 1.14 tv nc = strlen(fc);
944 1.14 tv if (argc >= 5)
945 1.2 glass #ifdef EXPR
946 1.14 tv nc = min(nc, expr(argv[4]));
947 1.2 glass #else
948 1.14 tv nc = min(nc, atoi(argv[4]));
949 1.2 glass #endif
950 1.2 glass if (fc >= ap && fc < ap + strlen(ap))
951 1.14 tv for (k = fc + nc - 1; k >= fc; k--)
952 1.2 glass putback(*k);
953 1.2 glass }
954 1.2 glass
955 1.2 glass /*
956 1.2 glass * map:
957 1.2 glass * map every character of s1 that is specified in from
958 1.2 glass * into s3 and replace in s. (source s1 remains untouched)
959 1.2 glass *
960 1.2 glass * This is a standard implementation of map(s,from,to) function of ICON
961 1.2 glass * language. Within mapvec, we replace every character of "from" with
962 1.2 glass * the corresponding character in "to". If "to" is shorter than "from",
963 1.2 glass * than the corresponding entries are null, which means that those
964 1.2 glass * characters dissapear altogether. Furthermore, imagine
965 1.2 glass * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
966 1.2 glass * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
967 1.2 glass * ultimately maps to `*'. In order to achieve this effect in an efficient
968 1.2 glass * manner (i.e. without multiple passes over the destination string), we
969 1.2 glass * loop over mapvec, starting with the initial source character. if the
970 1.2 glass * character value (dch) in this location is different than the source
971 1.2 glass * character (sch), sch becomes dch, once again to index into mapvec, until
972 1.2 glass * the character value stabilizes (i.e. sch = dch, in other words
973 1.2 glass * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
974 1.2 glass * character, it will stabilize, since mapvec[0] == 0 at all times. At the
975 1.2 glass * end, we restore mapvec* back to normal where mapvec[n] == n for
976 1.2 glass * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
977 1.2 glass * about 5 times faster than any algorithm that makes multiple passes over
978 1.2 glass * destination string.
979 1.2 glass */
980 1.14 tv static void
981 1.2 glass map(dest, src, from, to)
982 1.10 lukem char *dest;
983 1.14 tv const char *src;
984 1.14 tv const char *from;
985 1.14 tv const char *to;
986 1.14 tv {
987 1.14 tv const char *tmp;
988 1.14 tv unsigned char sch, dch;
989 1.14 tv static char frombis[257];
990 1.14 tv static char tobis[257];
991 1.14 tv static unsigned char mapvec[256] = {
992 1.14 tv 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
993 1.14 tv 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
994 1.14 tv 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
995 1.14 tv 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
996 1.14 tv 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
997 1.14 tv 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
998 1.14 tv 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115,
999 1.14 tv 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
1000 1.14 tv 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
1001 1.14 tv 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
1002 1.14 tv 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
1003 1.14 tv 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
1004 1.14 tv 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
1005 1.14 tv 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
1006 1.14 tv 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
1007 1.14 tv 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
1008 1.14 tv 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
1009 1.14 tv 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
1010 1.2 glass };
1011 1.2 glass
1012 1.2 glass if (*src) {
1013 1.14 tv if (mimic_gnu) {
1014 1.14 tv /*
1015 1.14 tv * expand character ranges on the fly
1016 1.14 tv */
1017 1.14 tv from = handledash(frombis, frombis + 256, from);
1018 1.14 tv to = handledash(tobis, tobis + 256, to);
1019 1.14 tv }
1020 1.2 glass tmp = from;
1021 1.2 glass /*
1022 1.2 glass * create a mapping between "from" and
1023 1.2 glass * "to"
1024 1.2 glass */
1025 1.2 glass while (*from)
1026 1.14 tv mapvec[(unsigned char)(*from++)] = (*to) ?
1027 1.14 tv (unsigned char)(*to++) : 0;
1028 1.2 glass
1029 1.2 glass while (*src) {
1030 1.14 tv sch = (unsigned char)(*src++);
1031 1.14 tv dch = mapvec[sch];
1032 1.2 glass while (dch != sch) {
1033 1.2 glass sch = dch;
1034 1.14 tv dch = mapvec[sch];
1035 1.2 glass }
1036 1.14 tv if ((*dest = (char)dch))
1037 1.2 glass dest++;
1038 1.2 glass }
1039 1.2 glass /*
1040 1.2 glass * restore all the changed characters
1041 1.2 glass */
1042 1.2 glass while (*tmp) {
1043 1.14 tv mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp);
1044 1.2 glass tmp++;
1045 1.2 glass }
1046 1.2 glass }
1047 1.14 tv *dest = '\0';
1048 1.14 tv }
1049 1.14 tv
1050 1.14 tv
1051 1.14 tv /*
1052 1.14 tv * handledash:
1053 1.14 tv * use buffer to copy the src string, expanding character ranges
1054 1.14 tv * on the way.
1055 1.14 tv */
1056 1.14 tv static const char *
1057 1.14 tv handledash(buffer, end, src)
1058 1.14 tv char *buffer;
1059 1.14 tv char *end;
1060 1.14 tv const char *src;
1061 1.14 tv {
1062 1.14 tv char *p;
1063 1.14 tv
1064 1.14 tv p = buffer;
1065 1.14 tv while(*src) {
1066 1.14 tv if (src[1] == '-' && src[2]) {
1067 1.14 tv unsigned char i;
1068 1.14 tv for (i = (unsigned char)src[0];
1069 1.14 tv i <= (unsigned char)src[2]; i++) {
1070 1.14 tv *p++ = i;
1071 1.14 tv if (p == end) {
1072 1.14 tv *p = '\0';
1073 1.14 tv return buffer;
1074 1.14 tv }
1075 1.14 tv }
1076 1.14 tv src += 3;
1077 1.14 tv } else
1078 1.14 tv *p++ = *src++;
1079 1.14 tv if (p == end)
1080 1.14 tv break;
1081 1.14 tv }
1082 1.14 tv *p = '\0';
1083 1.14 tv return buffer;
1084 1.1 cgd }
1085 1.14 tv
1086