diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2010-07-20 14:56:30 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2010-07-20 14:56:30 -0700 |
commit | 077fb93d2bfaf2d4acb356535026efe56c0e120e (patch) | |
tree | 61dc56c351f7bac2aea5dd016943b81f335d09d1 | |
parent | aed4eaa8f3d83880a98592937ca6eb8114550a33 (diff) | |
download | nasm-077fb93d2bfaf2d4acb356535026efe56c0e120e.tar.gz |
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>
-rw-r--r-- | doc/changes.src | 21 | ||||
-rw-r--r-- | doc/nasmdoc.src | 12 | ||||
-rw-r--r-- | preproc.c | 96 | ||||
-rw-r--r-- | test/ifenv.asm | 31 |
4 files changed, 125 insertions, 35 deletions
diff --git a/doc/changes.src b/doc/changes.src index 43a49978..e27faded 100644 --- a/doc/changes.src +++ b/doc/changes.src @@ -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 diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src index 05dc5b5f..eb1fe5e6 100644 --- a/doc/nasmdoc.src +++ b/doc/nasmdoc.src @@ -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} @@ -468,6 +468,23 @@ static Token *delete_Token(Token * t); #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 * place to do it for the moment, and it is a hack (ideally it would @@ -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; + } + } + + if (v) { + char *p = getenv(v); + if (!p) { + error(ERR_NONFATAL | ERR_PASS1, + "nonexistent environment variable `%s'", v); + p = ""; + } + t->text = nasm_strdup(p); } - t->text = nasm_strdup(p); - nasm_free(q); + 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 diff --git a/test/ifenv.asm b/test/ifenv.asm new file mode 100644 index 00000000..15f12f88 --- /dev/null +++ b/test/ifenv.asm @@ -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 + |