summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2009-01-07 07:21:35 -0700
committerEric Blake <ebb9@byu.net>2009-01-07 14:12:13 -0700
commit6502f317d49a62e0fffca97793bf923cf7897918 (patch)
treec616c6317c460cfd4d94185bfb92f1276e97359a
parentae9dfa87a514d290fe349710a9f643d52856f4ba (diff)
downloadm4-6502f317d49a62e0fffca97793bf923cf7897918.tar.gz
Enhance substr to support replacement text.
* doc/m4.texinfo (Substr): Document new semantics. * modules/m4.c (substr): Support optional fourth argument. * NEWS: Document this. Signed-off-by: Eric Blake <ebb9@byu.net> (cherry picked from commit 59d3cfafa8d73e43a974bc066722cd6220cb479f)
-rw-r--r--ChangeLog5
-rw-r--r--NEWS3
-rw-r--r--doc/m4.texinfo34
-rw-r--r--modules/m4.c26
4 files changed, 62 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 47f1897b..3a7ca973 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2009-01-07 Eric Blake <ebb9@byu.net>
+ Enhance substr to support replacement text.
+ * doc/m4.texinfo (Substr): Document new semantics.
+ * modules/m4.c (substr): Support optional fourth argument.
+ * NEWS: Document this.
+
Enhance substr to support negative values.
* doc/m4.texinfo (Substr): Document new semantics, and how to
simulate old.
diff --git a/NEWS b/NEWS
index b3396ff7..dd7e674a 100644
--- a/NEWS
+++ b/NEWS
@@ -243,7 +243,8 @@ promoted to 2.0.
macro. It has also been optimized for faster performance.
** The `substr' builtin now treats negative arguments as indices relative
- to the end of the string. The manual gives an
+ to the end of the string, and accepts an optional fourth argument of
+ text to supply in place of the selected substring. The manual gives an
example of how to recover M4 1.4.x behavior, as well as an example of
simulating the new negative argument semantics with older M4.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 6b515cfd..fbe42f2c 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -7011,7 +7011,8 @@ regexp(`GNUs not Unix', `\w\(\w+\)$', `POSIX_EXTENDED', `')
@cindex substrings, extracting
Substrings are extracted with @code{substr}:
-@deffn {Builtin (m4)} substr (@var{string}, @var{from}, @ovar{length})
+@deffn {Builtin (m4)} substr (@var{string}, @var{from}, @ovar{length}, @
+ @ovar{replace})
Performs a substring operation on @var{string}. If @var{from} is
positive, it represents the 0-based index where the substring begins.
If @var{length} is omitted, the substring ends at the end of
@@ -7030,9 +7031,13 @@ of @var{string} that overlap the selected indices. If the end point
lies before the beginning point, the substring chosen is the empty
string located at the starting index.
-The expansion is the selected substring, which may be empty. The
+If @var{replace} is omitted, then the expansion is only the selected
+substring, which may be empty. As a @acronym{GNU} extension,if
+@var{replace} is provided, then the expansion is the original
+@var{string} with the selected substring replaced by @var{replace}. The
expansion is empty and a warning issued if @var{from} or @var{length}
-cannot be parsed.
+cannot be parsed, or if @var{replace} is provided but the selected
+indices do not overlap with @var{string}.
The macro @code{substr} is recognized only with parameters.
@end deffn
@@ -7091,6 +7096,29 @@ substr(`abcdefghij', `-09', `08')
@result{}bcdefghi
@end example
+Another useful @acronym{GNU} extension, also added in M4 1.6, is the
+ability to replace a substring within the original @var{string}. An
+empty length substring at the beginning or end of @var{string} is valid,
+but selecting a substring that does not overlap @var{string} causes a
+warning.
+
+@example
+substr(`abcde', `1', `3', `t')
+@result{}ate
+substr(`abcde', `5', `', `f')
+@result{}abcdef
+substr(`abcde', `-3', `-4', `f')
+@result{}abfcde
+substr(`abcde', `-6', `1', `f')
+@result{}fabcde
+substr(`abcde', `-7', `1', `f')
+@error{}m4:stdin:5: Warning: substr: substring out of range
+@result{}
+substr(`abcde', `6', `', `f')
+@error{}m4:stdin:6: Warning: substr: substring out of range
+@result{}
+@end example
+
If backwards compabitility to M4 1.4.x behavior is necessary, the
following macro is sufficient to do the job (mimicking warnings about
empty @var{from} or @var{length} or an ignored fourth argument is left
diff --git a/modules/m4.c b/modules/m4.c
index b09510c8..b7d23d04 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -86,7 +86,7 @@ extern void m4_make_temp (m4 *, m4_obstack *, const m4_call_info *,
BUILTIN (pushdef, true, true, false, 1, 2 ) \
BUILTIN (shift, true, true, false, 1, -1 ) \
BUILTIN (sinclude, false, true, false, 1, 1 ) \
- BUILTIN (substr, false, true, true, 2, 3 ) \
+ BUILTIN (substr, false, true, true, 2, 4 ) \
BUILTIN (syscmd, false, true, true, 1, 1 ) \
BUILTIN (sysval, false, false, false, 0, 0 ) \
BUILTIN (traceoff, true, false, false, 0, -1 ) \
@@ -929,7 +929,9 @@ M4BUILTIN_HANDLER (index)
a length given by the third argument. If the third argument is
missing or empty, the substring extends to the end of the first
argument. As an extension, negative arguments are treated as
- indices relative to the string length. */
+ indices relative to the string length. Also, if a fourth argument
+ is supplied, the original string is output with the selected
+ substring replaced by the argument. */
M4BUILTIN_HANDLER (substr)
{
const m4_call_info *me = m4_arg_info (argv);
@@ -963,6 +965,26 @@ M4BUILTIN_HANDLER (substr)
end += start;
}
+ if (5 <= argc)
+ {
+ /* Replacement text provided. */
+ if (end < start)
+ end = start;
+ if (end < 0 || length < start)
+ {
+ m4_warn (context, 0, me, _("substring out of range"));
+ return;
+ }
+ if (start < 0)
+ start = 0;
+ if (length < end)
+ end = length;
+ obstack_grow (obs, str, start);
+ m4_push_arg (context, obs, argv, 4);
+ obstack_grow (obs, str + end, length - end);
+ return;
+ }
+
if (start < 0)
start = 0;
if (length < end)