Applying otto@'s diff to vmd.
Fixes an off-by-one line count when using include statements.

Ok ?

Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/parse.y,v
retrieving revision 1.33
diff -u -p -r1.33 parse.y
--- parse.y     26 Apr 2018 14:12:19 -0000      1.33
+++ parse.y     2 Jun 2018 20:23:16 -0000
@@ -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);

Reply via email to