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:
H. Peter Anvin 2010-07-20 14:56:30 -07:00
parent aed4eaa8f3
commit 077fb93d2b
4 changed files with 125 additions and 35 deletions

View File

@ -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

View File

@ -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}

View File

@ -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
View 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