aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-02-01 21:51:25 +0200
committerSergey Poznyakoff <gray@gnu.org>2021-02-01 21:51:25 +0200
commitedf38541a5d038bea74052cb169c9017ed7a2e8a (patch)
tree3738e25a4e8b8cf6cd892b5efb7fd139a93e759d
parent4c7dfbc3e0296f36c5692ae87c6699f36c641fc8 (diff)
downloadxenv-edf38541a5d038bea74052cb169c9017ed7a2e8a.tar.gz
xenv-edf38541a5d038bea74052cb169c9017ed7a2e8a.tar.bz2
Parse input #line directives.
-rw-r--r--xenv.l76
1 files changed, 70 insertions, 6 deletions
diff --git a/xenv.l b/xenv.l
index 3c0ad30..446b305 100644
--- a/xenv.l
+++ b/xenv.l
@@ -19,11 +19,13 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <sysexits.h>
#include <assert.h>
char const *progname; /* Program name */
-char const *filename; /* Name of the input file. */
+char *filename; /* Name of the input file. */
+size_t filename_size; /* Size of memory allocated for filename. */
unsigned lineno; /* Line number in the input file. */
int undef_error_option; /* Treat undefined variables as error. */
int synclines_option; /* Generate `#line NUM "FILE"' lines. */
@@ -52,6 +54,8 @@ static void expand_inline_flop(void);
static int cond_peek(void);
static void cond_push(int result);
static int cond_pop(void);
+
+static int parse_line_directive(char *text);
/*
* Given a '$$' preprocessor statement TEXT, find the variable identifier
@@ -101,6 +105,26 @@ xstrdup(char *str)
enomem();
return p;
}
+
+char *
+xrealloc(char *ptr, size_t size)
+{
+ char *p = realloc(ptr, size);
+ if (!p)
+ enomem();
+ return p;
+}
+
+static void
+set_filename(char const *name, size_t len)
+{
+ if (len + 1 > filename_size) {
+ filename_size = len + 1;
+ filename = xrealloc(filename, filename_size);
+ }
+ memcpy(filename, name, len);
+ filename[len] = 0;
+}
%}
IDENT [a-zA-Z_][a-zA-Z_0-9]*
WS [ \t][ \t]*
@@ -133,7 +157,13 @@ OWS [ \t]*
<SQ>"'" { BEGIN(save_state); ECHO; }
"'" { save_state = YYSTATE; BEGIN(SQ); ECHO; }
-
+
+<INITIAL>^"#line ".*\n {
+ if (parse_line_directive(yytext)) {
+ ECHO;
+ lineno++;
+ }
+ }
<INITIAL>"${*" { save_state = YYSTATE; BEGIN(COMMENT); }
<COMMENT>[^*\n]* /* eat anything that's not a '*' */
<COMMENT>"*"+[^*}\n]* /* eat up '*'s not followed by '}'s */
@@ -349,7 +379,7 @@ struct expand_inline {
char *varname; /* type == EXP_ASSIGN - assign the expansion
to that variable */
struct { /* type == EXP_ERROR - location of the error */
- char const *filename;
+ char *filename;
unsigned lineno;
} loc;
};
@@ -382,7 +412,7 @@ expand_inline_push(int type, char *varname, int varlen, int suppress)
memcpy(ep->varname, varname, varlen);
ep->varname[varlen] = 0;
} else if (type == EXP_ERROR) {
- ep->loc.filename = filename;
+ ep->loc.filename = xstrdup(filename);
ep->loc.lineno = lineno;
}
ep->fp = yyout;
@@ -467,6 +497,7 @@ expand_inline_pop(void)
fprintf(stderr, "%s:%u: ", ep->loc.filename,
ep->loc.lineno);
+ free(ep->loc.filename);
rewind(yyout);
while ((c = fgetc(yyout)) != EOF)
fputc(c, stderr);
@@ -481,7 +512,10 @@ expand_inline_pop(void)
emit_syncline = 1;
}
}
- }
+ } else
+ /* FIXME: Emit syncline only if there were newlines in the
+ suppressed text. */
+ emit_syncline = 1;
if (ep->type == EXP_ASSIGN)
free(ep->varname);
@@ -549,6 +583,36 @@ cond_pop(void)
return cond_stack[cond_tos--].result;
}
+static int
+parse_line_directive(char *text)
+{
+ unsigned long n;
+ char *fname, *p;
+
+ text += sizeof("#line ")-1;
+
+ n = strtoul(text, &p, 10);
+ if ((n == 0 && errno == ERANGE) || n > INT_MAX ||
+ !(*p == 0 || *p == ' ' || *p == '\t' || *p == '\n'))
+ return 1;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '\n' || *p == 0) {
+ lineno = (int) n;
+ return 0;
+ }
+ if (*p != '"')
+ return 1;
+ p++;
+ fname = p;
+ p = strchr(fname, '"');
+ if (!p)
+ return 1;
+ set_filename(fname, p - fname);
+ lineno = n;
+ return 0;
+}
+
/*
* Input file handling.
*/
@@ -568,7 +632,7 @@ open_input(char const *name)
exit(errno == ENOENT ? EX_NOINPUT : EX_OSERR);
}
yyin = fp;
- filename = name;
+ set_filename(name, strlen(name));
lineno = 1;
if (synclines_option)
fprintf(yyout, "#line %u \"%s\"\n", lineno, filename);

Return to:

Send suggestions and report system problems to the System administrator.