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