summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2010-07-20 14:56:30 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2010-07-20 14:56:30 -0700
commit077fb93d2bfaf2d4acb356535026efe56c0e120e (patch)
tree61dc56c351f7bac2aea5dd016943b81f335d09d1
parentaed4eaa8f3d83880a98592937ca6eb8114550a33 (diff)
downloadnasm-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.src21
-rw-r--r--doc/nasmdoc.src12
-rw-r--r--preproc.c96
-rw-r--r--test/ifenv.asm31
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}
diff --git a/preproc.c b/preproc.c
index ba1acd55..7fc3e74d 100644
--- a/preproc.c
+++ b/preproc.c
@@ -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
+