summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2018-05-09 11:07:21 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2018-05-09 11:07:21 +0000
commit5b493bf57f3ae945027b6f673cc4bb8371d68e55 (patch)
tree4a571bcd253113f55d13f734ec15dc62f01402eb /sbin
parentb15d269d762de135a3c4deff287d8988f6c20496 (diff)
Fix (include file ) line number counting by keeping track of the unget
buffer per file; also use that buffer to expand macros. ok sashan@ dennis@ krw@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/pfctl/parse.y125
1 files changed, 77 insertions, 48 deletions
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 53b2337b468..fba07e2ea43 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.671 2018/04/26 14:12:19 krw Exp $ */
+/* $OpenBSD: parse.y,v 1.672 2018/05/09 11:07:20 otto Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -70,6 +70,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;
@@ -81,8 +85,9 @@ int yylex(void);
int yyerror(const char *, ...);
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);
TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
@@ -5234,34 +5239,37 @@ lookup(char *s)
}
}
-#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;
-
- 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++;
+ int c;
+ 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 (popfile() == EOF)
return (EOF);
@@ -5270,8 +5278,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;
@@ -5280,28 +5288,39 @@ lgetc(int quotec)
file->lineno++;
}
- while (c == EOF) {
- if (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 (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
@@ -5309,14 +5328,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;
@@ -5344,7 +5358,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);
@@ -5366,8 +5380,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;
}
@@ -5552,7 +5571,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) {
+ warn("malloc");
+ fclose(nfile->stream);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ }
TAILQ_INSERT_TAIL(&files, nfile, entry);
return (nfile);
}
@@ -5567,6 +5595,7 @@ popfile(void)
TAILQ_REMOVE(&files, file, entry);
fclose(file->stream);
free(file->name);
+ free(file->ungetbuf);
free(file);
file = prev;
return (0);