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 - 1.210
> +++ parse.y 2 Jun 2018 19:31:08 -
> @@ -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
> - re