diff options
author | denis <denis@cvs.openbsd.org> | 2018-06-11 09:57:02 +0000 |
---|---|---|
committer | denis <denis@cvs.openbsd.org> | 2018-06-11 09:57:02 +0000 |
commit | a6954086e122ab19e108de9dbaa803d94f67dca2 (patch) | |
tree | 5988983cdda2e8753a03449b60337e9adb3e2e22 /usr.sbin/switchd | |
parent | 52359c977b99b54ea7b40b4664b6d61b133cb69d (diff) |
Fix an off-by-one line count when using include statements.
Thanks to otto@ for the initial diff.
OK benno@
Diffstat (limited to 'usr.sbin/switchd')
-rw-r--r-- | usr.sbin/switchd/parse.y | 128 |
1 files changed, 80 insertions, 48 deletions
diff --git a/usr.sbin/switchd/parse.y b/usr.sbin/switchd/parse.y index 52bad178e8f..8d751baf223 100644 --- a/usr.sbin/switchd/parse.y +++ b/usr.sbin/switchd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.6 2017/08/28 06:00:05 florian Exp $ */ +/* $OpenBSD: parse.y,v 1.7 2018/06/11 09:57:01 denis Exp $ */ /* * Copyright (c) 2007-2016 Reyk Floeter <reyk@openbsd.org> @@ -29,6 +29,7 @@ #include <sys/un.h> #include <ctype.h> +#include <err.h> #include <errno.h> #include <limits.h> #include <netdb.h> @@ -44,6 +45,10 @@ static struct file { TAILQ_ENTRY(file) entry; FILE *stream; char *name; + size_t ungetpos; + size_t ungetsize; + u_char *ungetbuf; + int eof_reached; int lineno; int errors; } *file, *topfile; @@ -56,8 +61,9 @@ int yyerror(const char *, ...) __attribute__((__nonnull__ (1))); int kw_cmp(const void *, const void *); int lookup(char *); +int igetc(void); int lgetc(int); -int lungetc(int); +void lungetc(int); int findeol(void); int host(const char *, struct sockaddr *, socklen_t); @@ -294,34 +300,39 @@ lookup(char *s) return (STRING); } -#define MAXPUSHBACK 128 +#define START_EXPAND 1 +#define DONE_EXPAND 2 -u_char *parsebuf; -int parseindex; -u_char pushback_buffer[MAXPUSHBACK]; -int pushback_index = 0; +static int expanding; int -lgetc(int quotec) +igetc(void) { - int c, next; + int c; - if (parsebuf) { - /* Read character from the parsebuffer instead of input. */ - if (parseindex >= 0) { - c = parsebuf[parseindex++]; - if (c != '\0') - return (c); - parsebuf = NULL; - } else - parseindex++; + while (1) { + if (file->ungetpos > 0) + c = file->ungetbuf[--file->ungetpos]; + else + c = getc(file->stream); + + if (c == START_EXPAND) + expanding = 1; + else if (c == DONE_EXPAND) + expanding = 0; + else + break; } + return (c); +} - if (pushback_index) - return (pushback_buffer[--pushback_index]); +int +lgetc(int quotec) +{ + int c, next; if (quotec) { - if ((c = getc(file->stream)) == EOF) { + if ((c = igetc()) == EOF) { yyerror("reached end of file while parsing " "quoted string"); if (file == topfile || popfile() == EOF) @@ -331,8 +342,8 @@ lgetc(int quotec) return (c); } - while ((c = getc(file->stream)) == '\\') { - next = getc(file->stream); + while ((c = igetc()) == '\\') { + next = igetc(); if (next != '\n') { c = next; break; @@ -349,28 +360,39 @@ lgetc(int quotec) c = ' '; } - while (c == EOF) { - if (file == topfile || popfile() == EOF) - return (EOF); - c = getc(file->stream); + if (c == EOF) { + /* + * Fake EOL when hit EOF for the first time. This gets line + * count right if last line in included file is syntactically + * invalid and has no newline. + */ + if (file->eof_reached == 0) { + file->eof_reached = 1; + return ('\n'); + } + while (c == EOF) { + if (file == topfile || popfile() == EOF) + return (EOF); + c = igetc(); + } } return (c); } -int +void lungetc(int c) { if (c == EOF) - return (EOF); - if (parsebuf) { - parseindex--; - if (parseindex >= 0) - return (c); + return; + + if (file->ungetpos >= file->ungetsize) { + void *p = reallocarray(file->ungetbuf, file->ungetsize, 2); + if (p == NULL) + err(1, "lungetc"); + file->ungetbuf = p; + file->ungetsize *= 2; } - if (pushback_index < MAXPUSHBACK-1) - return (pushback_buffer[pushback_index++] = c); - else - return (EOF); + file->ungetbuf[file->ungetpos++] = c; } int @@ -378,14 +400,9 @@ findeol(void) { int c; - parsebuf = NULL; - /* skip to either EOF or the first real EOL */ while (1) { - if (pushback_index) - c = pushback_buffer[--pushback_index]; - else - c = lgetc(0); + c = lgetc(0); if (c == '\n') { file->lineno++; break; @@ -413,7 +430,7 @@ top: if (c == '#') while ((c = lgetc(0)) != '\n' && c != EOF) ; /* nothing */ - if (c == '$' && parsebuf == NULL) { + if (c == '$' && !expanding) { while (1) { if ((c = lgetc(0)) == EOF) return (0); @@ -435,8 +452,13 @@ top: yyerror("macro '%s' not defined", buf); return (findeol()); } - parsebuf = val; - parseindex = 0; + p = val + strlen(val) - 1; + lungetc(DONE_EXPAND); + while (p >= val) { + lungetc(*p); + p--; + } + lungetc(START_EXPAND); goto top; } @@ -564,7 +586,16 @@ pushfile(const char *name, int secret) free(nfile); return (NULL); } - nfile->lineno = 1; + nfile->lineno = TAILQ_EMPTY(&files) ? 1 : 0; + nfile->ungetsize = 16; + nfile->ungetbuf = malloc(nfile->ungetsize); + if (nfile->ungetbuf == NULL) { + log_warn("malloc"); + fclose(nfile->stream); + free(nfile->name); + free(nfile); + return (NULL); + } TAILQ_INSERT_TAIL(&files, nfile, entry); return (nfile); } @@ -580,6 +611,7 @@ popfile(void) TAILQ_REMOVE(&files, file, entry); fclose(file->stream); free(file->name); + free(file->ungetbuf); free(file); file = prev; return (file ? 0 : EOF); @@ -603,7 +635,7 @@ parse_config(const char *filename, struct switchd *sc) if ((file = pushfile(filename, 0)) == NULL) { log_warn("failed to open %s", filename); - return (0); + return (-1); } topfile = file; setservent(1); |