summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authordenis <denis@cvs.openbsd.org>2018-06-11 09:32:56 +0000
committerdenis <denis@cvs.openbsd.org>2018-06-11 09:32:56 +0000
commitae04534bb454b25fde26dcf741ce6c884d520957 (patch)
treeb89a6291959a5642b429a68b7bd87fe438307270 /usr.sbin
parentaaae9b45642835fed798668dffd00c4d2dc6266e (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')
-rw-r--r--usr.sbin/vmd/parse.y125
1 files changed, 78 insertions, 47 deletions
diff --git a/usr.sbin/vmd/parse.y b/usr.sbin/vmd/parse.y
index 91e5d379821..b402a92fa85 100644
--- a/usr.sbin/vmd/parse.y
+++ b/usr.sbin/vmd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.33 2018/04/26 14:12:19 krw Exp $ */
+/* $OpenBSD: parse.y,v 1.34 2018/06/11 09:32:55 denis Exp $ */
/*
* Copyright (c) 2007-2016 Reyk Floeter <reyk@openbsd.org>
@@ -55,6 +55,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;
@@ -67,8 +71,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);
TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
@@ -684,34 +689,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)
@@ -721,8 +731,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;
@@ -739,28 +749,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
@@ -768,14 +789,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;
@@ -803,7 +819,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);
@@ -825,8 +841,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;
}
@@ -954,7 +975,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);
}
@@ -970,6 +1000,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);