mirror of
https://github.com/netwide-assembler/nasm.git
synced 2024-11-21 03:14:19 +08:00
preproc: allow non-identifier character in environment variables
Allow non-identifier characters in the name of environment variables, by surrounding them with string quotes (subject to ordinary string-quoting rules.) Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
parent
aed4eaa8f3
commit
077fb93d2b
@ -9,7 +9,8 @@ since 2007.
|
|||||||
|
|
||||||
\S{cl-2.09} Version 2.09
|
\S{cl-2.09} Version 2.09
|
||||||
|
|
||||||
\b \c{%ifenv}, \c{%elifenv}, \c{%ifnenv}, and \c{%elifnenv} directives introduced.
|
\b \c{%ifenv}, \c{%elifenv}, \c{%ifnenv}, and \c{%elifnenv} directives
|
||||||
|
introduced. See \k{ifenv}.
|
||||||
|
|
||||||
\b Fixed NULL dereference if environment variable is missed.
|
\b Fixed NULL dereference if environment variable is missed.
|
||||||
|
|
||||||
@ -19,7 +20,8 @@ since 2007.
|
|||||||
|
|
||||||
\b Fix for encoding the LFS, LGS and LSS in 64-bit mode.
|
\b Fix for encoding the LFS, LGS and LSS in 64-bit mode.
|
||||||
|
|
||||||
\b Fixes for compatibility with OpenWatcom compiler and DOS 8.3 file format limitation.
|
\b Fixes for compatibility with OpenWatcom compiler and DOS 8.3 file
|
||||||
|
format limitation.
|
||||||
|
|
||||||
\b Macros parameters range expansion introduced. See \k{mlmacrange}.
|
\b Macros parameters range expansion introduced. See \k{mlmacrange}.
|
||||||
|
|
||||||
@ -29,14 +31,17 @@ since 2007.
|
|||||||
|
|
||||||
\b Short intersegment jumps are permitted now.
|
\b Short intersegment jumps are permitted now.
|
||||||
|
|
||||||
\b An alignment more then 64 bytes are allowed for \c{win32}, \c{win64} output formats.
|
\b An alignment more then 64 bytes are allowed for \c{win32},
|
||||||
|
\c{win64} output formats.
|
||||||
|
|
||||||
\b \c{SECTALIGN} directive introduced. In most cases invisible to user.
|
\b \c{SECTALIGN} directive introduced. In most cases invisible to user.
|
||||||
|
|
||||||
\b \c{nojmp} option introduced in \c{smartalign} package. See \k{pkg_smartalign}.
|
\b \c{nojmp} option introduced in \c{smartalign} package. See
|
||||||
|
\k{pkg_smartalign}.
|
||||||
|
|
||||||
\b Short aliases \c{win}, \c{elf} and \c{macho} for output formats are introduced.
|
\b Short aliases \c{win}, \c{elf} and \c{macho} for output formats are
|
||||||
Each stands for \c{win32}, \c{elf32} and \c{macho32} accordingly.
|
introduced. Each stands for \c{win32}, \c{elf32} and \c{macho32}
|
||||||
|
accordingly.
|
||||||
|
|
||||||
\b Faster handling of missing directives implemented.
|
\b Faster handling of missing directives implemented.
|
||||||
|
|
||||||
@ -53,6 +58,10 @@ since 2007.
|
|||||||
\b Make \c{-Ox} the default optimization level. For the legacy
|
\b Make \c{-Ox} the default optimization level. For the legacy
|
||||||
behavior, specify \c{-O0} explicitly. See \k{opt-O}.
|
behavior, specify \c{-O0} explicitly. See \k{opt-O}.
|
||||||
|
|
||||||
|
\b Environment variables read with \c{%!} or tested with \c{%ifenv}
|
||||||
|
can now contain non-identifier characters if surrounded by quotes.
|
||||||
|
See \k{getenv}.
|
||||||
|
|
||||||
|
|
||||||
\S{cl-2.08.02} Version 2.08.02
|
\S{cl-2.08.02} Version 2.08.02
|
||||||
|
|
||||||
|
@ -3158,6 +3158,10 @@ the \c{%!<env>} directive exists.
|
|||||||
The usual \i\c{%elifenv}, \i\c\{%ifnenv}, and \i\c{%elifnenv}
|
The usual \i\c{%elifenv}, \i\c\{%ifnenv}, and \i\c{%elifnenv}
|
||||||
variants are also provided.
|
variants are also provided.
|
||||||
|
|
||||||
|
Just as for \c{%!<env>} the argument should be written as a string if
|
||||||
|
it contains characters that would not be legal in an identifier. See
|
||||||
|
\k{getenv}.
|
||||||
|
|
||||||
\H{rep} \i{Preprocessor Loops}\I{repeating code}: \i\c{%rep}
|
\H{rep} \i{Preprocessor Loops}\I{repeating code}: \i\c{%rep}
|
||||||
|
|
||||||
NASM's \c{TIMES} prefix, though useful, cannot be used to invoke a
|
NASM's \c{TIMES} prefix, though useful, cannot be used to invoke a
|
||||||
@ -3714,10 +3718,16 @@ For example, suppose that you have an environment variable \c{FOO}, and
|
|||||||
you want the contents of \c{FOO} to be embedded in your program. You
|
you want the contents of \c{FOO} to be embedded in your program. You
|
||||||
could do that as follows:
|
could do that as follows:
|
||||||
|
|
||||||
\c %defstr FOO %!FOO
|
\c %defstr FOO %!FOO
|
||||||
|
|
||||||
See \k{defstr} for notes on the \c{%defstr} directive.
|
See \k{defstr} for notes on the \c{%defstr} directive.
|
||||||
|
|
||||||
|
If the name of the environment variable contains non-identifier
|
||||||
|
characters, you can use string quotes to surround the name of the
|
||||||
|
variable, for example:
|
||||||
|
|
||||||
|
\c %defstr C_colon %!'C:'
|
||||||
|
|
||||||
|
|
||||||
\H{stdmac} \i{Standard Macros}
|
\H{stdmac} \i{Standard Macros}
|
||||||
|
|
||||||
|
96
preproc.c
96
preproc.c
@ -467,6 +467,23 @@ static Token *delete_Token(Token * t);
|
|||||||
#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
|
#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
|
||||||
#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
|
#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nasm_unquote with error if the string contains NUL characters.
|
||||||
|
* If the string contains NUL characters, issue an error and return
|
||||||
|
* the C len, i.e. truncate at the NUL.
|
||||||
|
*/
|
||||||
|
static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive)
|
||||||
|
{
|
||||||
|
size_t len = nasm_unquote(qstr, NULL);
|
||||||
|
size_t clen = strlen(qstr);
|
||||||
|
|
||||||
|
if (len != clen)
|
||||||
|
error(ERR_NONFATAL, "NUL character in `%s' directive",
|
||||||
|
pp_directives[directive]);
|
||||||
|
|
||||||
|
return clen;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle TASM specific directives, which do not contain a % in
|
* Handle TASM specific directives, which do not contain a % in
|
||||||
* front of them. We do it here because I could not find any other
|
* front of them. We do it here because I could not find any other
|
||||||
@ -912,6 +929,24 @@ static Token *tokenize(char *line)
|
|||||||
type = TOK_PREPROC_QQ; /* %?? */
|
type = TOK_PREPROC_QQ; /* %?? */
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
} else if (*p == '!') {
|
||||||
|
type = TOK_PREPROC_ID;
|
||||||
|
p++;
|
||||||
|
if (isidchar(*p)) {
|
||||||
|
do {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
while (isidchar(*p));
|
||||||
|
} else if (*p == '\'' || *p == '\"' || *p == '`') {
|
||||||
|
p = nasm_skip_string(p);
|
||||||
|
if (*p)
|
||||||
|
p++;
|
||||||
|
else
|
||||||
|
error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
|
||||||
|
} else {
|
||||||
|
/* %! without string or identifier */
|
||||||
|
type = TOK_OTHER; /* Legacy behavior... */
|
||||||
|
}
|
||||||
} else if (isidchar(*p) ||
|
} else if (isidchar(*p) ||
|
||||||
((*p == '!' || *p == '%' || *p == '$') &&
|
((*p == '!' || *p == '%' || *p == '$') &&
|
||||||
isidchar(p[1]))) {
|
isidchar(p[1]))) {
|
||||||
@ -1180,16 +1215,33 @@ static char *detoken(Token * tlist, bool expand_locals)
|
|||||||
|
|
||||||
list_for_each(t, tlist) {
|
list_for_each(t, tlist) {
|
||||||
if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
|
if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
|
||||||
char *p = getenv(t->text + 2);
|
char *v;
|
||||||
char *q = t->text;
|
char *q = t->text;
|
||||||
if (!p) {
|
|
||||||
error(ERR_NONFATAL | ERR_PASS1,
|
v = t->text + 2;
|
||||||
"nonexistent environment variable `%s'", q + 2);
|
if (*v == '\'' || *v == '\"' || *v == '`') {
|
||||||
p = "";
|
size_t len = nasm_unquote(v, NULL);
|
||||||
|
size_t clen = strlen(v);
|
||||||
|
|
||||||
|
if (len != clen) {
|
||||||
|
error(ERR_NONFATAL | ERR_PASS1,
|
||||||
|
"NUL character in %! string");
|
||||||
|
v = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t->text = nasm_strdup(p);
|
|
||||||
nasm_free(q);
|
if (v) {
|
||||||
|
char *p = getenv(v);
|
||||||
|
if (!p) {
|
||||||
|
error(ERR_NONFATAL | ERR_PASS1,
|
||||||
|
"nonexistent environment variable `%s'", v);
|
||||||
|
p = "";
|
||||||
|
}
|
||||||
|
t->text = nasm_strdup(p);
|
||||||
|
}
|
||||||
|
nasm_free(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expand local macros here and not during preprocessing */
|
/* Expand local macros here and not during preprocessing */
|
||||||
if (expand_locals &&
|
if (expand_locals &&
|
||||||
t->type == TOK_PREPROC_ID && t->text &&
|
t->type == TOK_PREPROC_ID && t->text &&
|
||||||
@ -1610,7 +1662,7 @@ static bool if_condition(Token * tline, enum preproc_token ct)
|
|||||||
struct tokenval tokval;
|
struct tokenval tokval;
|
||||||
expr *evalresult;
|
expr *evalresult;
|
||||||
enum pp_token_type needtype;
|
enum pp_token_type needtype;
|
||||||
const char *p;
|
char *p;
|
||||||
|
|
||||||
origline = tline;
|
origline = tline;
|
||||||
|
|
||||||
@ -1656,14 +1708,19 @@ static bool if_condition(Token * tline, enum preproc_token ct)
|
|||||||
while (tline) {
|
while (tline) {
|
||||||
skip_white_(tline);
|
skip_white_(tline);
|
||||||
if (!tline || (tline->type != TOK_ID &&
|
if (!tline || (tline->type != TOK_ID &&
|
||||||
|
tline->type != TOK_STRING &&
|
||||||
(tline->type != TOK_PREPROC_ID ||
|
(tline->type != TOK_PREPROC_ID ||
|
||||||
tline->text[1] != '!'))) {
|
tline->text[1] != '!'))) {
|
||||||
error(ERR_NONFATAL,
|
error(ERR_NONFATAL,
|
||||||
"`%s' expects environment variable names",
|
"`%s' expects environment variable names",
|
||||||
pp_directives[ct]);
|
pp_directives[ct]);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
p = tline->type == TOK_ID ? tline->text : tline->text + 2;
|
p = tline->text;
|
||||||
|
if (tline->type == TOK_PREPROC_ID)
|
||||||
|
p += 2; /* Skip leading %! */
|
||||||
|
if (*p == '\'' || *p == '\"' || *p == '`')
|
||||||
|
nasm_unquote_cstr(p, ct);
|
||||||
if (getenv(p))
|
if (getenv(p))
|
||||||
j = true;
|
j = true;
|
||||||
tline = tline->next;
|
tline = tline->next;
|
||||||
@ -2055,23 +2112,6 @@ static int parse_size(const char *str) {
|
|||||||
return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1];
|
return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* nasm_unquote with error if the string contains NUL characters.
|
|
||||||
* If the string contains NUL characters, issue an error and return
|
|
||||||
* the C len, i.e. truncate at the NUL.
|
|
||||||
*/
|
|
||||||
static size_t nasm_unquote_cstr(char *qstr, enum preproc_token directive)
|
|
||||||
{
|
|
||||||
size_t len = nasm_unquote(qstr, NULL);
|
|
||||||
size_t clen = strlen(qstr);
|
|
||||||
|
|
||||||
if (len != clen)
|
|
||||||
error(ERR_NONFATAL, "NUL character in `%s' directive",
|
|
||||||
pp_directives[directive]);
|
|
||||||
|
|
||||||
return clen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find and process preprocessor directive in passed line
|
* find and process preprocessor directive in passed line
|
||||||
* Find out if a line contains a preprocessor directive, and deal
|
* Find out if a line contains a preprocessor directive, and deal
|
||||||
|
31
test/ifenv.asm
Normal file
31
test/ifenv.asm
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
%macro import 1
|
||||||
|
%defstr %%incfile %!PROJECTBASEDIR/%{1}.inc
|
||||||
|
%defstr %%decfile %!'PROJECTBASEDIR'/%{1}.dec
|
||||||
|
db %%incfile, `\n`
|
||||||
|
db %%decfile, `\n`
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
%ifenv PROJECTBASEDIR
|
||||||
|
import foo
|
||||||
|
%else
|
||||||
|
%warning No PROJECTBASEDIR defined
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifenv %!PROJECTBASEDIR
|
||||||
|
import foo
|
||||||
|
%else
|
||||||
|
%warning No PROJECTBASEDIR defined
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifenv 'PROJECTBASEDIR'
|
||||||
|
import foo
|
||||||
|
%else
|
||||||
|
%warning No PROJECTBASEDIR defined
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifenv %!'PROJECTBASEDIR'
|
||||||
|
import foo
|
||||||
|
%else
|
||||||
|
%warning No PROJECTBASEDIR defined
|
||||||
|
%endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user