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