Index: head/usr.bin/m4/Makefile =================================================================== --- head/usr.bin/m4/Makefile (revision 269161) +++ head/usr.bin/m4/Makefile (revision 269162) @@ -1,31 +1,28 @@ -# $OpenBSD: Makefile,v 1.10 2002/04/26 13:13:41 espie Exp $ +# $OpenBSD: Makefile,v 1.13 2014/05/12 19:11:19 espie Exp $ # $FreeBSD$ # -DEXTENDED # if you want the paste & spaste macros. .include PROG= m4 CFLAGS+=-DEXTENDED -I${.CURDIR} -I${.CURDIR}/lib DPADD= ${LIBY} ${LIBL} ${LIBM} LDADD= -ly -ll -lm NO_WMISSING_VARIABLE_DECLARATIONS= SRCS= eval.c expr.c look.c main.c misc.c gnum4.c trace.c parser.y tokenizer.l .PATH: ${.CURDIR}/lib -SRCS+= ohash_create_entry.c ohash_delete.c ohash_do.c ohash_entries.c \ - ohash_enum.c ohash_init.c ohash_int.h ohash_interval.c \ - ohash_lookup_interval.c ohash_lookup_memory.c ohash_qlookup.c \ - ohash_qlookupi.c +SRCS+= ohash.c tokenizer.o: parser.h CLEANFILES+= parser.c parser.h tokenizer.o .if ${MK_TESTS} != "no" SUBDIR+= tests .endif .include Index: head/usr.bin/m4/eval.c =================================================================== --- head/usr.bin/m4/eval.c (revision 269161) +++ head/usr.bin/m4/eval.c (revision 269162) @@ -1,1014 +1,1014 @@ -/* $OpenBSD: eval.c,v 1.70 2012/04/12 17:00:11 espie Exp $ */ +/* $OpenBSD: eval.c,v 1.73 2014/07/11 21:04:17 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. 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 __FBSDID("$FreeBSD$"); /* * eval.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" 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 dochq(const char *[], int); static void dochc(const char *[], int); static void dom4wrap(const char *); 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(const char *, struct macro_definition *); 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 NULL 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(const char *argv[], int argc, int td, int is_traced) { size_t mark = SIZE_MAX; expansion_id++; if (td & RECDEF) m4errx(1, "expanding recursive definition for %s.", argv[1]); if (is_traced) mark = trace(argv, argc, infile+ilevel); if (td == MACRTYPE) expand_macro(argv, argc); else expand_builtin(argv, argc, td); if (mark != SIZE_MAX) finish_trace(mark); } /* * expand_builtin - evaluate built-in macros. */ void 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.. */ /* we keep the initial value for those built-ins that differentiate * between builtin() and builtin. */ ac = argc; if (argc == 3 && !*(argv[2]) && !mimic_gnu) 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 */ { int base = 10; int maxdigits = 0; const char *errstr; if (argc > 3) { base = strtonum(argv[3], 2, 36, &errstr); if (errstr) { m4errx(1, "expr: base %s invalid.", argv[3]); } } if (argc > 4) { maxdigits = strtonum(argv[4], 0, INT_MAX, &errstr); if (errstr) { m4errx(1, "expr: maxdigits %s invalid.", argv[4]); } } if (argc > 2) pbnumbase(expr(argv[2]), base, maxdigits); 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_macro_definition(argv[2]) != NULL) 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) { fflush(stdout); 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 (argc > 2) { if (!doincl(argv[2])) { if (mimic_gnu) { warn("%s at line %lu: include(%s)", CURRENT_NAME, CURRENT_LINE, argv[2]); exit_code = 1; } else 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; case FORMATTYPE: doformat(argv, argc); break; #endif case CHNQTYPE: dochq(argv, ac); break; case CHNCTYPE: 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); pushback(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++) macro_undefine(argv[n]); break; case POPDTYPE: /* * dopopdef - remove the topmost * definitions of macro(s) or m4 * keyword(s). */ if (argc > 2) for (n = 2; n < argc; n++) macro_popdef(argv[n]); 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, NULL); 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 */ if (argc > 2) dom4wrap(argv[2]); 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: m4errx(1, "eval: major botch."); break; } } /* * expand_macro - user-defined macro expansion */ void 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) PUSHBACK(*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]); pushback(COMMA); } pbstr(argv[2]); } break; case '@': if (argc > 2) { for (n = argc - 1; n > 2; n--) { pbstr(rquote); pbstr(argv[n]); pbstr(lquote); pushback(COMMA); } pbstr(rquote); pbstr(argv[2]); pbstr(lquote); } break; default: PUSHBACK(*p); PUSHBACK('$'); break; } p--; } p--; } if (p == t) /* do last character */ PUSHBACK(*p); } /* * dodefine - install definition in the table */ void dodefine(const char *name, const char *defn) { if (!*name && !mimic_gnu) m4errx(1, "null definition."); else macro_define(name, defn); } /* * dodefn - push back a quoted definition of * the given name. */ static void dodefn(const char *name) { struct macro_definition *p; if ((p = lookup_macro_definition(name)) != NULL) { if ((p->type & TYPEMASK) == MACRTYPE) { pbstr(rquote); pbstr(p->defn); pbstr(lquote); } else { pbstr(p->defn); 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(const char *name, const char *defn) { if (!*name && !mimic_gnu) m4errx(1, "null definition."); else macro_pushdef(name, defn); } /* * dump_one_def - dump the specified definition. */ static void dump_one_def(const char *name, struct macro_definition *p) { if (!traceout) traceout = stderr; if (mimic_gnu) { if ((p->type & TYPEMASK) == MACRTYPE) fprintf(traceout, "%s:\t%s\n", name, p->defn); else { fprintf(traceout, "%s:\t<%s>\n", name, p->defn); } } else fprintf(traceout, "`%s'\t`%s'\n", 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(const char *argv[], int argc) { int n; struct macro_definition *p; if (argc > 2) { for (n = 2; n < argc; n++) if ((p = lookup_macro_definition(argv[n])) != NULL) dump_one_def(argv[n], p); } else macro_for_all(dump_one_def); } /* * dotrace - mark some macros as traced/untraced depending upon on. */ static void 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(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(const char *ifile) { if (ilevel + 1 == MAXINP) m4errx(1, "too many include files."); if (fopen_trypath(infile+ilevel+1, ifile) != NULL) { ilevel++; bbase[ilevel] = bufbase = bp; return (1); } else return (0); } #ifdef EXTENDED /* * dopaste - include a given file without any * macro processing. */ static int dopaste(const char *pfile) { FILE *pf; int c; if ((pf = fopen(pfile, "r")) != NULL) { if (synch_lines) fprintf(active, "#line 1 \"%s\"\n", pfile); while ((c = getc(pf)) != EOF) putc(c, active); (void) fclose(pf); emit_synchline(); return (1); } else return (0); } #endif /* * dochq - change quote characters */ static void dochq(const char *argv[], int ac) { 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] = ECOMMT; rquote[1] = EOS; } } } /* * dochc - change comment characters */ static void dochc(const char *argv[], int argc) { /* XXX Note that there is no difference between no argument and a single * empty argument. */ if (argc == 2) { scommt[0] = EOS; ecommt[0] = EOS; } else { strlcpy(scommt, argv[2], sizeof(scommt)); if (argc == 3) { ecommt[0] = ECOMMT; ecommt[1] = EOS; } else { strlcpy(ecommt, argv[3], sizeof(ecommt)); } } } /* * dom4wrap - expand text at EOF */ static void dom4wrap(const char *text) { if (wrapindex >= maxwraps) { if (maxwraps == 0) maxwraps = 16; else maxwraps *= 2; - m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps), + m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps), "too many m4wraps"); } m4wraps[wrapindex++] = xstrdup(text); } /* * dodivert - divert the output to a temporary file */ static void 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); + if ((fd = mkstemp(fname)) < 0 || + unlink(fname) == -1 || + (outfile[n] = fdopen(fd, "w+")) == NULL) + err(1, "%s: cannot divert", fname); } active = outfile[n]; } /* * doundivert - undivert a specified output, or all * other outputs, in numerical order. */ static void doundiv(const char *argv[], int argc) { int ind; int n; if (argc > 2) { for (ind = 2; ind < argc; ind++) { const char *errstr; n = strtonum(argv[ind], 1, INT_MAX, &errstr); if (errstr) { if (errno == EINVAL && mimic_gnu) getdivfile(argv[ind]); } else { if (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(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--) pushback(*k); } /* * map: * map every character of s1 that is specified in from * into s3 and replace in s. (source s1 remains untouched) * * This is derived from the 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. */ static void 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]; int i; char seen[256]; 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" */ for (i = 0; i < 256; i++) seen[i] = 0; while (*from) { if (!seen[(unsigned char)(*from)]) { mapvec[(unsigned char)(*from)] = (unsigned char)(*to); seen[(unsigned char)(*from)] = 1; } from++; if (*to) to++; } while (*src) { sch = (unsigned char)(*src++); 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(char *buffer, char *end, const char *src) { char *p; p = buffer; while(*src) { if (src[1] == '-' && src[2]) { unsigned char i; if ((unsigned char)src[0] <= (unsigned char)src[2]) { for (i = (unsigned char)src[0]; i <= (unsigned char)src[2]; i++) { *p++ = i; if (p == end) { *p = '\0'; return buffer; } } } else { 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/extern.h =================================================================== --- head/usr.bin/m4/extern.h (revision 269161) +++ head/usr.bin/m4/extern.h (revision 269162) @@ -1,178 +1,180 @@ -/* $OpenBSD: extern.h,v 1.52 2012/04/12 17:00:11 espie Exp $ */ +/* $OpenBSD: extern.h,v 1.54 2014/05/12 19:11:19 espie Exp $ */ /* $NetBSD: extern.h,v 1.3 1996/01/13 23:25:24 pk Exp $ */ /*- * Copyright (c) 1991, 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. 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. * * @(#)extern.h 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ /* eval.c */ extern void eval(const char *[], int, int, int); extern void dodefine(const char *, const char *); extern unsigned long expansion_id; /* expr.c */ extern int expr(const char *); extern int32_t end_result; /* gnum4.c */ extern void addtoincludepath(const char *); extern struct input_file *fopen_trypath(struct input_file *, const char *); extern void doindir(const char *[], int); extern void dobuiltin(const char *[], int); extern void dopatsubst(const char *[], int); extern void doregexp(const char *[], int); extern void doprintlineno(struct input_file *); extern void doprintfilename(struct input_file *); extern void doesyscmd(const char *); extern void getdivfile(const char *); extern void doformat(const char *[], int); /* look.c */ #define FLAG_UNTRACED 0 #define FLAG_TRACED 1 #define FLAG_NO_TRACE 2 extern void init_macros(void); extern ndptr lookup(const char *); extern void mark_traced(const char *, int); extern struct ohash macros; extern struct macro_definition *lookup_macro_definition(const char *); extern void macro_define(const char *, const char *); extern void macro_pushdef(const char *, const char *); extern void macro_popdef(const char *); extern void macro_undefine(const char *); extern void setup_builtin(const char *, unsigned int); extern void macro_for_all(void (*)(const char *, struct macro_definition *)); #define macro_getdef(p) ((p)->d) #define macro_name(p) ((p)->name) #define macro_builtin_type(p) ((p)->builtin_type) #define is_traced(p) ((p)->trace_flags == FLAG_NO_TRACE ? (trace_flags & TRACE_ALL) : (p)->trace_flags) extern ndptr macro_getbuiltin(const char *); /* main.c */ extern void outputstr(const char *); extern void do_emit_synchline(void); extern int exit_code; #define emit_synchline() do { if (synch_lines) do_emit_synchline(); } while(0) /* misc.c */ extern void chrsave(int); extern char *compute_prevep(void); extern void getdiv(int); extern ptrdiff_t indx(const char *, const char *); extern void initspaces(void); extern void killdiv(void); extern void onintr(int); extern void pbnum(int); extern void pbnumbase(int, int, int); extern void pbunsigned(unsigned long); extern void pbstr(const char *); extern void pushback(int); -extern void *xalloc(size_t, const char *fmt, ...); -extern void *xrealloc(void *, size_t, const char *fmt, ...); +extern void *xalloc(size_t, const char *, ...); +extern void *xcalloc(size_t, size_t, const char *, ...); +extern void *xrealloc(void *, size_t, const char *, ...); +extern void *xreallocarray(void *, size_t, size_t, const char *, ...); extern char *xstrdup(const char *); extern void usage(void); extern void resizedivs(int); extern size_t buffer_mark(void); extern void dump_buffer(FILE *, size_t); extern void m4errx(int, const char *, ...); extern int obtain_char(struct input_file *); extern void set_input(struct input_file *, FILE *, const char *); extern void release_input(struct input_file *); /* speeded-up versions of chrsave/pushback */ #define PUSHBACK(c) \ do { \ if (bp >= endpbb) \ enlarge_bufspace(); \ *bp++ = (c); \ } while(0) #define CHRSAVE(c) \ do { \ if (ep >= endest) \ enlarge_strspace(); \ *ep++ = (c); \ } while(0) /* and corresponding exposure for local symbols */ extern void enlarge_bufspace(void); extern void enlarge_strspace(void); extern unsigned char *endpbb; extern char *endest; /* trace.c */ extern unsigned int trace_flags; #define TRACE_ALL 512 extern void trace_file(const char *); extern size_t trace(const char **, int, struct input_file *); extern void finish_trace(size_t); extern void set_trace_flags(const char *); extern FILE *traceout; extern stae *mstack; /* stack of m4 machine */ extern char *sstack; /* shadow stack, for string space extension */ extern FILE *active; /* active output file pointer */ extern struct input_file infile[];/* input file stack (0=stdin) */ extern FILE **outfile; /* diversion array(0=bitbucket) */ extern int maxout; /* maximum number of diversions */ extern int fp; /* m4 call frame pointer */ extern int ilevel; /* input file stack pointer */ extern int oindex; /* diversion index. */ extern int sp; /* current m4 stack pointer */ extern unsigned char *bp; /* first available character */ extern unsigned char *buf; /* push-back buffer */ extern unsigned char *bufbase; /* buffer base for this ilevel */ extern unsigned char *bbase[]; /* buffer base per ilevel */ extern char ecommt[MAXCCHARS+1];/* end character for comment */ extern char *ep; /* first free char in strspace */ extern char lquote[MAXCCHARS+1];/* left quote character (`) */ extern char **m4wraps; /* m4wrap string default. */ extern int maxwraps; /* size of m4wraps array */ extern int wrapindex; /* current index in m4wraps */ extern const char *null; /* as it says.. just a null. */ extern char rquote[MAXCCHARS+1];/* right quote character (') */ extern char scommt[MAXCCHARS+1];/* start character for comment */ extern int synch_lines; /* line synchronisation directives */ extern int mimic_gnu; /* behaves like gnu-m4 */ extern int prefix_builtins; /* prefix builtin macros with m4_ */ Index: head/usr.bin/m4/gnum4.c =================================================================== --- head/usr.bin/m4/gnum4.c (revision 269161) +++ head/usr.bin/m4/gnum4.c (revision 269162) @@ -1,665 +1,673 @@ -/* $OpenBSD: gnum4.c,v 1.42 2011/11/06 12:25:43 espie Exp $ */ +/* $OpenBSD: gnum4.c,v 1.46 2014/07/10 14:12:31 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 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 */ static 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(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(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(void) { 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(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(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(const char *argv[], int argc) { ndptr n; struct macro_definition *p = NULL; n = lookup(argv[2]); if (n == NULL || (p = macro_getdef(n)) == NULL) m4errx(1, "indir: undefined macro %s.", argv[2]); argv[1] = p->defn; eval(argv+1, argc-1, p->type, is_traced(n)); } void dobuiltin(const char *argv[], int argc) { ndptr p; argv[1] = NULL; p = macro_getbuiltin(argv[2]); if (p != NULL) eval(argv+1, argc-1, macro_builtin_type(p), is_traced(p)); else m4errx(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(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 exit_regerror(int, regex_t *, const char *); +static void do_subst(const char *, regex_t *, const char *, const char *, + regmatch_t *); +static void do_regexpindex(const char *, regex_t *, const char *, regmatch_t *); +static void do_regexp(const char *, regex_t *, const char *, const char *, + regmatch_t *); static void add_sub(int, 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(const char *c, size_t n) { if (n == 0) return; while (current + n > bufsize) { if (bufsize == 0) bufsize = 1024; else bufsize *= 2; buffer = xrealloc(buffer, bufsize, NULL); } memcpy(buffer+current, c, n); current += n; } static void addchar(int c) { if (current +1 > bufsize) { if (bufsize == 0) bufsize = 1024; else bufsize *= 2; buffer = xrealloc(buffer, bufsize, NULL); } buffer[current++] = c; } static char * getstring(void) { addchar('\0'); current = 0; return buffer; } static void -exit_regerror(int er, regex_t *re) +exit_regerror(int er, regex_t *re, const char *source) { size_t errlen; char *errbuf; errlen = regerror(er, re, NULL, 0); errbuf = xalloc(errlen, "malloc in regerror: %lu", (unsigned long)errlen); regerror(er, re, errbuf, errlen); - m4errx(1, "regular expression error: %s.", errbuf); + m4errx(1, "regular expression error in %s: %s.", source, errbuf); } static void add_sub(int n, const char *string, regex_t *re, regmatch_t *pm) { if (n > (int)re->re_nsub) warnx("No subexpression %d", 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(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])) { + if (isdigit((unsigned char)p[1])) { add_sub(*(++p) - '0', string, re, pm); continue; } } addchar(*p); } } static void -do_subst(const char *string, regex_t *re, const char *replace, regmatch_t *pm) +do_subst(const char *string, regex_t *re, const char *source, + 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); + exit_regerror(error, re, source); pbstr(string); } static void -do_regexp(const char *string, regex_t *re, const char *replace, regmatch_t *pm) +do_regexp(const char *string, regex_t *re, const char *source, + 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); + exit_regerror(error, re, source); } } static void -do_regexpindex(const char *string, regex_t *re, regmatch_t *pm) +do_regexpindex(const char *string, regex_t *re, const char *source, + 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); + exit_regerror(error, re, source); } } /* 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(const char *p) { /* + at start of regexp is a normal character for Gnu m4 */ if (*p == '^') { addchar(*p); p++; } if (*p == '+') { addchar('\\'); } /* 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(const char *argv[], int argc) { if (argc <= 3) { warnx("Too few arguments to patsubst"); return; } /* special case: empty regexp */ if (argv[3][0] == '\0') { const char *s; size_t len; if (argc > 4 && argv[4]) len = strlen(argv[4]); else len = 0; for (s = argv[2]; *s != '\0'; s++) { addchars(argv[4], len); addchar(*s); } } else { int error; regex_t re; regmatch_t *pmatch; int mode = REG_EXTENDED; + const char *source; size_t l = strlen(argv[3]); if (!mimic_gnu || (argv[3][0] == '^') || (l > 0 && argv[3][l-1] == '$')) mode |= REG_NEWLINE; - error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], - mode); + source = mimic_gnu ? twiddle(argv[3]) : argv[3]; + error = regcomp(&re, source, mode); if (error != 0) - exit_regerror(error, &re); + exit_regerror(error, &re, source); - pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL); - do_subst(argv[2], &re, + pmatch = xreallocarray(NULL, re.re_nsub+1, sizeof(regmatch_t), + NULL); + do_subst(argv[2], &re, source, argc > 4 && argv[4] != NULL ? argv[4] : "", pmatch); free(pmatch); regfree(&re); } pbstr(getstring()); } void doregexp(const char *argv[], int argc) { int error; regex_t re; regmatch_t *pmatch; + const char *source; if (argc <= 3) { warnx("Too few arguments to regexp"); return; } /* special gnu case */ if (argv[3][0] == '\0' && mimic_gnu) { if (argc == 4 || argv[4] == NULL) return; else pbstr(argv[4]); } - error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], - REG_EXTENDED|REG_NEWLINE); + source = mimic_gnu ? twiddle(argv[3]) : argv[3]; + error = regcomp(&re, source, REG_EXTENDED|REG_NEWLINE); if (error != 0) - exit_regerror(error, &re); + exit_regerror(error, &re, source); - pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL); + pmatch = xreallocarray(NULL, re.re_nsub+1, sizeof(regmatch_t), NULL); if (argc == 4 || argv[4] == NULL) - do_regexpindex(argv[2], &re, pmatch); + do_regexpindex(argv[2], &re, source, pmatch); else - do_regexp(argv[2], &re, argv[4], pmatch); + do_regexp(argv[2], &re, source, argv[4], pmatch); free(pmatch); regfree(&re); } void doformat(const char *argv[], int argc) { const char *format = argv[2]; int pos = 3; int left_padded; long width; size_t l; const char *thisarg = NULL; char temp[2]; long extra; while (*format != 0) { if (*format != '%') { addchar(*format++); continue; } format++; if (*format == '%') { addchar(*format++); continue; } if (*format == 0) { addchar('%'); break; } if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); width = strtol(argv[pos++], NULL, 10); } else { width = strtol(format, __DECONST(char **,&format), 10); } if (width < 0) { left_padded = 1; width = -width; } else { left_padded = 0; } if (*format == '.') { format++; if (*format == '*') { format++; if (pos >= argc) m4errx(1, "Format with too many format specifiers."); extra = strtol(argv[pos++], NULL, 10); } else { extra = strtol(format, __DECONST(char **, &format), 10); } } else { extra = LONG_MAX; } if (pos >= argc) m4errx(1, "Format with too many format specifiers."); switch(*format) { case 's': thisarg = argv[pos++]; break; case 'c': temp[0] = strtoul(argv[pos++], NULL, 10); temp[1] = 0; thisarg = temp; break; default: m4errx(1, "Unsupported format specification: %s.", argv[2]); } format++; l = strlen(thisarg); if ((long)l > extra) l = extra; if (!left_padded) { while ((long)l < width--) addchar(' '); } addchars(thisarg, l); if (left_padded) { while ((long)l < width--) addchar(' '); } } pbstr(getstring()); } void doesyscmd(const char *cmd) { int p[2]; pid_t pid, cpid; char *argv[4]; int cc; int status; /* Follow gnu m4 documentation: first flush buffers. */ fflush(NULL); argv[0] = __DECONST(char *, "sh"); argv[1] = __DECONST(char *, "-c"); argv[2] = __DECONST(char *, cmd); argv[3] = 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]); execv(_PATH_BSHELL, argv); 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()); } } void getdivfile(const char *name) { FILE *f; int c; f = fopen(name, "r"); if (!f) return; while ((c = getc(f))!= EOF) putc(c, active); (void) fclose(f); } Index: head/usr.bin/m4/lib/ohash_delete.c =================================================================== --- head/usr.bin/m4/lib/ohash_delete.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_delete.c (nonexistent) @@ -1,33 +0,0 @@ -/* $OpenBSD: ohash_delete.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" -/* hash_delete only frees the hash structure. Use hash_first/hash_next - * to free entries as well. */ -void -ohash_delete(struct ohash *h) -{ - (h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size, - h->info.data); -#ifndef NDEBUG - h->t = NULL; -#endif -} Property changes on: head/usr.bin/m4/lib/ohash_delete.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_interval.c =================================================================== --- head/usr.bin/m4/lib/ohash_interval.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_interval.c (nonexistent) @@ -1,38 +0,0 @@ -/* $OpenBSD: ohash_interval.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -uint32_t -ohash_interval(const char *s, const char **e) -{ - uint32_t k; - - if (!*e) - *e = s + strlen(s); - if (s == *e) - k = 0; - else - k = *s++; - while (s != *e) - k = ((k << 2) | (k >> 30)) ^ *s++; - return k; -} Property changes on: head/usr.bin/m4/lib/ohash_interval.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_qlookup.c =================================================================== --- head/usr.bin/m4/lib/ohash_qlookup.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_qlookup.c (nonexistent) @@ -1,29 +0,0 @@ -/* $OpenBSD: ohash_qlookup.c,v 1.2 2004/06/22 20:00:17 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -unsigned int -ohash_qlookup(struct ohash *h, const char *s) -{ - const char *e = NULL; - return ohash_qlookupi(h, s, &e); -} Property changes on: head/usr.bin/m4/lib/ohash_qlookup.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_entries.c =================================================================== --- head/usr.bin/m4/lib/ohash_entries.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_entries.c (nonexistent) @@ -1,28 +0,0 @@ -/* $OpenBSD: ohash_entries.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -unsigned int -ohash_entries(struct ohash *h) -{ - return h->total - h->deleted; -} Property changes on: head/usr.bin/m4/lib/ohash_entries.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_enum.c =================================================================== --- head/usr.bin/m4/lib/ohash_enum.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_enum.c (nonexistent) @@ -1,38 +0,0 @@ -/* $OpenBSD: ohash_enum.c,v 1.3 2004/06/22 20:00:16 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -void * -ohash_first(struct ohash *h, unsigned int *pos) -{ - *pos = 0; - return ohash_next(h, pos); -} - -void * -ohash_next(struct ohash *h, unsigned int *pos) -{ - for (; *pos < h->size; (*pos)++) - if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) - return __DECONST(void *, h->t[(*pos)++].p); - return NULL; -} Property changes on: head/usr.bin/m4/lib/ohash_enum.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_lookup_memory.c =================================================================== --- head/usr.bin/m4/lib/ohash_lookup_memory.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_lookup_memory.c (nonexistent) @@ -1,66 +0,0 @@ -/* $OpenBSD: ohash_lookup_memory.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -unsigned int -ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv) -{ - unsigned int i, incr; - unsigned int empty; - -#ifdef STATS_HASH - STAT_HASH_LOOKUP++; -#endif - empty = NONE; - i = hv % h->size; - incr = ((hv % (h->size-2)) & ~1) + 1; - while (h->t[i].p != NULL) { -#ifdef STATS_HASH - STAT_HASH_LENGTH++; -#endif - if (h->t[i].p == DELETED) { - if (empty == NONE) - empty = i; - } else if (h->t[i].hv == hv && - memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { - if (empty != NONE) { - h->t[empty].hv = hv; - h->t[empty].p = h->t[i].p; - h->t[i].p = DELETED; - return empty; - } else { -#ifdef STATS_HASH - STAT_HASH_POSITIVE++; -#endif - } return i; - } - i += incr; - if (i >= h->size) - i -= h->size; - } - - /* Found an empty position. */ - if (empty != NONE) - i = empty; - h->t[i].hv = hv; - return i; -} Property changes on: head/usr.bin/m4/lib/ohash_lookup_memory.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_create_entry.c =================================================================== --- head/usr.bin/m4/lib/ohash_create_entry.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_create_entry.c (nonexistent) @@ -1,40 +0,0 @@ -/* $OpenBSD: ohash_create_entry.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -/* This handles the common case of variable length keys, where the - * key is stored at the end of the record. - */ -void * -ohash_create_entry(struct ohash_info *i, const char *start, const char **end) -{ - char *p; - - if (!*end) - *end = start + strlen(start); - p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); - if (p) { - memcpy(p+i->key_offset, start, *end-start); - p[i->key_offset + (*end - start)] = '\0'; - } - return (void *)p; -} Property changes on: head/usr.bin/m4/lib/ohash_create_entry.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_lookup_interval.c =================================================================== --- head/usr.bin/m4/lib/ohash_lookup_interval.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_lookup_interval.c (nonexistent) @@ -1,70 +0,0 @@ -/* $OpenBSD: ohash_lookup_interval.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -unsigned int -ohash_lookup_interval(struct ohash *h, const char *start, const char *end, - uint32_t hv) -{ - unsigned int i, incr; - unsigned int empty; - -#ifdef STATS_HASH - STAT_HASH_LOOKUP++; -#endif - empty = NONE; - i = hv % h->size; - incr = ((hv % (h->size-2)) & ~1) + 1; - while (h->t[i].p != NULL) { -#ifdef STATS_HASH - STAT_HASH_LENGTH++; -#endif - if (h->t[i].p == DELETED) { - if (empty == NONE) - empty = i; - } else if (h->t[i].hv == hv && - strncmp(h->t[i].p+h->info.key_offset, start, - end - start) == 0 && - (h->t[i].p+h->info.key_offset)[end-start] == '\0') { - if (empty != NONE) { - h->t[empty].hv = hv; - h->t[empty].p = h->t[i].p; - h->t[i].p = DELETED; - return empty; - } else { -#ifdef STATS_HASH - STAT_HASH_POSITIVE++; -#endif - return i; - } - } - i += incr; - if (i >= h->size) - i -= h->size; - } - - /* Found an empty position. */ - if (empty != NONE) - i = empty; - h->t[i].hv = hv; - return i; -} Property changes on: head/usr.bin/m4/lib/ohash_lookup_interval.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_do.c =================================================================== --- head/usr.bin/m4/lib/ohash_do.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_do.c (nonexistent) @@ -1,113 +0,0 @@ -/* $OpenBSD: ohash_do.c,v 1.4 2004/06/22 20:00:16 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -static void ohash_resize(struct ohash *); - -static void -ohash_resize(struct ohash *h) -{ - struct _ohash_record *n; - unsigned int ns, j; - unsigned int i, incr; - - if (4 * h->deleted < h->total) - ns = h->size << 1; - else if (3 * h->deleted > 2 * h->total) - ns = h->size >> 1; - else - ns = h->size; - if (ns < MINSIZE) - ns = MINSIZE; -#ifdef STATS_HASH - STAT_HASH_EXPAND++; - STAT_HASH_SIZE += ns - h->size; -#endif - n = (h->info.halloc)(sizeof(struct _ohash_record) * ns, h->info.data); - if (!n) - return; - - for (j = 0; j < h->size; j++) { - if (h->t[j].p != NULL && h->t[j].p != DELETED) { - i = h->t[j].hv % ns; - incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1; - while (n[i].p != NULL) { - i += incr; - if (i >= ns) - i -= ns; - } - n[i].hv = h->t[j].hv; - n[i].p = h->t[j].p; - } - } - (h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size, - h->info.data); - h->t = n; - h->size = ns; - h->total -= h->deleted; - h->deleted = 0; -} - -void * -ohash_remove(struct ohash *h, unsigned int i) -{ - void *result = __DECONST(void *, h->t[i].p); - - if (result == NULL || result == DELETED) - return NULL; - -#ifdef STATS_HASH - STAT_HASH_ENTRIES--; -#endif - h->t[i].p = DELETED; - h->deleted++; - if (h->deleted >= MINDELETED && 4 * h->deleted > h->total) - ohash_resize(h); - return result; -} - -void * -ohash_find(struct ohash *h, unsigned int i) -{ - if (h->t[i].p == DELETED) - return NULL; - else - return __DECONST(void *, h->t[i].p); -} - -void * -ohash_insert(struct ohash *h, unsigned int i, void *p) -{ -#ifdef STATS_HASH - STAT_HASH_ENTRIES++; -#endif - if (h->t[i].p == DELETED) { - h->deleted--; - h->t[i].p = p; - } else { - h->t[i].p = p; - /* Arbitrary resize boundary. Tweak if not efficient enough. */ - if (++h->total * 4 > h->size * 3) - ohash_resize(h); - } - return p; -} Property changes on: head/usr.bin/m4/lib/ohash_do.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_qlookupi.c =================================================================== --- head/usr.bin/m4/lib/ohash_qlookupi.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_qlookupi.c (nonexistent) @@ -1,31 +0,0 @@ -/* $OpenBSD: ohash_qlookupi.c,v 1.2 2004/06/22 20:00:17 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -unsigned int -ohash_qlookupi(struct ohash *h, const char *s, const char **e) -{ - u_int32_t hv; - - hv = ohash_interval(s, e); - return ohash_lookup_interval(h, s, *e, hv); -} Property changes on: head/usr.bin/m4/lib/ohash_qlookupi.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash_init.c =================================================================== --- head/usr.bin/m4/lib/ohash_init.c (revision 269161) +++ head/usr.bin/m4/lib/ohash_init.c (nonexistent) @@ -1,43 +0,0 @@ -/* $OpenBSD: ohash_init.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */ -/* ex:ts=8 sw=4: - */ - -/* Copyright (c) 1999, 2004 Marc Espie - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include -__FBSDID("$FreeBSD$"); - -#include "ohash_int.h" - -void -ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) -{ - h->size = 1UL << size; - if (h->size < MINSIZE) - h->size = MINSIZE; -#ifdef STATS_HASH - STAT_HASH_CREATION++; - STAT_HASH_SIZE += h->size; -#endif - /* Copy info so that caller may free it. */ - h->info.key_offset = info->key_offset; - h->info.halloc = info->halloc; - h->info.hfree = info->hfree; - h->info.alloc = info->alloc; - h->info.data = info->data; - h->t = (h->info.halloc)(sizeof(struct _ohash_record) * h->size, - h->info.data); - h->total = h->deleted = 0; -} Property changes on: head/usr.bin/m4/lib/ohash_init.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash.c =================================================================== --- head/usr.bin/m4/lib/ohash.c (nonexistent) +++ head/usr.bin/m4/lib/ohash.c (revision 269162) @@ -0,0 +1,330 @@ +/* $OpenBSD: src/lib/libutil/ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */ + +/* Copyright (c) 1999, 2004 Marc Espie + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include "ohash.h" + +struct _ohash_record { + uint32_t hv; + const char *p; +}; + +#define DELETED ((const char *)h) +#define NONE (h->size) + +/* Don't bother changing the hash table if the change is small enough. */ +#define MINSIZE (1UL << 4) +#define MINDELETED 4 + +static void ohash_resize(struct ohash *); + + +/* This handles the common case of variable length keys, where the + * key is stored at the end of the record. + */ +void * +ohash_create_entry(struct ohash_info *i, const char *start, const char **end) +{ + char *p; + + if (!*end) + *end = start + strlen(start); + p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data); + if (p) { + memcpy(p+i->key_offset, start, *end-start); + p[i->key_offset + (*end - start)] = '\0'; + } + return (void *)p; +} + +/* hash_delete only frees the hash structure. Use hash_first/hash_next + * to free entries as well. */ +void +ohash_delete(struct ohash *h) +{ + (h->info.free)(h->t, h->info.data); +#ifndef NDEBUG + h->t = NULL; +#endif +} + +static void +ohash_resize(struct ohash *h) +{ + struct _ohash_record *n; + size_t ns; + unsigned int j; + unsigned int i, incr; + + if (4 * h->deleted < h->total) { + if (h->size >= (UINT_MAX >> 1U)) + ns = UINT_MAX; + else + ns = h->size << 1U; + } else if (3 * h->deleted > 2 * h->total) + ns = h->size >> 1U; + else + ns = h->size; + if (ns < MINSIZE) + ns = MINSIZE; +#ifdef STATS_HASH + STAT_HASH_EXPAND++; + STAT_HASH_SIZE += ns - h->size; +#endif + + n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data); + if (!n) + return; + + for (j = 0; j < h->size; j++) { + if (h->t[j].p != NULL && h->t[j].p != DELETED) { + i = h->t[j].hv % ns; + incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1; + while (n[i].p != NULL) { + i += incr; + if (i >= ns) + i -= ns; + } + n[i].hv = h->t[j].hv; + n[i].p = h->t[j].p; + } + } + (h->info.free)(h->t, h->info.data); + h->t = n; + h->size = ns; + h->total -= h->deleted; + h->deleted = 0; +} + +void * +ohash_remove(struct ohash *h, unsigned int i) +{ + void *result = (void *)h->t[i].p; + + if (result == NULL || result == DELETED) + return NULL; + +#ifdef STATS_HASH + STAT_HASH_ENTRIES--; +#endif + h->t[i].p = DELETED; + h->deleted++; + if (h->deleted >= MINDELETED && 4 * h->deleted > h->total) + ohash_resize(h); + return result; +} + +void * +ohash_find(struct ohash *h, unsigned int i) +{ + if (h->t[i].p == DELETED) + return NULL; + else + return (void *)h->t[i].p; +} + +void * +ohash_insert(struct ohash *h, unsigned int i, void *p) +{ +#ifdef STATS_HASH + STAT_HASH_ENTRIES++; +#endif + if (h->t[i].p == DELETED) { + h->deleted--; + h->t[i].p = p; + } else { + h->t[i].p = p; + /* Arbitrary resize boundary. Tweak if not efficient enough. */ + if (++h->total * 4 > h->size * 3) + ohash_resize(h); + } + return p; +} + +unsigned int +ohash_entries(struct ohash *h) +{ + return h->total - h->deleted; +} + +void * +ohash_first(struct ohash *h, unsigned int *pos) +{ + *pos = 0; + return ohash_next(h, pos); +} + +void * +ohash_next(struct ohash *h, unsigned int *pos) +{ + for (; *pos < h->size; (*pos)++) + if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL) + return (void *)h->t[(*pos)++].p; + return NULL; +} + +void +ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info) +{ + h->size = 1UL << size; + if (h->size < MINSIZE) + h->size = MINSIZE; +#ifdef STATS_HASH + STAT_HASH_CREATION++; + STAT_HASH_SIZE += h->size; +#endif + /* Copy info so that caller may free it. */ + h->info.key_offset = info->key_offset; + h->info.calloc = info->calloc; + h->info.free = info->free; + h->info.alloc = info->alloc; + h->info.data = info->data; + h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record), + h->info.data); + h->total = h->deleted = 0; +} + +uint32_t +ohash_interval(const char *s, const char **e) +{ + uint32_t k; + + if (!*e) + *e = s + strlen(s); + if (s == *e) + k = 0; + else + k = *s++; + while (s != *e) + k = ((k << 2) | (k >> 30)) ^ *s++; + return k; +} + +unsigned int +ohash_lookup_interval(struct ohash *h, const char *start, const char *end, + uint32_t hv) +{ + unsigned int i, incr; + unsigned int empty; + +#ifdef STATS_HASH + STAT_HASH_LOOKUP++; +#endif + empty = NONE; + i = hv % h->size; + incr = ((hv % (h->size-2)) & ~1) + 1; + while (h->t[i].p != NULL) { +#ifdef STATS_HASH + STAT_HASH_LENGTH++; +#endif + if (h->t[i].p == DELETED) { + if (empty == NONE) + empty = i; + } else if (h->t[i].hv == hv && + strncmp(h->t[i].p+h->info.key_offset, start, + end - start) == 0 && + (h->t[i].p+h->info.key_offset)[end-start] == '\0') { + if (empty != NONE) { + h->t[empty].hv = hv; + h->t[empty].p = h->t[i].p; + h->t[i].p = DELETED; + return empty; + } else { +#ifdef STATS_HASH + STAT_HASH_POSITIVE++; +#endif + return i; + } + } + i += incr; + if (i >= h->size) + i -= h->size; + } + + /* Found an empty position. */ + if (empty != NONE) + i = empty; + h->t[i].hv = hv; + return i; +} + +unsigned int +ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv) +{ + unsigned int i, incr; + unsigned int empty; + +#ifdef STATS_HASH + STAT_HASH_LOOKUP++; +#endif + empty = NONE; + i = hv % h->size; + incr = ((hv % (h->size-2)) & ~1) + 1; + while (h->t[i].p != NULL) { +#ifdef STATS_HASH + STAT_HASH_LENGTH++; +#endif + if (h->t[i].p == DELETED) { + if (empty == NONE) + empty = i; + } else if (h->t[i].hv == hv && + memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) { + if (empty != NONE) { + h->t[empty].hv = hv; + h->t[empty].p = h->t[i].p; + h->t[i].p = DELETED; + return empty; + } else { +#ifdef STATS_HASH + STAT_HASH_POSITIVE++; +#endif + } return i; + } + i += incr; + if (i >= h->size) + i -= h->size; + } + + /* Found an empty position. */ + if (empty != NONE) + i = empty; + h->t[i].hv = hv; + return i; +} + +unsigned int +ohash_qlookup(struct ohash *h, const char *s) +{ + const char *e = NULL; + return ohash_qlookupi(h, s, &e); +} + +unsigned int +ohash_qlookupi(struct ohash *h, const char *s, const char **e) +{ + uint32_t hv; + + hv = ohash_interval(s, e); + return ohash_lookup_interval(h, s, *e, hv); +} Property changes on: head/usr.bin/m4/lib/ohash.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.bin/m4/lib/ohash.h =================================================================== --- head/usr.bin/m4/lib/ohash.h (revision 269161) +++ head/usr.bin/m4/lib/ohash.h (revision 269162) @@ -1,75 +1,76 @@ -#ifndef OHASH_H -#define OHASH_H -/* $OpenBSD: ohash.h,v 1.8 2005/12/29 18:54:47 jaredy Exp $ */ -/* ex:ts=8 sw=4: - */ +/* $OpenBSD: src/lib/libutil/ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */ /* Copyright (c) 1999, 2004 Marc Espie * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ +#ifndef OHASH_H +#define OHASH_H + /* Open hashing support. * Open hashing was chosen because it is much lighter than other hash * techniques, and more efficient in most cases. */ +/* user-visible data structure */ struct ohash_info { ptrdiff_t key_offset; void *data; /* user data */ - void *(*halloc)(size_t, void *); - void (*hfree)(void *, size_t, void *); + void *(*calloc)(size_t, size_t, void *); + void (*free)(void *, void *); void *(*alloc)(size_t, void *); }; struct _ohash_record; +/* private structure. It's there just so you can do a sizeof */ struct ohash { struct _ohash_record *t; struct ohash_info info; unsigned int size; unsigned int total; unsigned int deleted; }; /* For this to be tweakable, we use small primitives, and leave part of the * logic to the client application. e.g., hashing is left to the client * application. We also provide a simple table entry lookup that yields * a hashing table index (opaque) to be used in find/insert/remove. * The keys are stored at a known position in the client data. */ __BEGIN_DECLS void ohash_init(struct ohash *, unsigned, struct ohash_info *); void ohash_delete(struct ohash *); unsigned int ohash_lookup_interval(struct ohash *, const char *, - const char *, u_int32_t); + const char *, uint32_t); unsigned int ohash_lookup_memory(struct ohash *, const char *, - size_t, u_int32_t); + size_t, uint32_t) + __attribute__ ((__bounded__(__string__,2,3))); void *ohash_find(struct ohash *, unsigned int); void *ohash_remove(struct ohash *, unsigned int); void *ohash_insert(struct ohash *, unsigned int, void *); void *ohash_first(struct ohash *, unsigned int *); void *ohash_next(struct ohash *, unsigned int *); unsigned int ohash_entries(struct ohash *); void *ohash_create_entry(struct ohash_info *, const char *, const char **); -u_int32_t ohash_interval(const char *, const char **); +uint32_t ohash_interval(const char *, const char **); unsigned int ohash_qlookupi(struct ohash *, const char *, const char **); unsigned int ohash_qlookup(struct ohash *, const char *); __END_DECLS #endif - Index: head/usr.bin/m4/lib/ohash_init.3 =================================================================== --- head/usr.bin/m4/lib/ohash_init.3 (revision 269161) +++ head/usr.bin/m4/lib/ohash_init.3 (revision 269162) @@ -1,231 +1,273 @@ -.\" $OpenBSD: ohash_init.3,v 1.14 2007/05/31 19:19:30 jmc Exp $ +.\" $OpenBSD: ohash_init.3,v 1.2 2014/05/13 14:01:41 jmc Exp $ .\" Copyright (c) 1999 Marc Espie .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" $FreeBSD$ .\" -.Dd $Mdocdate: May 31 2007 $ -.Dt OPEN_HASH 3 +.Dd May 12 2014 +.Dt OHASH_INIT 3 .Os .Sh NAME .Nm ohash_init , .Nm ohash_delete , .Nm ohash_lookup_interval , .Nm ohash_lookup_memory , .Nm ohash_find , .Nm ohash_remove , .Nm ohash_insert , .Nm ohash_first , .Nm ohash_next , .Nm ohash_entries .Nd light-weight open hashing .Sh SYNOPSIS .In stdint.h .In stddef.h .In ohash.h .Ft void .Fn ohash_init "struct ohash *h" "unsigned int size" "struct ohash_info *info" .Ft void .Fn ohash_delete "struct ohash *h" .Ft "unsigned int" .Fn ohash_lookup_interval "struct ohash *h" "const char *start" "const char *end" "uint32_t hv" .Ft "unsigned int" .Fn ohash_lookup_memory "struct ohash *h" "const char *k" "size_t s" "uint32_t hv" .Ft void * .Fn ohash_find "struct ohash *h" "unsigned int i" .Ft void * .Fn ohash_remove "struct ohash *h" "unsigned int i" .Ft void * .Fn ohash_insert "struct ohash *h" "unsigned int i" "void *p" .Ft void * .Fn ohash_first "struct ohash *h" "unsigned int *i" .Ft void * .Fn ohash_next "struct ohash *h" "unsigned int *i" .Ft "unsigned int" .Fn ohash_entries "struct ohash *h" .Sh DESCRIPTION These functions have been designed as a fast, extensible alternative to the usual hash table functions. They provide storage and retrieval of records indexed by keys, where a key is a contiguous sequence of bytes at a fixed position in each record. Keys can either be NUL-terminated strings or fixed-size memory areas. All functions take a pointer to an ohash structure as the .Fa h function argument. Storage for this structure should be provided by user code. .Pp .Fn ohash_init initializes the table to store roughly 2 to the power .Fa size elements. .Fa info -holds the position of the key in each record, and two pointers to +is a pointer to a +.Fa struct ohash_info . +.Bd -literal -offset indent +struct ohash_info { + ptrdiff_t key_offset; + void *data; /* user data */ + void *(*calloc)(size_t, size_t, void *); + void (*free)(void *, void *); + void *(*alloc)(size_t, void *); +}; +.Ed +.Pp +The +.Va offset +field holds the position of the key in each record; +the +.Va calloc +and +.Va free +fields are pointers to .Xr calloc 3 and .Xr free 3 Ns -like -functions, to use for managing the table internal storage. +functions, used for managing the table internal storage; +the +.Va alloc +field is only used by the utility function +.Xr ohash_create_entry 3 . .Pp +Each of these functions are called similarly to their standard counterpart, +but with an extra +.Ft void * +parameter corresponding to the content of the field +.Fa data , +which can be used to communicate specific information to the functions. +.Pp +.Fn ohash_init +stores a copy of those fields internally, so +.Fa info +can be reclaimed after initialization. +.Pp .Fn ohash_delete frees storage internal to .Fa h . Elements themselves should be freed by the user first, using for instance .Fn ohash_first and .Fn ohash_next . .Pp .Fn ohash_lookup_interval and .Fn ohash_lookup_memory are the basic look-up element functions. The hashing function result is provided by the user as .Fa hv . These return a .Qq slot in the ohash table .Fa h , to be used with .Fn ohash_find , .Fn ohash_insert , or .Fn ohash_remove . This slot is only valid up to the next call to .Fn ohash_insert or .Fn ohash_remove . .Pp .Fn ohash_lookup_interval handles string-like keys. .Fn ohash_lookup_interval assumes the key is the interval between .Fa start and .Fa end , exclusive, though the actual elements stored in the table should only contain NUL-terminated keys. .Pp .Fn ohash_lookup_memory assumes the key is the memory area starting at .Fa k of size .Fa s . All bytes are significant in key comparison. .Pp .Fn ohash_find retrieves an element from a slot .Fa i returned by the .Fn ohash_lookup* functions. It returns .Dv NULL if the slot is empty. .Pp .Fn ohash_insert inserts a new element .Fa p at slot .Fa i . Slot .Fa i must be empty and element .Fa p must have a key corresponding to the .Fn ohash_lookup* call. .Pp .Fn ohash_remove removes the element at slot .Fa i . It returns the removed element, for user code to dispose of, or .Dv NULL if the slot was empty. .Pp .Fn ohash_first and .Fn ohash_next can be used to access all elements in an ohash table, like this: .Bd -literal -offset indent for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i)) do_something_with(n); .Ed .Pp .Fa i points to an auxiliary unsigned integer used to record the current position in the ohash table. Those functions are safe to use even while entries are added to/removed -from the table, but in such a case they do not guarantee that new entries +from the table, but in such a case they don't guarantee that new entries will be returned. As a special case, they can safely be used to free elements in the table. .Pp .Fn ohash_entries returns the number of elements in the hash table. .Sh STORAGE HANDLING Only .Fn ohash_init , .Fn ohash_insert , .Fn ohash_remove and .Fn ohash_delete -may call the user-supplied memory functions. +may call the user-supplied memory functions: +.Bd -literal -offset indent +p = (*info->calloc)(n, sizeof_record, info->data); +/* copy data from old to p */ +(*info->free)(old, info->data); +.Ed +.Pp It is the responsibility of the user memory allocation code to verify that those calls did not fail. .Pp If memory allocation fails, .Fn ohash_init returns a useless hash table. .Fn ohash_insert and .Fn ohash_remove still perform the requested operation, but the returned table should be considered read-only. It can still be accessed by .Fn ohash_lookup* , .Fn ohash_find , .Fn ohash_first and .Fn ohash_next to dump relevant information to disk before aborting. .Sh THREAD SAFETY The open hashing functions are not thread-safe by design. In particular, in a threaded environment, there is no guarantee that a .Qq slot will not move between a .Fn ohash_lookup* and a .Fn ohash_find , .Fn ohash_insert or .Fn ohash_remove call. .Pp Multi-threaded applications should explicitly protect ohash table access. .Sh SEE ALSO +.Xr hcreate 3 , .Xr ohash_interval 3 .Rs .%A Donald E. Knuth .%B The Art of Computer Programming .%V Vol. 3 .%P pp 506-550 .%D 1973 .Re .Sh STANDARDS Those functions are completely non-standard and should be avoided in portable programs. .Sh HISTORY Those functions were designed and written for .Ox .Xr make 1 by Marc Espie in 1999. Index: head/usr.bin/m4/lib/ohash_interval.3 =================================================================== --- head/usr.bin/m4/lib/ohash_interval.3 (revision 269161) +++ head/usr.bin/m4/lib/ohash_interval.3 (revision 269162) @@ -1,92 +1,95 @@ -.\" $OpenBSD: ohash_interval.3,v 1.11 2007/05/31 19:19:30 jmc Exp $ +.\" $OpenBSD: ohash_interval.3,v 1.1 2014/05/12 19:09:00 espie Exp $ .\" Copyright (c) 2001 Marc Espie .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" $FreeBSD$ .\" -.Dd $Mdocdate: May 31 2007 $ -.Dt OPEN_HASH_HELPER 3 +.Dd June 5 2013 +.Dt OHASH_INTERVAL 3 .Os .Sh NAME .Nm ohash_interval , .Nm ohash_create_entry , .Nm ohash_qlookup , .Nm ohash_qlookupi .Nd helper functions for open hashing .Sh SYNOPSIS .In stdint.h .In stddef.h .In ohash.h .Ft uint32_t .Fn ohash_interval "const char *start" "const char **pend" .Ft "void *" .Fn ohash_create_entry "struct ohash_info *info" "const char *start" "const char **pend" .Ft "unsigned int" .Fn ohash_qlookupi "struct ohash *h" "const char *start" "const char **pend" .Ft "unsigned int" .Fn ohash_qlookup "struct ohash *h" "const char *start" .Sh DESCRIPTION These functions are commonly used to simplify open hashing usage, and use similar conventions. They operate indifferently on NUL-terminated strings .Po by setting .Fa *pend = .Dv NULL .Pc or memory ranges .Po delimited by .Fa start and .Fa *pend .Pc . For NUL-terminated strings, as a side effect, those functions set .Fa *pend to the terminating NUL byte. .Pp .Fn ohash_interval is a simple hashing function that yields good results on common data sets. .Pp .Fn ohash_create_entry can be used to create a new record with a given key. In that case, the alloc field of .Fa info should point to a .Xr malloc 3 Ns -like -function to allocate the storage. +function to allocate the storage: +.Bd -literal -offset indent +p = (*info->alloc)(sz, info->data); +.Ed .Pp .Fn ohash_qlookupi is a wrapper function that simply calls .Fn ohash_interval and .Fn ohash_lookup_interval . .Pp .Fn ohash_qlookup is a variation on .Fn ohash_qlookupi designed for NUL-terminated strings. .Sh SEE ALSO .Xr ohash_init 3 .Sh STANDARDS Those functions are completely non-standard and should be avoided in portable programs. .Sh HISTORY Those functions were designed and written for .Ox .Xr make 1 by Marc Espie in 1999. Index: head/usr.bin/m4/look.c =================================================================== --- head/usr.bin/m4/look.c (revision 269161) +++ head/usr.bin/m4/look.c (revision 269162) @@ -1,277 +1,275 @@ -/* $OpenBSD: look.c,v 1.22 2010/09/07 19:58:09 marco Exp $ */ +/* $OpenBSD: look.c,v 1.23 2014/05/12 19:11:19 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. 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 __FBSDID("$FreeBSD$"); /* * look.c * Facility: m4 macro processor * by: oz */ #include #include #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" -static void *hash_alloc(size_t, void *); -static void hash_free(void *, size_t, void *); +static void *hash_calloc(size_t, size_t, void *); +static void hash_free(void *, void *); static void *element_alloc(size_t, void *); static void setup_definition(struct macro_definition *, const char *, const char *); static struct ohash_info macro_info = { offsetof(struct ndblock, name), - NULL, hash_alloc, hash_free, element_alloc }; + NULL, hash_calloc, hash_free, element_alloc }; struct ohash macros; /* Support routines for hash tables. */ void * -hash_alloc(size_t s, __unused void *u) +hash_calloc(size_t n, size_t s, void *u __unused) { - void *storage = xalloc(s, "hash alloc"); - if (storage) - memset(storage, 0, s); + void *storage = xcalloc(n, s, "hash alloc"); return storage; } void -hash_free(void *p, __unused size_t s, __unused void *u) +hash_free(void *p, void *u __unused) { free(p); } void * -element_alloc(size_t s, __unused void *u) +element_alloc(size_t s, void *u __unused) { return xalloc(s, "element alloc"); } void init_macros(void) { ohash_init(¯os, 10, ¯o_info); } /* * find name in the hash table */ ndptr lookup(const char *name) { return ohash_find(¯os, ohash_qlookup(¯os, name)); } struct macro_definition * lookup_macro_definition(const char *name) { ndptr p; p = ohash_find(¯os, ohash_qlookup(¯os, name)); if (p) return p->d; else return NULL; } static void setup_definition(struct macro_definition *d, const char *defn, const char *name) { ndptr p; if (strncmp(defn, BUILTIN_MARKER, sizeof(BUILTIN_MARKER)-1) == 0 && (p = macro_getbuiltin(defn+sizeof(BUILTIN_MARKER)-1)) != NULL) { d->type = macro_builtin_type(p); d->defn = xstrdup(defn+sizeof(BUILTIN_MARKER)-1); } else { if (!*defn) d->defn = __DECONST(char *, null); else d->defn = xstrdup(defn); d->type = MACRTYPE; } if (STREQ(name, defn)) d->type |= RECDEF; } static ndptr create_entry(const char *name) { const char *end = NULL; unsigned int i; ndptr n; i = ohash_qlookupi(¯os, name, &end); n = ohash_find(¯os, i); if (n == NULL) { n = ohash_create_entry(¯o_info, name, &end); ohash_insert(¯os, i, n); n->trace_flags = FLAG_NO_TRACE; n->builtin_type = MACRTYPE; n->d = NULL; } return n; } void macro_define(const char *name, const char *defn) { ndptr n = create_entry(name); if (n->d != NULL) { if (n->d->defn != null) free(n->d->defn); } else { n->d = xalloc(sizeof(struct macro_definition), NULL); n->d->next = NULL; } setup_definition(n->d, defn, name); } void macro_pushdef(const char *name, const char *defn) { ndptr n; struct macro_definition *d; n = create_entry(name); d = xalloc(sizeof(struct macro_definition), NULL); d->next = n->d; n->d = d; setup_definition(n->d, defn, name); } void macro_undefine(const char *name) { ndptr n = lookup(name); if (n != NULL) { struct macro_definition *r, *r2; for (r = n->d; r != NULL; r = r2) { r2 = r->next; if (r->defn != null) free(r->defn); free(r); } n->d = NULL; } } void macro_popdef(const char *name) { ndptr n = lookup(name); if (n != NULL) { struct macro_definition *r = n->d; if (r != NULL) { n->d = r->next; if (r->defn != null) free(r->defn); free(r); } } } void macro_for_all(void (*f)(const char *, struct macro_definition *)) { ndptr n; unsigned int i; for (n = ohash_first(¯os, &i); n != NULL; n = ohash_next(¯os, &i)) if (n->d != NULL) f(n->name, n->d); } void setup_builtin(const char *name, unsigned int type) { ndptr n; char *name2; if (prefix_builtins) { name2 = xalloc(strlen(name)+3+1, NULL); memcpy(name2, "m4_", 3); memcpy(name2 + 3, name, strlen(name)+1); } else name2 = xstrdup(name); n = create_entry(name2); n->builtin_type = type; n->d = xalloc(sizeof(struct macro_definition), NULL); n->d->defn = name2; n->d->type = type; n->d->next = NULL; } void mark_traced(const char *name, int on) { ndptr p; unsigned int i; if (name == NULL) { if (on) trace_flags |= TRACE_ALL; else trace_flags &= ~TRACE_ALL; for (p = ohash_first(¯os, &i); p != NULL; p = ohash_next(¯os, &i)) p->trace_flags = FLAG_NO_TRACE; } else { p = create_entry(name); p->trace_flags = on; } } ndptr macro_getbuiltin(const char *name) { ndptr p; p = lookup(name); if (p == NULL || p->builtin_type == MACRTYPE) return NULL; else return p; } Index: head/usr.bin/m4/m4.1 =================================================================== --- head/usr.bin/m4/m4.1 (revision 269161) +++ head/usr.bin/m4/m4.1 (revision 269162) @@ -1,508 +1,512 @@ .\" $NetBSD: m4.1,v 1.23 2012/04/08 22:00:39 wiz Exp $ -.\" @(#) $OpenBSD: m4.1,v 1.59 2010/10/21 13:20:51 jmc Exp $ +.\" @(#) $OpenBSD: m4.1,v 1.62 2014/04/14 07:00:47 jmc 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. 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. .\" .\" $FreeBSD$ .\" -.Dd October 21, 2010 +.Dd January 12 2014 $ .Dt M4 1 .Os .Sh NAME .Nm m4 .Nd macro language processor .Sh SYNOPSIS .Nm .Op Fl gPs .Oo .Sm off .Fl D Ar name Op No = Ar value .Sm on .Oc .Op Fl d Ar flags .Op Fl I Ar dirname .Op Fl o Ar filename .Op Fl t Ar macro .Op Fl U Ns Ar name .Op Ar .Sh DESCRIPTION The .Nm utility is a macro processor that can be used as a front end to any language (e.g., C, ratfor, fortran, lex, and yacc). If no input files are given, .Nm reads from the standard input, otherwise files specified on the command line are processed in the given order. Input files can be regular files, files in the m4 include paths, or a single dash .Pq Sq - , denoting standard input. .Nm writes the processed text to the standard output, unless told otherwise. .Pp Macro calls have the form name(argument1[, argument2, ..., argumentN]). .Pp There cannot be any space following the macro name and the open parenthesis .Pq Sq \&( . If the macro name is not followed by an open parenthesis it is processed with no arguments. .Pp Macro names consist of a leading alphabetic or underscore possibly followed by alphanumeric or underscore characters, e.g., valid macro names match the pattern .Dq [a-zA-Z_][a-zA-Z0-9_]* . .Pp In arguments to macros, leading unquoted space, tab, and newline .Pq Sq \en characters are ignored. To quote strings, use left and right single quotes -.Po e.g.,\ \& -.Sq "\ this is a string with a leading space" -.Pc . +.Pq e.g., Sq \ \&this is a string with a leading space . You can change the quote characters with the .Ic changequote built-in macro. .Pp Most built-ins do not make any sense without arguments, and hence are not recognized as special when not followed by an open parenthesis. .Pp The options are as follows: .Bl -tag -width Ds .It Fl D Ns Ar name Ns Op Pf = Ns Ar value Define the symbol .Ar name to have some value (or .Dv NULL ) . .It Fl d Ar "flags" Set trace flags. .Ar flags may hold the following: .Bl -tag -width Ds .It Ar a print macro arguments. .It Ar c print macro expansion over several lines. .It Ar e print result of macro expansion. .It Ar f print filename location. .It Ar l print line number. .It Ar q quote arguments and expansion with the current quotes. .It Ar t start with all macros traced. .It Ar x number macro expansions. .It Ar V turn on all options. .El .Pp By default, trace is set to .Qq eq . .It Fl g Activate GNU-m4 compatibility mode. In this mode, translit handles simple character ranges (e.g., a-z), regular expressions mimic emacs behavior, multiple m4wrap calls are handled as a stack, the number of diversions is unlimited, empty names for macro definitions are allowed, and eval understands .Sq 0rbase:value numbers. .It Fl I Ar "dirname" Add directory .Ar dirname to the include path. .It Fl o Ar filename Send trace output to .Ar filename . .It Fl P Prefix all built-in macros with .Sq m4_ . For example, instead of writing .Ic define , use .Ic m4_define . .It Fl s Output line synchronization directives, suitable for .Xr cpp 1 . .It Fl t Ar macro Turn tracing on for .Ar macro . .It Fl "U" Ns Ar "name" Undefine the symbol .Ar name . .El .Sh SYNTAX .Nm provides the following built-in macros. They may be redefined, losing their original meaning. Return values are null unless otherwise stated. .Bl -tag -width changequote .It Fn builtin name Calls a built-in by its .Fa name , overriding possible redefinitions. .It Fn changecom startcomment endcomment Changes the start comment and end comment sequences. Comment sequences may be up to five characters long. The default values are the hash sign and the newline character. .Bd -literal -offset indent # This is a comment .Ed .Pp With no arguments, comments are turned off. With one single argument, the end comment sequence is set to the newline character. .It Fn changequote beginquote endquote Defines the open quote and close quote sequences. Quote sequences may be up to five characters long. The default values are the backquote character and the quote character. .Bd -literal -offset indent `Here is a quoted string' .Ed .Pp With no arguments, the default quotes are restored. With one single argument, the close quote sequence is set to the newline character. .It Fn decr arg Decrements the argument .Fa arg by 1. The argument .Fa arg must be a valid numeric string. .It Fn define name value Define a new macro named by the first argument .Fa name to have the value of the second argument .Fa value . Each occurrence of .Sq $n (where .Ar n is 0 through 9) is replaced by the .Ar n Ns 'th argument. .Sq $0 is the name of the calling macro. Undefined arguments are replaced by a null string. .Sq $# is replaced by the number of arguments; .Sq $* is replaced by all arguments comma separated; .Sq $@ is the same as .Sq $* but all arguments are quoted against further expansion. .It Fn defn name ... Returns the quoted definition for each argument. This can be used to rename macro definitions (even for built-in macros). .It Fn divert num There are 10 output queues (numbered 0-9). At the end of processing .Nm concatenates all the queues in numerical order to produce the final output. Initially the output queue is 0. The divert macro allows you to select a new output queue (an invalid argument passed to divert causes output to be discarded). .It Ic divnum Returns the current output queue number. .It Ic dnl Discard input characters up to and including the next newline. .It Fn dumpdef name ... Prints the names and definitions for the named items, or for everything if no arguments are passed. .It Fn errprint msg Prints the first argument on the standard error output stream. .It Fn esyscmd cmd Passes its first argument to a shell and returns the shell's standard output. Note that the shell shares its standard input and standard error with .Nm . -.It Fn eval expr +.It Fn eval expr[,radix[,minimum]] Computes the first argument as an arithmetic expression using 32-bit arithmetic. Operators are the standard C ternary, arithmetic, logical, shift, relational, bitwise, and parentheses operators. You can specify octal, decimal, and hexadecimal numbers as in C. -The second argument (if any) -specifies the radix for the result and the third argument (if any) +The optional second argument +.Fa radix +specifies the radix for the result and the optional third argument +.Fa minimum specifies the minimum number of digits in the result. .It Fn expr expr This is an alias for .Ic eval . .It Fn format formatstring arg1 ... Returns .Fa formatstring with escape sequences substituted with .Fa arg1 and following arguments, in a way similar to .Xr printf 3 . This built-in is only available in GNU-m4 compatibility mode, and the only parameters implemented are there for autoconf compatibility: left-padding flag, an optional field width, a maximum field width, *-specified field widths, and the %s and %c data type. .It Fn ifdef name yes no If the macro named by the first argument is defined then return the second argument, otherwise the third. If there is no third argument, the value is .Dv NULL . The word .Qq unix is predefined. .It Fn ifelse a b yes ... If the first argument .Fa a matches the second argument .Fa b then .Fn ifelse returns the third argument .Fa yes . If the match fails the three arguments are discarded and the next three arguments are used until there is zero or one arguments left, either this last argument or .Dv NULL is returned if no other matches were found. .It Fn include name Returns the contents of the file specified in the first argument. If the file is not found as is, look through the include path: first the directories specified with .Fl I on the command line, then the environment variable .Ev M4PATH , as a colon-separated list of directories. Include aborts with an error message if the file cannot be included. .It Fn incr arg Increments the argument by 1. The argument must be a valid numeric string. .It Fn index string substring Returns the index of the second argument in the first argument (e.g., .Ic index(the quick brown fox jumped, fox) returns 16). If the second argument is not found index returns \-1. .It Fn indir macro arg1 ... Indirectly calls the macro whose name is passed as the first argument, with the remaining arguments passed as first, ... arguments. .It Fn len arg Returns the number of characters in the first argument. Extra arguments are ignored. .It Fn m4exit code Immediately exits with the return value specified by the first argument, 0 if none. .It Fn m4wrap todo Allows you to define what happens at the final .Dv EOF , usually for cleanup purposes (e.g., .Ic m4wrap("cleanup(tempfile)") causes the macro cleanup to be invoked after all other processing is done). .Pp Multiple calls to .Fn m4wrap get inserted in sequence at the final .Dv EOF . .It Fn maketemp template Like .Ic mkstemp . .It Fn mkstemp template Invokes .Xr mkstemp 3 on the first argument, and returns the modified string. This can be used to create unique temporary file names. .It Fn paste file Includes the contents of the file specified by the first argument without any macro processing. Aborts with an error message if the file cannot be included. .It Fn patsubst string regexp replacement Substitutes a regular expression in a string with a replacement string. Usual substitution patterns apply: an ampersand .Pq Sq \&& is replaced by the string matching the regular expression. The string .Sq \e# , where .Sq # is a digit, is replaced by the corresponding back-reference. .It Fn popdef arg ... Restores the .Ic pushdef Ns ed definition for each argument. .It Fn pushdef macro def Takes the same arguments as .Ic define , but it saves the definition on a stack for later retrieval by .Fn popdef . .It Fn regexp string regexp replacement Finds a regular expression in a string. If no further arguments are given, it returns the first match position or \-1 if no match. If a third argument is provided, it returns the replacement string, with sub-patterns replaced. .It Fn shift arg1 ... Returns all but the first argument, the remaining arguments are quoted and pushed back with commas in between. The quoting nullifies the effect of the extra scan that will subsequently be performed. .It Fn sinclude file Similar to .Ic include , except it ignores any errors. .It Fn spaste file Similar to .Fn paste , except it ignores any errors. .It Fn substr string offset length Returns a substring of the first argument starting at the offset specified by the second argument and the length specified by the third argument. If no third argument is present it returns the rest of the string. .It Fn syscmd cmd Passes the first argument to the shell. Nothing is returned. .It Ic sysval Returns the return value from the last .Ic syscmd . .It Fn traceon arg ... Enables tracing of macro expansions for the given arguments, or for all macros if no argument is given. .It Fn traceoff arg ... Disables tracing of macro expansions for the given arguments, or for all macros if no argument is given. .It Fn translit string mapfrom mapto Transliterate the characters in the first argument from the set given by the second argument to the set given by the third. You cannot use .Xr tr 1 style abbreviations. .It Fn undefine name1 ... Removes the definition for the macros specified by its arguments. .It Fn undivert arg ... Flushes the named output queues (or all queues if no arguments). .It Ic unix A pre-defined macro for testing the OS platform. .It Ic __line__ Returns the current file's line number. .It Ic __file__ Returns the current file's name. .El .Sh EXIT STATUS .Ex -std m4 .Pp But note that the .Ic m4exit macro can modify the exit status. .Sh STANDARDS The .Nm -utility is mostly compliant with the +utility is compliant with the .St -p1003.1-2008 specification. .Pp The flags -.Op Fl dgIot +.Op Fl dgIPot and the macros .Ic builtin , .Ic esyscmd , .Ic expr , .Ic format , .Ic indir , .Ic paste , .Ic patsubst , .Ic regexp , .Ic spaste , .Ic unix , .Ic __line__ , and .Ic __file__ are extensions to that specification. .Pp .Ic maketemp is not supposed to be a synonym for .Ic mkstemp , but instead to be an insecure temporary file name creation function. -The change causes no known compatibility issues. +It is marked by +.St -p1003.1-2008 +as being obsolescent and should not be used if portability is a concern. .Pp -The output format of tracing and of +The output format of +.Ic traceon +and .Ic dumpdef are not specified in any standard, are likely to change and should not be relied upon. The current format of tracing is closely modelled on .Nm gnu-m4 , to allow .Nm autoconf to work. .Pp The built-ins .Ic pushdef and .Ic popdef handle macro definitions as a stack. However, .Ic define interacts with the stack in an undefined way. In this implementation, .Ic define replaces the top-most definition only. Other implementations may erase all definitions on the stack instead. .Pp All built-ins do expand without arguments in many other .Nm . .Pp Many other .Nm have dire size limitations with respect to buffer sizes. .Sh AUTHORS .An -nosplit .An Ozan Yigit Aq Mt oz@sis.yorku.ca and .An Richard A. O'Keefe Aq Mt ok@goanna.cs.rmit.OZ.AU . .Pp GNU-m4 compatibility extensions by .An Marc Espie Aq Mt espie@cvs.openbsd.org . Index: head/usr.bin/m4/main.c =================================================================== --- head/usr.bin/m4/main.c (revision 269161) +++ head/usr.bin/m4/main.c (revision 269162) @@ -1,634 +1,635 @@ -/* $OpenBSD: main.c,v 1.81 2012/04/12 17:00:11 espie Exp $ */ +/* $OpenBSD: main.c,v 1.83 2014/05/12 19:11:19 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. 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. */ /* * main.c * Facility: m4 macro processor * by: oz */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "mdef.h" #include "stdd.h" #include "extern.h" #include "pathnames.h" 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) */ 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.. */ char **m4wraps = NULL; /* m4wraps array. */ int maxwraps = 0; /* size of m4wraps array */ int wrapindex = 0; /* current offset in m4wraps */ 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 synch_lines = 0; /* line synchronisation for C preprocessor */ int prefix_builtins = 0; /* -P option to prefix builtin keywords */ struct keyblk { const char *knam; /* keyword name */ int ktyp; /* keyword type */ }; static 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 }, { "mkstemp", 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)) #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 reallyoutputstr(const char *); static void reallyputchar(int); static void enlarge_stack(void); int main(int, char *[]); int exit_code = 0; int main(int argc, char *argv[]) { int c; int n; char *p; if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); init_macros(); initspaces(); STACKMAX = INITSTACKMAX; - mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL); - sstack = (char *)xalloc(STACKMAX, NULL); + mstack = xreallocarray(NULL, STACKMAX, sizeof(stae), NULL); + sstack = xalloc(STACKMAX, NULL); maxout = 0; outfile = NULL; resizedivs(MAXOUT); while ((c = getopt(argc, argv, "gst:d:D:U:o:I:P")) != -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 'P': prefix_builtins = 1; break; case 'U': /* undefine... */ macro_popdef(optarg); break; case 'g': mimic_gnu = 1; break; case 'd': set_trace_flags(optarg); break; case 's': synch_lines = 1; break; case 't': mark_traced(optarg, 1); break; case 'o': trace_file(optarg); break; case '?': usage(); } argc -= optind; argv += optind; initkwds(); if (mimic_gnu) setup_builtin("format", FORMATTYPE); 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) */ 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; macro(); release_input(infile); } if (wrapindex) { int i; ilevel = 0; /* in case m4wrap includes.. */ bufbase = bp = buf; /* use the entire buffer */ if (mimic_gnu) { while (wrapindex != 0) { for (i = 0; i < wrapindex; i++) pbstr(m4wraps[i]); wrapindex =0; macro(); } } else { for (i = 0; i < wrapindex; i++) { pbstr(m4wraps[i]); macro(); } } } 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 exit_code; } /* * 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(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) { pushback(t); while (--i) pushback(*--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(void) { char token[MAXTOK+1]; int t, l; ndptr p; int nlpar; cycle { t = gpbc(); 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) reallyputchar(l); else CHRSAVE(l); } } } while (nlpar != 0); } else if (sp < 0 && LOOK_AHEAD(t, scommt)) { reallyoutputstr(scommt); for(;;) { t = gpbc(); if (LOOK_AHEAD(t, ecommt)) { reallyoutputstr(ecommt); break; } if (t == EOF) break; reallyputchar(t); } } else if (t == '_' || isalpha(t)) { p = inspect(t, token); if (p != NULL) pushback(l = gpbc()); if (p == NULL || (l != LPAREN && (macro_getdef(p)->type & NEEDARGS) != 0)) outputstr(token); else { /* * real thing.. First build a call frame: */ pushf(fp); /* previous call frm */ pushf(macro_getdef(p)->type); /* type of the call */ pushf(is_traced(p)); pushf(0); /* parenthesis level */ fp = sp; /* new frame pointer */ /* * now push the string arguments: */ pushs1(macro_getdef(p)->defn); /* defn string */ pushs1((char *)macro_name(p)); /* macro name */ pushs(ep); /* start next..*/ if (l != LPAREN && PARLEV == 0) { /* no bracks */ chrsave(EOS); if (sp == (int)STACKMAX) errx(1, "internal stack overflow"); eval((const char **) mstack+fp+1, 2, CALTYP, TRACESTATUS); ep = PREVEP; /* flush strspace */ sp = PREVSP; /* previous sp.. */ fp = PREVFP; /* rewind stack...*/ } } } else if (t == EOF) { - if (sp > -1 && ilevel <= 0) { + if (!mimic_gnu /* you can puke right there */ + && sp > -1 && ilevel <= 0) { warnx( "unexpected end of input, unclosed parenthesis:"); dump_stack(paren, PARLEV); exit(1); } if (ilevel <= 0) break; /* all done thanks.. */ release_input(infile+ilevel--); emit_synchline(); bufbase = bbase[ilevel]; continue; } else if (sp < 0) { /* not in a macro at all */ reallyputchar(t); /* output directly.. */ } else switch(t) { case LPAREN: if (PARLEV > 0) chrsave(t); while (isspace(l = gpbc())) /* skip blank, tab, nl.. */ if (PARLEV > 0) chrsave(l); pushback(l); record(paren, PARLEV++); break; case RPAREN: if (--PARLEV > 0) chrsave(t); else { /* end of argument list */ chrsave(EOS); if (sp == (int)STACKMAX) errx(1, "internal stack overflow"); eval((const char **) mstack+fp+1, sp-fp, CALTYP, TRACESTATUS); 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())) ; pushback(l); pushs(ep); } else chrsave(t); break; default: if (LOOK_AHEAD(t, scommt)) { char *cp; for (cp = scommt; *cp; cp++) chrsave(*cp); for(;;) { t = gpbc(); if (LOOK_AHEAD(t, ecommt)) { for (cp = ecommt; *cp; cp++) chrsave(*cp); break; } if (t == EOF) break; CHRSAVE(t); } } else CHRSAVE(t); /* stack the char */ break; } } } /* * output string directly, without pushing it for reparses. */ void outputstr(const char *s) { if (sp < 0) reallyoutputstr(s); else while (*s) CHRSAVE(*s++); } void reallyoutputstr(const char *s) { if (synch_lines) { while (*s) { fputc(*s, active); if (*s++ == '\n') { infile[ilevel].synch_lineno++; if (infile[ilevel].synch_lineno != infile[ilevel].lineno) do_emit_synchline(); } } } else fputs(s, active); } void reallyputchar(int c) { putc(c, active); if (synch_lines && c == '\n') { infile[ilevel].synch_lineno++; if (infile[ilevel].synch_lineno != infile[ilevel].lineno) do_emit_synchline(); } } /* * build an input token.. * consider only those starting with _ or A-Za-z. */ static ndptr inspect(int c, char *tp) { char *name = tp; char *etp = tp+MAXTOK; ndptr p; *tp++ = c; while ((isalnum(c = gpbc()) || c == '_') && tp < etp) *tp++ = c; if (c != EOF) PUSHBACK(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) reallyputchar(c); else CHRSAVE(c); } *name = EOS; return NULL; } p = ohash_find(¯os, ohash_qlookupi(¯os, name, (const char **)&tp)); if (p == NULL) return NULL; if (macro_getdef(p) == NULL) return NULL; 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(void) { unsigned int type; int i; for (i = 0; i < (int)MAXKEYS; i++) { type = keywrds[i].ktyp & TYPEMASK; if ((keywrds[i].ktyp & NOARGS) == 0) type |= NEEDARGS; setup_builtin(keywrds[i].knam, type); } } static void record(struct position *t, int lev) { if (lev < MAXRECORD) { t[lev].name = CURRENT_NAME; t[lev].line = CURRENT_LINE; } } static void 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(void) { STACKMAX += STACKMAX/2; - mstack = xrealloc(mstack, sizeof(stae) * STACKMAX, + mstack = xreallocarray(mstack, STACKMAX, sizeof(stae), "Evaluation stack overflow (%lu)", (unsigned long)STACKMAX); sstack = xrealloc(sstack, STACKMAX, "Evaluation stack overflow (%lu)", (unsigned long)STACKMAX); } Index: head/usr.bin/m4/misc.c =================================================================== --- head/usr.bin/m4/misc.c (revision 269161) +++ head/usr.bin/m4/misc.c (revision 269162) @@ -1,427 +1,485 @@ -/* $OpenBSD: misc.c,v 1.42 2010/09/07 19:58:09 marco Exp $ */ +/* $OpenBSD: misc.c,v 1.44 2014/05/12 19:11:19 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. 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 __FBSDID("$FreeBSD$"); #include #include #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; unsigned char *buf; /* push-back buffer */ unsigned char *bufbase; /* the base for current ilevel */ unsigned char *bbase[MAXINP]; /* the base for each ilevel */ unsigned char *bp; /* first available character */ unsigned char *endpbb; /* end of push-back buffer */ /* * find the index of second str in the first str. */ ptrdiff_t indx(const char *s1, const char *s2) { char *t; t = strstr(s1, s2); if (t == NULL) return (-1); else return (t - s1); } /* * pushback - push character back onto input */ void pushback(int c) { if (c == EOF) return; if (bp >= endpbb) enlarge_bufspace(); *bp++ = c; } /* * pbstr - push string back onto input * pushback is replicated to improve * performance. */ void pbstr(const char *s) { size_t n; n = strlen(s); while (endpbb - bp <= (long)n) enlarge_bufspace(); while (n > 0) *bp++ = s[--n]; } /* * pbnum - convert number to string, push back on input. */ void pbnum(int n) { pbnumbase(n, 10, 0); } void pbnumbase(int n, int base, int d) { static char digits[36] = "0123456789abcdefghijklmnopqrstuvwxyz"; int num; int printed = 0; if (base > 36) m4errx(1, "base %d > 36: not supported.", base); if (base < 2) m4errx(1, "bad base %d for conversion.", base); num = (n < 0) ? -n : n; do { pushback(digits[num % base]); printed++; } while ((num /= base) > 0); if (n < 0) printed++; while (printed++ < d) pushback('0'); if (n < 0) pushback('-'); } /* * pbunsigned - convert unsigned long to string, push back on input. */ void pbunsigned(unsigned long n) { do { pushback(n % 10 + '0'); } while ((n /= 10) > 0); } void initspaces(void) { int i; strspace = xalloc(strsize+1, NULL); ep = strspace; endest = strspace+strsize; - buf = (unsigned char *)xalloc(bufsize, NULL); + buf = xalloc(bufsize, NULL); bufbase = buf; bp = buf; endpbb = buf + bufsize; for (i = 0; i < MAXINP; i++) bbase[i] = buf; } void enlarge_strspace(void) { 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(void) { unsigned char *newbuf; int i; bufsize += bufsize/2; newbuf = xrealloc(buf, bufsize, "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(int c) { if (ep >= endest) enlarge_strspace(); *ep++ = c; } /* * read in a diversion file, and dispose it. */ void getdiv(int n) { int c; if (active == outfile[n]) m4errx(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(__unused int signo) +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(void) { int n; for (n = 0; n < maxout; n++) if (outfile[n] != NULL) { (void) fclose(outfile[n]); } } extern char *__progname; void -m4errx(int evaluation, const char *fmt, ...) +m4errx(int eval, const char *fmt, ...) { fprintf(stderr, "%s: ", __progname); fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE); if (fmt != NULL) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } fprintf(stderr, "\n"); - exit(evaluation); + exit(eval); } /* * resizedivs: allocate more diversion files */ void resizedivs(int n) { int i; - outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n, + outfile = xreallocarray(outfile, n, sizeof(FILE *), "too many diverts %d", n); for (i = maxout; i < n; i++) outfile[i] = NULL; maxout = n; } void * xalloc(size_t n, const char *fmt, ...) { void *p = malloc(n); if (p == NULL) { if (fmt == NULL) err(1, "malloc"); else { va_list va; va_start(va, fmt); verr(1, fmt, va); va_end(va); } } return p; } void * +xcalloc(size_t n, size_t s, const char *fmt, ...) +{ + void *p = calloc(n, s); + + if (p == NULL) { + if (fmt == NULL) + err(1, "calloc"); + else { + va_list va; + + va_start(va, fmt); + verr(1, fmt, va); + va_end(va); + } + } + return p; +} + +void * xrealloc(void *old, size_t n, const char *fmt, ...) { char *p = realloc(old, n); if (p == NULL) { free(old); if (fmt == NULL) err(1, "realloc"); + else { + va_list va; + + va_start(va, fmt); + verr(1, fmt, va); + va_end(va); + } + } + return p; +} + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) + +static void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return NULL; + } + return realloc(optr, size * nmemb); +} + +void * +xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...) +{ + void *p = reallocarray(old, s1, s2); + + if (p == NULL) { + free(old); + if (fmt == NULL) + err(1, "reallocarray"); else { va_list va; va_start(va, fmt); verr(1, fmt, va); va_end(va); } } return p; } char * xstrdup(const char *s) { char *p = strdup(s); if (p == NULL) err(1, "strdup"); return p; } void usage(void) { fprintf(stderr, "usage: m4 [-gPs] [-Dname[=value]] [-d flags] " "[-I dirname] [-o filename]\n" "\t[-t macro] [-Uname] [file ...]\n"); exit(1); } int obtain_char(struct input_file *f) { if (f->c == EOF) return EOF; f->c = fgetc(f->file); if (f->c == '\n') f->lineno++; return f->c; } void set_input(struct input_file *f, FILE *real, const char *name) { f->file = real; f->lineno = 1; f->c = 0; f->name = xstrdup(name); emit_synchline(); } void do_emit_synchline(void) { fprintf(active, "#line %lu \"%s\"\n", infile[ilevel].lineno, infile[ilevel].name); infile[ilevel].synch_lineno = infile[ilevel].lineno; } void 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(struct input_file *f) { pbunsigned(f->lineno); } void 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(void) { return bp - buf; } void dump_buffer(FILE *f, size_t m) { unsigned char *s; for (s = bp; s-buf > (long)m;) fputc(*--s, f); }