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