index eb29c87982deb5b3c3364b6e1027498251f54d88..695720df29a9bf2603043d366f218a8916322f01 100644 (file)
+2007年11月29日 Eric Blake <ebb9@byu.net>
+
+ Stage 3b: cache length, rather than computing it, in modules.
+ * m4/hash.c (m4_hash_remove): Avoid double free on remove
+ failure.
+ * m4/output.c (m4_shipout_string): Change semantics of len param.
+ (m4_shipout_int): Use cached length.
+ * m4/input.c (m4_push_string_finish): Likewise.
+ * modules/m4.h (m4_make_temp_func): Add parameter.
+ * m4/macro.c (expand_token, m4_arg_len): Use cached length.
+ (collect_arguments, expand_macro): Alter signature.
+ (trace_format): Don't use out-of-scope buffer.
+ (process_macro): All callers changed.
+ * m4/utility.c (m4_dump_args): Likewise.
+ * m4/symtab.c (m4_symbol_value_print): Likewise.
+ * modules/gnu.c (__file__, __program__, builtin, indir)
+ (m4symbols, mkdtemp, regexp_compile, regexp_substitute,
+ renamesyms, patsubst, regexp, regexp_compile): Likewise.
+ * modules/load.c (m4modules): Likewise.
+ * modules/m4.c (defn, m4wrap, maketemp, m4_make_temp)
+ (numb_obstack, ifdef, ifelse, divert, len, substr): Likewise.
+ * modules/perl.c (perleval): Likewise.
+ * modules/stdlib.c (getcwd, getenv, getlogin, getpwnam, getpwuid)
+ (hostname, uname, setenv): Likewise.
+ * modules/mpeval.c (numb_obstack): Likewise.
+ * src/freeze.c (dump_symbol_CB): Likewise.
+ * doc/m4.texinfo (Renamesyms, Dumpdef, Changesyntax): Adjust test.
+ * tests/builtins.at (mkstemp): Likewise.
+ * tests/others.at (iso8859): XFAIL this test, now that
+ length-based handling allows NUL through part but not all of M4.
+
2007年11月28日 Eric Blake <ebb9@byu.net>
Stage 3a: cache length, rather than computing it, in libm4.
index 0dc3d4873e7ee0656c381f62e9ae4fc7d320a117..f298973b8276bbc000973623f59c54b1ee4b17e7 100644 (file)
@@ -2451,15 +2451,28 @@ The macro @code{renamesyms} is recognized only with parameters.
This macro was added in M4 2.0.
@end deffn
-Here is an example that performs the same renaming as the
+Here is an example that starts by performing a similar renaming to the
@option{--prefix-builtins} option (or @option{-P}). Where
@option{--prefix-builtins} only renames M4 builtin macros,
@code{renamesyms} will rename any macros that match when it runs,
-including text macros.
+including text macros. The rest of the example demonstrates the
+behavior of unanchored regular expressions in symbol renaming.
@example
+define(`foo', `bar')
+@result{}
renamesyms(`^.*$', `m4_\&')
@result{}
+foo
+@result{}foo
+m4_foo
+@result{}bar
+m4_defn(`m4_foo')
+@result{}bar
+m4_renamesyms(`f', `g')
+@result{}
+m4_igdeg(`m4_goo', `m4_goo')
+@result{}bar
@end example
If @var{resyntax} is given, @var{regexp} must be given according to
@result{}
m4_renamesyms(`^m4_m4(\w*)$', `m4_1円', `POSIX_EXTENDED')
@result{}
+m4_wrap(__line__
+)
+@result{}
+^D
+@result{}3
@end example
When a symbol has multiple definitions, thanks to @code{pushdef}, the
@samp{q} flag is implied when the @option{--debug} option (@option{-d},
@pxref{Debugging options, , Invoking m4}) is used in the command line
without arguments. Also, @option{--debuglen} (@pxref{Debuglen}) can affect
-output, by truncating longer strings.
+output, by truncating longer strings (but not builtin and module names).
@comment options: -ds -l3
@example
dumpdef(`foo', `dnl', `indir', `__gnu__')
@error{}__gnu__:@tabchar{}@{gnu@}
@error{}dnl:@tabchar{}<dnl>@{m4@}
-@error{}foo:@tabchar{}3, <div...>@{m4@}, 1 l...
-@error{}indir:@tabchar{}<ind...>@{gnu@}
+@error{}foo:@tabchar{}3, <divnum>@{m4@}, 1 l...
+@error{}indir:@tabchar{}<indir>@{gnu@}
@result{}
debugmode(`-m')
@result{}
@result{}foo
@@foo
@result{}bar
+@@bar
+@result{}@@bar
@@changesyntax(`@@\', `O@@')
@result{}
foo
index 4297fe4bff436b42134d32450a956fa7136d59bf..c47a7e489f9ceafb7bf80276ee82242c3218d4ef 100644 (file)
/* Remove from HASH, the first node with key KEY; comparing keys with
HASH's cmp_func. Any nodes with the same KEY previously hidden by
the removed node will become visible again. The key field of the
- removed node is returned, or the original KEY If there was no
- match. This is unsafe if multiple iterators are visiting HASH, or
- when a lone iterator is visiting on a different key. */
+ removed node is returned, or NULL if there was no match. This is
+ unsafe if multiple iterators are visiting HASH, or when a lone
+ iterator is visiting on a different key. */
void *
m4_hash_remove (m4_hash *hash, const void *key)
{
size_t n;
+ hash_node *node = NULL;
#ifndef NDEBUG
m4_hash_iterator *iter = HASH_ITER (hash);
#endif
n = BUCKET_COUNT (hash, key);
+ do
+ {
+ hash_node *next = node ? NODE_NEXT (node) : BUCKET_NTH (hash, n);
- {
- hash_node *node = NULL;
-
- do
- {
- hash_node *next = node ? NODE_NEXT (node) : BUCKET_NTH (hash, n);
-
- if (next && ((*HASH_CMP_FUNC (hash)) (NODE_KEY (next), key) == 0))
- {
- if (node)
- NODE_NEXT (node) = NODE_NEXT (next);
- else
- BUCKET_NTH (hash, n) = NODE_NEXT (next);
+ if (next && ((*HASH_CMP_FUNC (hash)) (NODE_KEY (next), key) == 0))
+ {
+ if (node)
+ NODE_NEXT (node) = NODE_NEXT (next);
+ else
+ BUCKET_NTH (hash, n) = NODE_NEXT (next);
- key = NODE_KEY (next);
+ key = NODE_KEY (next);
#ifndef NDEBUG
- if (iter)
- assert (ITERATOR_PLACE (iter) == next);
- NODE_KEY (next) = NULL;
+ if (iter)
+ assert (ITERATOR_PLACE (iter) == next);
+ NODE_KEY (next) = NULL;
#endif
- node_delete (hash, next);
- break;
- }
- node = next;
- }
- while (node);
- }
+ node_delete (hash, next);
+ return (void *) key; /* Cast away const. */
+ }
+ node = next;
+ }
+ while (node);
- return (void *) key;
+ return NULL;
}
/* Return the address of the value field of the first node in HASH
index 37cdcce6fd4f3fb5bfd8068d89d1a3152b4b06b4..08c5f646ff97bb89793cb7e8b35bed556163387b 100644 (file)
m4_push_string_finish (void)
{
m4_input_block *ret = NULL;
+ size_t len = obstack_object_size (current_input);
if (next == NULL)
- return isp;
+ {
+ assert (!len);
+ return isp;
+ }
- if (obstack_object_size (current_input) > 0)
+ if (len)
{
- next->u.u_s.len = obstack_object_size (current_input);
+ next->u.u_s.len = len;
obstack_1grow (current_input, '0円');
next->u.u_s.str = obstack_finish (current_input);
next->prev = isp;
index d9538532cdb3ec4e05cc55ab0164b22c4946016b..5769f9961082d08e82e68ba6d5a4c394d1eb9aa7 100644 (file)
#include "intprops.h"
-static m4_macro_args *collect_arguments (m4 *, const char *, m4_symbol *,
- m4_obstack *, unsigned int,
- m4_obstack *);
-static void expand_macro (m4 *, const char *, m4_symbol *);
+static m4_macro_args *collect_arguments (m4 *, const char *, size_t,
+ m4_symbol *, m4_obstack *,
+ unsigned int, m4_obstack *);
+static void expand_macro (m4 *, const char *, size_t, m4_symbol *);
static void expand_token (m4 *, m4_obstack *, m4__token_type,
m4_symbol_value *, int);
static bool expand_argument (m4 *, m4_obstack *, m4_symbol_value *,
case M4_TOKEN_SIMPLE:
case M4_TOKEN_STRING:
case M4_TOKEN_SPACE:
- m4_shipout_text (context, obs, text, strlen (text), line);
+ m4_shipout_text (context, obs, text, m4_get_symbol_value_len (token),
+ line);
break;
case M4_TOKEN_WORD:
{
const char *textp = text;
+ size_t len = m4_get_symbol_value_len (token);
+ size_t len2 = len;
if (m4_has_syntax (M4SYNTAX, to_uchar (*textp), M4_SYNTAX_ESCAPE))
- ++textp;
+ {
+ textp++;
+ len2--;
+ }
symbol = m4_symbol_lookup (M4SYMTAB, textp);
assert (!symbol || !m4_is_symbol_void (symbol));
|| (symbol->value->type == M4_SYMBOL_FUNC
&& BIT_TEST (SYMBOL_FLAGS (symbol), VALUE_BLIND_ARGS_BIT)
&& !m4__next_token_is_open (context)))
- {
- m4_shipout_text (context, obs, text, strlen (text), line);
- }
+ m4_shipout_text (context, obs, text, len, line);
else
- expand_macro (context, textp, symbol);
+ expand_macro (context, textp, len2, symbol);
}
break;
@@ -245,7 +249,7 @@ expand_argument (m4 *context, m4_obstack *obs, m4_symbol_value *argp,
until a call to collect_arguments parses more tokens. SYMBOL is
the result of the symbol table lookup on NAME. */
static void
-expand_macro (m4 *context, const char *name, m4_symbol *symbol)
+expand_macro (m4 *context, const char *name, size_t len, m4_symbol *symbol)
{
char *argc_base = NULL; /* Base of argc_stack on entry. */
unsigned int argc_size; /* Size of argc_stack on entry. */
@@ -298,8 +302,8 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
if (traced && m4_is_debug_bit (context, M4_DEBUG_TRACE_CALL))
trace_prepre (context, name, my_call_id, value);
- argv = collect_arguments (context, name, symbol, &argv_stack, argv_size,
- &argc_stack);
+ argv = collect_arguments (context, name, len, symbol, &argv_stack,
+ argv_size, &argc_stack);
/* Calling collect_arguments invalidated name, but we copied it as
argv[0]. */
name = argv->argv0;
@@ -336,14 +340,15 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
}
/* Collect all the arguments to a call of the macro SYMBOL (called
- NAME). The arguments are stored on the obstack ARGUMENTS and a
- table of pointers to the arguments on the obstack ARGPTR. ARGPTR
- is an incomplete object, currently occupying ARGV_BASE bytes.
- Return the object describing all of the macro arguments. */
+ NAME, with length LEN). The arguments are stored on the obstack
+ ARGUMENTS and a table of pointers to the arguments on the obstack
+ ARGPTR. ARGPTR is an incomplete object, currently occupying
+ ARGV_BASE bytes. Return the object describing all of the macro
+ arguments. */
static m4_macro_args *
-collect_arguments (m4 *context, const char *name, m4_symbol *symbol,
- m4_obstack *argptr, unsigned int argv_base,
- m4_obstack *arguments)
+collect_arguments (m4 *context, const char *name, size_t len,
+ m4_symbol *symbol, m4_obstack *argptr,
+ unsigned int argv_base, m4_obstack *arguments)
{
m4_symbol_value token;
m4_symbol_value *tokenp;
@@ -356,7 +361,8 @@ collect_arguments (m4 *context, const char *name, m4_symbol *symbol,
args.argc = 1;
args.inuse = false;
- args.argv0 = (char *) obstack_copy0 (arguments, name, strlen (name));
+ args.argv0 = (char *) obstack_copy0 (arguments, name, len);
+ args.argv0_len = len;
args.arraylen = 0;
obstack_grow (argptr, &args, offsetof (m4_macro_args, array));
name = args.argv0;
@@ -460,7 +466,8 @@ process_macro (m4 *context, m4_symbol_value *value, m4_obstack *obs,
text = endp;
}
if (i < argc)
- m4_shipout_string (context, obs, M4ARG (i), 0, false);
+ m4_shipout_string (context, obs, M4ARG (i), m4_arg_len (argv, i),
+ false);
break;
case '#': /* number of arguments */
@@ -505,14 +512,9 @@ process_macro (m4 *context, m4_symbol_value *value, m4_obstack *obs,
if (arg)
{
i = SYMBOL_ARG_INDEX (*arg);
-
- if (i < argc)
- m4_shipout_string (context, obs, M4ARG (i), 0, false);
- else
- {
- assert (!"INTERNAL ERROR: out of range reference");
- abort ();
- }
+ assert (i < argc);
+ m4_shipout_string (context, obs, M4ARG (i),
+ m4_arg_len (argv, i), false);
}
}
else
@@ -549,6 +551,8 @@ trace_format (m4 *context, const char *fmt, ...)
va_list args;
char ch;
const char *s;
+ char nbuf[INT_BUFSIZE_BOUND (sizeof (int) > sizeof (size_t)
+ ? sizeof (int) : sizeof (size_t))];
va_start (args, fmt);
@@ -569,7 +573,6 @@ trace_format (m4 *context, const char *fmt, ...)
case 'd':
{
int d = va_arg (args, int);
- char nbuf[INT_BUFSIZE_BOUND (int)];
sprintf (nbuf, "%d", d);
s = nbuf;
@@ -581,7 +584,6 @@ trace_format (m4 *context, const char *fmt, ...)
assert (ch == 'u');
{
size_t z = va_arg (args, size_t);
- char nbuf[INT_BUFSIZE_BOUND (size_t)];
sprintf (nbuf, "%zu", z);
s = nbuf;
obstack_free (&context->trace_messages, line);
}
-/* Do pre-argument-collction tracing for macro NAME. Used from
+/* Do pre-argument-collection tracing for macro NAME. Used from
expand_macro (). */
static void
trace_prepre (m4 *context, const char *name, size_t id, m4_symbol_value *value)
@@ -749,14 +751,13 @@ m4_arg_text (m4_macro_args *argv, unsigned int index)
size_t
m4_arg_len (m4_macro_args *argv, unsigned int index)
{
- /* TODO - update m4_macro_args to cache this. */
if (index == 0)
- return strlen (argv->argv0);
+ return argv->argv0_len;
if (argv->argc <= index)
return 0;
if (!m4_is_symbol_value_text (argv->array[index - 1]))
return SIZE_MAX;
- return strlen (m4_get_symbol_value_text (argv->array[index - 1]));
+ return m4_get_symbol_value_len (argv->array[index - 1]);
}
/* Given ARGV, return the builtin function referenced by argument
index 3eb77588307c82e54805d203b55f5349c3791220..ed2a451bb6a988ec05eecf2606e20ffc03000e60 100644 (file)
m4_shipout_int (m4_obstack *obs, int val)
{
char buf[INT_BUFSIZE_BOUND (int)];
-
- sprintf(buf, "%d", val);
- obstack_grow (obs, buf, strlen (buf));
+ int len = sprintf(buf, "%d", val);
+ obstack_grow (obs, buf, len);
}
+/* Output the text S, of length LEN, to OBS. If QUOTED, also output
+ current quote characters around S. If LEN is SIZE_MAX, use the
+ string length of S instead. */
void
m4_shipout_string (m4 *context, m4_obstack *obs, const char *s, size_t len,
bool quoted)
{
+ assert (obs);
if (s == NULL)
s = "";
- if (len == 0)
- len = strlen(s);
+ if (len == SIZE_MAX)
+ len = strlen(s);
if (quoted)
obstack_grow (obs, context->syntax->lquote.string,
index 7c253a0d9bcaafd6f3bfe6d97067e4daa8f47aba..2f83f7b5602f072c103dc5dff4d0562fa86ce556 100644 (file)
@@ -485,15 +485,23 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack *obs, bool quote,
{
const char *text;
size_t len;
+ bool truncated = false;
if (m4_is_symbol_value_text (value))
{
text = m4_get_symbol_value_text (value);
+ len = m4_get_symbol_value_len (value);
+ if (arg_length && arg_length < len)
+ {
+ len = arg_length;
+ truncated = true;
+ }
}
else if (m4_is_symbol_value_func (value))
{
const m4_builtin *bp = m4_get_symbol_value_builtin (value);
text = bp->name;
+ len = strlen (text);
lquote = "<";
rquote = ">";
quote = true;
@@ -502,6 +510,7 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack *obs, bool quote,
{
text = m4_get_symbol_value_placeholder (value);
/* FIXME - is it worth translating "placeholder for "? */
+ len = strlen (text);
lquote = "<placeholder for ";
rquote = ">";
quote = true;
@@ -512,11 +521,10 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack *obs, bool quote,
abort ();
}
- len = arg_length ? strnlen (text, arg_length) : strlen (text);
if (quote)
obstack_grow (obs, lquote, strlen (lquote));
obstack_grow (obs, text, len);
- if (len == arg_length && text[len] != '0円')
+ if (truncated)
obstack_grow (obs, "...", 3);
if (quote)
obstack_grow (obs, rquote, strlen (rquote));
m4_set_symbol_value_text (m4_symbol_value *value, const char *text, size_t len)
{
assert (value && text);
- /* TODO - this assertion requires NUL-terminated text. Do we want
- to optimize memory usage and use purely length-based
- manipulation, for one less byte per string? Perhaps only without
- NDEBUG? */
- assert (strlen (text) <= len);
+ /* TODO - this assertion enforces NUL-terminated text with no
+ intermediate NULs. Do we want to optimize memory usage and use
+ purely length-based manipulation, for one less byte per string?
+ Perhaps only without NDEBUG? Also, do we want to support
+ embedded NUL? */
+ assert (strlen (text) == len);
value->type = M4_SYMBOL_TEXT;
value->u.u_t.text = text;
index 53d2a18c1d284e75d4955a19da8fa7e861b9a790..72205a8d03af76ebea82d2d5a5a41e14b87668d3 100644 (file)
@@ -114,7 +114,8 @@ m4_dump_args (m4 *context, m4_obstack *obs, unsigned int start,
else
need_sep = true;
- m4_shipout_string (context, obs, M4ARG (i), 0, quoted);
+ m4_shipout_string (context, obs, M4ARG (i), m4_arg_len (argv, i),
+ quoted);
}
}
index 560e0d5eb611d55b92ec2375716ed9b8a2939be0..bc34692c246e3db813aa8de18ccd04a83bac64cd 100644 (file)
/* Storage for the cache of regular expressions. */
static m4_pattern_buffer regex_cache[REGEX_CACHE_SIZE];
-/* Compile a REGEXP using the RESYNTAX flavor, and return the buffer.
- On error, report the problem on behalf of CALLER, and return
- NULL. */
+/* Compile a REGEXP of length LEN using the RESYNTAX flavor, and
+ return the buffer. On error, report the problem on behalf of
+ CALLER, and return NULL. */
static m4_pattern_buffer *
regexp_compile (m4 *context, const char *caller, const char *regexp,
- int resyntax)
+ size_t len, int resyntax)
{
/* regex_cache is guaranteed to start life 0-initialized, which
works in the algorithm below.
@@ -150,7 +150,6 @@ regexp_compile (m4 *context, const char *caller, const char *regexp,
m4_pattern_buffer *victim; /* cache slot to replace */
unsigned victim_count; /* track which victim to replace */
struct re_pattern_buffer *pat;/* newly compiled regex */
- size_t len = strlen (regexp); /* regex length */
/* First, check if REGEXP is already cached with the given RESYNTAX.
If so, increase its use count and return it. */
@@ -214,7 +213,7 @@ regexp_compile (m4 *context, const char *caller, const char *regexp,
/* Wrap up GNU Regex re_search call to work with an m4_pattern_buffer.
If NO_SUB, then storing matches in buf->regs is not necessary. */
-static int
+static regoff_t
regexp_search (m4_pattern_buffer *buf, const char *string, const int size,
const int start, const int range, bool no_sub)
{
@@ -282,23 +281,22 @@ substitute (m4 *context, m4_obstack *obs, const char *caller,
by regexp_compile) in VICTIM, substitute REPLACE. Non-matching
characters are copied verbatim, and the result copied to the
obstack. Errors are reported on behalf of CALLER. Return true if
- a substitution was made. If IGNORE_DUPLICATES is set, don't worry
- about completing the obstack when returning false. */
+ a substitution was made. If OPTIMIZE is set, don't worry about
+ copying the input if no changes are made. */
static bool
regexp_substitute (m4 *context, m4_obstack *obs, const char *caller,
- const char *victim, const char *regexp,
+ const char *victim, size_t len, const char *regexp,
m4_pattern_buffer *buf, const char *replace,
- bool ignore_duplicates)
+ bool optimize)
{
- int matchpos = 0; /* start position of match */
- int offset = 0; /* current match offset */
- int length = strlen (victim);
- bool subst = false; /* if a substitution has been made */
+ regoff_t matchpos = 0; /* start position of match */
+ size_t offset = 0; /* current match offset */
+ bool subst = !optimize; /* if a substitution has been made */
- while (offset <= length)
+ while (offset <= len)
{
- matchpos = regexp_search (buf, victim, length, offset, length - offset,
+ matchpos = regexp_search (buf, victim, len, offset, len - offset,
false);
if (matchpos < 0)
@@ -311,8 +309,8 @@ regexp_substitute (m4 *context, m4_obstack *obs, const char *caller,
if (matchpos == -2)
m4_error (context, 0, 0, caller,
_("error matching regular expression `%s'"), regexp);
- else if (!ignore_duplicates && (offset < length))
- obstack_grow (obs, victim + offset, length - offset);
+ else if (offset < len && subst)
+ obstack_grow (obs, victim + offset, len - offset);
break;
}
@@ -333,14 +331,12 @@ regexp_substitute (m4 *context, m4_obstack *obs, const char *caller,
offset = buf->regs.end[0];
if (buf->regs.start[0] == buf->regs.end[0])
{
- obstack_1grow (obs, victim[offset]);
+ if (offset < len)
+ obstack_1grow (obs, victim[offset]);
offset++;
}
}
- if (!ignore_duplicates || subst)
- obstack_1grow (obs, '0円');
-
return subst;
}
**/
M4BUILTIN_HANDLER (__file__)
{
- m4_shipout_string (context, obs, m4_get_current_file (context), 0, true);
+ m4_shipout_string (context, obs, m4_get_current_file (context), SIZE_MAX,
+ true);
}
**/
M4BUILTIN_HANDLER (__program__)
{
- m4_shipout_string (context, obs, m4_get_program_name (), 0, true);
+ m4_shipout_string (context, obs, m4_get_program_name (), SIZE_MAX, true);
}
new_argv->argc = argc - 1;
new_argv->inuse = false;
new_argv->argv0 = name;
+ new_argv->argv0_len = m4_arg_len (argv, 1);
new_argv->arraylen = argc - 2;
memcpy (&new_argv->array[0], &argv->array[1],
(argc - 2) * sizeof (m4_symbol_value *));
new_argv->argc = argc - 1;
new_argv->inuse = false;
new_argv->argv0 = name;
+ new_argv->argv0_len = m4_arg_len (argv, 1);
new_argv->arraylen = argc - 2;
memcpy (&new_argv->array[0], &argv->array[1],
(argc - 2) * sizeof (m4_symbol_value *));
M4_MODULE_IMPORT (m4, m4_make_temp);
if (m4_make_temp)
- m4_make_temp (context, obs, M4ARG (0), M4ARG (1), true);
+ m4_make_temp (context, obs, M4ARG (0), M4ARG (1), m4_arg_len (argv, 1),
+ true);
else
assert (!"Unable to import from m4 module");
}
replacement, we need not waste time with it. */
if (!*pattern && !*replace)
{
- const char *str = M4ARG (1);
- obstack_grow (obs, str, strlen (str));
+ obstack_grow (obs, M4ARG (1), m4_arg_len (argv, 1));
return;
}
- buf = regexp_compile (context, me, pattern, resyntax);
+ buf = regexp_compile (context, me, pattern, m4_arg_len (argv, 2), resyntax);
if (!buf)
return;
- regexp_substitute (context, obs, me, M4ARG (1), pattern, buf,
- replace, false);
+ regexp_substitute (context, obs, me, M4ARG (1), m4_arg_len (argv, 1),
+ pattern, buf, replace, false);
}
const char *pattern; /* regular expression */
const char *replace; /* optional replacement string */
m4_pattern_buffer *buf; /* compiled regular expression */
- int startpos; /* start position of match */
- int length; /* length of first argument */
+ regoff_t startpos; /* start position of match */
+ size_t len; /* length of first argument */
int resyntax;
me = M4ARG (0);
return;
}
- buf = regexp_compile (context, me, pattern, resyntax);
+ buf = regexp_compile (context, me, pattern, m4_arg_len (argv, 2), resyntax);
if (!buf)
return;
- length = strlen (M4ARG (1));
- startpos = regexp_search (buf, M4ARG (1), length, 0, length,
- replace == NULL);
+ len = m4_arg_len (argv, 1);
+ startpos = regexp_search (buf, M4ARG (1), len, 0, len, replace == NULL);
if (startpos == -2)
{
return;
}
- buf = regexp_compile (context, me, regexp, resyntax);
+ buf = regexp_compile (context, me, regexp, m4_arg_len (argv, 1),
+ resyntax);
if (!buf)
return;
{
const char *name = data.base[0];
- if (regexp_substitute (context, &rename_obs, me, name, regexp,
- buf, replace, true))
+ if (regexp_substitute (context, &rename_obs, me, name, strlen (name),
+ regexp, buf, replace, true))
{
- const char *renamed = obstack_finish (&rename_obs);
-
- m4_symbol_rename (M4SYMTAB, name, renamed);
+ obstack_1grow (&rename_obs, '0円');
+ m4_symbol_rename (M4SYMTAB, name,
+ (char *) obstack_finish (&rename_obs));
}
}
for (; data.size > 0; --data.size, data.base++)
{
- m4_shipout_string (context, obs, data.base[0], 0, true);
+ m4_shipout_string (context, obs, data.base[0], SIZE_MAX, true);
if (data.size > 1)
obstack_1grow (obs, ',');
}
index 11f9ecf2f611d084bebc23c86f776707536aca97..4ee1cc6201a54be62b147d1b7eecfbfa21b1a67c 100644 (file)
if (module)
do
{
- m4_shipout_string (context, obs, m4_get_module_name (module), 0, true);
+ m4_shipout_string (context, obs, m4_get_module_name (module), SIZE_MAX,
+ true);
if ((module = m4__module_next (module)))
obstack_1grow (obs, ',');
index 87584a2eecf4da13c8ca09e748d42bc07d66aa1f..827fabbc70162d1667200c43bd6edc85b55eb487 100644 (file)
@@ -54,7 +54,7 @@ extern void m4_dump_symbols (m4 *context, m4_dump_symbol_data *data,
bool complain);
extern const char *m4_expand_ranges (const char *s, m4_obstack *obs);
extern void m4_make_temp (m4 *context, m4_obstack *obs, const char *macro,
- const char *name, bool dir);
+ const char *name, size_t len, bool dir);
/* stdlib--.h defines mkstemp to a safer replacement, but this
interferes with our preprocessor table of builtin definitions. */
M4BUILTIN_HANDLER (ifdef)
{
- m4_symbol *symbol;
- const char *result;
-
- symbol = m4_symbol_lookup (M4SYMTAB, M4ARG (1));
-
- if (symbol)
- result = M4ARG (2);
- else if (argc >= 4)
- result = M4ARG (3);
- else
- result = NULL;
-
- if (result)
- obstack_grow (obs, result, strlen (result));
+ unsigned int index = m4_symbol_lookup (M4SYMTAB, M4ARG (1)) ? 2 : 3;
+ obstack_grow (obs, M4ARG (index), m4_arg_len (argv, index));
}
M4BUILTIN_HANDLER (ifelse)
{
const char *me = M4ARG (0);
- const char *result;
unsigned int index;
/* The valid ranges of argc for ifelse is discontinuous, we cannot
index = 1;
argc--;
- result = NULL;
- while (result == NULL)
-
- if (strcmp (M4ARG (index), M4ARG (index + 1)) == 0)
- result = M4ARG (index + 2);
-
- else
+ while (1)
+ {
+ if (strcmp (M4ARG (index), M4ARG (index + 1)) == 0)
+ {
+ obstack_grow (obs, M4ARG (index + 2), m4_arg_len (argv, index + 2));
+ return;
+ }
switch (argc)
{
case 3:
case 4:
case 5:
- result = M4ARG (index + 3);
- break;
+ obstack_grow (obs, M4ARG (index + 3), m4_arg_len (argv, index + 3));
+ return;
default:
argc -= 3;
index += 3;
}
-
- obstack_grow (obs, result, strlen (result));
+ }
}
if (!symbol)
m4_warn (context, 0, me, _("undefined macro `%s'"), name);
else if (m4_is_symbol_text (symbol))
- m4_shipout_string (context, obs, m4_get_symbol_text (symbol), 0, true);
+ m4_shipout_string (context, obs, m4_get_symbol_text (symbol),
+ m4_get_symbol_len (symbol), true);
else if (m4_is_symbol_func (symbol))
m4_push_builtin (context, m4_get_symbol_value (symbol));
else if (m4_is_symbol_placeholder (symbol))
M4BUILTIN_HANDLER (divert)
{
int i = 0;
- const char *text;
if (argc >= 2 && !m4_numeric_arg (context, M4ARG (0), M4ARG (1), &i))
return;
-
m4_make_diversion (context, i);
-
- text = M4ARG (2);
- m4_shipout_text (context, NULL, text, strlen (text),
+ m4_shipout_text (context, NULL, M4ARG (2), m4_arg_len (argv, 2),
m4_get_current_line (context));
}
export this function as a helper to that? */
void
m4_make_temp (m4 *context, m4_obstack *obs, const char *macro,
- const char *name, bool dir)
+ const char *name, size_t len, bool dir)
{
int fd;
- int len;
int i;
if (m4_get_safer_opt (context))
@@ -732,14 +714,11 @@ m4_make_temp (m4 *context, m4_obstack *obs, const char *macro,
/* Guarantee that there are six trailing 'X' characters, even if the
user forgot to supply them. */
assert (obstack_object_size (obs) == 0);
- len = strlen (name);
obstack_grow (obs, name, len);
for (i = 0; len > 0 && i < 6; i++)
if (name[--len] != 'X')
break;
- for (; i < 6; i++)
- obstack_1grow (obs, 'X');
- obstack_1grow (obs, '0円');
+ obstack_grow0 (obs, "XXXXXX", 6 - i);
/* Make the temporary object. */
errno = 0;
@@ -755,8 +734,16 @@ m4_make_temp (m4 *context, m4_obstack *obs, const char *macro,
name);
obstack_free (obs, obstack_finish (obs));
}
- else if (! dir)
- close (fd);
+ else
+ {
+ if (! dir)
+ close (fd);
+ /* Undo the trailing NUL. */
+ /* FIXME - shouldn't this return a quoted string, on the rather
+ small chance that the user has a macro matching the random
+ file name chosen? */
+ obstack_blank (obs, -1);
+ }
}
/* Use the first argument as at template for a temporary file name. */
maketemp(XXXXXXXX) -> `X00nnnnn', where nnnnn is 16-bit pid
*/
const char *str = M4ARG (1);
- int len = strlen (str);
+ size_t len = m4_arg_len (argv, 1);
int i;
int len2;
str = ntoa ((number) getpid (), 10);
len2 = strlen (str);
if (len2 > len - i)
- obstack_grow0 (obs, str + len2 - (len - i), len - i);
+ obstack_grow (obs, str + len2 - (len - i), len - i);
else
{
while (i++ < len - len2)
obstack_1grow (obs, '0');
- obstack_grow0 (obs, str, len2);
+ obstack_grow (obs, str, len2);
}
}
else
- m4_make_temp (context, obs, M4ARG (0), M4ARG (1), false);
+ m4_make_temp (context, obs, M4ARG (0), M4ARG (1), m4_arg_len (argv, 1),
+ false);
}
/* Use the first argument as a template for a temporary file name. */
M4BUILTIN_HANDLER (mkstemp)
{
- m4_make_temp (context, obs, M4ARG (0), M4ARG (1), false);
+ m4_make_temp (context, obs, M4ARG (0), M4ARG (1), m4_arg_len (argv, 1),
+ false);
}
/* Print all arguments on standard error. */
{
assert (obstack_object_size (obs) == 0);
if (m4_get_posixly_correct_opt (context))
- m4_shipout_string (context, obs, M4ARG (1), 0, false);
+ m4_shipout_string (context, obs, M4ARG (1), m4_arg_len (argv, 1), false);
else
m4_dump_args (context, obs, 1, argv, " ", false);
obstack_1grow (obs, '0円');
/* Expand to the length of the first argument. */
M4BUILTIN_HANDLER (len)
{
- m4_shipout_int (obs, strlen (M4ARG (1)));
+ m4_shipout_int (obs, m4_arg_len (argv, 1));
}
/* The macro expands to the first index of the second argument in the first
if (argc <= 2)
{
- obstack_grow (obs, str, strlen (str));
+ obstack_grow (obs, str, m4_arg_len (argv, 1));
return;
}
- length = avail = strlen (str);
+ length = avail = m4_arg_len (argv, 1);
if (!m4_numeric_arg (context, me, M4ARG (2), &start))
return;
numb_obstack(m4_obstack *obs, number value, int radix, int min)
{
const char *s;
+ size_t len;
+
if (radix == 1)
{
/* FIXME - this code currently depends on undefined behavior. */
@@ -1186,7 +1177,6 @@ numb_obstack(m4_obstack *obs, number value, int radix, int min)
obstack_1grow (obs, '0');
while (value-- != 0)
obstack_1grow (obs, '1');
- obstack_1grow (obs, '0円');
return;
}
@@ -1197,10 +1187,11 @@ numb_obstack(m4_obstack *obs, number value, int radix, int min)
obstack_1grow (obs, '-');
s++;
}
- for (min -= strlen (s); --min >= 0;)
+ len = strlen (s);
+ for (min -= len; --min >= 0;)
obstack_1grow (obs, '0');
- obstack_grow (obs, s, strlen (s));
+ obstack_grow (obs, s, len);
}
index 4783d0a429db829615a5a2c3b17ecedf28e9cf73..81dfef460117eaf15df212d2f73dba80a0b520a6 100644 (file)
@@ -43,7 +43,8 @@ typedef void m4_dump_symbols_func (m4 *context, m4_dump_symbol_data *data,
bool complain);
typedef const char *m4_expand_ranges_func (const char *s, m4_obstack *obs);
typedef void m4_make_temp_func (m4 *context, m4_obstack *obs,
- const char *macro, const char *name, bool dir);
+ const char *macro, const char *name,
+ size_t len, bool dir);
END_C_DECLS
index a7027523b0b221113c25bb3e3f38b24be6a9e2a1..e70eb091b22f07680a58db91e88ea0c77d362c7a 100644 (file)
@@ -174,6 +174,7 @@ numb_obstack (m4_obstack *obs, const number value, const int radix,
int min)
{
const char *s;
+ size_t len;
mpz_t i;
mpz_init (i);
@@ -186,10 +187,11 @@ numb_obstack (m4_obstack *obs, const number value, const int radix,
obstack_1grow (obs, '-');
s++;
}
- for (min -= strlen (s); --min >= 0;)
+ len = strlen (s);
+ for (min -= len; --min >= 0;)
obstack_1grow (obs, '0');
- obstack_grow (obs, s, strlen (s));
+ obstack_grow (obs, s, len);
mpq_get_den (i, value);
if (mpz_cmp_si (i, (long) 1) != 0)
index 58161b17eee0f17e41ff1c913b6f5f3a6a638dc2..f129af092ad5d9ce65c3e003183704e792662c2d 100644 (file)
val = perl_eval_pv (M4ARG (i), true);
- m4_shipout_string (context, obs, SvPV (val, PL_na), 0, false);
+ m4_shipout_string (context, obs, SvPV (val, PL_na), SIZE_MAX, false);
}
}
index 62fdae7cbbec13978fb26ad7aa179ec1c81f100b..0063ed8c04c8d5f22a8b6833bacbe9425e0c4345 100644 (file)
**/
M4BUILTIN_HANDLER (getcwd)
{
+ /* FIXME - Use gnulib module for arbitrary-length cwd. */
char buf[1024];
char *bp;
bp = getcwd (buf, sizeof buf);
if (bp != NULL) /* in case of error return null string */
- m4_shipout_string (context, obs, buf, 0, false);
+ m4_shipout_string (context, obs, buf, SIZE_MAX, false);
}
/**
env = getenv (M4ARG (1));
if (env != NULL)
- m4_shipout_string (context, obs, env, 0, false);
+ m4_shipout_string (context, obs, env, SIZE_MAX, false);
}
/**
return;
assert (obstack_object_size (obs) == 0);
- obstack_grow (obs, M4ARG (1), strlen (M4ARG (1)));
+ obstack_grow (obs, M4ARG (1), m4_arg_len (argv, 1));
obstack_1grow (obs, '=');
- obstack_grow (obs, M4ARG (2), strlen (M4ARG (2)));
- obstack_1grow (obs, '0円');
+ obstack_grow0 (obs, M4ARG (2), m4_arg_len (argv, 2));
{
char *env = obstack_finish (obs);
login = getlogin ();
if (login != NULL)
- m4_shipout_string (context, obs, login, 0, false);
+ m4_shipout_string (context, obs, login, SIZE_MAX, false);
}
/**
if (pw != NULL)
{
- m4_shipout_string (context, obs, pw->pw_name, 0, true);
+ m4_shipout_string (context, obs, pw->pw_name, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_passwd, 0, true);
+ m4_shipout_string (context, obs, pw->pw_passwd, SIZE_MAX, true);
obstack_1grow (obs, ',');
m4_shipout_int (obs, pw->pw_uid);
obstack_1grow (obs, ',');
m4_shipout_int (obs, pw->pw_gid);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_gecos, 0, true);
+ m4_shipout_string (context, obs, pw->pw_gecos, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_dir, 0, true);
+ m4_shipout_string (context, obs, pw->pw_dir, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_shell, 0, true);
+ m4_shipout_string (context, obs, pw->pw_shell, SIZE_MAX, true);
}
}
if (pw != NULL)
{
- m4_shipout_string (context, obs, pw->pw_name, 0, true);
+ m4_shipout_string (context, obs, pw->pw_name, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_passwd, 0, true);
+ m4_shipout_string (context, obs, pw->pw_passwd, SIZE_MAX, true);
obstack_1grow (obs, ',');
m4_shipout_int (obs, pw->pw_uid);
obstack_1grow (obs, ',');
m4_shipout_int (obs, pw->pw_gid);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_gecos, 0, true);
+ m4_shipout_string (context, obs, pw->pw_gecos, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_dir, 0, true);
+ m4_shipout_string (context, obs, pw->pw_dir, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, pw->pw_shell, 0, true);
+ m4_shipout_string (context, obs, pw->pw_shell, SIZE_MAX, true);
}
}
if (gethostname (buf, sizeof buf) < 0)
return;
- m4_shipout_string (context, obs, buf, 0, false);
+ m4_shipout_string (context, obs, buf, SIZE_MAX, false);
}
/**
if (uname (&ut) == 0)
{
- m4_shipout_string (context, obs, ut.sysname, 0, true);
+ m4_shipout_string (context, obs, ut.sysname, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, ut.nodename, 0, true);
+ m4_shipout_string (context, obs, ut.nodename, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, ut.release, 0, true);
+ m4_shipout_string (context, obs, ut.release, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, ut.version, 0, true);
+ m4_shipout_string (context, obs, ut.version, SIZE_MAX, true);
obstack_1grow (obs, ',');
- m4_shipout_string (context, obs, ut.machine, 0, true);
+ m4_shipout_string (context, obs, ut.machine, SIZE_MAX, true);
}
}
index c17f4f33357a5f6cfa33628b9fa03ae533594417..8430dda50322824d72c23f6cebf155392d329cbc 100644 (file)
@@ -168,7 +168,7 @@ dump_symbol_CB (m4_symbol_table *symtab, const char *symbol_name,
if (m4_is_symbol_text (symbol))
{
const char *text = m4_get_symbol_text (symbol);
- size_t text_len = strlen (text);
+ size_t text_len = m4_get_symbol_len (symbol);
xfprintf (file, "T%zu,%zu", symbol_len, text_len);
if (module)
xfprintf (file, ",%zu", module_len);
index a23aaa94cf5be6c380a144c39a149d639429b16e..eeaf0d3c8a71afb016b0aa06436e012af98eaff3 100644 (file)
AT_SETUP([mkstemp])
+AT_KEYWORDS([maketemp])
+
dnl Check that on error, the expansion is void
AT_DATA([[in]],
[[mkstemp(`no_such_dir/m4-fooXXXXXX')
]], [[m4:in:1: mkstemp: cannot create file from template `no_such_dir/m4-fooXXXXXX': No such file or directory
]])
+dnl Check that extra X are appended, but not trailing NUL
+AT_DATA([[in]], [[len(mkstemp(`m4-fooXXXXX'))
+]])
+AT_CHECK_M4([in], [0], [[12
+]])
+
dnl Check that umask has an effect
AT_DATA([[in]],
[[substr(esyscmd(`ls -ld 'mkstemp(`m4-fooXXXXXX')), `0', `10')
@@ -546,7 +554,7 @@ AT_CHECK([umask 700; m4 < in], [0], [[----------
dnl Check for Solaris compatibility of maketemp. Hopefully the pid is
dnl less than 20 decimal digits. Also check that --safer does not affect
dnl traditional behavior of maketemp, which is textual only.
-AT_DATA([[stdin]],
+AT_DATA([[in]],
[[maketemp()
maketemp(X)
maketemp(XX)
]])
dnl Abuse our knowledge of AT_CHECK_M4 so that we can get stderr filtering...
AT_CHECK_M4([-G -Q --safer], [0], [stdout], [],
-[stdin& echo $! > pid; wait $!])
+[in& echo $! > pid; wait $!])
pid=`cat pid`
cat >expout <<EOF
index b50e3389f6e8250ed5362ec64e0a2ac48b5b6007..dd1e381fc82beb5695fed52fccf76cc9d6662935 100644 (file)
# is no use in trying to handle it here... Well, until autom4te provides
# us with means to.
+# However, since progress is being made to let M4 handle NUL, this test
+# is xfailed for now.
+AT_XFAIL_IF([:])
+
AT_DATA([[expout]],
[[# Testing quotes
DEFINE # eol