diff options
author | Eric Blake <ebb9@byu.net> | 2007-12-19 17:16:28 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2008-06-17 06:30:53 -0600 |
commit | 40c640f486bf7a99c6e16d91332f25872f501488 (patch) | |
tree | a9379e4a249893c6ad8b9212c545320ee13c1987 | |
parent | 6167507cf07ddbc838e14e3d66803b360e63f6f2 (diff) | |
download | m4-40c640f486bf7a99c6e16d91332f25872f501488.tar.gz |
Stage25: allow NUL in quote, comment delimiters
-rw-r--r-- | doc/m4.texinfo | 7 | ||||
-rw-r--r-- | examples/null.err | bin | 505 -> 572 bytes | |||
-rw-r--r-- | examples/null.m4 | bin | 5891 -> 6189 bytes | |||
-rw-r--r-- | examples/null.out | bin | 404 -> 468 bytes | |||
-rw-r--r-- | m4/gnulib-cache.m4 | 4 | ||||
-rw-r--r-- | src/builtin.c | 64 | ||||
-rw-r--r-- | src/debug.c | 88 | ||||
-rw-r--r-- | src/format.c | 47 | ||||
-rw-r--r-- | src/freeze.c | 29 | ||||
-rw-r--r-- | src/input.c | 175 | ||||
-rw-r--r-- | src/m4.h | 59 | ||||
-rw-r--r-- | src/output.c | 23 | ||||
-rw-r--r-- | src/path.c | 6 |
13 files changed, 207 insertions, 295 deletions
diff --git a/doc/m4.texinfo b/doc/m4.texinfo index be8a0d9c..d6b7b59f 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -7006,12 +7006,13 @@ ifdef(`__unix__', , `errprint(` skipping: syscmd does not have unix semantics ')m4exit(`77')')dnl changequote(`[', `]')dnl -syscmd([printf 'define(-\0-,hi)dnl +syscmd([printf 'define(-\0-,hi)changequote([,\0])changecom(--\0)dnl divert(1)undivert(null.out)' | ]__program__[ -F in.m4f \ - && printf 'errprint(indir(-\0-))' | ]__program__[ -R in.m4f \ + && printf 'errprint([divnum\0] #-- indir(-\0-))' \ + | ]__program__[ -R in.m4f \ && rm in.m4f])errprint([ ]sysval[ ])dnl -@error{}hi 0 +@error{}divnum #-- hi 0 @end example @end ignore diff --git a/examples/null.err b/examples/null.err Binary files differindex 05a1ba3c..5f989ee6 100644 --- a/examples/null.err +++ b/examples/null.err diff --git a/examples/null.m4 b/examples/null.m4 Binary files differindex c9283605..de76742a 100644 --- a/examples/null.m4 +++ b/examples/null.m4 diff --git a/examples/null.out b/examples/null.out Binary files differindex 66f41b55..5e90221e 100644 --- a/examples/null.out +++ b/examples/null.out diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 index cb115a0d..dffdf8d1 100644 --- a/m4/gnulib-cache.m4 +++ b/m4/gnulib-cache.m4 @@ -15,11 +15,11 @@ # Specification in the form of a command-line invocation: -# gnulib-tool --import --dir=. --local-dir=local --lib=libm4 --source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests --no-libtool --macro-prefix=M4 announce-gen assert avltree-oset binary-io clean-temp cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer freadptr freadseek fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack quote regex stdbool stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror version-etc version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix +# gnulib-tool --import --dir=. --local-dir=local --lib=libm4 --source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests --no-libtool --macro-prefix=M4 announce-gen assert autobuild avltree-oset binary-io c-stack clean-temp cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer freadptr freadseek fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack obstack-printf-posix progname quote regex stdbool stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror version-etc version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([local]) -gl_MODULES([announce-gen assert avltree-oset binary-io clean-temp cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer freadptr freadseek fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack quote regex stdbool stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror version-etc version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix]) +gl_MODULES([announce-gen assert autobuild avltree-oset binary-io c-stack clean-temp cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer freadptr freadseek fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack obstack-printf-posix progname quote regex stdbool stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror version-etc version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix]) gl_AVOID([]) gl_SOURCE_BASE([lib]) gl_M4_BASE([m4]) diff --git a/src/builtin.c b/src/builtin.c index 0fd7331e..c171ea96 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -586,7 +586,7 @@ numeric_arg (const call_info *name, const char *arg, int *valuep) /* Digits for number to ascii conversions. */ static char const digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; -const char * +static const char * ntoa (int32_t value, int radix) { bool negative; @@ -628,10 +628,7 @@ ntoa (int32_t value, int radix) static void shipout_int (struct obstack *obs, int val) { - const char *s; - - s = ntoa ((int32_t) val, 10); - obstack_grow (obs, s, strlen (s)); + obstack_printf (obs, "%d", val); } @@ -907,11 +904,10 @@ m4_dumpdef (struct obstack *obs, int argc, macro_arguments *argv) { case TOKEN_TEXT: if (debug_level & DEBUG_TRACE_QUOTE) - DEBUG_PRINT3 ("%s%s%s\n", - curr_quote.str1, SYMBOL_TEXT (data.base[0]), - curr_quote.str2); - else - DEBUG_PRINT1 ("%s\n", SYMBOL_TEXT (data.base[0])); + fwrite (curr_quote.str1, 1, curr_quote.len1, debug); + fputs (SYMBOL_TEXT (data.base[0]), debug); + if (debug_level & DEBUG_TRACE_QUOTE) + fwrite (curr_quote.str2, 1, curr_quote.len2, debug); break; case TOKEN_FUNC: @@ -921,7 +917,7 @@ m4_dumpdef (struct obstack *obs, int argc, macro_arguments *argv) assert (!"m4_dumpdef"); abort (); } - DEBUG_PRINT1 ("<%s>\n", bp->name); + xfprintf (debug, "<%s>", bp->name); break; default: @@ -929,6 +925,7 @@ m4_dumpdef (struct obstack *obs, int argc, macro_arguments *argv) abort (); break; } + fputc ('\n', debug); } } @@ -1210,11 +1207,14 @@ m4_eval (struct obstack *obs, int argc, macro_arguments *argv) obstack_1grow (obs, '-'); value = -value; } - /* This assumes 2's-complement for correctly handling INT_MIN. */ - while (min-- - value > 0) - obstack_1grow (obs, '0'); - while (value-- != 0) - obstack_1grow (obs, '1'); + if ((uint32_t) value < min) + { + obstack_blank (obs, min - value); + memset ((char *) obstack_next_free (obs) - (min - value), '0', + min - value); + } + obstack_blank (obs, value); + memset ((char *) obstack_next_free (obs) - value, '1', value); return; } @@ -1226,10 +1226,9 @@ m4_eval (struct obstack *obs, int argc, macro_arguments *argv) s++; } len = strlen (s); - for (min -= len; --min >= 0;) - obstack_1grow (obs, '0'); - - obstack_grow (obs, s, len); + if (min < len) + min = len; + obstack_printf (obs, "%.*d%s", min - len, 0, s); } static void @@ -1377,8 +1376,8 @@ m4_changequote (struct obstack *obs, int argc, macro_arguments *argv) bad_argc (arg_info (argv), argc, 0, 2); /* Explicit NULL distinguishes between empty and missing argument. */ - set_quotes ((argc >= 2) ? ARG (1) : NULL, - (argc >= 3) ? ARG (2) : NULL); + set_quotes ((argc >= 2) ? ARG (1) : NULL, ARG_LEN (1), + (argc >= 3) ? ARG (2) : NULL, ARG_LEN (2)); } /*--------------------------------------------------------------------. @@ -1392,8 +1391,8 @@ m4_changecom (struct obstack *obs, int argc, macro_arguments *argv) bad_argc (arg_info (argv), argc, 0, 2); /* Explicit NULL distinguishes between empty and missing argument. */ - set_comment ((argc >= 2) ? ARG (1) : NULL, - (argc >= 3) ? ARG (2) : NULL); + set_comment ((argc >= 2) ? ARG (1) : NULL, ARG_LEN (1), + (argc >= 3) ? ARG (2) : NULL, ARG_LEN (2)); } #ifdef ENABLE_CHANGEWORD @@ -1534,23 +1533,20 @@ m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv) const char *str = ARG (1); size_t len = ARG_LEN (1); size_t i; - size_t len2; + struct obstack *scratch = arg_scratch (); + size_t pid_len = obstack_printf (scratch, "%lu", + (unsigned long) getpid ()); + char *pid = (char *) obstack_copy0 (scratch, "", 0); m4_warn (0, me, _("recommend using mkstemp instead")); for (i = len; i > 1; i--) if (str[i - 1] != 'X') break; obstack_grow (obs, str, i); - str = ntoa ((int32_t) getpid (), 10); - len2 = strlen (str); - if (len2 > len - i) - obstack_grow (obs, str + len2 - (len - i), len - i); + if (len - i < pid_len) + obstack_grow (obs, pid + pid_len - (len - i), len - i); else - { - while (i++ < len - len2) - obstack_1grow (obs, '0'); - obstack_grow (obs, str, len2); - } + obstack_printf (obs, "%.*d%s", len - i - pid_len, 0, pid); } else mkstemp_helper (obs, me, ARG (1), ARG_LEN (1)); diff --git a/src/debug.c b/src/debug.c index 2b2388f4..c3f85bd6 100644 --- a/src/debug.c +++ b/src/debug.c @@ -215,17 +215,25 @@ debug_set_output (const call_info *caller, const char *name) `-----------------------------------------------------------------------*/ void -debug_message_prefix (void) +debug_message (const char *format, ...) { - xfprintf (debug, "m4debug:"); - if (current_line) - { - if (debug_level & DEBUG_TRACE_FILE) - xfprintf (debug, "%s:", current_file); - if (debug_level & DEBUG_TRACE_LINE) - xfprintf (debug, "%d:", current_line); - } - putc (' ', debug); + va_list args; + if (debug) + { + xfprintf (debug, "m4debug:"); + if (current_line) + { + if (debug_level & DEBUG_TRACE_FILE) + xfprintf (debug, "%s:", current_file); + if (debug_level & DEBUG_TRACE_LINE) + xfprintf (debug, "%d:", current_line); + } + putc (' ', debug); + va_start (args, format); + xvfprintf (debug, format, args); + va_end (args); + putc ('\n', debug); + } } /* The rest of this file contains the functions for macro tracing output. @@ -234,55 +242,6 @@ debug_message_prefix (void) output from interfering with other debug messages generated by the various builtins. */ -/*-------------------------------------------------------------------. -| Tracing output to the obstack is formatted here, by a simplified | -| printf-like function trace_format (). Understands only %s (1 arg: | -| text), %d (1 arg: integer). | -`-------------------------------------------------------------------*/ - -static void -trace_format (const char *fmt, ...) -{ - va_list args; - char ch; - int d; - const char *s; - size_t maxlen; - - va_start (args, fmt); - - while (true) - { - while ((ch = *fmt++) != '\0' && ch != '%') - obstack_1grow (&trace, ch); - - if (ch == '\0') - break; - - maxlen = SIZE_MAX; - switch (*fmt++) - { - case 's': - s = va_arg (args, const char *); - break; - - case 'd': - d = va_arg (args, int); - s = ntoa (d, 10); - break; - - default: - s = ""; - break; - } - - if (shipout_string_trunc (&trace, s, SIZE_MAX, &maxlen)) - break; - } - - va_end (args); -} - /*------------------------------------------------------------------. | Format the standard header attached to all tracing output lines, | | using the context in INFO as appropriate. Return the offset into | @@ -294,14 +253,15 @@ trace_header (const call_info *info) { int trace_level = info->debug_level; unsigned int result = obstack_object_size (&trace); - trace_format ("m4trace:"); + + obstack_grow (&trace, "m4trace:", 8); if (trace_level & DEBUG_TRACE_FILE) - trace_format ("%s:", info->file); + obstack_printf (&trace, "%s:", info->file); if (trace_level & DEBUG_TRACE_LINE) - trace_format ("%d:", info->line); - trace_format (" -%d- ", expansion_level); + obstack_printf (&trace, "%d:", info->line); + obstack_printf (&trace, " -%d- ", expansion_level); if (trace_level & DEBUG_TRACE_CALLID) - trace_format ("id %d: ", info->call_id); + obstack_printf (&trace, "id %d: ", info->call_id); return result; } diff --git a/src/format.c b/src/format.c index c783d11e..33258534 100644 --- a/src/format.c +++ b/src/format.c @@ -156,9 +156,7 @@ expand_format (struct obstack *obs, int argc, macro_arguments *argv) char ok[128]; /* Buffer and stuff. */ - char *base; /* Current position in obs. */ - size_t len; /* Length of formatted text. */ - char *str; /* Malloc'd buffer of formatted text. */ + int result = 0; enum {CHAR, INT, LONG, DOUBLE, STR} datatype; f = fmt = ARG_STR (i, argc, argv); @@ -352,56 +350,39 @@ expand_format (struct obstack *obs, int argc, macro_arguments *argv) } *p++ = c; *p = '\0'; - base = obstack_next_free (obs); - len = obstack_room (obs); switch (datatype) { case CHAR: - str = asnprintf (base, &len, fstart, width, - ARG_INT (i, argc, argv)); + result = obstack_printf (obs, fstart, width, + ARG_INT (i, argc, argv)); break; case INT: - str = asnprintf (base, &len, fstart, width, prec, - ARG_INT (i, argc, argv)); + result = obstack_printf (obs, fstart, width, prec, + ARG_INT (i, argc, argv)); break; case LONG: - str = asnprintf (base, &len, fstart, width, prec, - ARG_LONG (i, argc, argv)); + result = obstack_printf (obs, fstart, width, prec, + ARG_LONG (i, argc, argv)); break; case DOUBLE: - str = asnprintf (base, &len, fstart, width, prec, - ARG_DOUBLE (i, argc, argv)); + result = obstack_printf (obs, fstart, width, prec, + ARG_DOUBLE (i, argc, argv)); break; case STR: - str = asnprintf (base, &len, fstart, width, prec, - ARG_STR (i, argc, argv)); + result = obstack_printf (obs, fstart, width, prec, + ARG_STR (i, argc, argv)); break; default: abort (); } - - if (str == NULL) - /* NULL is unexpected (EILSEQ and EINVAL are not possible - based on our construction of fstart, leaving only ENOMEM, - which should always be fatal). */ - m4_error (EXIT_FAILURE, errno, me, - _("unable to format output for `%s'"), f); - else if (str == base) - /* The output was already computed in place, but we need to - account for its size. */ - obstack_blank_fast (obs, len); - else - { - /* The output exceeded available obstack space, copy the - allocated string. */ - obstack_grow (obs, str, len); - free (str); - } + /* Since obstack_printf can only fail with EILSEQ or EINVAL, but + we constructed fstart, the result should not be negative. */ + assert (0 <= result); } } diff --git a/src/freeze.c b/src/freeze.c index 34ccca08..dd856337 100644 --- a/src/freeze.c +++ b/src/freeze.c @@ -71,16 +71,27 @@ produce_frozen_state (const char *name) /* Dump quote delimiters. */ - if (strcmp (curr_quote.str1, DEF_LQUOTE) - || strcmp (curr_quote.str2, DEF_RQUOTE)) - xfprintf (file, "Q%d,%d\n%s%s\n", (int) curr_quote.len1, - (int) curr_quote.len2, curr_quote.str1, curr_quote.str2); + if (curr_quote.len1 != 1 || curr_quote.len2 != 1 + || *curr_quote.str1 != *DEF_LQUOTE || *curr_quote.str2 != *DEF_RQUOTE) + { + xfprintf (file, "Q%d,%d\n", (int) curr_quote.len1, + (int) curr_quote.len2); + fwrite (curr_quote.str1, 1, curr_quote.len1, file); + fwrite (curr_quote.str2, 1, curr_quote.len2, file); + fputc ('\n', file); + } /* Dump comment delimiters. */ - if (strcmp (curr_comm.str1, DEF_BCOMM) || strcmp (curr_comm.str2, DEF_ECOMM)) - xfprintf (file, "C%d,%d\n%s%s\n", (int) curr_comm.len1, - (int) curr_comm.len2, curr_comm.str1, curr_comm.str2); + if (curr_comm.len1 != 1 || curr_comm.len2 != 1 + || *curr_comm.str1 != *DEF_BCOMM || *curr_comm.str2 != *DEF_ECOMM) + { + xfprintf (file, "C%d,%d\n", (int) curr_comm.len1, + (int) curr_comm.len2); + fwrite (curr_comm.str1, 1, curr_comm.len1, file); + fwrite (curr_comm.str2, 1, curr_comm.len2, file); + fputc ('\n', file); + } /* Dump all symbols. */ @@ -318,7 +329,7 @@ reload_frozen_state (const char *name) /* Change comment strings. */ - set_comment (string[0], string[1]); + set_comment (string[0], number[0], string[1], number[1]); break; case 'D': @@ -350,7 +361,7 @@ reload_frozen_state (const char *name) /* Change quote strings. */ - set_quotes (string[0], string[1]); + set_quotes (string[0], number[0], string[1], number[1]); break; default: diff --git a/src/input.c b/src/input.c index 49a4d244..75f86146 100644 --- a/src/input.c +++ b/src/input.c @@ -255,7 +255,7 @@ push_file (FILE *fp, const char *title, bool close_when_done) } if (debug_level & DEBUG_TRACE_INPUT) - DEBUG_MESSAGE1 ("input read from %s", title); + debug_message ("input read from %s", title); i = (input_block *) obstack_alloc (current_input, sizeof *i); i->type = INPUT_FILE; @@ -656,10 +656,10 @@ pop_input (bool cleanup) if (debug_level & DEBUG_TRACE_INPUT) { if (tmp != &input_eof) - DEBUG_MESSAGE2 ("input reverted to %s, line %d", - tmp->file, tmp->line); + debug_message ("input reverted to %s, line %d", + tmp->file, tmp->line); else - DEBUG_MESSAGE ("input exhausted"); + debug_message ("input exhausted"); } if (ferror (isp->u.u_f.fp)) @@ -1182,8 +1182,8 @@ init_argv_token (struct obstack *obs, token_data *td) last element of the $@ ref is reparsed, we must increase the argv refcount here, to compensate for the fact that it will be decreased once the final element is parsed. */ - assert (*curr_comm.str1 != ',' && *curr_comm.str1 != ')' - && *curr_comm.str1 != *curr_quote.str1); + assert (!curr_comm.len1 || (*curr_comm.str1 != ',' && *curr_comm.str1 != ')' + && *curr_comm.str1 != *curr_quote.str1)); ch = peek_input (true); if (ch != ',' && ch != ')') { @@ -1198,25 +1198,26 @@ init_argv_token (struct obstack *obs, token_data *td) /*------------------------------------------------------------------. | This function is for matching a string against a prefix of the | -| input stream. If the string S matches the input and CONSUME is | -| true, the input is discarded; otherwise any characters read are | -| pushed back again. The function is used only when multicharacter | -| quotes or comment delimiters are used. | +| input stream. If the string S of length SLEN matches the input | +| and CONSUME is true, the input is discarded; otherwise any | +| characters read are pushed back again. The function is used only | +| when multicharacter quotes or comment delimiters are used. | `------------------------------------------------------------------*/ static bool -match_input (const char *s, bool consume) +match_input (const char *s, size_t slen, bool consume) { int n; /* number of characters matched */ int ch; /* input character */ const char *t; bool result = false; + assert (slen); ch = peek_input (false); if (ch != to_uchar (*s)) return false; /* fail */ - if (s[1] == '\0') + if (slen == 1) { if (consume) next_char (false, false); @@ -1228,7 +1229,7 @@ match_input (const char *s, bool consume) { next_char (false, false); n++; - if (*s == '\0') /* long match */ + if (--slen == 1) /* long match */ { if (consume) return true; @@ -1244,20 +1245,21 @@ match_input (const char *s, bool consume) return result; } -/*--------------------------------------------------------------------. -| The macro MATCH() is used to match a string S against the input. | -| The first character is handled inline, for speed. Hopefully, this | -| will not hurt efficiency too much when single character quotes and | -| comment delimiters are used. If CONSUME, then CH is the result of | -| next_char, and a successful match will discard the matched string. | -| Otherwise, CH is the result of peek_input, and the input stream is | -| effectively unchanged. | -`--------------------------------------------------------------------*/ +/*---------------------------------------------------------------. +| The macro MATCH() is used to match a string S of length SLEN | +| against the input. The first character is handled inline, for | +| speed. Hopefully, this will not hurt efficiency too much when | +| single character quotes and comment delimiters are used. If | +| CONSUME, then CH is the result of next_char, and a successful | +| match will discard the matched string. Otherwise, CH is the | +| result of peek_input, and the input stream is effectively | +| unchanged. | +`---------------------------------------------------------------*/ -#define MATCH(ch, s, consume) \ - (to_uchar ((s)[0]) == (ch) \ - && (ch) != '\0' \ - && ((s)[1] == '\0' || (match_input ((s) + (consume), consume)))) +#define MATCH(ch, s, slen, consume) \ + ((slen) && to_uchar ((s)[0]) == (ch) \ + && ((slen) == 1 \ + || (match_input ((s) + (consume), (slen) - (consume), consume)))) /*----------------------------------------------------------. @@ -1289,14 +1291,14 @@ input_init (void) start_of_input_line = false; - curr_quote.str1 = xstrdup (DEF_LQUOTE); - curr_quote.len1 = strlen (curr_quote.str1); - curr_quote.str2 = xstrdup (DEF_RQUOTE); - curr_quote.len2 = strlen (curr_quote.str2); - curr_comm.str1 = xstrdup (DEF_BCOMM); - curr_comm.len1 = strlen (curr_comm.str1); - curr_comm.str2 = xstrdup (DEF_ECOMM); - curr_comm.len2 = strlen (curr_comm.str2); + curr_quote.str1 = xmemdup (DEF_LQUOTE, 1); + curr_quote.len1 = 1; + curr_quote.str2 = xmemdup (DEF_RQUOTE, 1); + curr_quote.len2 = 1; + curr_comm.str1 = xmemdup (DEF_BCOMM, 1); + curr_comm.len1 = 1; + curr_comm.str2 = xmemdup (DEF_ECOMM, 1); + curr_comm.len2 = 1; #ifdef ENABLE_CHANGEWORD set_word_regexp (NULL, user_word_regexp); @@ -1306,14 +1308,15 @@ input_init (void) } -/*--------------------------------------------------------------------. -| Set the quote delimiters to LQ and RQ. Used by m4_changequote (). | -| Pass NULL if the argument was not present, to distinguish from an | -| explicit empty string. | -`--------------------------------------------------------------------*/ +/*-----------------------------------------------------------------. +| Set the quote delimiters to LQ and RQ, with respective lengths | +| LQ_LEN and RQ_LEN. Used by m4_changequote (). Pass NULL if the | +| argument was not present, to distinguish from an explicit empty | +| string. | +`-----------------------------------------------------------------*/ void -set_quotes (const char *lq, const char *rq) +set_quotes (const char *lq, size_t lq_len, const char *rq, size_t rq_len) { /* POSIX states that with 0 arguments, the default quotes are used. POSIX XCU ERN 112 states that behavior is implementation-defined @@ -1325,31 +1328,39 @@ set_quotes (const char *lq, const char *rq) if (!lq) { lq = DEF_LQUOTE; + lq_len = 1; rq = DEF_RQUOTE; + rq_len = 1; + } + else if (!rq || (lq_len && !rq_len)) + { + rq = DEF_RQUOTE; + rq_len = 1; } - else if (!rq || (*lq && !*rq)) - rq = DEF_RQUOTE; - if (strcmp (curr_quote.str1, lq) == 0 && strcmp (curr_quote.str2, rq) == 0) + if (curr_quote.len1 == lq_len && curr_quote.len2 == rq_len + && memcmp (curr_quote.str1, lq, lq_len) == 0 + && memcmp (curr_quote.str2, rq, rq_len) == 0) return; free (curr_quote.str1); free (curr_quote.str2); - curr_quote.str1 = xstrdup (lq); - curr_quote.len1 = strlen (curr_quote.str1); - curr_quote.str2 = xstrdup (rq); - curr_quote.len2 = strlen (curr_quote.str2); + curr_quote.str1 = xmemdup (lq, lq_len); + curr_quote.len1 = lq_len; + curr_quote.str2 = xmemdup (rq, rq_len); + curr_quote.len2 = rq_len; set_quote_age (); } -/*--------------------------------------------------------------------. -| Set the comment delimiters to BC and EC. Used by m4_changecom (). | -| Pass NULL if the argument was not present, to distinguish from an | -| explicit empty string. | -`--------------------------------------------------------------------*/ +/*-----------------------------------------------------------------. +| Set the comment delimiters to BC and EC, with respective lengths | +| BC_LEN and EC_LEN. Used by m4_changecom (). Pass NULL if the | +| argument was not present, to distinguish from an explicit empty | +| string. | +`-----------------------------------------------------------------*/ void -set_comment (const char *bc, const char *ec) +set_comment (const char *bc, size_t bc_len, const char *ec, size_t ec_len) { /* POSIX requires no arguments to disable comments. It requires empty arguments to be used as-is, but this is counter to @@ -1359,19 +1370,27 @@ set_comment (const char *bc, const char *ec) This implementation assumes the aardvark will be approved. See the texinfo for what some other implementations do. */ if (!bc) - bc = ec = ""; - else if (!ec || (*bc && !*ec)) - ec = DEF_ECOMM; + { + bc = ec = ""; + bc_len = ec_len = 0; + } + else if (!ec || (bc_len && !ec_len)) + { + ec = DEF_ECOMM; + ec_len = 1; + } - if (strcmp (curr_comm.str1, bc) == 0 && strcmp (curr_comm.str2, ec) == 0) + if (curr_comm.len1 == bc_len && curr_comm.len2 == ec_len + && memcmp (curr_comm.str1, bc, bc_len) == 0 + && memcmp (curr_comm.str2, ec, ec_len) == 0) return; free (curr_comm.str1); free (curr_comm.str2); - curr_comm.str1 = xstrdup (bc); - curr_comm.len1 = strlen (curr_comm.str1); - curr_comm.str2 = xstrdup (ec); - curr_comm.len2 = strlen (curr_comm.str2); + curr_comm.str1 = xmemdup (bc, bc_len); + curr_comm.len1 = bc_len; + curr_comm.str2 = xmemdup (ec, ec_len); + curr_comm.len2 = ec_len; set_quote_age (); } @@ -1461,18 +1480,26 @@ set_quote_age (void) quote_age to zero, but at least a quote_age of zero always produces correct results (although it may take more time in doing so). */ - /* Hueristic of characters that might impact rescan if they appear in - a quote delimiter. */ + /* Hueristic of characters that might impact rescan if they appear + in a quote delimiter. Using a single NUL as one of the two quote + delimiters is safe, but strchr matches it, so we must special + case the strchr below. If we were willing to guarantee a + trailing NUL, we could use strpbrk(quote, unsafe) rather than + strchr(unsafe, *quote) and avoid the special case; on the other + hand, many strpbrk implementations are not as efficient as + strchr, and we save memory by avoiding the trailing NUL. */ #define Letters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" static const char unsafe[] = Letters "_0123456789(,) \t\n\r\f\v"; #undef Letters if (curr_quote.len1 == 1 && curr_quote.len2 == 1 - && strpbrk (curr_quote.str1, unsafe) == NULL - && strpbrk (curr_quote.str2, unsafe) == NULL + && (!*curr_quote.str1 || strchr (unsafe, *curr_quote.str1) == NULL) + && (!*curr_quote.str2 || strchr (unsafe, *curr_quote.str2) == NULL) && default_word_regexp && *curr_quote.str1 != *curr_quote.str2 - && *curr_comm.str1 != '(' && *curr_comm.str1 != ',' - && *curr_comm.str1 != ')' && *curr_comm.str1 != *curr_quote.str1) + && (!curr_comm.len1 + || (*curr_comm.str1 != '(' && *curr_comm.str1 != ',' + && *curr_comm.str1 != ')' + && *curr_comm.str1 != *curr_quote.str1))) current_quote_age = (((*curr_quote.str1 & 0xff) << 8) | (*curr_quote.str2 & 0xff)); else @@ -1627,7 +1654,7 @@ next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv, return TOKEN_ARGV; } - if (MATCH (ch, curr_comm.str1, true)) + if (MATCH (ch, curr_comm.str1, curr_comm.len1, true)) { if (obs) obs_td = obs; @@ -1652,7 +1679,7 @@ next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv, init_macro_token (obs, obs ? td : NULL); continue; } - if (MATCH (ch, curr_comm.str2, true)) + if (MATCH (ch, curr_comm.str2, curr_comm.len2, true)) { obstack_grow (obs_td, curr_comm.str2, curr_comm.len2); break; @@ -1711,7 +1738,7 @@ next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv, #endif /* ENABLE_CHANGEWORD */ - else if (!MATCH (ch, curr_quote.str1, true)) + else if (!MATCH (ch, curr_quote.str1, curr_quote.len1, true)) { assert (ch < CHAR_EOF); switch (ch) @@ -1756,13 +1783,13 @@ next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv, init_macro_token (obs, obs ? td : NULL); else if (ch == CHAR_QUOTE) append_quote_token (obs, td); - else if (MATCH (ch, curr_quote.str2, true)) + else if (MATCH (ch, curr_quote.str2, curr_quote.len2, true)) { if (--quote_level == 0) break; obstack_grow (obs_td, curr_quote.str2, curr_quote.len2); } - else if (MATCH (ch, curr_quote.str1, true)) + else if (MATCH (ch, curr_quote.str1, curr_quote.len1, true)) { quote_level++; obstack_grow (obs_td, curr_quote.str1, curr_quote.len1); @@ -1858,7 +1885,7 @@ peek_token (void) { result = TOKEN_MACDEF; } - else if (MATCH (ch, curr_comm.str1, false)) + else if (MATCH (ch, curr_comm.str1, curr_comm.len1, false)) { result = TOKEN_STRING; } @@ -1870,7 +1897,7 @@ peek_token (void) { result = TOKEN_WORD; } - else if (MATCH (ch, curr_quote.str1, false)) + else if (MATCH (ch, curr_quote.str1, curr_quote.len1, false)) { result = TOKEN_STRING; } @@ -198,63 +198,11 @@ extern FILE *debug; /* default flags -- equiv: aeq */ #define DEBUG_TRACE_DEFAULT 0x007 -#define DEBUG_PRINT1(Fmt, Arg1) \ - do \ - { \ - if (debug != NULL) \ - xfprintf (debug, Fmt, Arg1); \ - } \ - while (0) - -#define DEBUG_PRINT3(Fmt, Arg1, Arg2, Arg3) \ - do \ - { \ - if (debug != NULL) \ - xfprintf (debug, Fmt, Arg1, Arg2, Arg3); \ - } \ - while (0) - -#define DEBUG_MESSAGE(Fmt) \ - do \ - { \ - if (debug != NULL) \ - { \ - debug_message_prefix (); \ - xfprintf (debug, Fmt); \ - putc ('\n', debug); \ - } \ - } \ - while (0) - -#define DEBUG_MESSAGE1(Fmt, Arg1) \ - do \ - { \ - if (debug != NULL) \ - { \ - debug_message_prefix (); \ - xfprintf (debug, Fmt, Arg1); \ - putc ('\n', debug); \ - } \ - } \ - while (0) - -#define DEBUG_MESSAGE2(Fmt, Arg1, Arg2) \ - do \ - { \ - if (debug != NULL) \ - { \ - debug_message_prefix (); \ - xfprintf (debug, Fmt, Arg1, Arg2); \ - putc ('\n', debug); \ - } \ - } \ - while (0) - void debug_init (void); int debug_decode (const char *); void debug_flush_files (void); bool debug_set_output (const call_info *, const char *); -void debug_message_prefix (void); +void debug_message (const char *, ...) M4_GNUC_PRINTF (1, 2); void trace_prepre (const call_info *); unsigned int trace_pre (macro_arguments *); @@ -429,8 +377,8 @@ extern string_pair curr_quote; #define DEF_BCOMM "#" #define DEF_ECOMM "\n" -void set_quotes (const char *, const char *); -void set_comment (const char *, const char *); +void set_quotes (const char *, size_t, const char *, size_t); +void set_comment (const char *, size_t, const char *, size_t); #ifdef ENABLE_CHANGEWORD void set_word_regexp (const call_info *, const char *); #endif @@ -583,7 +531,6 @@ void undivert_all (void); void expand_user_macro (struct obstack *, symbol *, int, macro_arguments *); void m4_placeholder (struct obstack *, int, macro_arguments *); void init_pattern_buffer (struct re_pattern_buffer *, struct re_registers *); -const char *ntoa (int32_t, int); const builtin *find_builtin_by_addr (builtin_func *); const builtin *find_builtin_by_name (const char *); diff --git a/src/output.c b/src/output.c index ee1907b2..6d74ecd0 100644 --- a/src/output.c +++ b/src/output.c @@ -191,12 +191,7 @@ m4_tmpname (int divnum) static size_t offset; if (buffer == NULL) { - obstack_grow (&diversion_storage, output_temp_dir->dir_name, - strlen (output_temp_dir->dir_name)); - obstack_1grow (&diversion_storage, '/'); - obstack_1grow (&diversion_storage, 'm'); - obstack_1grow (&diversion_storage, '4'); - obstack_1grow (&diversion_storage, '-'); + obstack_printf (&diversion_storage, "%s/m4-", output_temp_dir->dir_name); offset = obstack_object_size (&diversion_storage); buffer = (char *) obstack_alloc (&diversion_storage, INT_BUFSIZE_BOUND (divnum)); @@ -473,7 +468,6 @@ void divert_text (struct obstack *obs, const char *text, int length, int line) { static bool start_of_output_line = true; - const char *cursor; /* If output goes to an obstack, merely add TEXT to it. */ @@ -533,20 +527,15 @@ divert_text (struct obstack *obs, const char *text, int length, int line) if (output_current_line != line) { - OUTPUT_CHARACTER ('#'); - OUTPUT_CHARACTER ('l'); - OUTPUT_CHARACTER ('i'); - OUTPUT_CHARACTER ('n'); - OUTPUT_CHARACTER ('e'); - OUTPUT_CHARACTER (' '); - for (cursor = ntoa (line, 10); *cursor; cursor++) - OUTPUT_CHARACTER (*cursor); + static char line_buf[sizeof "#line " + INT_BUFSIZE_BOUND (line)]; + sprintf (line_buf, "#line %d", line); + output_text (line_buf, strlen (line_buf)); + assert (strlen (line_buf) < sizeof line_buf); if (output_current_line < 1 && current_file[0] != '\0') { OUTPUT_CHARACTER (' '); OUTPUT_CHARACTER ('"'); - for (cursor = current_file; *cursor; cursor++) - OUTPUT_CHARACTER (*cursor); + output_text (current_file, strlen (current_file)); OUTPUT_CHARACTER ('"'); } OUTPUT_CHARACTER ('\n'); @@ -1,7 +1,7 @@ /* GNU m4 -- A simple macro processor - Copyright (C) 1989, 1990, 1991, 1992, 1993, 2004, 2006, 2007 Free - Software Foundation, Inc. + Copyright (C) 1989, 1990, 1991, 1992, 1993, 2004, 2006, 2007, 2008 + Free Software Foundation, Inc. This file is part of GNU M4. @@ -160,7 +160,7 @@ m4_path_search (const char *file, char **result) if (fp != NULL) { if (debug_level & DEBUG_TRACE_PATH) - DEBUG_MESSAGE2 ("path search for `%s' found `%s'", file, name); + debug_message ("path search for `%s' found `%s'", file, name); if (set_cloexec_flag (fileno (fp), true) != 0) m4_warn (errno, NULL, _("cannot protect input file across forks")); if (result) |