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
|
||||
|
||||
\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.
|
||||
|
||||
@ -19,7 +20,8 @@ since 2007.
|
||||
|
||||
\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}.
|
||||
|
||||
@ -29,14 +31,17 @@ since 2007.
|
||||
|
||||
\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{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.
|
||||
Each stands for \c{win32}, \c{elf32} and \c{macho32} accordingly.
|
||||
\b Short aliases \c{win}, \c{elf} and \c{macho} for output formats are
|
||||
introduced. Each stands for \c{win32}, \c{elf32} and \c{macho32}
|
||||
accordingly.
|
||||
|
||||
\b Faster handling of missing directives implemented.
|
||||
|
||||
@ -53,6 +58,10 @@ since 2007.
|
||||
\b Make \c{-Ox} the default optimization level. For the legacy
|
||||
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
|
||||
|
||||
|
@ -3158,6 +3158,10 @@ the \c{%!<env>} directive exists.
|
||||
The usual \i\c{%elifenv}, \i\c\{%ifnenv}, and \i\c{%elifnenv}
|
||||
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}
|
||||
|
||||
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
|
||||
could do that as follows:
|
||||
|
||||
\c %defstr FOO %!FOO
|
||||
\c %defstr FOO %!FOO
|
||||
|
||||
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}
|
||||
|
||||
|
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_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
|
||||
* 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; /* %?? */
|
||||
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) ||
|
||||
((*p == '!' || *p == '%' || *p == '$') &&
|
||||
isidchar(p[1]))) {
|
||||
@ -1180,16 +1215,33 @@ static char *detoken(Token * tlist, bool expand_locals)
|
||||
|
||||
list_for_each(t, tlist) {
|
||||
if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
|
||||
char *p = getenv(t->text + 2);
|
||||
char *q = t->text;
|
||||
if (!p) {
|
||||
error(ERR_NONFATAL | ERR_PASS1,
|
||||
"nonexistent environment variable `%s'", q + 2);
|
||||
p = "";
|
||||
char *v;
|
||||
char *q = t->text;
|
||||
|
||||
v = t->text + 2;
|
||||
if (*v == '\'' || *v == '\"' || *v == '`') {
|
||||
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 */
|
||||
if (expand_locals &&
|
||||
t->type == TOK_PREPROC_ID && t->text &&
|
||||
@ -1610,7 +1662,7 @@ static bool if_condition(Token * tline, enum preproc_token ct)
|
||||
struct tokenval tokval;
|
||||
expr *evalresult;
|
||||
enum pp_token_type needtype;
|
||||
const char *p;
|
||||
char *p;
|
||||
|
||||
origline = tline;
|
||||
|
||||
@ -1656,14 +1708,19 @@ static bool if_condition(Token * tline, enum preproc_token ct)
|
||||
while (tline) {
|
||||
skip_white_(tline);
|
||||
if (!tline || (tline->type != TOK_ID &&
|
||||
tline->type != TOK_STRING &&
|
||||
(tline->type != TOK_PREPROC_ID ||
|
||||
tline->text[1] != '!'))) {
|
||||
tline->text[1] != '!'))) {
|
||||
error(ERR_NONFATAL,
|
||||
"`%s' expects environment variable names",
|
||||
pp_directives[ct]);
|
||||
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))
|
||||
j = true;
|
||||
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];
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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