On Sat, Jun 02, 2018 at 10:32:52PM +0200, Denis Fondras wrote:
> Applying otto@'s diff to smtpd.
> Fixes an off-by-one line count when using include statements.
> 
> Ok ?
> 

tested, ok gilles@


> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
> retrieving revision 1.210
> diff -u -p -r1.210 parse.y
> --- parse.y   1 Jun 2018 20:31:33 -0000       1.210
> +++ parse.y   2 Jun 2018 19:31:08 -0000
> @@ -63,6 +63,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;
> @@ -73,8 +77,9 @@ int          yyparse(void);
>  int           yylex(void);
>  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           yyerror(const char *, ...)
>      __attribute__((__format__ (printf, 1, 2)))
> @@ -1663,34 +1668,39 @@ lookup(char *s)
>               return (STRING);
>  }
>  
> -#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 (file == topfile || popfile() == EOF)
> @@ -1700,8 +1710,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;
> @@ -1710,28 +1720,39 @@ lgetc(int quotec)
>               file->lineno++;
>       }
>  
> -     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
> @@ -1739,9 +1760,6 @@ findeol(void)
>  {
>       int     c;
>  
> -     parsebuf = NULL;
> -     pushback_index = 0;
> -
>       /* skip to either EOF or the first real EOL */
>       while (1) {
>               c = lgetc(0);
> @@ -1772,7 +1790,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);
> @@ -1794,8 +1812,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;
>       }
>  
> @@ -1957,7 +1980,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("warn: malloc");
> +             fclose(nfile->stream);
> +             free(nfile->name);
> +             free(nfile);
> +             return (NULL);
> +     }
>       TAILQ_INSERT_TAIL(&files, nfile, entry);
>       return (nfile);
>  }
> @@ -1973,6 +2005,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);
> 

-- 
Gilles Chehade

https://www.poolp.org                                          @poolpOrg

Reply via email to