Index: head/usr.bin/m4/Makefile =================================================================== --- head/usr.bin/m4/Makefile (revision 95886) +++ head/usr.bin/m4/Makefile (revision 95887) @@ -1,13 +1,13 @@ -# $OpenBSD: Makefile,v 1.8 2001/09/18 14:55:52 espie Exp $ +# $OpenBSD: Makefile,v 1.10 2002/04/26 13:13:41 espie Exp $ # $FreeBSD$ # -DEXTENDED # if you want the paste & spaste macros. PROG= m4 CFLAGS+=-DEXTENDED SRCS= eval.c expr.c look.c main.c misc.c gnum4.c trace.c MAN= m4.1 .include Index: head/usr.bin/m4/eval.c =================================================================== --- head/usr.bin/m4/eval.c (revision 95886) +++ head/usr.bin/m4/eval.c (revision 95887) @@ -1,1097 +1,1053 @@ -/* $OpenBSD: eval.c,v 1.43 2002/02/16 21:27:48 millert Exp $ */ +/* $OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $ */ /* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ozan Yigit at York University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include -__SCCSID("@(#)eval.c 8.2 (Berkeley) 4/27/95"); -__RCSID_SOURCE("$OpenBSD: eval.c,v 1.43 2002/02/16 21:27:48 millert Exp $"); +__SCCSID("@(#)eval.c 8.2 (Berkeley) 4/27/95"); +__RCSID_SOURCE("$OpenBSD: eval.c,v 1.44 2002/04/26 16:15:16 espie Exp $"); __FBSDID("$FreeBSD$"); /* * eval.c * Facility: m4 macro processor * by: oz */ #include #include #include #include #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" #include "pathnames.h" #define BUILTIN_MARKER "__builtin_" static void dodefn(const char *); static void dopushdef(const char *, const char *); static void dodump(const char *[], int); static void dotrace(const char *[], int, int); static void doifelse(const char *[], int); static int doincl(const char *); static int dopaste(const char *); static void gnu_dochq(const char *[], int); static void dochq(const char *[], int); static void gnu_dochc(const char *[], int); static void dochc(const char *[], int); static void dodiv(int); static void doundiv(const char *[], int); static void dosub(const char *[], int); static void map(char *, const char *, const char *, const char *); static const char *handledash(char *, char *, const char *); static void expand_builtin(const char *[], int, int); static void expand_macro(const char *[], int); static void dump_one_def(ndptr); unsigned long expansion_id; /* * eval - eval all macros and builtins calls * argc - number of elements in argv. * argv - element vector : * argv[0] = definition of a user * macro or nil if built-in. * argv[1] = name of the macro or * built-in. * argv[2] = parameters to user-defined * . macro or built-in. * . * * A call in the form of macro-or-builtin() will result in: * argv[0] = nullstr * argv[1] = macro-or-builtin * argv[2] = nullstr * * argc is 3 for macro-or-builtin() and 2 for macro-or-builtin */ void -eval(argv, argc, td) - const char *argv[]; - int argc; - int td; +eval(const char *argv[], int argc, int td) { ssize_t mark = -1; expansion_id++; if (td & RECDEF) errx(1, "%s at line %lu: expanding recursive definition for %s", CURRENT_NAME, CURRENT_LINE, argv[1]); if (traced_macros && is_traced(argv[1])) mark = trace(argv, argc, infile+ilevel); if (td == MACRTYPE) expand_macro(argv, argc); else expand_builtin(argv, argc, td); if (mark != -1) finish_trace(mark); } /* * expand_builtin - evaluate built-in macros. */ void -expand_builtin(argv, argc, td) - const char *argv[]; - int argc; - int td; +expand_builtin(const char *argv[], int argc, int td) { int c, n; int ac; static int sysval = 0; #ifdef DEBUG printf("argc = %d\n", argc); for (n = 0; n < argc; n++) printf("argv[%d] = %s\n", n, argv[n]); fflush(stdout); #endif /* * if argc == 3 and argv[2] is null, then we * have macro-or-builtin() type call. We adjust * argc to avoid further checking.. */ ac = argc; if (argc == 3 && !*(argv[2])) argc--; switch (td & TYPEMASK) { case DEFITYPE: if (argc > 2) dodefine(argv[2], (argc > 3) ? argv[3] : null); break; case PUSDTYPE: if (argc > 2) dopushdef(argv[2], (argc > 3) ? argv[3] : null); break; case DUMPTYPE: dodump(argv, argc); break; case TRACEONTYPE: dotrace(argv, argc, 1); break; case TRACEOFFTYPE: dotrace(argv, argc, 0); break; case EXPRTYPE: /* * doexpr - evaluate arithmetic * expression */ if (argc > 2) pbnum(expr(argv[2])); break; case IFELTYPE: if (argc > 4) doifelse(argv, argc); break; case IFDFTYPE: /* * doifdef - select one of two * alternatives based on the existence of * another definition */ if (argc > 3) { if (lookup(argv[2]) != nil) pbstr(argv[3]); else if (argc > 4) pbstr(argv[4]); } break; case LENGTYPE: /* * dolen - find the length of the * argument */ pbnum((argc > 2) ? strlen(argv[2]) : 0); break; case INCRTYPE: /* * doincr - increment the value of the * argument */ if (argc > 2) pbnum(atoi(argv[2]) + 1); break; case DECRTYPE: /* * dodecr - decrement the value of the * argument */ if (argc > 2) pbnum(atoi(argv[2]) - 1); break; case SYSCTYPE: /* * dosys - execute system command */ if (argc > 2) sysval = system(argv[2]); break; case SYSVTYPE: /* * dosysval - return value of the last * system call. * */ pbnum(sysval); break; case ESYSCMDTYPE: if (argc > 2) doesyscmd(argv[2]); break; case INCLTYPE: if (argc > 2) if (!doincl(argv[2])) err(1, "%s at line %lu: include(%s)", CURRENT_NAME, CURRENT_LINE, argv[2]); break; case SINCTYPE: if (argc > 2) (void) doincl(argv[2]); break; #ifdef EXTENDED case PASTTYPE: if (argc > 2) if (!dopaste(argv[2])) err(1, "%s at line %lu: paste(%s)", CURRENT_NAME, CURRENT_LINE, argv[2]); break; case SPASTYPE: if (argc > 2) (void) dopaste(argv[2]); break; #endif case CHNQTYPE: if (mimic_gnu) gnu_dochq(argv, ac); else dochq(argv, argc); break; case CHNCTYPE: if (mimic_gnu) gnu_dochc(argv, ac); else dochc(argv, argc); break; case SUBSTYPE: /* * dosub - select substring * */ if (argc > 3) dosub(argv, argc); break; case SHIFTYPE: /* * doshift - push back all arguments * except the first one (i.e. skip * argv[2]) */ if (argc > 3) { for (n = argc - 1; n > 3; n--) { pbstr(rquote); pbstr(argv[n]); pbstr(lquote); putback(COMMA); } pbstr(rquote); pbstr(argv[3]); pbstr(lquote); } break; case DIVRTYPE: if (argc > 2 && (n = atoi(argv[2])) != 0) dodiv(n); else { active = stdout; oindex = 0; } break; case UNDVTYPE: doundiv(argv, argc); break; case DIVNTYPE: /* * dodivnum - return the number of * current output diversion */ pbnum(oindex); break; case UNDFTYPE: /* * doundefine - undefine a previously * defined macro(s) or m4 keyword(s). */ if (argc > 2) for (n = 2; n < argc; n++) remhash(argv[n], ALL); break; case POPDTYPE: /* * dopopdef - remove the topmost * definitions of macro(s) or m4 * keyword(s). */ if (argc > 2) for (n = 2; n < argc; n++) remhash(argv[n], TOP); break; case MKTMTYPE: /* * dotemp - create a temporary file */ if (argc > 2) { int fd; char *temp; temp = xstrdup(argv[2]); fd = mkstemp(temp); if (fd == -1) err(1, "%s at line %lu: couldn't make temp file %s", CURRENT_NAME, CURRENT_LINE, argv[2]); close(fd); pbstr(temp); free(temp); } break; case TRNLTYPE: /* * dotranslit - replace all characters in * the source string that appears in the * "from" string with the corresponding * characters in the "to" string. */ if (argc > 3) { char *temp; temp = xalloc(strlen(argv[2])+1); if (argc > 4) map(temp, argv[2], argv[3], argv[4]); else map(temp, argv[2], argv[3], null); pbstr(temp); free(temp); } else if (argc > 2) pbstr(argv[2]); break; case INDXTYPE: /* * doindex - find the index of the second * argument string in the first argument * string. -1 if not present. */ pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1); break; case ERRPTYPE: /* * doerrp - print the arguments to stderr * file */ if (argc > 2) { for (n = 2; n < argc; n++) fprintf(stderr, "%s ", argv[n]); fprintf(stderr, "\n"); } break; case DNLNTYPE: /* * dodnl - eat-up-to and including * newline */ while ((c = gpbc()) != '\n' && c != EOF) ; break; case M4WRTYPE: /* * dom4wrap - set up for * wrap-up/wind-down activity */ m4wraps = (argc > 2) ? xstrdup(argv[2]) : null; break; case EXITTYPE: /* * doexit - immediate exit from m4. */ killdiv(); exit((argc > 2) ? atoi(argv[2]) : 0); break; case DEFNTYPE: if (argc > 2) for (n = 2; n < argc; n++) dodefn(argv[n]); break; case INDIRTYPE: /* Indirect call */ if (argc > 2) doindir(argv, argc); break; case BUILTINTYPE: /* Builtins only */ if (argc > 2) dobuiltin(argv, argc); break; case PATSTYPE: if (argc > 2) dopatsubst(argv, argc); break; case REGEXPTYPE: if (argc > 2) doregexp(argv, argc); break; case LINETYPE: doprintlineno(infile+ilevel); break; case FILENAMETYPE: doprintfilename(infile+ilevel); break; case SELFTYPE: pbstr(rquote); pbstr(argv[1]); pbstr(lquote); break; default: errx(1, "%s at line %lu: eval: major botch.", CURRENT_NAME, CURRENT_LINE); break; } } /* * expand_macro - user-defined macro expansion */ void -expand_macro(argv, argc) - const char *argv[]; - int argc; +expand_macro(const char *argv[], int argc) { const char *t; const char *p; int n; int argno; t = argv[0]; /* defn string as a whole */ p = t; while (*p) p++; p--; /* last character of defn */ while (p > t) { if (*(p - 1) != ARGFLAG) PUTBACK(*p); else { switch (*p) { case '#': pbnum(argc - 2); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if ((argno = *p - '0') < argc - 1) pbstr(argv[argno + 1]); break; case '*': if (argc > 2) { for (n = argc - 1; n > 2; n--) { pbstr(argv[n]); putback(COMMA); } pbstr(argv[2]); } break; case '@': if (argc > 2) { for (n = argc - 1; n > 2; n--) { pbstr(rquote); pbstr(argv[n]); pbstr(lquote); putback(COMMA); } pbstr(rquote); pbstr(argv[2]); pbstr(lquote); } break; default: PUTBACK(*p); PUTBACK('$'); break; } p--; } p--; } if (p == t) /* do last character */ PUTBACK(*p); } /* * dodefine - install definition in the table */ void -dodefine(name, defn) - const char *name; - const char *defn; +dodefine(const char *name, const char *defn) { ndptr p; int n; if (!*name) errx(1, "%s at line %lu: null definition.", CURRENT_NAME, CURRENT_LINE); if ((p = lookup(name)) == nil) p = addent(name); else if (p->defn != null) free((char *) p->defn); if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0) { n = builtin_type(defn+sizeof(BUILTIN_MARKER)-1); if (n != -1) { p->type = n & TYPEMASK; if ((n & NOARGS) == 0) p->type |= NEEDARGS; p->defn = xstrdup(null); return; } } if (!*defn) p->defn = xstrdup(null); else p->defn = xstrdup(defn); p->type = MACRTYPE; if (STREQ(name, defn)) p->type |= RECDEF; } /* * dodefn - push back a quoted definition of * the given name. */ static void -dodefn(name) - const char *name; +dodefn(const char *name) { ndptr p; const char *real; if ((p = lookup(name)) != nil) { if (p->defn != null) { pbstr(rquote); pbstr(p->defn); pbstr(lquote); } else if ((real = builtin_realname(p->type)) != NULL) { pbstr(real); pbstr(BUILTIN_MARKER); } } } /* * dopushdef - install a definition in the hash table * without removing a previous definition. Since * each new entry is entered in *front* of the * hash bucket, it hides a previous definition from * lookup. */ static void -dopushdef(name, defn) - const char *name; - const char *defn; +dopushdef(const char *name, const char *defn) { ndptr p; if (!*name) errx(1, "%s at line %lu: null definition", CURRENT_NAME, CURRENT_LINE); p = addent(name); if (!*defn) p->defn = xstrdup(null); else p->defn = xstrdup(defn); p->type = MACRTYPE; if (STREQ(name, defn)) p->type |= RECDEF; } /* * dump_one_def - dump the specified definition. */ static void -dump_one_def(p) - ndptr p; +dump_one_def(ndptr p) { const char *real; if (mimic_gnu) { if ((p->type & TYPEMASK) == MACRTYPE) fprintf(traceout, "%s:\t%s\n", p->name, p->defn); else { real = builtin_realname(p->type); if (real == NULL) real = null; fprintf(traceout, "%s:\t<%s>\n", p->name, real); } } else fprintf(traceout, "`%s'\t`%s'\n", p->name, p->defn); } /* * dodumpdef - dump the specified definitions in the hash * table to stderr. If nothing is specified, the entire * hash table is dumped. */ static void -dodump(argv, argc) - const char *argv[]; - int argc; +dodump(const char *argv[], int argc) { int n; ndptr p; if (argc > 2) { for (n = 2; n < argc; n++) if ((p = lookup(argv[n])) != nil) dump_one_def(p); } else { for (n = 0; n < HASHSIZE; n++) for (p = hashtab[n]; p != nil; p = p->nxtptr) dump_one_def(p); } } /* * dotrace - mark some macros as traced/untraced depending upon on. */ static void -dotrace(argv, argc, on) - const char *argv[]; - int argc; - int on; +dotrace(const char *argv[], int argc, int on) { int n; if (argc > 2) { for (n = 2; n < argc; n++) mark_traced(argv[n], on); } else mark_traced(NULL, on); } /* * doifelse - select one of two alternatives - loop. */ static void -doifelse(argv, argc) - const char *argv[]; - int argc; +doifelse(const char *argv[], int argc) { cycle { if (STREQ(argv[2], argv[3])) pbstr(argv[4]); else if (argc == 6) pbstr(argv[5]); else if (argc > 6) { argv += 3; argc -= 3; continue; } break; } } /* * doinclude - include a given file. */ static int -doincl(ifile) - const char *ifile; +doincl(const char *ifile) { if (ilevel + 1 == MAXINP) errx(1, "%s at line %lu: too many include files.", CURRENT_NAME, CURRENT_LINE); if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { ilevel++; if ((inname[ilevel] = strdup(ifile)) == NULL) err(1, NULL); inlineno[ilevel] = 1; bbase[ilevel] = bufbase = bp; emitline(); return (1); } else return (0); } #ifdef EXTENDED /* * dopaste - include a given file without any * macro processing. */ static int -dopaste(pfile) - const char *pfile; +dopaste(const char *pfile) { FILE *pf; int c; if ((pf = fopen(pfile, "r")) != NULL) { fprintf(active, "#line 1 \"%s\"\n", pfile); while ((c = getc(pf)) != EOF) putc(c, active); (void) fclose(pf); emitline(); return (1); } else return (0); } #endif static void -gnu_dochq(argv, ac) - const char *argv[]; - int ac; +gnu_dochq(const char *argv[], int ac) { /* In gnu-m4 mode, the only way to restore quotes is to have no * arguments at all. */ if (ac == 2) { lquote[0] = LQUOTE, lquote[1] = EOS; rquote[0] = RQUOTE, rquote[1] = EOS; } else { strlcpy(lquote, argv[2], sizeof(lquote)); if(ac > 3) strlcpy(rquote, argv[3], sizeof(rquote)); else rquote[0] = EOS; } } /* * dochq - change quote characters */ static void -dochq(argv, argc) - const char *argv[]; - int argc; +dochq(const char *argv[], int argc) { if (argc > 2) { if (*argv[2]) strlcpy(lquote, argv[2], sizeof(lquote)); else { lquote[0] = LQUOTE; lquote[1] = EOS; } if (argc > 3) { if (*argv[3]) strlcpy(rquote, argv[3], sizeof(rquote)); } else strcpy(rquote, lquote); } else { lquote[0] = LQUOTE, lquote[1] = EOS; rquote[0] = RQUOTE, rquote[1] = EOS; } } static void -gnu_dochc(argv, ac) - const char *argv[]; - int ac; +gnu_dochc(const char *argv[], int ac) { /* In gnu-m4 mode, no arguments mean no comment * arguments at all. */ if (ac == 2) { scommt[0] = EOS; ecommt[0] = EOS; } else { if (*argv[2]) strlcpy(scommt, argv[2], sizeof(scommt)); else scommt[0] = SCOMMT, scommt[1] = EOS; if(ac > 3 && *argv[3]) strlcpy(ecommt, argv[3], sizeof(ecommt)); else ecommt[0] = ECOMMT, ecommt[1] = EOS; } } /* * dochc - change comment characters */ static void -dochc(argv, argc) - const char *argv[]; - int argc; +dochc(const char *argv[], int argc) { if (argc > 2) { if (*argv[2]) strlcpy(scommt, argv[2], sizeof(scommt)); if (argc > 3) { if (*argv[3]) strlcpy(ecommt, argv[3], sizeof(ecommt)); } else ecommt[0] = ECOMMT, ecommt[1] = EOS; } else { scommt[0] = SCOMMT, scommt[1] = EOS; ecommt[0] = ECOMMT, ecommt[1] = EOS; } } /* * dodivert - divert the output to a temporary file */ static void -dodiv(n) - int n; +dodiv(int n) { int fd; oindex = n; if (n >= maxout) { if (mimic_gnu) resizedivs(n + 10); else n = 0; /* bitbucket */ } if (n < 0) n = 0; /* bitbucket */ if (outfile[n] == NULL) { char fname[] = _PATH_DIVNAME; if ((fd = mkstemp(fname)) < 0 || (outfile[n] = fdopen(fd, "w+")) == NULL) err(1, "%s: cannot divert", fname); if (unlink(fname) == -1) err(1, "%s: cannot unlink", fname); } active = outfile[n]; } /* * doundivert - undivert a specified output, or all * other outputs, in numerical order. */ static void -doundiv(argv, argc) - const char *argv[]; - int argc; +doundiv(const char *argv[], int argc) { int ind; int n; if (argc > 2) { for (ind = 2; ind < argc; ind++) { n = atoi(argv[ind]); if (n > 0 && n < maxout && outfile[n] != NULL) getdiv(n); } } else for (n = 1; n < maxout; n++) if (outfile[n] != NULL) getdiv(n); } /* * dosub - select substring */ static void -dosub(argv, argc) - const char *argv[]; - int argc; +dosub(const char *argv[], int argc) { const char *ap, *fc, *k; int nc; ap = argv[2]; /* target string */ #ifdef EXPR fc = ap + expr(argv[3]); /* first char */ #else fc = ap + atoi(argv[3]); /* first char */ #endif nc = strlen(fc); if (argc >= 5) #ifdef EXPR nc = min(nc, expr(argv[4])); #else nc = min(nc, atoi(argv[4])); #endif if (fc >= ap && fc < ap + strlen(ap)) for (k = fc + nc - 1; k >= fc; k--) putback(*k); } /* * map: * map every character of s1 that is specified in from * into s3 and replace in s. (source s1 remains untouched) * * This is a standard implementation of map(s,from,to) function of ICON * language. Within mapvec, we replace every character of "from" with * the corresponding character in "to". If "to" is shorter than "from", * than the corresponding entries are null, which means that those * characters dissapear altogether. Furthermore, imagine * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' * ultimately maps to `*'. In order to achieve this effect in an efficient * manner (i.e. without multiple passes over the destination string), we * loop over mapvec, starting with the initial source character. if the * character value (dch) in this location is different than the source * character (sch), sch becomes dch, once again to index into mapvec, until * the character value stabilizes (i.e. sch = dch, in other words * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary * character, it will stabilize, since mapvec[0] == 0 at all times. At the * end, we restore mapvec* back to normal where mapvec[n] == n for * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is * about 5 times faster than any algorithm that makes multiple passes over * destination string. */ static void -map(dest, src, from, to) - char *dest; - const char *src; - const char *from; - const char *to; +map(char *dest, const char *src, const char *from, const char *to) { const char *tmp; unsigned char sch, dch; static char frombis[257]; static char tobis[257]; static unsigned char mapvec[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 }; if (*src) { if (mimic_gnu) { /* * expand character ranges on the fly */ from = handledash(frombis, frombis + 256, from); to = handledash(tobis, tobis + 256, to); } tmp = from; /* * create a mapping between "from" and * "to" */ while (*from) mapvec[(unsigned char)(*from++)] = (*to) ? (unsigned char)(*to++) : 0; while (*src) { sch = (unsigned char)(*src++); dch = mapvec[sch]; while (dch != sch) { sch = dch; dch = mapvec[sch]; } if ((*dest = (char)dch)) dest++; } /* * restore all the changed characters */ while (*tmp) { mapvec[(unsigned char)(*tmp)] = (unsigned char)(*tmp); tmp++; } } *dest = '\0'; } /* * handledash: * use buffer to copy the src string, expanding character ranges * on the way. */ static const char * -handledash(buffer, end, src) - char *buffer; - char *end; - const char *src; +handledash(char *buffer, char *end, const char *src) { char *p; p = buffer; while(*src) { if (src[1] == '-' && src[2]) { unsigned char i; for (i = (unsigned char)src[0]; i <= (unsigned char)src[2]; i++) { *p++ = i; if (p == end) { *p = '\0'; return buffer; } } src += 3; } else *p++ = *src++; if (p == end) break; } *p = '\0'; return buffer; } - Index: head/usr.bin/m4/expr.c =================================================================== --- head/usr.bin/m4/expr.c (revision 95886) +++ head/usr.bin/m4/expr.c (revision 95887) @@ -1,618 +1,616 @@ -/* $OpenBSD: expr.c,v 1.12 2002/02/16 21:27:48 millert Exp $ */ +/* $OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $ */ /* $NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ozan Yigit at York University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include -__SCCSID("@(#)expr.c 8.2 (Berkeley) 4/29/95"); -__RCSID_SOURCE("$OpenBSD: expr.c,v 1.12 2002/02/16 21:27:48 millert Exp $"); +__SCCSID("@(#)expr.c 8.2 (Berkeley) 4/29/95"); +__RCSID_SOURCE("$OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $"); __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "mdef.h" #include "extern.h" /* * expression evaluator: performs a standard recursive * descent parse to evaluate any expression permissible * within the following grammar: * * expr : query EOS * query : lor * | lor "?" query ":" query * lor : land { "||" land } * land : not { "&&" not } * not : eqrel * | '!' not * eqrel : shift { eqrelop shift } * shift : primary { shop primary } * primary : term { addop term } * term : exp { mulop exp } * exp : unary { expop unary } * unary : factor * | unop unary * factor : constant * | "(" query ")" * constant: num * | "'" CHAR "'" * num : DIGIT * | DIGIT num * shop : "<<" * | ">>" * eqrel : "=" * | "==" * | "!=" * | "<" * | ">" * | "<=" * | ">=" * * * This expression evaluator is lifted from a public-domain * C Pre-Processor included with the DECUS C Compiler distribution. * It is hacked somewhat to be suitable for m4. * * Originally by: Mike Lutz * Bob Harper */ #define EQL 0 #define NEQ 1 #define LSS 2 #define LEQ 3 #define GTR 4 #define GEQ 5 #define OCTAL 8 #define DECIMAL 10 #define HEX 16 static const char *nxtch; /* Parser scan pointer */ static const char *where; static int query(void); static int lor(void); static int land(void); static int not(void); static int eqrel(void); static int shift(void); static int primary(void); static int term(void); static int exp(void); static int unary(void); static int factor(void); static int constant(void); static int num(void); static int geteqrel(void); static int skipws(void); static void experr(const char *); /* * For longjmp */ #include static jmp_buf expjump; /* * macros: * ungetch - Put back the last character examined. * getch - return the next character from expr string. */ #define ungetch() nxtch-- #define getch() *nxtch++ int -expr(expbuf) - const char *expbuf; +expr(const char *expbuf) { int rval; nxtch = expbuf; where = expbuf; if (setjmp(expjump) != 0) return FALSE; rval = query(); if (skipws() == EOS) return rval; printf("m4: ill-formed expression.\n"); return FALSE; } /* * query : lor | lor '?' query ':' query */ static int query() { - int bool, true_val, false_val; + int result, true_val, false_val; - bool = lor(); + result = lor(); if (skipws() != '?') { ungetch(); - return bool; + return result; } true_val = query(); if (skipws() != ':') experr("bad query"); false_val = query(); - return bool ? true_val : false_val; + return result ? true_val : false_val; } /* * lor : land { '||' land } */ static int lor() { int c, vl, vr; vl = land(); while ((c = skipws()) == '|') { if (getch() != '|') ungetch(); vr = land(); vl = vl || vr; } ungetch(); return vl; } /* * land : not { '&&' not } */ static int land() { int c, vl, vr; vl = not(); while ((c = skipws()) == '&') { if (getch() != '&') ungetch(); vr = not(); vl = vl && vr; } ungetch(); return vl; } /* * not : eqrel | '!' not */ static int not() { int val, c; if ((c = skipws()) == '!' && getch() != '=') { ungetch(); val = not(); return !val; } if (c == '!') ungetch(); ungetch(); return eqrel(); } /* * eqrel : shift { eqrelop shift } */ static int eqrel() { int vl, vr, eqrelval; vl = shift(); while ((eqrelval = geteqrel()) != -1) { vr = shift(); switch (eqrelval) { case EQL: vl = (vl == vr); break; case NEQ: vl = (vl != vr); break; case LEQ: vl = (vl <= vr); break; case LSS: vl = (vl < vr); break; case GTR: vl = (vl > vr); break; case GEQ: vl = (vl >= vr); break; } } return vl; } /* * shift : primary { shop primary } */ static int shift() { int vl, vr, c; vl = primary(); while (((c = skipws()) == '<' || c == '>') && getch() == c) { vr = primary(); if (c == '<') vl <<= vr; else vl >>= vr; } if (c == '<' || c == '>') ungetch(); ungetch(); return vl; } /* * primary : term { addop term } */ static int primary() { int c, vl, vr; vl = term(); while ((c = skipws()) == '+' || c == '-') { vr = term(); if (c == '+') vl += vr; else vl -= vr; } ungetch(); return vl; } /* * := { } */ static int term() { int c, vl, vr; vl = exp(); while ((c = skipws()) == '*' || c == '/' || c == '%') { vr = exp(); switch (c) { case '*': vl *= vr; break; case '/': if (vr == 0) errx(1, "division by zero in eval."); else vl /= vr; break; case '%': if (vr == 0) errx(1, "modulo zero in eval."); else vl %= vr; break; } } ungetch(); return vl; } /* * := { } */ static int exp() { int c, vl, vr, n; vl = unary(); switch (c = skipws()) { case '*': if (getch() != '*') { ungetch(); break; } case '^': vr = exp(); n = 1; while (vr-- > 0) n *= vl; return n; } ungetch(); return vl; } /* * unary : factor | unop unary */ static int unary() { int val, c; if ((c = skipws()) == '+' || c == '-' || c == '~') { val = unary(); switch (c) { case '+': return val; case '-': return -val; case '~': return ~val; } } ungetch(); return factor(); } /* * factor : constant | '(' query ')' */ static int factor() { int val; if (skipws() == '(') { val = query(); if (skipws() != ')') experr("bad factor"); return val; } ungetch(); return constant(); } /* * constant: num | 'char' * Note: constant() handles multi-byte constants */ static int constant() { int i; int value; int c; int v[sizeof(int)]; if (skipws() != '\'') { ungetch(); return num(); } for (i = 0; i < (int)sizeof(int); i++) { if ((c = getch()) == '\'') { ungetch(); break; } if (c == '\\') { switch (c = getch()) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': ungetch(); c = num(); break; case 'n': c = 012; break; case 'r': c = 015; break; case 't': c = 011; break; case 'b': c = 010; break; case 'f': c = 014; break; } } v[i] = c; } if (i == 0 || getch() != '\'') experr("illegal character constant"); for (value = 0; --i >= 0;) { value <<= 8; value += v[i]; } return value; } /* * num : digit | num digit */ static int num() { int rval, c, base; int ndig; rval = 0; ndig = 0; c = skipws(); if (c == '0') { c = skipws(); if (c == 'x' || c == 'X') { base = HEX; c = skipws(); } else { base = OCTAL; ndig++; } } else base = DECIMAL; for(;;) { switch(c) { case '8': case '9': if (base == OCTAL) goto bad_digit; /*FALLTHRU*/ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': rval *= base; rval += c - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': c = tolower(c); case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': if (base == HEX) { rval *= base; rval += c - 'a' + 10; break; } /*FALLTHRU*/ default: goto bad_digit; } c = getch(); ndig++; } bad_digit: ungetch(); if (ndig == 0) experr("bad constant"); return rval; } /* * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>=' */ static int geteqrel() { int c1, c2; c1 = skipws(); c2 = getch(); switch (c1) { case '=': if (c2 != '=') ungetch(); return EQL; case '!': if (c2 == '=') return NEQ; ungetch(); ungetch(); return -1; case '<': if (c2 == '=') return LEQ; ungetch(); return LSS; case '>': if (c2 == '=') return GEQ; ungetch(); return GTR; default: ungetch(); ungetch(); return -1; } } /* * Skip over any white space and return terminating char. */ static int skipws() { int c; while ((c = getch()) <= ' ' && c > EOS) ; return c; } /* * resets environment to eval(), prints an error * and forces eval to return FALSE. */ static void -experr(msg) - const char *msg; +experr(const char *msg) { printf("m4: %s in expr %s.\n", msg, where); longjmp(expjump, -1); } Index: head/usr.bin/m4/gnum4.c =================================================================== --- head/usr.bin/m4/gnum4.c (revision 95886) +++ head/usr.bin/m4/gnum4.c (revision 95887) @@ -1,560 +1,520 @@ -/* $OpenBSD: gnum4.c,v 1.16 2002/02/16 21:27:48 millert Exp $ */ +/* $OpenBSD: gnum4.c,v 1.18 2002/04/26 16:15:16 espie Exp $ */ /* * Copyright (c) 1999 Marc Espie * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * functions needed to support gnu-m4 extensions, including a fake freezing */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" int mimic_gnu = 0; /* * Support for include path search * First search in the the current directory. * If not found, and the path is not absolute, include path kicks in. * First, -I options, in the order found on the command line. * Then M4PATH env variable */ struct path_entry { char *name; struct path_entry *next; } *first, *last; static struct path_entry *new_path_entry(const char *); static void ensure_m4path(void); static struct input_file *dopath(struct input_file *, const char *); static struct path_entry * -new_path_entry(dirname) - const char *dirname; +new_path_entry(const char *dirname) { struct path_entry *n; n = malloc(sizeof(struct path_entry)); if (!n) errx(1, "out of memory"); n->name = strdup(dirname); if (!n->name) errx(1, "out of memory"); n->next = 0; return n; } void -addtoincludepath(dirname) - const char *dirname; +addtoincludepath(const char *dirname) { struct path_entry *n; n = new_path_entry(dirname); if (last) { last->next = n; last = n; } else last = first = n; } static void ensure_m4path() { static int envpathdone = 0; char *envpath; char *sweep; char *path; if (envpathdone) return; envpathdone = TRUE; envpath = getenv("M4PATH"); if (!envpath) return; /* for portability: getenv result is read-only */ envpath = strdup(envpath); if (!envpath) errx(1, "out of memory"); for (sweep = envpath; (path = strsep(&sweep, ":")) != NULL;) addtoincludepath(path); free(envpath); } static struct input_file * -dopath(i, filename) - struct input_file *i; - const char *filename; +dopath(struct input_file *i, const char *filename) { char path[MAXPATHLEN]; struct path_entry *pe; FILE *f; for (pe = first; pe; pe = pe->next) { snprintf(path, sizeof(path), "%s/%s", pe->name, filename); if ((f = fopen(path, "r")) != 0) { set_input(i, f, path); return i; } } return NULL; } struct input_file * -fopen_trypath(i, filename) - struct input_file *i; - const char *filename; +fopen_trypath(struct input_file *i, const char *filename) { FILE *f; f = fopen(filename, "r"); if (f != NULL) { set_input(i, f, filename); return i; } if (filename[0] == '/') return NULL; ensure_m4path(); return dopath(i, filename); } void -doindir(argv, argc) - const char *argv[]; - int argc; +doindir(const char *argv[], int argc) { ndptr p; p = lookup(argv[2]); if (p == NULL) errx(1, "undefined macro %s", argv[2]); argv[1] = p->defn; eval(argv+1, argc-1, p->type); } void -dobuiltin(argv, argc) - const char *argv[]; - int argc; +dobuiltin(const char *argv[], int argc) { int n; argv[1] = NULL; n = builtin_type(argv[2]); if (n != -1) eval(argv+1, argc-1, n); else errx(1, "unknown builtin %s", argv[2]); } /* We need some temporary buffer space, as pb pushes BACK and substitution * proceeds forward... */ static char *buffer; static size_t bufsize = 0; static size_t current = 0; static void addchars(const char *, size_t); -static void addchar(char); +static void addchar(int); static char *twiddle(const char *); static char *getstring(void); static void exit_regerror(int, regex_t *); static void do_subst(const char *, regex_t *, const char *, regmatch_t *); static void do_regexpindex(const char *, regex_t *, regmatch_t *); static void do_regexp(const char *, regex_t *, const char *, regmatch_t *); static void add_sub(size_t, const char *, regex_t *, regmatch_t *); static void add_replace(const char *, regex_t *, const char *, regmatch_t *); #define addconstantstring(s) addchars((s), sizeof(s)-1) static void -addchars(c, n) - const char *c; - size_t n; +addchars(const char *c, size_t n) { if (n == 0) return; while (current + n > bufsize) { if (bufsize == 0) bufsize = 1024; else bufsize *= 2; buffer = realloc(buffer, bufsize); if (buffer == NULL) errx(1, "out of memory"); } memcpy(buffer+current, c, n); current += n; } static void -addchar(c) - char c; +addchar(int c) { if (current +1 > bufsize) { if (bufsize == 0) bufsize = 1024; else bufsize *= 2; buffer = realloc(buffer, bufsize); if (buffer == NULL) errx(1, "out of memory"); } buffer[current++] = c; } static char * getstring() { addchar('\0'); current = 0; return buffer; } static void -exit_regerror(er, re) - int er; - regex_t *re; +exit_regerror(int er, regex_t *re) { size_t errlen; char *errbuf; errlen = regerror(er, re, NULL, 0); errbuf = xalloc(errlen); regerror(er, re, errbuf, errlen); errx(1, "regular expression error: %s", errbuf); } static void -add_sub(n, string, re, pm) - size_t n; - const char *string; - regex_t *re; - regmatch_t *pm; +add_sub(size_t n, const char *string, regex_t *re, regmatch_t *pm) { if (n > re->re_nsub) warnx("No subexpression %zu", n); /* Subexpressions that did not match are * not an error. */ else if (pm[n].rm_so != -1 && pm[n].rm_eo != -1) { addchars(string + pm[n].rm_so, pm[n].rm_eo - pm[n].rm_so); } } /* Add replacement string to the output buffer, recognizing special * constructs and replacing them with substrings of the original string. */ static void -add_replace(string, re, replace, pm) - const char *string; - regex_t *re; - const char *replace; - regmatch_t *pm; +add_replace(const char *string, regex_t *re, const char *replace, regmatch_t *pm) { const char *p; for (p = replace; *p != '\0'; p++) { if (*p == '&' && !mimic_gnu) { add_sub(0, string, re, pm); continue; } if (*p == '\\') { if (p[1] == '\\') { addchar(p[1]); p++; continue; } if (p[1] == '&') { if (mimic_gnu) add_sub(0, string, re, pm); else addchar(p[1]); p++; continue; } if (isdigit(p[1])) { add_sub(*(++p) - '0', string, re, pm); continue; } } addchar(*p); } } static void -do_subst(string, re, replace, pm) - const char *string; - regex_t *re; - const char *replace; - regmatch_t *pm; +do_subst(const char *string, regex_t *re, const char *replace, regmatch_t *pm) { int error; int flags = 0; const char *last_match = NULL; while ((error = regexec(re, string, re->re_nsub+1, pm, flags)) == 0) { if (pm[0].rm_eo != 0) { if (string[pm[0].rm_eo-1] == '\n') flags = 0; else flags = REG_NOTBOL; } /* NULL length matches are special... We use the `vi-mode' * rule: don't allow a NULL-match at the last match * position. */ if (pm[0].rm_so == pm[0].rm_eo && string + pm[0].rm_so == last_match) { if (*string == '\0') return; addchar(*string); if (*string++ == '\n') flags = 0; else flags = REG_NOTBOL; continue; } last_match = string + pm[0].rm_so; addchars(string, pm[0].rm_so); add_replace(string, re, replace, pm); string += pm[0].rm_eo; } if (error != REG_NOMATCH) exit_regerror(error, re); pbstr(string); } static void -do_regexp(string, re, replace, pm) - const char *string; - regex_t *re; - const char *replace; - regmatch_t *pm; +do_regexp(const char *string, regex_t *re, const char *replace, regmatch_t *pm) { int error; switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) { case 0: add_replace(string, re, replace, pm); pbstr(getstring()); break; case REG_NOMATCH: break; default: exit_regerror(error, re); } } static void -do_regexpindex(string, re, pm) - const char *string; - regex_t *re; - regmatch_t *pm; +do_regexpindex(const char *string, regex_t *re, regmatch_t *pm) { int error; switch(error = regexec(re, string, re->re_nsub+1, pm, 0)) { case 0: pbunsigned(pm[0].rm_so); break; case REG_NOMATCH: pbnum(-1); break; default: exit_regerror(error, re); } } /* In Gnu m4 mode, parentheses for backmatch don't work like POSIX 1003.2 * says. So we twiddle with the regexp before passing it to regcomp. */ static char * -twiddle(p) - const char *p; +twiddle(const char *p) { /* This could use strcspn for speed... */ while (*p != '\0') { if (*p == '\\') { switch(p[1]) { case '(': case ')': case '|': addchar(p[1]); break; case 'w': addconstantstring("[_a-zA-Z0-9]"); break; case 'W': addconstantstring("[^_a-zA-Z0-9]"); break; case '<': addconstantstring("[[:<:]]"); break; case '>': addconstantstring("[[:>:]]"); break; default: addchars(p, 2); break; } p+=2; continue; } if (*p == '(' || *p == ')' || *p == '|') addchar('\\'); addchar(*p); p++; } return getstring(); } /* patsubst(string, regexp, opt replacement) */ /* argv[2]: string * argv[3]: regexp * argv[4]: opt rep */ void -dopatsubst(argv, argc) - const char *argv[]; - int argc; +dopatsubst(const char *argv[], int argc) { int error; regex_t re; regmatch_t *pmatch; if (argc <= 3) { warnx("Too few arguments to patsubst"); return; } error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], REG_NEWLINE | REG_EXTENDED); if (error != 0) exit_regerror(error, &re); pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1)); do_subst(argv[2], &re, argc != 4 && argv[4] != NULL ? argv[4] : "", pmatch); pbstr(getstring()); free(pmatch); regfree(&re); } void -doregexp(argv, argc) - const char *argv[]; - int argc; +doregexp(const char *argv[], int argc) { int error; regex_t re; regmatch_t *pmatch; if (argc <= 3) { warnx("Too few arguments to regexp"); return; } error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], REG_EXTENDED); if (error != 0) exit_regerror(error, &re); pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1)); if (argv[4] == NULL || argc == 4) do_regexpindex(argv[2], &re, pmatch); else do_regexp(argv[2], &re, argv[4], pmatch); free(pmatch); regfree(&re); } void -doesyscmd(cmd) - const char *cmd; +doesyscmd(const char *cmd) { int p[2]; pid_t pid, cpid; int cc; int status; /* Follow gnu m4 documentation: first flush buffers. */ fflush(NULL); /* Just set up standard output, share stderr and stdin with m4 */ if (pipe(p) == -1) err(1, "bad pipe"); switch(cpid = fork()) { case -1: err(1, "bad fork"); /* NOTREACHED */ case 0: (void) close(p[0]); (void) dup2(p[1], 1); (void) close(p[1]); execl(_PATH_BSHELL, "sh", "-c", cmd, NULL); exit(1); default: /* Read result in two stages, since m4's buffer is * pushback-only. */ (void) close(p[1]); do { char result[BUFSIZE]; cc = read(p[0], result, sizeof result); if (cc > 0) addchars(result, cc); } while (cc > 0 || (cc == -1 && errno == EINTR)); (void) close(p[0]); while ((pid = wait(&status)) != cpid && pid >= 0) continue; pbstr(getstring()); } } Index: head/usr.bin/m4/look.c =================================================================== --- head/usr.bin/m4/look.c (revision 95886) +++ head/usr.bin/m4/look.c (revision 95887) @@ -1,151 +1,146 @@ -/* $OpenBSD: look.c,v 1.9 2002/02/16 21:27:48 millert Exp $ */ +/* $OpenBSD: look.c,v 1.10 2002/04/26 16:15:16 espie Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ozan Yigit at York University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include -__SCCSID("@(#)look.c 8.1 (Berkeley) 6/6/93"); +__SCCSID("@(#)look.c 8.1 (Berkeley) 6/6/93"); +__RCSID_SOURCE("$OpenBSD: look.c,v 1.10 2002/04/26 16:15:16 espie Exp $"); __FBSDID("$FreeBSD$"); /* * look.c * Facility: m4 macro processor * by: oz */ #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" static void freent(ndptr); -unsigned -hash(name) - const char *name; +unsigned int +hash(const char *name) { unsigned int h = 0; while (*name) h = (h << 5) + h + *name++; return (h); } /* * find name in the hash table */ ndptr -lookup(name) - const char *name; +lookup(const char *name) { ndptr p; unsigned int h; h = hash(name); for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr) if (h == p->hv && STREQ(name, p->name)) break; return (p); } /* * hash and create an entry in the hash table. * The new entry is added in front of a hash bucket. */ ndptr -addent(name) - const char *name; +addent(const char *name) { unsigned int h; ndptr p; h = hash(name); p = (ndptr) xalloc(sizeof(struct ndblock)); p->nxtptr = hashtab[h % HASHSIZE]; hashtab[h % HASHSIZE] = p; p->name = xstrdup(name); p->hv = h; return p; } static void -freent(p) - ndptr p; +freent(ndptr p) { free((char *) p->name); if (p->defn != null) free((char *) p->defn); free((char *) p); } /* * remove an entry from the hashtable */ void -remhash(name, all) - const char *name; - int all; +remhash(const char *name, int all) { unsigned int h; ndptr xp, tp, mp; h = hash(name); mp = hashtab[h % HASHSIZE]; tp = nil; while (mp != nil) { if (mp->hv == h && STREQ(mp->name, name)) { mp = mp->nxtptr; if (tp == nil) { freent(hashtab[h % HASHSIZE]); hashtab[h % HASHSIZE] = mp; } else { xp = tp->nxtptr; tp->nxtptr = mp; freent(xp); } if (!all) break; } else { tp = mp; mp = mp->nxtptr; } } } Index: head/usr.bin/m4/main.c =================================================================== --- head/usr.bin/m4/main.c (revision 95886) +++ head/usr.bin/m4/main.c (revision 95887) @@ -1,657 +1,644 @@ -/* $OpenBSD: main.c,v 1.52 2002/02/16 21:27:48 millert Exp $ */ +/* $OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $ */ /* $NetBSD: main.c,v 1.12 1997/02/08 23:54:49 cgd Exp $ */ /*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ozan Yigit at York University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"); -__SCCSID("@(#)main.c 8.1 (Berkeley) 6/6/93"); -__RCSID_SOURCE("$OpenBSD: main.c,v 1.52 2002/02/16 21:27:48 millert Exp $"); +__SCCSID("@(#)main.c 8.1 (Berkeley) 6/6/93"); +__RCSID_SOURCE("$OpenBSD: main.c,v 1.53 2002/04/26 16:15:16 espie Exp $"); __FBSDID("$FreeBSD$"); /* * main.c * Facility: m4 macro processor * by: oz */ #include #include #include #include #include #include #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" #include "pathnames.h" ndptr hashtab[HASHSIZE]; /* hash table for macros etc. */ stae *mstack; /* stack of m4 machine */ char *sstack; /* shadow stack, for string space extension */ static size_t STACKMAX; /* current maximum size of stack */ int sp; /* current m4 stack pointer */ int fp; /* m4 call frame pointer */ struct input_file infile[MAXINP];/* input file stack (0=stdin) */ char *inname[MAXINP]; /* names of these input files */ int inlineno[MAXINP]; /* current number in each input file */ FILE **outfile; /* diversion array(0=bitbucket)*/ int maxout; FILE *active; /* active output file pointer */ int ilevel = 0; /* input file stack pointer */ int oindex = 0; /* diversion index.. */ const char *null = ""; /* as it says.. just a null.. */ const char *m4wraps = ""; /* m4wrap string default.. */ char lquote[MAXCCHARS+1] = {LQUOTE}; /* left quote character (`) */ char rquote[MAXCCHARS+1] = {RQUOTE}; /* right quote character (') */ char scommt[MAXCCHARS+1] = {SCOMMT}; /* start character for comment */ char ecommt[MAXCCHARS+1] = {ECOMMT}; /* end character for comment */ int synccpp; /* Line synchronisation for C preprocessor */ struct keyblk keywrds[] = { /* m4 keywords to be installed */ { "include", INCLTYPE }, { "sinclude", SINCTYPE }, { "define", DEFITYPE }, { "defn", DEFNTYPE }, { "divert", DIVRTYPE | NOARGS }, { "expr", EXPRTYPE }, { "eval", EXPRTYPE }, { "substr", SUBSTYPE }, { "ifelse", IFELTYPE }, { "ifdef", IFDFTYPE }, { "len", LENGTYPE }, { "incr", INCRTYPE }, { "decr", DECRTYPE }, { "dnl", DNLNTYPE | NOARGS }, { "changequote", CHNQTYPE | NOARGS }, { "changecom", CHNCTYPE | NOARGS }, { "index", INDXTYPE }, #ifdef EXTENDED { "paste", PASTTYPE }, { "spaste", SPASTYPE }, /* Newer extensions, needed to handle gnu-m4 scripts */ { "indir", INDIRTYPE}, { "builtin", BUILTINTYPE}, { "patsubst", PATSTYPE}, { "regexp", REGEXPTYPE}, { "esyscmd", ESYSCMDTYPE}, { "__file__", FILENAMETYPE | NOARGS}, { "__line__", LINETYPE | NOARGS}, #endif { "popdef", POPDTYPE }, { "pushdef", PUSDTYPE }, { "dumpdef", DUMPTYPE | NOARGS }, { "shift", SHIFTYPE | NOARGS }, { "translit", TRNLTYPE }, { "undefine", UNDFTYPE }, { "undivert", UNDVTYPE | NOARGS }, { "divnum", DIVNTYPE | NOARGS }, { "maketemp", MKTMTYPE }, { "errprint", ERRPTYPE | NOARGS }, { "m4wrap", M4WRTYPE | NOARGS }, { "m4exit", EXITTYPE | NOARGS }, { "syscmd", SYSCTYPE }, { "sysval", SYSVTYPE | NOARGS }, { "traceon", TRACEONTYPE | NOARGS }, { "traceoff", TRACEOFFTYPE | NOARGS }, #if defined(unix) || defined(__unix__) { "unix", SELFTYPE | NOARGS }, #else #ifdef vms { "vms", SELFTYPE | NOARGS }, #endif #endif }; #define MAXKEYS (sizeof(keywrds)/sizeof(struct keyblk)) extern int optind; extern char *optarg; #define MAXRECORD 50 static struct position { char *name; unsigned long line; } quotes[MAXRECORD], paren[MAXRECORD]; static void record(struct position *, int); static void dump_stack(struct position *, int); static void macro(void); static void initkwds(void); static ndptr inspect(int, char *); static int do_look_ahead(int, const char *); static void enlarge_stack(void); int main(int, char *[]); int -main(argc,argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { int c; int n; char *p; traceout = stderr; if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); initkwds(); initspaces(); STACKMAX = INITSTACKMAX; mstack = (stae *)xalloc(sizeof(stae) * STACKMAX); sstack = (char *)xalloc(STACKMAX); maxout = 0; outfile = NULL; resizedivs(MAXOUT); while ((c = getopt(argc, argv, "gst:d:D:U:o:I:")) != -1) switch(c) { case 'D': /* define something..*/ for (p = optarg; *p; p++) if (*p == '=') break; if (*p) *p++ = EOS; dodefine(optarg, p); break; case 'I': addtoincludepath(optarg); break; case 'U': /* undefine... */ remhash(optarg, TOP); break; case 'g': mimic_gnu = 1; break; case 'd': set_trace_flags(optarg); break; case 's': synccpp = 1; break; case 't': mark_traced(optarg, 1); break; case 'o': trace_file(optarg); break; case '?': usage(); } argc -= optind; argv += optind; active = stdout; /* default active output */ bbase[0] = bufbase; if (!argc) { sp = -1; /* stack pointer initialized */ fp = 0; /* frame pointer initialized */ set_input(infile+0, stdin, "stdin"); /* default input (naturally) */ if ((inname[0] = strdup("-")) == NULL) err(1, NULL); inlineno[0] = 1; emitline(); macro(); } else for (; argc--; ++argv) { p = *argv; if (p[0] == '-' && p[1] == EOS) set_input(infile, stdin, "stdin"); else if (fopen_trypath(infile, p) == NULL) err(1, "%s", p); sp = -1; fp = 0; if ((inname[0] = strdup(p)) == NULL) err(1, NULL); inlineno[0] = 1; emitline(); macro(); release_input(infile); } if (*m4wraps) { /* anything for rundown ?? */ ilevel = 0; /* in case m4wrap includes.. */ bufbase = bp = buf; /* use the entire buffer */ pbstr(m4wraps); /* user-defined wrapup act */ macro(); /* last will and testament */ } if (active != stdout) active = stdout; /* reset output just in case */ for (n = 1; n < maxout; n++) /* default wrap-up: undivert */ if (outfile[n] != NULL) getdiv(n); /* remove bitbucket if used */ if (outfile[0] != NULL) { (void) fclose(outfile[0]); } return 0; } /* * Look ahead for `token'. * (on input `t == token[0]') * Used for comment and quoting delimiters. * Returns 1 if `token' present; copied to output. * 0 if `token' not found; all characters pushed back */ static int -do_look_ahead(t, token) - int t; - const char *token; +do_look_ahead(int t, const char *token) { int i; assert((unsigned char)t == (unsigned char)token[0]); for (i = 1; *++token; i++) { t = gpbc(); if (t == EOF || (unsigned char)t != (unsigned char)*token) { putback(t); while (--i) putback(*--token); return 0; } } return 1; } #define LOOK_AHEAD(t, token) (t != EOF && \ (unsigned char)(t)==(unsigned char)(token)[0] && \ do_look_ahead(t,token)) /* * macro - the work horse.. */ static void macro() { char token[MAXTOK+1]; int t, l; ndptr p; int nlpar; cycle { t = gpbc(); if (t == '_' || isalpha(t)) { p = inspect(t, token); if (p != nil) putback(l = gpbc()); if (p == nil || (l != LPAREN && (p->type & NEEDARGS) != 0)) outputstr(token); else { /* * real thing.. First build a call frame: */ pushf(fp); /* previous call frm */ pushf(p->type); /* type of the call */ pushf(0); /* parenthesis level */ fp = sp; /* new frame pointer */ /* * now push the string arguments: */ pushs1(p->defn); /* defn string */ pushs1(p->name); /* macro name */ pushs(ep); /* start next..*/ if (l != LPAREN && PARLEV == 0) { /* no bracks */ chrsave(EOS); if (sp == STACKMAX) errx(1, "internal stack overflow"); eval((const char **) mstack+fp+1, 2, CALTYP); ep = PREVEP; /* flush strspace */ sp = PREVSP; /* previous sp.. */ fp = PREVFP; /* rewind stack...*/ } } } else if (t == EOF) { if (sp > -1) { warnx( "unexpected end of input, unclosed parenthesis:"); dump_stack(paren, PARLEV); exit(1); } if (ilevel <= 0) break; /* all done thanks.. */ release_input(infile+ilevel--); free(inname[ilevel+1]); bufbase = bbase[ilevel]; emitline(); continue; } /* * non-alpha token possibly seen.. * [the order of else if .. stmts is important.] */ else if (LOOK_AHEAD(t,lquote)) { /* strip quotes */ nlpar = 0; record(quotes, nlpar++); /* * Opening quote: scan forward until matching * closing quote has been found. */ do { l = gpbc(); if (LOOK_AHEAD(l,rquote)) { if (--nlpar > 0) outputstr(rquote); } else if (LOOK_AHEAD(l,lquote)) { record(quotes, nlpar++); outputstr(lquote); } else if (l == EOF) { if (nlpar == 1) warnx("unclosed quote:"); else warnx("%d unclosed quotes:", nlpar); dump_stack(quotes, nlpar); exit(1); } else { if (nlpar > 0) { if (sp < 0) putc(l, active); else CHRSAVE(l); } } } while (nlpar != 0); } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { fputs(scommt, active); for(;;) { t = gpbc(); if (LOOK_AHEAD(t, ecommt)) { fputs(ecommt, active); break; } if (t == EOF) break; putc(t, active); } } else if (sp < 0) { /* not in a macro at all */ putc(t, active); /* output directly.. */ } else switch(t) { case LPAREN: if (PARLEV > 0) chrsave(t); while (isspace(l = gpbc())) ; /* skip blank, tab, nl.. */ putback(l); record(paren, PARLEV++); break; case RPAREN: if (--PARLEV > 0) chrsave(t); else { /* end of argument list */ chrsave(EOS); if (sp == STACKMAX) errx(1, "internal stack overflow"); eval((const char **) mstack+fp+1, sp-fp, CALTYP); ep = PREVEP; /* flush strspace */ sp = PREVSP; /* previous sp.. */ fp = PREVFP; /* rewind stack...*/ } break; case COMMA: if (PARLEV == 1) { chrsave(EOS); /* new argument */ while (isspace(l = gpbc())) ; putback(l); pushs(ep); } else chrsave(t); break; default: if (LOOK_AHEAD(t, scommt)) { char *pc; for (pc = scommt; *pc; pc++) chrsave(*pc); for(;;) { t = gpbc(); if (LOOK_AHEAD(t, ecommt)) { for (pc = ecommt; *pc; pc++) chrsave(*pc); break; } if (t == EOF) break; CHRSAVE(t); } } else CHRSAVE(t); /* stack the char */ break; } } } /* * output string directly, without pushing it for reparses. */ void -outputstr(s) - const char *s; +outputstr(const char *s) { if (sp < 0) while (*s) putc(*s++, active); else while (*s) CHRSAVE(*s++); } /* * build an input token.. * consider only those starting with _ or A-Za-z. This is a * combo with lookup to speed things up. */ static ndptr -inspect(c, tp) - int c; - char *tp; +inspect(int c, char *tp) { char *name = tp; char *etp = tp+MAXTOK; ndptr p; unsigned int h; h = *tp++ = c; while ((isalnum(c = gpbc()) || c == '_') && tp < etp) h = (h << 5) + h + (*tp++ = c); if (c != EOF) PUTBACK(c); *tp = EOS; /* token is too long, it won't match anything, but it can still * be output. */ if (tp == ep) { outputstr(name); while (isalnum(c = gpbc()) || c == '_') { if (sp < 0) putc(c, active); else CHRSAVE(c); } *name = EOS; return nil; } for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr) if (h == p->hv && STREQ(name, p->name)) break; return p; } /* * initkwds - initialise m4 keywords as fast as possible. * This very similar to install, but without certain overheads, * such as calling lookup. Malloc is not used for storing the * keyword strings, since we simply use the static pointers * within keywrds block. */ static void initkwds() { size_t i; unsigned int h; ndptr p; for (i = 0; i < MAXKEYS; i++) { h = hash(keywrds[i].knam); p = (ndptr) xalloc(sizeof(struct ndblock)); p->nxtptr = hashtab[h % HASHSIZE]; hashtab[h % HASHSIZE] = p; p->name = xstrdup(keywrds[i].knam); p->defn = xstrdup(null); p->hv = h; p->type = keywrds[i].ktyp & TYPEMASK; if ((keywrds[i].ktyp & NOARGS) == 0) p->type |= NEEDARGS; } } /* Look up a builtin type, even if overridden by the user */ int -builtin_type(key) - const char *key; +builtin_type(const char *key) { int i; for (i = 0; i != MAXKEYS; i++) if (STREQ(keywrds[i].knam, key)) return keywrds[i].ktyp; return -1; } const char * -builtin_realname(n) - int n; +builtin_realname(int n) { int i; for (i = 0; i != MAXKEYS; i++) if (((keywrds[i].ktyp ^ n) & TYPEMASK) == 0) return keywrds[i].knam; return NULL; } static void -record(t, lev) - struct position *t; - int lev; +record(struct position *t, int lev) { if (lev < MAXRECORD) { t[lev].name = CURRENT_NAME; t[lev].line = CURRENT_LINE; } } static void -dump_stack(t, lev) - struct position *t; - int lev; +dump_stack(struct position *t, int lev) { int i; for (i = 0; i < lev; i++) { if (i == MAXRECORD) { fprintf(stderr, " ...\n"); break; } fprintf(stderr, " %s at line %lu\n", t[i].name, t[i].line); } } static void enlarge_stack() { STACKMAX *= 2; mstack = realloc(mstack, sizeof(stae) * STACKMAX); sstack = realloc(sstack, STACKMAX); if (mstack == NULL || sstack == NULL) errx(1, "Evaluation stack overflow (%lu)", (unsigned long)STACKMAX); } /* Emit preprocessor #line directive if -s option used. */ void emitline(void) { if (synccpp) fprintf(active, "#line %d \"%s\"\n", inlineno[ilevel], inname[ilevel]); } Index: head/usr.bin/m4/misc.c =================================================================== --- head/usr.bin/m4/misc.c (revision 95886) +++ head/usr.bin/m4/misc.c (revision 95887) @@ -1,380 +1,359 @@ -/* $OpenBSD: misc.c,v 1.26 2001/11/16 23:50:40 deraadt Exp $ */ +/* $OpenBSD: misc.c,v 1.27 2002/04/26 16:15:16 espie Exp $ */ /* $NetBSD: misc.c,v 1.6 1995/09/28 05:37:41 tls Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ozan Yigit at York University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include -__SCCSID("@(#)misc.c 8.1 (Berkeley) 6/6/93"); -__RCSID_SOURCE("$OpenBSD: misc.c,v 1.26 2001/11/16 23:50:40 deraadt Exp $"); +__SCCSID("@(#)misc.c 8.1 (Berkeley) 6/6/93"); +__RCSID_SOURCE("$OpenBSD: misc.c,v 1.27 2002/04/26 16:15:16 espie Exp $"); __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" #include "pathnames.h" char *ep; /* first free char in strspace */ static char *strspace; /* string space for evaluation */ char *endest; /* end of string space */ static size_t strsize = STRSPMAX; static size_t bufsize = BUFSIZE; char *buf; /* push-back buffer */ char *bufbase; /* the base for current ilevel */ char *bbase[MAXINP]; /* the base for each ilevel */ char *bp; /* first available character */ char *endpbb; /* end of push-back buffer */ /* * find the index of second str in the first str. */ ptrdiff_t -indx(s1, s2) - const char *s1; - const char *s2; +indx(const char *s1, const char *s2) { char *t; t = strstr(s1, s2); if (t == NULL) return (-1); else return (t - s1); } /* * putback - push character back onto input */ void -putback(c) - int c; +putback(int c) { if (c == EOF) return; if (bp >= endpbb) enlarge_bufspace(); *bp++ = c; } /* * pbstr - push string back onto input * putback is replicated to improve * performance. */ void -pbstr(s) - const char *s; +pbstr(const char *s) { size_t n; n = strlen(s); while ((size_t)(endpbb - bp) <= n) enlarge_bufspace(); while (n > 0) *bp++ = s[--n]; } /* * pbnum - convert number to string, push back on input. */ void -pbnum(n) - int n; +pbnum(int n) { int num; num = (n < 0) ? -n : n; do { putback(num % 10 + '0'); } while ((num /= 10) > 0); if (n < 0) putback('-'); } /* * pbunsigned - convert unsigned long to string, push back on input. */ void -pbunsigned(n) - unsigned long n; +pbunsigned(unsigned long n) { do { putback(n % 10 + '0'); } while ((n /= 10) > 0); } void initspaces() { int i; strspace = xalloc(strsize+1); ep = strspace; endest = strspace+strsize; buf = (char *)xalloc(bufsize); bufbase = buf; bp = buf; endpbb = buf + bufsize; for (i = 0; i < MAXINP; i++) bbase[i] = buf; } void enlarge_strspace() { char *newstrspace; int i; strsize *= 2; newstrspace = malloc(strsize + 1); if (!newstrspace) errx(1, "string space overflow"); memcpy(newstrspace, strspace, strsize/2); for (i = 0; i <= sp; i++) if (sstack[i]) mstack[i].sstr = (mstack[i].sstr - strspace) + newstrspace; ep = (ep-strspace) + newstrspace; free(strspace); strspace = newstrspace; endest = strspace + strsize; } void enlarge_bufspace() { char *newbuf; int i; bufsize *= 2; newbuf = realloc(buf, bufsize); if (!newbuf) errx(1, "too many characters pushed back"); for (i = 0; i < MAXINP; i++) bbase[i] = (bbase[i]-buf)+newbuf; bp = (bp-buf)+newbuf; bufbase = (bufbase-buf)+newbuf; buf = newbuf; endpbb = buf+bufsize; } /* * chrsave - put single char on string space */ void -chrsave(c) - int c; +chrsave(int c) { if (ep >= endest) enlarge_strspace(); *ep++ = c; } /* * read in a diversion file, and dispose it. */ void -getdiv(n) - int n; +getdiv(int n) { int c; if (active == outfile[n]) errx(1, "undivert: diversion still active"); rewind(outfile[n]); while ((c = getc(outfile[n])) != EOF) putc(c, active); (void) fclose(outfile[n]); outfile[n] = NULL; } void -onintr(signo) - int signo __unused; +onintr(int signo __unused) { #define intrmessage "m4: interrupted.\n" write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1); _exit(1); } /* * killdiv - get rid of the diversion files */ void killdiv() { int n; for (n = 0; n < maxout; n++) if (outfile[n] != NULL) { (void) fclose(outfile[n]); } } /* * resizedivs: allocate more diversion files */ void -resizedivs(n) - int n; +resizedivs(int n) { int i; outfile = (FILE **)realloc(outfile, sizeof(FILE *) * n); if (outfile == NULL) errx(1, "too many diverts %d", n); for (i = maxout; i < n; i++) outfile[i] = NULL; maxout = n; } void * -xalloc(n) - size_t n; +xalloc(size_t n) { char *p = malloc(n); if (p == NULL) err(1, "malloc"); return p; } char * -xstrdup(s) - const char *s; +xstrdup(const char *s) { char *p = strdup(s); if (p == NULL) err(1, "strdup"); return p; } void usage() { fprintf(stderr, "usage: m4 [-d flags] [-t name] [-gs] [-D name[=value]]...\n" " [-U name]... [-I dirname]... file...\n"); exit(1); } int -obtain_char(f) - struct input_file *f; +obtain_char(struct input_file *f) { if (f->c == EOF) return EOF; else if (f->c == '\n') f->lineno++; f->c = fgetc(f->file); return f->c; } void -set_input(f, real, name) - struct input_file *f; - FILE *real; - const char *name; +set_input(struct input_file *f, FILE *real, const char *name) { f->file = real; f->lineno = 1; f->c = 0; f->name = xstrdup(name); } void -release_input(f) - struct input_file *f; +release_input(struct input_file *f) { if (f->file != stdin) fclose(f->file); f->c = EOF; /* * XXX can't free filename, as there might still be * error information pointing to it. */ } void -doprintlineno(f) - struct input_file *f; +doprintlineno(struct input_file *f) { pbunsigned(f->lineno); } void -doprintfilename(f) - struct input_file *f; +doprintfilename(struct input_file *f) { pbstr(rquote); pbstr(f->name); pbstr(lquote); } /* * buffer_mark/dump_buffer: allows one to save a mark in a buffer, * and later dump everything that was added since then to a file. */ size_t buffer_mark() { return bp - buf; } void -dump_buffer(f, m) - FILE *f; - size_t m; +dump_buffer(FILE *f, size_t m) { char *s; for (s = bp; s - buf > (int)m;) fputc(*--s, f); } Index: head/usr.bin/m4/trace.c =================================================================== --- head/usr.bin/m4/trace.c (revision 95886) +++ head/usr.bin/m4/trace.c (revision 95887) @@ -1,276 +1,265 @@ -/* $OpenBSD: trace.c,v 1.4 2002/02/16 21:27:48 millert Exp $ */ +/* $OpenBSD: trace.c,v 1.6 2002/04/26 16:15:16 espie Exp $ */ /* * Copyright (c) 2001 Marc Espie. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +__RCSID_SOURCE("$OpenBSD: trace.c,v 1.6 2002/04/26 16:15:16 espie Exp $"); __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" FILE *traceout; int traced_macros = 0; #define TRACE_ARGS 1 #define TRACE_EXPANSION 2 #define TRACE_QUOTE 4 #define TRACE_FILENAME 8 #define TRACE_LINENO 16 #define TRACE_CONT 32 #define TRACE_ID 64 #define TRACE_NEWFILE 128 /* not implemented yet */ #define TRACE_INPUT 256 /* not implemented yet */ #define TRACE_ALL 512 static struct t { struct t *next; char *name; int on; } *l; static unsigned int letter_to_flag(int); static void print_header(struct input_file *); static struct t *find_trace_entry(const char *); static int frame_level(void); static unsigned int flags = TRACE_QUOTE | TRACE_EXPANSION; static struct t * -find_trace_entry(name) - const char *name; +find_trace_entry(const char *name) { struct t *n; for (n = l; n != NULL; n = n->next) if (STREQ(n->name, name)) return n; return NULL; } void -mark_traced(name, on) - const char *name; - int on; +mark_traced(const char *name, int on) { struct t *n, *n2; traced_macros = 1; if (name == NULL) { if (on) flags |= TRACE_ALL; else { flags &= ~TRACE_ALL; traced_macros = 0; } for (n = l; n != NULL; n = n2) { n2 = n->next; free(n->name); free(n); } l = NULL; } else { n = find_trace_entry(name); if (n == NULL) { - n = xalloc(sizeof(struct t)); - n->name = xstrdup(name); - n->next = l; - l = n; + n = xalloc(sizeof(struct t)); + n->name = xstrdup(name); + n->next = l; + l = n; } n->on = on; } } int -is_traced(name) - const char *name; +is_traced(const char *name) { struct t *n; for (n = l; n != NULL; n = n->next) if (STREQ(n->name, name)) return n->on; return (flags & TRACE_ALL) ? 1 : 0; } void -trace_file(name) - const char *name; +trace_file(const char *name) { if (traceout != stderr) fclose(traceout); traceout = fopen(name, "w"); if (!traceout) err(1, "can't open %s", name); } static unsigned int -letter_to_flag(c) - int c; +letter_to_flag(int c) { switch(c) { case 'a': return TRACE_ARGS; case 'e': return TRACE_EXPANSION; case 'q': return TRACE_QUOTE; case 'c': return TRACE_CONT; case 'x': return TRACE_ID; case 'f': return TRACE_FILENAME; case 'l': return TRACE_LINENO; case 'p': return TRACE_NEWFILE; case 'i': return TRACE_INPUT; case 't': return TRACE_ALL; case 'V': return ~0; default: return 0; } } void -set_trace_flags(s) - const char *s; +set_trace_flags(const char *s) { char mode = 0; unsigned int f = 0; traced_macros = 1; if (*s == '+' || *s == '-') mode = *s++; while (*s) f |= letter_to_flag(*s++); switch(mode) { case 0: flags = f; break; case '+': flags |= f; break; case '-': flags &= ~f; break; } } static int frame_level() { int level; int framep; for (framep = fp, level = 0; framep != 0; level++,framep = mstack[framep-2].sfra) ; return level; } static void -print_header(inp) - struct input_file *inp; +print_header(struct input_file *inp) { fprintf(traceout, "m4trace:"); if (flags & TRACE_FILENAME) fprintf(traceout, "%s:", inp->name); if (flags & TRACE_LINENO) fprintf(traceout, "%lu:", inp->lineno); fprintf(traceout, " -%d- ", frame_level()); if (flags & TRACE_ID) fprintf(traceout, "id %lu: ", expansion_id); } ssize_t -trace(argv, argc, inp) - const char **argv; - int argc; - struct input_file *inp; +trace(const char *argv[], int argc, struct input_file *inp) { print_header(inp); if (flags & TRACE_CONT) { fprintf(traceout, "%s ...\n", argv[1]); print_header(inp); } fprintf(traceout, "%s", argv[1]); if ((flags & TRACE_ARGS) && argc > 2) { char delim[3]; int i; delim[0] = LPAREN; delim[1] = EOS; for (i = 2; i < argc; i++) { fprintf(traceout, "%s%s%s%s", delim, (flags & TRACE_QUOTE) ? lquote : "", argv[i], (flags & TRACE_QUOTE) ? rquote : ""); delim[0] = COMMA; delim[1] = ' '; delim[2] = EOS; } fprintf(traceout, "%c", RPAREN); } if (flags & TRACE_CONT) { fprintf(traceout, " -> ???\n"); print_header(inp); fprintf(traceout, argc > 2 ? "%s(...)" : "%s", argv[1]); } if (flags & TRACE_EXPANSION) return buffer_mark(); else { fprintf(traceout, "\n"); return -1; } } void -finish_trace(mark) -size_t mark; +finish_trace(size_t mark) { fprintf(traceout, " -> "); if (flags & TRACE_QUOTE) fprintf(traceout, "%s", lquote); dump_buffer(traceout, mark); if (flags & TRACE_QUOTE) fprintf(traceout, "%s", rquote); fprintf(traceout, "\n"); }