Add %defstr, %idefstr
authorH. Peter Anvin <hpa@zytor.com>
Thu, 5 Jun 2008 00:23:14 +0000 (17:23 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 5 Jun 2008 00:23:14 +0000 (17:23 -0700)
Add %defstr and %idefstr, to define a macro as a quoted string.

CHANGES
doc/nasmdoc.src
pptok.dat
preproc.c

diff --git a/CHANGES b/CHANGES
index cb6cfc6..2e71c4f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -20,6 +20,7 @@
 * %substr can now be used to get other than one-character substrings.
 * New type of character/string constants, using backquotes (`...`),
   which support C-style escape sequences.
+* %defstr and %idefstr to stringize macro definitions before creation.
 
 2.02
 ----
index 03ef92e..912479c 100644 (file)
@@ -1957,7 +1957,7 @@ You can \i{pre-define} single-line macros using the `-d' option on
 the NASM command line: see \k{opt-d}.
 
 
-\S{xdefine} Enhancing %define: \I\c{%ixdefine}\i\c{%xdefine}
+\S{xdefine} Enhancing \c{%define}: \I\c{%ixdefine}\i\c{%xdefine}
 
 To have a reference to an embedded single-line macro resolved at the
 time that it is embedded, as opposed to when the calling macro is
@@ -2074,7 +2074,7 @@ instruction has been used as a label in older code.  For example:
 
 \c %idefine pause $%?                  ; Hide the PAUSE instruction
 
-\S{undef} Undefining macros: \i\c{%undef}
+\S{undef} Undefining Macros: \i\c{%undef}
 
 Single-line macros can be removed with the \c{%undef} command.  For
 example, the following sequence:
@@ -2121,6 +2121,27 @@ a relocatable reference such as a code or data address, or anything
 involving a register).
 
 
+\S{defstr} Defining Strings: \I\c{%idefstr}\i\c{%defstr}
+
+\c{%defstr}, and its case-insensitive counterpart \c{%idefstr}, define
+or redefine a single-line macro without parameters, but converts the
+entire right-hand side, after macro expansion, to a quoted string
+before definition.
+
+For example:
+
+\c %defstr test TEST
+
+is equivalent to
+
+\c %define test 'TEST'
+
+This can be used, for example, with the \c{%!} construct (see
+\k{getenv}):
+
+\c %defstr PATH %!PATH         ; The operating system PATH variable
+
+
 \H{strlen} \i{String Handling in Macros}: \i\c{%strlen} and \i\c{%substr}
 
 It's often useful to be able to handle strings in macros. NASM
@@ -3637,18 +3658,9 @@ 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 %define FOO    %!FOO
-\c %define quote   '
-\c
-\c tmpstr  db      quote FOO quote
+\c %defstr FOO    %!FOO
 
-At the time of writing, this will generate an "unterminated string"
-warning at the time of defining "quote", and it will add a space
-before and after the string that is read in. I was unable to find
-a simple workaround (although a workaround can be created using a
-multi-line macro), so I believe that you will need to either learn how
-to create more complex macros, or allow for the extra spaces if you
-make use of this feature in that way.
+See \k{defstr} for notes on the \c{%defstr} directive.
 
 
 \C{directive} \i{Assembler Directives}
index a70a2a1..1396eef 100644 (file)
--- a/pptok.dat
+++ b/pptok.dat
@@ -17,6 +17,7 @@
 %assign
 %clear
 %define
+%defstr
 %depend
 %elif*
 %else
@@ -28,6 +29,7 @@
 %exitrep
 %iassign
 %idefine
+%idefstr
 %if*
 %imacro
 %include
index 475cb7e..5d0d87a 100644 (file)
--- a/preproc.c
+++ b/preproc.c
@@ -1028,7 +1028,7 @@ static Token *delete_Token(Token * t)
  * If expand_locals is not zero, identifiers of the form "%$*xxx"
  * will be transformed into ..@ctxnum.xxx
  */
-static char *detoken(Token * tlist, int expand_locals)
+static char *detoken(Token * tlist, bool expand_locals)
 {
     Token *t;
     int len;
@@ -2647,6 +2647,49 @@ static int do_directive(Token * tline)
        free_tlist(origline);
         return DIRECTIVE_FOUND;
 
+    case PP_DEFSTR:
+    case PP_IDEFSTR:
+       casesense = (i == PP_DEFSTR);
+
+        tline = tline->next;
+        skip_white_(tline);
+        tline = expand_id(tline);
+        if (!tline || (tline->type != TOK_ID &&
+                       (tline->type != TOK_PREPROC_ID ||
+                        tline->text[1] != '$'))) {
+            error(ERR_NONFATAL, "`%s' expects a macro identifier",
+                 pp_directives[i]);
+            free_tlist(origline);
+            return DIRECTIVE_FOUND;
+        }
+
+        ctx = get_ctx(tline->text, false);
+
+        mname = tline->text;
+        last = tline;
+        tline = expand_smacro(tline->next);
+       last->next = NULL;
+
+        while (tok_type_(tline, TOK_WHITESPACE))
+           tline = delete_Token(tline);
+
+       p = detoken(tline, false);
+        macro_start = nasm_malloc(sizeof(*macro_start));
+        macro_start->next = NULL;
+       macro_start->text = nasm_quote(p, strlen(p));
+       macro_start->type = TOK_STRING;
+        macro_start->mac = NULL;
+       nasm_free(p);
+
+        /*
+         * We now have a macro name, an implicit parameter count of
+         * zero, and a string token to use as an expansion. Create
+         * and store an SMacro.
+         */
+       define_smacro(ctx, mname, casesense, 0, macro_start);
+        free_tlist(origline);
+        return DIRECTIVE_FOUND;
+
     case PP_PATHSEARCH:
     {
        FILE *fp;