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

Ok ?

Index: parse.y
===================================================================
RCS file: /cvs/src/sbin/iked/parse.y,v
retrieving revision 1.71
diff -u -p -r1.71 parse.y
--- parse.y     26 Apr 2018 14:12:19 -0000      1.71
+++ parse.y     27 May 2018 14:41:47 -0000
@@ -59,6 +59,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;
@@ -77,8 +81,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);
@@ -434,7 +439,7 @@ comma               : ','
 include                : INCLUDE STRING                {
                        struct file     *nfile;
 
-                       if ((nfile = pushfile($2, 0)) == NULL) {
+                       if ((nfile = pushfile($2, 1)) == NULL) {
                                yyerror("failed to include file %s", $2);
                                free($2);
                                YYERROR;
@@ -1213,34 +1218,39 @@ lookup(char *s)
        }
 }
 
-#define MAXPUSHBACK    128
+#define START_EXPAND   1
+#define DONE_EXPAND    2
 
-unsigned char  *parsebuf;
-int             parseindex;
-unsigned 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 (popfile() == EOF)
@@ -1250,8 +1260,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;
@@ -1261,27 +1271,38 @@ lgetc(int quotec)
        }
 
        while (c == EOF) {
-               if (popfile() == EOF)
-                       return (EOF);
-               c = getc(file->stream);
+               /*
+                * 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
@@ -1289,14 +1310,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;
@@ -1324,7 +1340,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);
@@ -1346,8 +1362,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;
        }
 
@@ -1510,7 +1531,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);
 }
@@ -1525,6 +1555,7 @@ popfile(void)
                TAILQ_REMOVE(&files, file, entry);
                fclose(file->stream);
                free(file->name);
+               free(file->ungetbuf);
                free(file);
                file = prev;
                return (0);

Reply via email to