[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: dangling pointer bug and proposed patch
From: |
Eric Blake |
Subject: |
Re: dangling pointer bug and proposed patch |
Date: |
Tue, 05 Sep 2006 07:25:28 -0600 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060719 Thunderbird/1.5.0.5 Mnenhy/0.7.4.666 |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
According to Eric Blake on 6/3/2006 2:51 PM:
> Also, notice that m4 1.4.4 does the following inconsistent behavior:
> define(`f',`1')f(popdef(`f')pushdef(`f',`2'))
> 1
> define(`g',`1')g(define(`g',`2'))
> 2
>
> So, the following patch is my proposed solution to the original problem of
> core dumps when undefining a symbol while it is still in use by a pending
> expansion.
> It will take some work to forward port a similar patch to CVS head.
And it is now finally ported.
2006-09-05 Eric Blake <address@hidden>
* m4/macro.c (expansion_level, macro_call_id): Change to size_t.
All users updated.
(expand_token): Avoid assertion just added to docs.
(expand_macro): Track pending expansions, for when a symbol's
definition changes during argument collection.
(m4_macro_call, process_macro): Operate on symbol value, not
symbol, since symbol may have changed during argument collection.
* m4/m4private.h (m4_symbol_value): Add pending_expansions member.
(VALUE_PENDING, SYMBOL_PENDING, VALUE_DELETED_BIT): New defines.
(m4_get_symbol_value): Add fast macro version.
* m4/m4module.h (M4_BUILTIN_FLAGS_MASK): New enumerator.
(m4_macro_call): Adjust prototype.
* m4/module.c (install_builtin_table): Check that flags are valid
when creating builtin.
* m4/symtab.c (m4__symtab_remove_module_references): Use
m4_symbol_value_delete, rather than inlining it.
(m4_symbol_value_copy): Copy placeholder text.
(symbol_popval): Use m4_symbol_value_delete.
(m4_symbol_value_delete): Implementation was missing when NDEBUG.
Handle pending expansions.
* modules/gnu.c (indir): Update to new prototype.
* doc/m4.texinfo: Fix menus to be consistent with section names.
(Defn): Add test that macro tokens flatten to empty string;
triggered an assert before this patch.
(Ifelse): Merge another node.
(Loops): Split into...
(Forloop, Foreach): New nodes; work is still underway on them.
(Answers): Add more info on foreach macro; work is still underway.
(Indir): Add test that indir collects arguments before looking up
macro.
* TODO: Update based on this patch.
- --
Life is short - so eat dessert first!
Eric Blake address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFE/XrH84KuGfSFAYARAvmzAKCgJHpGIfYqI8asCRVpXltnrotlnwCZAdqq
BODsh3hGxUmq3okWPbnfsp4=
=BeOR
-----END PGP SIGNATURE-----
Index: TODO
===================================================================
RCS file: /sources/m4/m4/TODO,v
retrieving revision 1.19
diff -u -p -r1.19 TODO
--- TODO 22 Aug 2006 16:16:47 -0000 1.19
+++ TODO 5 Sep 2006 13:23:50 -0000
@@ -10,9 +10,6 @@ for any of these ideas or if you have ot
+ The test case `other-tests/stackovf.test' does not work.
- + Some characters, such as comma, are still hardcoded, and do not
- follow changes in the syntax table.
-
+ stack overflow is basically broken
The routines to detect stack overflow throuh segv are basically
@@ -28,17 +25,6 @@ for any of these ideas or if you have ot
Marc Espie
address@hidden
- + ~/src/ace % m4 --trace undefine -dV nostromo Err 1$
- m4 debug: NONE: 0: input read from stdin
- undefine(`undefine')
- m4trace:stdin:1: -1- id 1: undefine ...
- m4trace:stdin:1: -1- id 1: undefine(`undefine') -> ???
- m4trace:stdin:1: -1- id 1: address@hidden(...)
-
- --
- Akim Demaille
- address@hidden
-
* FEATURES OR PROBLEMS
@@ -74,9 +60,6 @@ for any of these ideas or if you have ot
--
Stepan Kasal <address@hidden>
- + The $ used in user defined macros cannot be changed through
- changesyntax. It should be handled as a modifier.
-
+ If configured --with-gmp for multiple precision arithmetic there are
some warnings, but it passes the tests.
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.39
diff -u -p -r1.39 m4.texinfo
--- doc/m4.texinfo 31 Aug 2006 03:21:35 -0000 1.39
+++ doc/m4.texinfo 5 Sep 2006 13:23:51 -0000
@@ -124,7 +124,7 @@ file in the distribution). @xref{Experi
* File Inclusion:: File inclusion
* Diversions:: Diverting and undiverting output
-* Modules:: Extending m4 with dynamic runtime modules
+* Modules:: Extending M4 with dynamic runtime modules
* Text handling:: Macros for text handling
* Arithmetic:: Macros for doing arithmetic
@@ -132,8 +132,7 @@ file in the distribution). @xref{Experi
* Miscellaneous:: Miscellaneous builtin macros
* Frozen files:: Fast loading of frozen state
-* Compatibility:: Compatibility with other versions of m4
-* Experiments:: Experimental features in GNU M4
+* Compatibility:: Compatibility with other versions of @code{m4}
* Answers:: Correct version of some examples
* Copying This Manual:: How to make copies of this manual
* Indices:: Indices of concepts and macros
@@ -152,11 +151,11 @@ Introduction and preliminaries
Lexical and syntactic conventions
* Names:: Macro names
-* Quoted strings:: Quoting input to m4
-* Comments:: Comments in m4 input
+* Quoted strings:: Quoting input to @code{m4}
+* Comments:: Comments in @code{m4} input
* Other tokens:: Other kinds of input tokens
-* Input processing:: How m4 copies input to output
-* Regular expression syntax:: How m4 interprets regular expressions
+* Input processing:: How @code{m4} copies input to output
+* Regular expression syntax:: How @code{m4} interprets regular expressions
How to invoke macros
@@ -170,7 +169,7 @@ How to define new macros
* Define:: Defining a new macro
* Arguments:: Arguments to macros
-* Pseudo Arguments:: Pseudo arguments to macros
+* Pseudo Arguments:: Special arguments to macros
* Undefine:: Deleting a macro
* Defn:: Renaming macros
* Pushdef:: Temporarily redefining macros
@@ -178,14 +177,15 @@ How to define new macros
* Indir:: Indirect call of macros
* Builtin:: Indirect call of builtins
-
* Symbols:: Getting the defined macro names
Conditionals, loops, and recursion
* Ifdef:: Testing if a macro is defined
* Ifelse:: If-else construct, or multibranch
-* Loops:: Loops and recursion in m4
+* Shift:: Recursion in @code{m4}
+* Forloop:: Iteration by counting
+* Foreach:: Iteration by list contents
How to debug macros and input
@@ -201,7 +201,7 @@ Input control
* Changecom:: Changing the comment delimiters
* Changeresyntax:: Changing the regular expression syntax
* Changesyntax:: Changing the lexical structure of the input
-* M4wrap:: Saving input until end of input
+* M4wrap:: Saving text until end of input
File inclusion
@@ -215,7 +215,7 @@ Diverting and undiverting output
* Divnum:: Diversion numbers
* Cleardiv:: Discarding diverted text
-Extending m4 with dynamic runtime modules
+Extending M4 with dynamic runtime modules
* Listing Modules:: Listing loaded modules
* Load:: Loading additional modules
@@ -238,19 +238,19 @@ Macros for doing arithmetic
* Eval:: Evaluating integer expressions
* Mpeval:: Multiple precision arithmetic
-Running shell commands
+Macros for running shell commands
* Platform macros:: Determining the platform
* Syscmd:: Executing simple commands
* Esyscmd:: Reading the output of commands
* Sysval:: Exit status
-* Maketemp:: Making names for temporary files
+* Maketemp:: Making temporary files
Miscellaneous builtin macros
* Errprint:: Printing error messages
* Location:: Printing current location
-* M4exit:: Exiting from m4
+* M4exit:: Exiting from @code{m4}
* Syncoutput:: Turning on and off sync lines
Fast loading of frozen state
@@ -263,15 +263,16 @@ Compatibility with other versions of @co
* Extensions:: Extensions in @acronym{GNU} M4
* Incompatibilities:: Other incompatibilities
+* Experiments:: Experimental features in @acronym{GNU} M4
-Copying This Manual
+How to make copies of this manual
* GNU Free Documentation License:: License for copying this manual
-Indices
+Indices of concepts and macros
* Concept index:: Index for many concepts
-* Macro index:: Index for all m4 macros
+* Macro index:: Index for all @code{m4} macros
@end detailmenu
@end menu
@@ -811,15 +812,15 @@ exception of the @sc{nul} character (the
@menu
* Names:: Macro names
-* Quoted strings:: Quoting input to m4
-* Comments:: Comments in m4 input
+* Quoted strings:: Quoting input to @code{m4}
+* Comments:: Comments in @code{m4} input
* Other tokens:: Other kinds of input tokens
-* Input processing:: How m4 copies input to output
-* Regular expression syntax:: How m4 interprets regular expressions
+* Input processing:: How @code{m4} copies input to output
+* Regular expression syntax:: How @code{m4} interprets regular expressions
@end menu
@node Names
address@hidden Names
address@hidden Macro names
@cindex names
A name is any sequence of letters, digits, and the character @kbd{_}
@@ -835,7 +836,7 @@ changed at any time, using the builtin m
@xref{Changesyntax}, for more information.
@node Quoted strings
address@hidden Quoted strings
address@hidden Quoting input to @code{m4}
@cindex quoted string
A quoted string is a sequence of characters surrounded by quote
@@ -864,7 +865,7 @@ The quote characters can be changed at a
(@pxref{Changesyntax}).
@node Comments
address@hidden Comments
address@hidden Comments in @code{m4} input
@cindex comments
Comments in @code{m4} are normally delimited by the characters @samp{#}
@@ -900,7 +901,7 @@ the builtin macros @code{changecom} (@px
@code{changesyntax} (@pxref{Changesyntax}).
@node Other tokens
address@hidden Other tokens
address@hidden Other kinds of input tokens
Any character, that is neither a part of a name, nor of a quoted string,
nor a comment, is a token by itself. When not in the context of macro
@@ -912,7 +913,7 @@ roles, explained later. Which character
can be adjusted with @code{changesyntax} (@pxref{Changesyntax}).
@node Input processing
address@hidden Input Processing
address@hidden How @code{m4} copies input to output
As @code{m4} reads the input token by token, it will copy each token
directly to the output immediately.
@@ -968,7 +969,7 @@ This process continues until there are n
all the input has been consumed.
@node Regular expression syntax
address@hidden Regular Expression Syntax
address@hidden How @code{m4} interprets regular expressions
There are several contexts where @code{m4} parses an argument as a
regular expression. This section describes the various flavors of
@@ -1253,14 +1254,15 @@ f
It is an error if the end of file occurs while collecting arguments.
address@hidden status: 1
@example
define(
^D
address@hidden:stdin:1: ERROR: end of file in argument list
address@hidden:stdin:1: end of file in argument list
@end example
@node Quoting Arguments
address@hidden Quoting macro arguments
address@hidden On Quoting Arguments to macros
@cindex quoted macro arguments
@cindex macros, quoted arguments to
@@ -1335,7 +1337,7 @@ value, and bring back the original value
@menu
* Define:: Defining a new macro
* Arguments:: Arguments to macros
-* Pseudo Arguments:: Pseudo arguments to macros
+* Pseudo Arguments:: Special arguments to macros
* Undefine:: Deleting a macro
* Defn:: Renaming macros
* Pushdef:: Temporarily redefining macros
@@ -1343,7 +1345,6 @@ value, and bring back the original value
* Indir:: Indirect call of macros
* Builtin:: Indirect call of builtins
-
* Symbols:: Getting the defined macro names
@end menu
@@ -1780,11 +1781,14 @@ echo(foo)
@end example
Using @code{defn} to generate special tokens for builtin macros outside
-of expected contexts can sometimes trigger warnings.
+of expected contexts can sometimes trigger warnings. But most of the
+time, such tokens are silently converted to the empty string.
@example
+defn(`defn')
address@hidden
define(defn(`divnum'), `cannot redefine a builtin token')
address@hidden:stdin:1: Warning: define: invalid macro name ignored
address@hidden:stdin:2: Warning: define: invalid macro name ignored
@result{}
divnum
@result{}0
@@ -2003,6 +2007,25 @@ The point is, here, that larger macro pa
defined, that will not be called by accident. They can @emph{only} be
called through the builtin @code{indir}.
+One other point to observe is that argument collection occurs before
address@hidden invokes @var{name}, so if argument collection changes the
+value of @var{name}, that will be reflected in the final expansion.
+This is different than the behavior when invoking macros directly,
+where the definition that was in effect before argument collection is
+used.
+
address@hidden
+define(`f', `1')
address@hidden
+f(define(`f', `2'))
address@hidden
+indir(`f', define(`f', `3'))
address@hidden
+indir(`f', undefine(`f'))
address@hidden:stdin:4: Warning: indir: undefined macro `f'
address@hidden
address@hidden example
+
@node Builtin
@section Indirect call of builtins
@@ -2124,11 +2147,13 @@ something a number of times, or while so
@menu
* Ifdef:: Testing if a macro is defined
* Ifelse:: If-else construct, or multibranch
-* Loops:: Loops and recursion in m4
+* Shift:: Recursion in @code{m4}
+* Forloop:: Iteration by counting
+* Foreach:: Iteration by list contents
@end menu
@node Ifdef
address@hidden Testing macro definitions
address@hidden Testing if a macro is defined
@cindex conditionals
There are two different builtin conditionals in @code{m4}. The first is
@@ -2156,7 +2181,7 @@ ifdef(`no_such_macro', `yes', `no', `ext
@end example
@node Ifelse
address@hidden Comparing strings
address@hidden If-else construct, or multibranch
@cindex comparing strings
The other conditional, @code{ifelse}, is much more powerful. It can be
@@ -2164,13 +2189,30 @@ used as a way to introduce a long commen
as a multibranch, depending on the number of arguments supplied:
@deffn {Builtin (m4)} ifelse (@var{comment})
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2},
@var{equal}, @w{opt @var{not-equal})}
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2},
@var{equal}, @dots{})
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2},
@var{equal}, @
+ @ovar{not-equal})
address@hidden {Builtin (m4)} ifelse (@var{string-1}, @var{string-2},
@var{equal-1}, @
+ @var{string-3}, @var{string-4}, @var{equal-2}, @dots{})
Used with only one argument, the @code{ifelse} simply discards it and
-produces no output. This is a common @code{m4} idiom for introducing a
+produces no output.
+
+If called with three or four arguments, @code{ifelse} expands into
address@hidden, if @var{string-1} and @var{string-2} are equal (character
+for character), otherwise it expands to @var{not-equal}. A final fifth
+argument is ignored, after triggering a warning.
+
+If called with six or more arguments, and @var{string-1} and
address@hidden are equal, @code{ifelse} expands into @var{equal-1},
+otherwise the first three arguments are discarded and the processing
+starts again.
+
+The macro @code{ifelse} is recognized only with parameters.
address@hidden deffn
+
+Using only one argument is a common @code{m4} idiom for introducing a
block comment, as an alternative to repeatedly using @code{dnl}. This
-special usage is recognized by GNU @code{m4}, so that in this case, the
-warning about missing arguments is never triggered.
+special usage is recognized by @acronym{GNU} @code{m4}, so that in this
+case, the warning about missing arguments is never triggered.
@example
ifelse(`some comments')
@@ -2180,43 +2222,64 @@ ifelse(`foo', `bar')
@result{}
@end example
-If called with three or four arguments, @code{ifelse} expands into
address@hidden, if @var{string-1} and @var{string-2} are equal (character
-for character), otherwise it expands to @var{not-equal}.
+Using three or four arguments provides decision points.
@example
ifelse(`foo', `bar', `true')
@result{}
ifelse(`foo', `foo', `true')
@result{}true
-ifelse(`foo', `bar', `true', `false')
address@hidden
-ifelse(`foo', `foo', `true', `false')
+define(`foo', `bar')
address@hidden
+ifelse(foo, `bar', `true', `false')
@result{}true
+ifelse(foo, `foo', `true', `false')
address@hidden
address@hidden example
+
+Notice how the first argument was used unquoted; it is common to compare
+the expansion of a macro with a string. With this macro, you can now
+reproduce the behavior of many of the builtins, where the macro is
+recognized only with arguments.
+
address@hidden
+define(`foo', `ifelse(`$#', `0', ``$0'', `arguments:$#')')
address@hidden
+foo
address@hidden
+foo()
address@hidden:1
+foo(`a', `b', `c')
address@hidden:3
@end example
@cindex multibranches
However, @code{ifelse} can take more than four arguments. If given more
than four arguments, @code{ifelse} works like a @code{case} or @code{switch}
statement in traditional programming languages. If @var{string-1} and
address@hidden are equal, @code{ifelse} expands into @var{equal}, otherwise
address@hidden are equal, @code{ifelse} expands into @var{equal-1}, otherwise
the procedure is repeated with the first three arguments discarded. This
calls for an example:
@example
+ifelse(`foo', `bar', `third', `gnu', `gnats')
address@hidden:stdin:1: Warning: ifelse: extra arguments ignored: 5 > 4
address@hidden
+ifelse(`foo', `bar', `third', `gnu', `gnats', `sixth')
address@hidden
ifelse(`foo', `bar', `third', `gnu', `gnats', `sixth', `seventh')
@result{}seventh
+ifelse(`foo', `bar', `3', `gnu', `gnats', `6', `7', `8')
address@hidden:stdin:4: Warning: ifelse: extra arguments ignored: 8 > 7
address@hidden
@end example
-The macro @code{ifelse} is recognized only with parameters.
address@hidden deffn
-
Naturally, the normal case will be slightly more advanced than these
examples. A common use of @code{ifelse} is in macros implementing loops
of various kinds.
address@hidden Loops
address@hidden Loops and recursion
address@hidden Shift
address@hidden Recursion in @code{m4}
@cindex recursive macros
@cindex macros, recursive
@@ -2231,9 +2294,12 @@ previously.
There is a builtin macro, @code{shift}, which can, among other things,
be used for iterating through the actual arguments to a macro:
address@hidden {Builtin (m4)} shift (@dots{})
address@hidden takes any number of arguments, and expands to all but the first
-argument, separated by commas, with each argument quoted.
address@hidden {Builtin (m4)} shift (@var{arg1}, @dots{})
+Takes any number of arguments, and expands to all its arguments except
address@hidden, separated by commas, with each argument quoted.
+
+The macro @code{shift} is recognized only with parameters.
address@hidden deffn
@example
shift
@@ -2243,10 +2309,14 @@ shift(`bar')
shift(`foo', `bar', `baz')
@result{}bar,baz
@end example
+
+An example of the use of @code{shift} is this macro:
+
address@hidden Composite reverse (@dots{})
+Takes any number of arguments, and reverse their order.
@end deffn
-An example of the use of @code{shift} is this macro, which reverses the
-order of its arguments:
+It is implemented as:
@example
define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'',
@@ -2261,14 +2331,66 @@ reverse(`foo', `bar', `gnats', `and gnus
@end example
While not a very interesting macro, it does show how simple loops can be
-made with @code{shift}, @code{ifelse} and recursion.
+made with @code{shift}, @code{ifelse} and recursion. It also shows
+that @code{shift} is usually used with @samp{$@@}. Sometimes, a
+recursive algorithm requires adding quotes to each element:
+
address@hidden Composite quote (@dots{})
address@hidden Composite dquote (@dots{})
address@hidden Composite dquote_elt (@dots{})
+Takes any number of arguments, and quoting. With @code{quote}, only one
+level of quoting is added, effectively removing whitespace after commas
+and turning the arguments into a string. With @code{dquote}, two
+levels of quoting are added, one around each element, and one around
+the list. And with @code{dquote_elt}, two levels of quoting are added
+around each element.
address@hidden deffn
+
+Here is an implementation, along with an example usage.
+
address@hidden FIXME - these macros are worth reusing in other examples;
address@hidden factor them into examples/quote.m4.
address@hidden
+define(`quote', `ifelse(`$#', `0', `', ``$*'')')dnl
+define(`dquote', ``$@@'')dnl
+define(`dquote_elt', `ifelse(`$#', `0', `', `$#', `1', ```$1''',
+ ```$1'',dquote_elt(shift($@@))')')dnl
+-quote-dquote-dquote_elt-
address@hidden
+-quote(`1')-dquote(`1')-dquote_elt(`1')-
address@hidden'-`1'-
+-quote(`1',`2')-dquote(`1',`2')-dquote_elt(`1',`2')-
address@hidden,2-`1',`2'-`1',`2'-
+dquote(dquote_elt(`1',`2'))
address@hidden'',``2''
+dquote_elt(dquote(`1',`2'))
address@hidden',`2''
address@hidden example
+
+The last two lines show that when given two arguments, @code{dquote}
+results in one string, while @code{dquote_elt} results in two.
+
address@hidden Forloop
address@hidden Iteration by counting
address@hidden forloops
address@hidden for loops
@cindex loops, counting
@cindex counting loops
-Here is an example of a loop macro that implements a simple forloop. It
-can, for example, be used for simple counting:
+Here is an example of a loop macro that implements a simple for loop.
address@hidden FIXME - this section still needs some work done
+
address@hidden Composite forloop (@var{iterator}, @var{start}, @var{end},
@var{text})
+Takes the name in @var{iterator}, which must be a valid macro name, and
+successively assign it each integer value from @var{start} to @var{end},
+inclusive. For each assignment to @var{iterator}, append @var{text} to
+the expansion of the @code{forloop}. @var{text} may refer to
address@hidden Any definition of @var{iterator} prior to this
+invocation is restored.
address@hidden deffn
+It can, for example, be used for simple counting:
+
address@hidden FIXME - include(`forloop.m4')
@comment ignore
@example
forloop(`i', 1, 8, `i ')
@@ -2325,12 +2447,69 @@ enough for general use. They lack even b
like start value less than final value, and the first argument not being
a name. Correcting these errors are left as an exercise to the reader.
address@hidden FIXME - it would be nice to introduce foreach here, and even
address@hidden give an example like this for finding defined macros that meet
address@hidden a certain pattern (see examples/foreach.m4):
address@hidden define(`quote', ``$@'')
address@hidden foreach(`macro', (quote(symbols)),
address@hidden `regexp(macro, `.*_.*', ``\&',')')
address@hidden Foreach
address@hidden Iteration by list contents
+
address@hidden for each loops
address@hidden loops, list iteration
address@hidden iterating over lists
+Here is an example of a loop macro that implements list iteration.
address@hidden FIXME - this section still needs some work done
+
address@hidden Composite foreach (@var{iterator}, @var{paren-list}, @var{text})
+Takes the name in @var{iterator}, which must be a valid macro name, and
+successively assign it each value from @var{paren-list}.
address@hidden is a comma-separated list of elements surrounded by
+parentheses. For each assignment to @var{iterator}, append @var{text}
+to the expansion of @code{foreach}. @var{text} may refer to
address@hidden Any definition of @var{iterator} prior to this
+invocation is restored.
address@hidden deffn
+
+As an example, this displays each word in a list inside of a sentence.
+
address@hidden FIXME - include(`foreach.m4')
address@hidden ignore
address@hidden
+foreach(`x', `(foo, bar, foobar)', `Word was: x
+')
address@hidden was: foo
address@hidden was: bar
address@hidden was: foobar
address@hidden example
+
+The implementation of the @code{foreach} macro is a bit more involved;
+it is a wrapper around two helper macros. First, @code{_arg1} is needed
+to grab the first element of a list. Second, @code{_foreach} implements
+the recursion, successively walking through the original list.
+
+Here is an actual implementation of @code{forloop}, followed by a
+demonstration of using it to filter out a list of symbols that contain
address@hidden
+
address@hidden FIXME - include(foreach.m4),include(quote.m4)
address@hidden
+define(`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')dnl
+define(`_arg1', ``$1'')dnl
+define(`_foreach',
+ `ifelse($2, `()', ,
+ `define(`$1',
+ `_arg1$2')$3`'_foreach(`$1', `(shift$2)',
+ `$3')')')dnl
+define(`dquote', ``$@@'')
address@hidden
+foreach(`macro', (dquote(symbols)), `regexp(macro, `.*if.*', ``\&',')')
address@hidden,ifelse,shift,
address@hidden example
+
+The example had to use a helper @code{quote} to ensure that the output
+from @code{symbols} was double quoted; without it, the macro would have
+gone into an infinite loop thanks to macros being reinvoked during the
+rescanning. Choosing @samp{()} as the list delimiters made this
+example rather awkward in terms of proper quoting. (A different
+implementation can be acheived by changing @var{list} from a
+parenthesized list to a quoted list; try reimplementing @code{foreach}
+with these semantics yourself, then check @pxref{Answers}).
@node Debugging
@chapter How to debug macros and input
@@ -2534,7 +2713,7 @@ to @code{m4}.
* Changecom:: Changing the comment delimiters
* Changeresyntax:: Changing the regular expression syntax
* Changesyntax:: Changing the lexical structure of the input
-* M4wrap:: Saving input until end of input
+* M4wrap:: Saving text until end of input
@end menu
@node Dnl
@@ -2630,7 +2809,7 @@ as they will be confused with names in t
the quoting mechanism.
@node Changecom
address@hidden Changing comment delimiters
address@hidden Changing the comment delimiters
@cindex changing comment delimiters
@cindex comment delimiters, changing
@@ -3101,7 +3280,7 @@ macro calls.
@node M4wrap
address@hidden Saving input
address@hidden Saving text until end of input
@cindex saving input
@cindex input, saving
@@ -3473,7 +3652,7 @@ diversions, given by the arguments. (Th
should try to see if you can find it and correct it. @xref{Answers}.)
@node Modules
address@hidden Runtime Dynamic Modules
address@hidden Extending M4 with dynamic runtime modules
@cindex modules
@sc{gnu} m4-1.4.x had a monolithic architecture. All of its
@@ -3979,7 +4158,7 @@ patreg(`aba abb 121', `\(.\)\(.\)\1', `\
@node Format
address@hidden Formatted output
address@hidden Formatting strings (printf-like)
@cindex formatted output
@cindex output, formatted
@@ -4006,7 +4185,7 @@ len(format(`%-*X', `5000', `1'))
@result{}5000
@end example
-Using the @code{forloop} macro defined in @xref{Loops}, this
+Using the @code{forloop} macro defined in @xref{Forloop}, this
example shows how @code{format} can be used to produce tabular output.
@comment ignore
@@ -4074,7 +4253,7 @@ given arguments.
@end deffn
@node Eval
address@hidden Evaluating integer or rational expressions
address@hidden Evaluating integer expressions
@cindex integer expression evaluation
@cindex evaluation, of integer expressions
@@ -4213,7 +4392,7 @@ The builtin macro @code{mpeval} is recog
@end deffn
@node Shell commands
address@hidden Running shell commands
address@hidden Macros for running shell commands
@cindex executing shell commands
@cindex running shell commands
@@ -4227,8 +4406,8 @@ commands from within @code{m4}.
* Platform macros:: Determining the platform
* Syscmd:: Executing simple commands
* Esyscmd:: Reading the output of commands
-* Sysval:: Exit codes
-* Maketemp:: Making names for temporary files
+* Sysval:: Exit status
+* Maketemp:: Making temporary files
@end menu
@node Platform macros
@@ -4299,7 +4478,7 @@ arguments.
@end deffn
@node Sysval
address@hidden Exit codes
address@hidden Exit status
@cindex exit code from shell commands
@cindex shell commands, exit code from
@@ -4323,7 +4502,7 @@ sysval
@end example
@node Maketemp
address@hidden Making names for temporary files
address@hidden Making temporary files
@cindex temporary file names
@cindex files, names of temporary
@@ -4357,7 +4536,7 @@ any of the previous chapters.
@menu
* Errprint:: Printing error messages
* Location:: Printing current location
-* M4exit:: Exiting from m4
+* M4exit:: Exiting from @code{m4}
* Syncoutput:: Turning on and off sync lines
@end menu
@@ -4433,7 +4612,7 @@ not followed, e.g., diverted text is not
(@pxref{M4wrap}) is not reread.
@node Syncoutput
address@hidden Turning sync lines on and off within @code{m4}
address@hidden Turning on and off sync lines
@cindex Toggling sync lines within @code{m4}
@deffn {Builtin (gnu)} syncoutput (@var{truth})
@@ -4661,12 +4840,13 @@ There are also differences in BSD flavor
is made to summarize these here.
@menu
-* Extensions:: Extensions in GNU m4
+* Extensions:: Extensions in @acronym{GNU} M4
* Incompatibilities:: Other incompatibilities
+* Experiments:: Experimental features in @acronym{GNU} M4
@end menu
@node Extensions
address@hidden Extensions in GNU @code{m4}
address@hidden Extensions in @acronym{GNU} M4
@cindex GNU extensions
@cindex @acronym{POSIX}
@@ -4835,7 +5015,7 @@ define the macro @code{__windows__}, whi
@node Experiments
address@hidden Experimental features in GNU M4
address@hidden Experimental features in @acronym{GNU} M4
Certain features of GNU @code{m4} are experimental.
@@ -4877,6 +5057,82 @@ unproven and might go away. Do not coun
Some of the examples in this manuals are buggy. Correctly working
macros are presented here.
+The @code{foreach} macro (@pxref{Foreach}) as presented required the
+user to use parentheses to delineate the list. This approach is
+quadratic, because the entire list is propagated through each recursion,
+with additional invocations of the shift macro added on each iteration:
+
address@hidden FIXME - include(foreach.m4),include(quote.m4)
address@hidden options: -d-V
address@hidden
+define(`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')dnl
+define(`_arg1', ``$1'')dnl
+define(`_foreach',
+ `ifelse($2, `()', ,
+ `define(`$1',
+ `_arg1$2')$3`'_foreach(`$1', `(shift$2)',
+ `$3')')')dnl
+define(`dquote', ``$@'')
address@hidden
+foreach(`macro', (dquote(symbols)), `regexp(macro, `shift', `\&')')
address@hidden
+traceon(`shift')
address@hidden
+foreach(`a', `(1,2,3)', `a
+')
address@hidden
address@hidden: -2- shift
address@hidden: -2- shift
address@hidden
address@hidden: -3- shift
address@hidden: -2- shift
address@hidden: -3- shift
address@hidden: -2- shift
address@hidden
address@hidden: -4- shift
address@hidden: -3- shift
address@hidden: -2- shift
address@hidden
address@hidden example
+
+An alternative implementation takes a quoted list, with semantics that
+the list is expanded once before iteration, and has the benefit that
+each iteration operates on a shorter list, giving linear performance on
+long lists. Another way of viewing these semantics is that the
+outermost quotes delineates the list, then each element of the list must
+be quoted as though the list delimiters were not present. Notice the
+difference when iterating over @code{symbols}; we must use
address@hidden instead of @code{dquote} to get the necessary quoting.
+
address@hidden FIXME - include(foreach.m4),include(quote.m4)
address@hidden options: -d-V
address@hidden
+define(`foreach', `pushdef(`$1')_foreach($@@)popdef(`$1')')dnl
+define(`_arg1', ``$1'')dnl
+define(`quote', `ifelse(`$#', `0', `', ``$*'')')dnl
+define(`dquote', ``$@@'')dnl
+define(`dquote_elt', `ifelse(`$#', `0', `', `$#', `1', ```$1''',
+ ```$1'',dquote_elt(shift($@@))')')dnl
+define(`_rest', `ifelse(`$#', `1', , `dquote(shift($@@))')')dnl
+define(`_foreach',
+ `ifelse(quote($2), , ,
+ `define(`$1',
+ `_arg1($2)')$3`'_foreach(`$1', _rest($2),
+ `$3')')')dnl
+foreach(`macro', `dquote_elt(symbols)', `regexp(macro, `shift', `\&')')
address@hidden
+traceon(`shift')
address@hidden
+foreach(`a', ``1',`2',`3'', `a
+')
address@hidden
address@hidden: -3- shift
address@hidden
address@hidden: -3- shift
address@hidden
address@hidden
address@hidden example
+
The @code{cleardivert} macro (@pxref{Cleardiv}) cannot, as it stands, be
called without arguments to clear all pending diversions. A macro that
achieves that as well is:
@@ -4895,7 +5151,7 @@ otherwise they will be passed to undiver
@c ========================================================== Appendices
@node Copying This Manual
address@hidden Copying This Manual
address@hidden How to make copies of this manual
@cindex License
@menu
@@ -4905,20 +5161,20 @@ otherwise they will be passed to undiver
@include fdl.texi
@node Indices
address@hidden Indices
address@hidden Indices of concepts and macros
@menu
* Concept index:: Index for many concepts
-* Macro index:: Index for all m4 macros
+* Macro index:: Index for all @code{m4} macros
@end menu
@node Concept index
address@hidden Concept index
address@hidden Index for many concepts
@printindex cp
@node Macro index
address@hidden Macro index
address@hidden Index for all @code{m4} macros
References are exclusively to the places where a builtin is introduced
the first time.
Index: m4/m4module.h
===================================================================
RCS file: /sources/m4/m4/m4/m4module.h,v
retrieving revision 1.81
diff -u -p -r1.81 m4module.h
--- m4/m4module.h 28 Aug 2006 12:48:54 -0000 1.81
+++ m4/m4module.h 5 Sep 2006 13:23:51 -0000
@@ -51,9 +51,12 @@ enum {
/* Set if macro should only be recognized with arguments; may only
be set if min_args is nonzero. */
M4_BUILTIN_BLIND = (1 << 1),
- /* set if macro has side effects even when there are too few
+ /* Set if macro has side effects even when there are too few
arguments; may only be set if min_args is nonzero. */
- M4_BUILTIN_SIDE_EFFECT = (1 << 2)
+ M4_BUILTIN_SIDE_EFFECT = (1 << 2),
+
+ /* Mask of valid flag bits. Any other bits must be set to 0. */
+ M4_BUILTIN_FLAGS_MASK = (1 << 3) - 1
};
struct m4_builtin
@@ -253,8 +256,9 @@ extern const m4_builtin *m4_builtin_find
/* --- MACRO MANAGEMENT --- */
extern void m4_macro_expand_input (m4 *);
-extern void m4_macro_call (m4 *, m4_symbol *, m4_obstack *,
- int, m4_symbol_value **);
+extern void m4_macro_call (m4 *, m4_symbol_value *,
+ m4_obstack *, int,
+ m4_symbol_value **);
Index: m4/m4private.h
===================================================================
RCS file: /sources/m4/m4/m4/m4private.h,v
retrieving revision 1.57
diff -u -p -r1.57 m4private.h
--- m4/m4private.h 29 Aug 2006 20:38:30 -0000 1.57
+++ m4/m4private.h 5 Sep 2006 13:23:51 -0000
@@ -167,7 +167,9 @@ struct m4_symbol_value {
int flags;
m4_hash * arg_signature;
- int min_args, max_args;
+ unsigned int min_args;
+ unsigned int max_args;
+ size_t pending_expansions;
m4__symbol_type type;
union {
@@ -182,6 +184,7 @@ struct m4_symbol_value {
#define VALUE_ARG_SIGNATURE(T) ((T)->arg_signature)
#define VALUE_MIN_ARGS(T) ((T)->min_args)
#define VALUE_MAX_ARGS(T) ((T)->max_args)
+#define VALUE_PENDING(T) ((T)->pending_expansions)
#define SYMBOL_NEXT(S) (VALUE_NEXT ((S)->value))
#define SYMBOL_HANDLE(S) (VALUE_HANDLE ((S)->value))
@@ -189,15 +192,18 @@ struct m4_symbol_value {
#define SYMBOL_ARG_SIGNATURE(S) (VALUE_ARG_SIGNATURE ((S)->value))
#define SYMBOL_MIN_ARGS(S) (VALUE_MIN_ARGS ((S)->value))
#define SYMBOL_MAX_ARGS(S) (VALUE_MAX_ARGS ((S)->value))
+#define SYMBOL_PENDING(S) (VALUE_PENDING ((S)->value))
/* Fast macro versions of symbol table accessor functions,
that also have an identically named function exported in m4module.h. */
#ifdef NDEBUG
# define m4_get_symbol_traced(S) ((S)->traced)
# define m4_set_symbol_traced(S, V) ((S)->traced = (V))
+# define m4_get_symbol_value(S) ((S)->value)
+# define m4_set_symbol_value(S, V) ((S)->value = (V))
# define m4_symbol_value_create() xzalloc (sizeof (m4_symbol_value))
-# define m4_symbol_value_delete(V) (DELETE (V))
+/* m4_symbol_value_delete is too complex for a simple macro. */
# define m4_is_symbol_value_text(V) ((V)->type == M4_SYMBOL_TEXT)
# define m4_is_symbol_value_func(V) ((V)->type == M4_SYMBOL_FUNC)
@@ -219,15 +225,15 @@ struct m4_symbol_value {
-/* m4_symbol_value.flags bit masks. Be sure these are consistent with
- M4_BUILTIN_* bit masks, so we can copy m4_builtin.flags to
- m4_symbol_arg.flags. However, if we ever add blind support to user
- macros, then these names are better for use in the symbol
- table: */
+/* m4_symbol_value.flags bit masks. Be sure these are a consistent
+ superset of the M4_BUILTIN_* bit masks, so we can copy
+ m4_builtin.flags to m4_symbol_arg.flags. We can use additional
+ bits for private use. */
#define VALUE_MACRO_ARGS_BIT (1 << 0)
#define VALUE_BLIND_ARGS_BIT (1 << 1)
#define VALUE_SIDE_EFFECT_ARGS_BIT (1 << 2)
+#define VALUE_DELETED_BIT (1 << 3)
struct m4_symbol_arg {
Index: m4/macro.c
===================================================================
RCS file: /sources/m4/m4/m4/macro.c,v
retrieving revision 1.51
diff -u -p -r1.51 macro.c
--- m4/macro.c 31 Aug 2006 03:21:35 -0000 1.51
+++ m4/macro.c 5 Sep 2006 13:23:51 -0000
@@ -35,14 +35,14 @@ static void expand_token (m4 *co
static bool expand_argument (m4 *context, m4_obstack *obs,
m4_symbol_value *argp);
-static void process_macro (m4 *context, m4_symbol *symbol,
+static void process_macro (m4 *context, m4_symbol_value *value,
m4_obstack *expansion, int argc,
m4_symbol_value **argv);
-static void trace_prepre (m4 *context, const char *, int);
-static void trace_pre (m4 *context, const char *, int, int,
+static void trace_prepre (m4 *context, const char *, size_t);
+static void trace_pre (m4 *context, const char *, size_t, int,
m4_symbol_value **);
-static void trace_post (m4 *context, const char *, int, int,
+static void trace_post (m4 *context, const char *, size_t, int,
m4_symbol_value **, const char *);
/* It would be nice if we could use M4_GNUC_PRINTF(2, 3) on
@@ -50,15 +50,15 @@ static void trace_post (m4 *context,
it would lead to compiler warnings. */
static void trace_format (m4 *context, const char *fmt, ...);
-static void trace_header (m4 *, int);
+static void trace_header (m4 *, size_t);
static void trace_flush (m4 *);
/* Current recursion level in expand_macro (). */
-static int expansion_level = 0;
+static size_t expansion_level = 0;
/* The number of the current call of expand_macro (). */
-static int macro_call_id = 0;
+static size_t macro_call_id = 0;
/* This function reads all input, and expands each token, one at a time. */
void
@@ -81,7 +81,10 @@ expand_token (m4 *context, m4_obstack *o
m4__token_type type, m4_symbol_value *token)
{
m4_symbol *symbol;
- char *text = xstrdup (m4_get_symbol_value_text (token));
+ /* Copy name, since expand_macro can consume additional tokens,
+ invalidating the current token. */
+ char *text = (m4_is_symbol_value_text (token)
+ ? xstrdup (m4_get_symbol_value_text (token)) : NULL);
switch (type)
{ /* TOKSW */
@@ -172,7 +175,9 @@ expand_argument (m4 *context, m4_obstack
{
m4_set_symbol_value_text (argp, text);
}
- return (bool) (m4_has_syntax (M4SYNTAX, *m4_get_symbol_value_text
(&token), M4_SYNTAX_COMMA));
+ return m4_has_syntax (M4SYNTAX,
+ *m4_get_symbol_value_text (&token),
+ M4_SYNTAX_COMMA);
}
if (m4_has_syntax (M4SYNTAX, *text, M4_SYNTAX_OPEN))
@@ -225,8 +230,13 @@ expand_macro (m4 *context, const char *n
m4_obstack *expansion;
const char *expanded;
bool traced;
- int my_call_id;
+ size_t my_call_id;
+ m4_symbol_value *value;
+ /* Grab the current value of this macro, because it may change while
+ collecting arguments. */
+ value = m4_get_symbol_value (symbol);
+ VALUE_PENDING (value)++;
expansion_level++;
if (expansion_level > m4_get_nesting_limit_opt (context))
m4_error (context, EXIT_FAILURE, 0, _("\
@@ -236,8 +246,8 @@ recursion limit of %d exceeded, use -L<N
macro_call_id++;
my_call_id = macro_call_id;
- traced = (bool) (m4_is_debug_bit (context, M4_DEBUG_TRACE_ALL)
- || m4_get_symbol_traced (symbol));
+ traced = (m4_is_debug_bit (context, M4_DEBUG_TRACE_ALL)
+ || m4_get_symbol_traced (symbol));
obstack_init (&argptr);
obstack_init (&arguments);
@@ -254,13 +264,16 @@ recursion limit of %d exceeded, use -L<N
trace_pre (context, name, my_call_id, argc, argv);
expansion = m4_push_string_init (context);
- m4_macro_call (context, symbol, expansion, argc, argv);
+ m4_macro_call (context, value, expansion, argc, argv);
expanded = m4_push_string_finish ();
if (traced)
trace_post (context, name, my_call_id, argc, argv, expanded);
--expansion_level;
+ --VALUE_PENDING (value);
+ if (BIT_TEST (VALUE_FLAGS (value), VALUE_DELETED_BIT))
+ m4_symbol_value_delete (value);
obstack_free (&arguments, NULL);
obstack_free (&argptr, NULL);
@@ -314,27 +327,27 @@ collect_arguments (m4 *context, const ch
the call, stored in the ARGV table. The expansion is left on
the obstack EXPANSION. Macro tracing is also handled here. */
void
-m4_macro_call (m4 *context, m4_symbol *symbol, m4_obstack *expansion,
+m4_macro_call (m4 *context, m4_symbol_value *value, m4_obstack *expansion,
int argc, m4_symbol_value **argv)
{
if (m4_bad_argc (context, argc, argv,
- SYMBOL_MIN_ARGS (symbol), SYMBOL_MAX_ARGS (symbol),
- BIT_TEST (SYMBOL_FLAGS (symbol),
+ VALUE_MIN_ARGS (value), VALUE_MAX_ARGS (value),
+ BIT_TEST (VALUE_FLAGS (value),
VALUE_SIDE_EFFECT_ARGS_BIT)))
return;
- if (m4_is_symbol_text (symbol))
+ if (m4_is_symbol_value_text (value))
{
- process_macro (context, symbol, expansion, argc, argv);
+ process_macro (context, value, expansion, argc, argv);
}
- else if (m4_is_symbol_func (symbol))
+ else if (m4_is_symbol_value_func (value))
{
- (*m4_get_symbol_func (symbol)) (context, expansion, argc, argv);
+ (*m4_get_symbol_value_func (value)) (context, expansion, argc, argv);
}
- else if (m4_is_symbol_placeholder (symbol))
+ else if (m4_is_symbol_value_placeholder (value))
{
m4_warn (context, 0,
_("%s: builtin `%s' requested by frozen file not found"),
- M4ARG (0), m4_get_symbol_placeholder (symbol));
+ M4ARG (0), m4_get_symbol_value_placeholder (value));
}
else
{
@@ -349,13 +362,13 @@ m4_macro_call (m4 *context, m4_symbol *s
definition, giving the expansion text. ARGC and ARGV are the arguments,
as usual. */
static void
-process_macro (m4 *context, m4_symbol *symbol, m4_obstack *obs,
+process_macro (m4 *context, m4_symbol_value *value, m4_obstack *obs,
int argc, m4_symbol_value **argv)
{
const unsigned char *text;
int i;
- for (text = m4_get_symbol_text (symbol); *text != '\0';)
+ for (text = m4_get_symbol_value_text (value); *text != '\0';)
{
char ch;
@@ -370,6 +383,10 @@ process_macro (m4 *context, m4_symbol *s
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
+ /* FIXME - multidigit arguments should convert over to ${10}
+ syntax instead of $10; see
+ http://lists.gnu.org/archive/html/m4-discuss/2006-08/msg00028.html
+ for more discussion. */
if (m4_get_posixly_correct_opt (context) || !isdigit(text[1]))
{
i = *text++ - '0';
@@ -377,7 +394,7 @@ process_macro (m4 *context, m4_symbol *s
else
{
char *endp;
- i = (int)strtol (text, &endp, 10);
+ i = (int) strtol (text, &endp, 10);
text = endp;
}
if (i < argc)
@@ -397,7 +414,7 @@ process_macro (m4 *context, m4_symbol *s
default:
if (m4_get_posixly_correct_opt (context)
- || !SYMBOL_ARG_SIGNATURE (symbol))
+ || !VALUE_ARG_SIGNATURE (value))
{
obstack_1grow (obs, ch);
}
@@ -421,7 +438,7 @@ process_macro (m4 *context, m4_symbol *s
{
struct m4_symbol_arg **arg
= (struct m4_symbol_arg **)
- m4_hash_lookup (SYMBOL_ARG_SIGNATURE (symbol), key);
+ m4_hash_lookup (VALUE_ARG_SIGNATURE (value), key);
if (arg)
{
@@ -462,8 +479,9 @@ process_macro (m4 *context, m4_symbol *s
various builtins. */
/* Tracing output is formatted here, by a simplified printf-to-obstack
- function trace_format (). Understands only %S, %s, %d, %l (optional
- left quote) and %r (optional right quote). */
+ function trace_format (). Understands only %S (length-limited
+ string), %s, %d, %z (size_t value), %l (optional left quote) and %r
+ (optional right quote). */
static void
trace_format (m4 *context, const char *fmt, ...)
{
@@ -471,6 +489,7 @@ trace_format (m4 *context, const char *f
char ch;
int d;
+ size_t z;
char nbuf[32];
const char *s;
int slen;
@@ -515,6 +534,16 @@ trace_format (m4 *context, const char *f
s = nbuf;
break;
+ case 'z':
+ if (sizeof (size_t) < sizeof (int))
+ z = va_arg (args, int);
+ else
+ z = va_arg (args, size_t);
+ /* FIXME - it would be nice to assume POSIX-mandated %zu. */
+ sprintf (nbuf, "%lu", (unsigned long) z);
+ s = nbuf;
+ break;
+
default:
s = "";
break;
@@ -535,7 +564,7 @@ trace_format (m4 *context, const char *f
/* Format the standard header attached to all tracing output lines. */
static void
-trace_header (m4 *context, int id)
+trace_header (m4 *context, size_t id)
{
trace_format (context, "m4trace:");
if (m4_get_current_line (context))
@@ -545,9 +574,9 @@ trace_header (m4 *context, int id)
if (m4_is_debug_bit (context, M4_DEBUG_TRACE_LINE))
trace_format (context, "%d:", m4_get_current_line (context));
}
- trace_format (context, " -%d- ", expansion_level);
+ trace_format (context, " -%z- ", expansion_level);
if (m4_is_debug_bit (context, M4_DEBUG_TRACE_CALLID))
- trace_format (context, "id %d: ", id);
+ trace_format (context, "id %z: ", id);
}
/* Print current tracing line, and clear the obstack. */
@@ -566,7 +595,7 @@ trace_flush (m4 *context)
/* Do pre-argument-collction tracing for macro NAME. Used from
expand_macro (). */
static void
-trace_prepre (m4 *context, const char *name, int id)
+trace_prepre (m4 *context, const char *name, size_t id)
{
trace_header (context, id);
trace_format (context, "%s ...", name);
@@ -576,7 +605,7 @@ trace_prepre (m4 *context, const char *n
/* Format the parts of a trace line, that can be made before the macro is
actually expanded. Used from expand_macro (). */
static void
-trace_pre (m4 *context, const char *name, int id,
+trace_pre (m4 *context, const char *name, size_t id,
int argc, m4_symbol_value **argv)
{
int i;
@@ -633,7 +662,7 @@ trace_pre (m4 *context, const char *name
/* Format the final part of a trace line and print it all. Used from
expand_macro (). */
static void
-trace_post (m4 *context, const char *name, int id,
+trace_post (m4 *context, const char *name, size_t id,
int argc, m4_symbol_value **argv, const char *expanded)
{
if (m4_is_debug_bit (context, M4_DEBUG_TRACE_CALL))
Index: m4/module.c
===================================================================
RCS file: /sources/m4/m4/m4/module.c,v
retrieving revision 1.42
diff -u -p -r1.42 module.c
--- m4/module.c 29 Aug 2006 20:38:30 -0000 1.42
+++ m4/module.c 5 Sep 2006 13:23:51 -0000
@@ -150,6 +150,7 @@ install_builtin_table (m4 *context, lt_d
assert (bp->min_args > 0
|| (bp->flags & (M4_BUILTIN_BLIND
| M4_BUILTIN_SIDE_EFFECT)) == 0);
+ assert ((bp->flags & ~M4_BUILTIN_FLAGS_MASK) == 0);
m4_set_symbol_value_func (value, bp->func);
VALUE_HANDLE (value) = handle;
Index: m4/symtab.c
===================================================================
RCS file: /sources/m4/m4/m4/symtab.c,v
retrieving revision 1.58
diff -u -p -r1.58 symtab.c
--- m4/symtab.c 1 Sep 2006 23:11:05 -0000 1.58
+++ m4/symtab.c 5 Sep 2006 13:23:51 -0000
@@ -51,7 +51,8 @@ struct m4_symbol_table {
static m4_symbol *symtab_fetch (m4_symbol_table*, const char *);
static void symbol_popval (m4_symbol *symbol);
-static void * symbol_destroy_CB (m4_symbol_table *symtab, const char
*name,
+static void * symbol_destroy_CB (m4_symbol_table *symtab,
+ const char *name,
m4_symbol *symbol, void *ignored);
static void * arg_destroy_CB (m4_hash *hash, const void *name,
void *arg, void *ignored);
@@ -140,7 +141,8 @@ symtab_fetch (m4_symbol_table *symtab, c
/* Remove every symbol that references the given module handle from
the symbol table. */
void
-m4__symtab_remove_module_references (m4_symbol_table *symtab, lt_dlhandle
handle)
+m4__symtab_remove_module_references (m4_symbol_table *symtab,
+ lt_dlhandle handle)
{
m4_hash_iterator *place = 0;
@@ -165,9 +167,7 @@ m4__symtab_remove_module_references (m4_
VALUE_NEXT (data) = VALUE_NEXT (next);
assert (next->type != M4_SYMBOL_PLACEHOLDER);
- if (next->type == M4_SYMBOL_TEXT)
- free (m4_get_symbol_value_text (next));
- free (next);
+ m4_symbol_value_delete (next);
}
else
data = next;
@@ -186,8 +186,8 @@ m4__symtab_remove_module_references (m4_
on every symbol so that m4_symbol_popdef() doesn't try to preserve
the table entry. */
static void *
-symbol_destroy_CB (m4_symbol_table *symtab, const char *name, m4_symbol
*symbol,
- void *ignored)
+symbol_destroy_CB (m4_symbol_table *symtab, const char *name,
+ m4_symbol *symbol, void *ignored)
{
char *key = xstrdup ((char *) name);
@@ -224,7 +224,8 @@ m4_symbol_lookup (m4_symbol_table *symta
associated with NAME, push the new VALUE on top of the value stack
for this symbol. Otherwise create a new association. */
m4_symbol *
-m4_symbol_pushdef (m4_symbol_table *symtab, const char *name, m4_symbol_value
*value)
+m4_symbol_pushdef (m4_symbol_table *symtab, const char *name,
+ m4_symbol_value *value)
{
m4_symbol *symbol;
@@ -289,6 +290,7 @@ m4_symbol_popdef (m4_symbol_table *symta
}
}
+/* Remove the top-most value from SYMBOL's stack. */
static void
symbol_popval (m4_symbol *symbol)
{
@@ -301,17 +303,29 @@ symbol_popval (m4_symbol *symbol)
if (stale)
{
symbol->value = VALUE_NEXT (stale);
+ m4_symbol_value_delete (stale);
+ }
+}
- if (VALUE_ARG_SIGNATURE (stale))
+/* Remove VALUE from the symbol table, and mark it as deleted. If no
+ expansions are pending, reclaim its resources. */
+void
+m4_symbol_value_delete (m4_symbol_value *value)
+{
+ if (VALUE_PENDING (value) > 0)
+ BIT_SET (VALUE_FLAGS (value), VALUE_DELETED_BIT);
+ else
+ {
+ if (VALUE_ARG_SIGNATURE (value))
{
- m4_hash_apply (VALUE_ARG_SIGNATURE (stale), arg_destroy_CB, NULL);
- m4_hash_delete (VALUE_ARG_SIGNATURE (stale));
+ m4_hash_apply (VALUE_ARG_SIGNATURE (value), arg_destroy_CB, NULL);
+ m4_hash_delete (VALUE_ARG_SIGNATURE (value));
}
- if (m4_is_symbol_value_text (stale))
- free (m4_get_symbol_value_text (stale));
- else if (m4_is_symbol_value_placeholder (stale))
- free (m4_get_symbol_value_placeholder (stale));
- free (stale);
+ if (m4_is_symbol_value_text (value))
+ free (m4_get_symbol_value_text (value));
+ else if (m4_is_symbol_value_placeholder (value))
+ free (m4_get_symbol_value_placeholder (value));
+ free (value);
}
}
@@ -384,16 +398,20 @@ m4_symbol_value_copy (m4_symbol_value *d
m4_hash_delete (VALUE_ARG_SIGNATURE (dest));
}
- /* Copy the valuecontents over, being careful to preserve
+ /* Copy the value contents over, being careful to preserve
the next pointer. */
next = VALUE_NEXT (dest);
- bcopy (src, dest, sizeof (m4_symbol_value));
+ memcpy (dest, src, sizeof (m4_symbol_value));
VALUE_NEXT (dest) = next;
/* Caller is supposed to free text token strings, so we have to
copy the string not just its address in that case. */
if (m4_is_symbol_value_text (src))
m4_set_symbol_value_text (dest, xstrdup (m4_get_symbol_value_text (src)));
+ else if (m4_is_symbol_value_placeholder (src))
+ m4_set_symbol_value_placeholder (dest,
+ xstrdup (m4_get_symbol_value_placeholder
+ (src)));
if (VALUE_ARG_SIGNATURE (src))
VALUE_ARG_SIGNATURE (dest) = m4_hash_dup (VALUE_ARG_SIGNATURE (src),
Index: modules/gnu.c
===================================================================
RCS file: /sources/m4/m4/modules/gnu.c,v
retrieving revision 1.53
diff -u -p -r1.53 gnu.c
--- modules/gnu.c 31 Aug 2006 03:21:35 -0000 1.53
+++ modules/gnu.c 5 Sep 2006 13:23:51 -0000
@@ -507,7 +507,8 @@ M4BUILTIN_HANDLER (indir)
if (symbol == NULL)
m4_warn (context, 0, _("%s: undefined macro `%s'"), M4ARG (0), name);
else
- m4_macro_call (context, symbol, obs, argc - 1, argv + 1);
+ m4_macro_call (context, m4_get_symbol_value (symbol), obs,
+ argc - 1, argv + 1);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: dangling pointer bug and proposed patch,
Eric Blake <=