Module Name: src Committed By: christos Date: Sat Jan 16 16:59:18 UTC 2016
Modified Files: src/usr.bin/m4: gnum4.c Log Message: - don't eat the rest of the string when no match in patsubst - include the pattern in the error printing of regex - handle 3 argument and empty patterns the gnu way - add support for freezing and thawing state (not working yet) To generate a diff of this commit: cvs rdiff -u -r1.9 -r1.10 src/usr.bin/m4/gnum4.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/m4/gnum4.c diff -u src/usr.bin/m4/gnum4.c:1.9 src/usr.bin/m4/gnum4.c:1.10 --- src/usr.bin/m4/gnum4.c:1.9 Tue Mar 20 16:34:58 2012 +++ src/usr.bin/m4/gnum4.c Sat Jan 16 11:59:18 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: gnum4.c,v 1.9 2012/03/20 20:34:58 matt Exp $ */ +/* $NetBSD: gnum4.c,v 1.10 2016/01/16 16:59:18 christos Exp $ */ /* $OpenBSD: gnum4.c,v 1.39 2008/08/21 21:01:04 espie Exp $ */ /* @@ -33,7 +33,7 @@ #include "nbtool_config.h" #endif #include <sys/cdefs.h> -__RCSID("$NetBSD: gnum4.c,v 1.9 2012/03/20 20:34:58 matt Exp $"); +__RCSID("$NetBSD: gnum4.c,v 1.10 2016/01/16 16:59:18 christos Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -203,10 +203,11 @@ static void addchars(const char *, size_ static void addchar(int); static char *twiddle(const char *); static char *getstring(void); -static void exit_regerror(int, regex_t *) __dead; -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, const char *, regex_t *) __dead; +static void do_subst(const char *, const char *, regex_t *, const char *, + regmatch_t *); +static void do_regexpindex(const char *, const char *, regex_t *, regmatch_t *); +static void do_regexp(const char *, const char *, regex_t *, const char *, regmatch_t *); static void add_sub(size_t, const char *, regex_t *, regmatch_t *); static void add_replace(const char *, regex_t *, const char *, regmatch_t *); #define addconstantstring(s) addchars((s), sizeof(s)-1) @@ -250,7 +251,7 @@ getstring(void) static void -exit_regerror(int er, regex_t *re) +exit_regerror(int er, const char *pat, regex_t *re) { size_t errlen; char *errbuf; @@ -259,14 +260,18 @@ exit_regerror(int er, regex_t *re) 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: %s for: `%s'", errbuf, pat); } static void add_sub(size_t n, const char *string, regex_t *re, regmatch_t *pm) { - if (n > re->re_nsub) - warnx("No subexpression %zu", n); + if (n > re->re_nsub) { + if (!quiet) + warnx("No subexpression %zu", n); + if (fatal_warnings) + exit(EXIT_FAILURE); + } /* Subexpressions that did not match are * not an error. */ else if (pm[n].rm_so != -1 && @@ -313,7 +318,8 @@ add_replace(const char *string, regex_t } static void -do_subst(const char *string, regex_t *re, const char *replace, regmatch_t *pm) +do_subst(const char *pat, const char *string, regex_t *re, const char *replace, + regmatch_t *pm) { int error; int flags = 0; @@ -346,14 +352,18 @@ do_subst(const char *string, regex_t *re addchars(string, pm[0].rm_so); add_replace(string, re, replace, pm); string += pm[0].rm_eo; + buffer[current] = '\0'; } + while (*string) + addchar(*string++); if (error != REG_NOMATCH) - exit_regerror(error, re); + exit_regerror(error, pat, re); pbstr(string); } static void -do_regexp(const char *string, regex_t *re, const char *replace, regmatch_t *pm) +do_regexp(const char *pat, const char *string, regex_t *re, const char *replace, + regmatch_t *pm) { int error; @@ -365,12 +375,12 @@ do_regexp(const char *string, regex_t *r case REG_NOMATCH: break; default: - exit_regerror(error, re); + exit_regerror(error, pat, re); } } static void -do_regexpindex(const char *string, regex_t *re, regmatch_t *pm) +do_regexpindex(const char *pat, const char *string, regex_t *re, regmatch_t *pm) { int error; @@ -382,7 +392,7 @@ do_regexpindex(const char *string, regex pbnum(-1); break; default: - exit_regerror(error, re); + exit_regerror(error, pat, re); } } @@ -437,6 +447,33 @@ twiddle(const char *p) return getstring(); } +static int +checkempty(const char *argv[], int argc) +{ + const char *s; + size_t len; + + if (argc != 3 && argv[3][0] != '\0') + return 0; + + if (argc == 3) { + if (!quiet) + warnx("Too few arguments to patsubst"); + if (fatal_warnings) + exit(EXIT_FAILURE); + } + + if (argv[4] && argc > 4) + len = strlen(argv[4]); + else + len = 0; + for (s = argv[2]; *s != '\0'; s++) { + addchars(argv[4], len); + addchar(*s); + } + return 1; +} + /* patsubst(string, regexp, opt replacement) */ /* argv[2]: string * argv[3]: regexp @@ -445,23 +482,17 @@ twiddle(const char *p) void dopatsubst(const char *argv[], int argc) { - if (argc <= 3) { - warnx("Too few arguments to patsubst"); + if (argc < 3) { + if (!quiet) + warnx("Too few arguments to patsubst"); + if (fatal_warnings) + exit(EXIT_FAILURE); return; } /* special case: empty regexp */ - if (argv[3][0] == '\0') { - const char *s; - size_t len; - if (argv[4] && argc > 4) - len = strlen(argv[4]); - else - len = 0; - for (s = argv[2]; *s != '\0'; s++) { - addchars(argv[4], len); - addchar(*s); - } - } else { + if (!checkempty(argv, argc)) { + + const char *pat; int error; regex_t re; regmatch_t *pmatch; @@ -473,13 +504,13 @@ dopatsubst(const char *argv[], int argc) (l > 0 && argv[3][l-1] == '$')) mode |= REG_NEWLINE; - error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], - mode); + pat = mimic_gnu ? twiddle(argv[3]) : argv[3]; + error = regcomp(&re, pat, mode); if (error != 0) - exit_regerror(error, &re); + exit_regerror(error, pat, &re); pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL); - do_subst(argv[2], &re, + do_subst(pat, argv[2], &re, argc > 4 && argv[4] != NULL ? argv[4] : "", pmatch); free(pmatch); regfree(&re); @@ -493,21 +524,29 @@ doregexp(const char *argv[], int argc) int error; regex_t re; regmatch_t *pmatch; + const char *pat; - if (argc <= 3) { - warnx("Too few arguments to regexp"); + if (argc < 3) { + if (!quiet) + warnx("Too few arguments to regexp"); + if (fatal_warnings) + exit(EXIT_FAILURE); return; } - error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3], - REG_EXTENDED); + if (checkempty(argv, argc)) { + return; + } + + pat = mimic_gnu ? twiddle(argv[3]) : argv[3]; + error = regcomp(&re, pat, REG_EXTENDED); if (error != 0) - exit_regerror(error, &re); + exit_regerror(error, pat, &re); pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL); if (argv[4] == NULL || argc == 4) - do_regexpindex(argv[2], &re, pmatch); + do_regexpindex(pat, argv[2], &re, pmatch); else - do_regexp(argv[2], &re, argv[4], pmatch); + do_regexp(pat, argv[2], &re, argv[4], pmatch); free(pmatch); regfree(&re); } @@ -667,3 +706,112 @@ getdivfile(const char *name) putc(c, active); (void) fclose(f); } + +#ifdef REAL_FREEZE +void +freeze_state(const char *fname) +{ + FILE *f; + + if ((f = fopen(fname, "wb")) == NULL) + m4errx(EXIT_FAILURE, "Can't open output freeze file `%s' (%s)", + fname, strerror(errno)); + fprintf(f, "# This is a frozen state file generated by %s\nV1\n", + getprogname()); + fprintf(f, "Q%zu,%zu\n%s%s\n", strlen(lquote), strlen(rquote), + lquote, rquote); + fprintf(f, "C%zu,%zu\n%s%s\n", strlen(scommt), strlen(ecommt), + scommt, ecommt); + dump_state(f); + /* XXX: diversions? */ + fprintf(f, "D-1,0\n"); + fprintf(f, "# End of frozen state file\n"); + fclose(f); +} + +void +thaw_state(const char *fname) +{ + char *name = NULL; + size_t nl, namelen = 0; + char *defn = NULL; + size_t dl, defnlen = 0; + size_t lineno = 0; + char line[1024], *ptr, type; + FILE *f; + + if ((f = fopen(fname, "rb")) == NULL) + m4errx(EXIT_FAILURE, "Can't open frozen file `%s' (%s)", + fname, strerror(errno)); + +#define GET() if (fgets(line, (int)sizeof(line), f) == NULL) goto out +#define GETSTR(s, l) if (fread(s, 1, l, f) != l) goto out; else s[l] = '\0' + + GET(); /* comment */ + GET(); /* version */ + if ((ptr = strrchr(line, '\n')) != NULL) + *ptr = '\0'; + if (strcmp(line, "V1") != 0) + m4errx(EXIT_FAILURE, "Bad frozen version `%s'", line); + + for (;;) { + GET(); + lineno++; + switch (*line) { + case '\n': + continue; + case '#': + free(name); + free(defn); + fclose(f); + return; + default: + if (sscanf(line, "%c%zu,%zu\n", &type, &nl, &dl) != 3) + m4errx(EXIT_FAILURE, "%s, %zu: Bad line `%s'", + fname, lineno, line); + break; + } + + switch (type) { + case 'Q': + if (nl >= sizeof(lquote) || dl >= sizeof(rquote)) + m4errx(EXIT_FAILURE, "%s, %zu: Quote too long", + fname, lineno); + GETSTR(lquote, nl); + GETSTR(rquote, dl); + break; + + case 'C': + if (nl >= sizeof(scommt) || dl >= sizeof(ecommt)) + m4errx(EXIT_FAILURE, "%s, %zu: Comment too long", + fname, lineno); + GETSTR(scommt, nl); + GETSTR(ecommt, dl); + break; + + case 'T': + case 'F': + if (nl >= namelen) + name = xrealloc(name, namelen = nl + 1, + "name grow"); + if (dl >= defnlen) + defn = xrealloc(defn, defnlen = dl + 1, + "defn grow"); + GETSTR(name, nl); + GETSTR(defn, dl); + macro_pushdef(name, defn); + break; + + case 'D': + /* XXX: Not implemented */ + break; + + default: + m4errx(EXIT_FAILURE, "%s, %zu: Unknown type %c", + fname, lineno,type); + } + } +out: + m4errx(EXIT_FAILURE, "Unexprected end of file in `%s'", fname); +} +#endif