m4-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU M4 source repository branch, master, updated. cvs-readonly-184


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-184-g6502f31
Date: Thu, 08 Jan 2009 13:20:30 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU M4 source repository".

http://git.sv.gnu.org/gitweb/?p=m4.git;a=commitdiff;h=6502f317d49a62e0fffca97793bf923cf7897918

The branch, master has been updated
       via  6502f317d49a62e0fffca97793bf923cf7897918 (commit)
       via  ae9dfa87a514d290fe349710a9f643d52856f4ba (commit)
      from  e6819ca240b76700f07c31ba157f7795caada02e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 6502f317d49a62e0fffca97793bf923cf7897918
Author: Eric Blake <address@hidden>
Date:   Wed Jan 7 07:21:35 2009 -0700

    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 <address@hidden>
    (cherry picked from commit 59d3cfafa8d73e43a974bc066722cd6220cb479f)

commit ae9dfa87a514d290fe349710a9f643d52856f4ba
Author: Eric Blake <address@hidden>
Date:   Tue Jan 6 22:03:27 2009 -0700

    Enhance substr to support negative values.
    
    * doc/m4.texinfo (Substr): Document new semantics, and how to
    simulate old.
    * modules/m4.c (substr): Support negative values.
    * NEWS: Document this.
    
    Signed-off-by: Eric Blake <address@hidden>
    (cherry picked from commit e9e4abba45f7e9f368cf497e14bc2ce64b867a02)

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog      |   13 ++++
 NEWS           |   10 +++-
 doc/m4.texinfo |  187 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 modules/m4.c   |   70 ++++++++++++++++-----
 4 files changed, 251 insertions(+), 29 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index aa41fcc..3a7ca97 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-01-07  Eric Blake  <address@hidden>
+
+       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.
+       * modules/m4.c (substr): Support negative values.
+       * NEWS: Document this.
+
 2009-01-05  Eric Blake  <address@hidden>
 
        Maintainer cleanups.
diff --git a/NEWS b/NEWS
index ca4e0b0..dd7e674 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,6 @@
 GNU m4 NEWS - History of user-visible changes.         -*- outline -*-
-Copyright (C) 1992, 1993, 1994, 1998, 2000, 2001, 2006, 2007, 2008 Free
-Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1998, 2000, 2001, 2006, 2007, 2008, 2009
+Free Software Foundation, Inc.
 
 * Noteworthy changes in Version 1.9b (200x-??-??) [beta]
   Released by ????, based on git version 1.9a-*
@@ -242,6 +242,12 @@ promoted to 2.0.
    the current expansion is nested within argument collection of another
    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, 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.
+
 ** The `-d'/`--debug' command-line option now understands `-' and `+'
    modifiers, the way the builtin `debugmode' has always done; this allows
    `-d-V' to disable prior debug settings from the command line, similar to
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index c5e36dd..fbe42f2 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -46,7 +46,7 @@ This manual (@value{UPDATED}) is for @acronym{GNU} M4 (version
 language.
 
 Copyright @copyright{} 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999,
-2000, 2001, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+2000, 2001, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -7011,13 +7011,33 @@ regexp(`GNUs not Unix', `\w\(\w+\)$', `POSIX_EXTENDED', 
`')
 @cindex substrings, extracting
 Substrings are extracted with @code{substr}:
 
address@hidden {Builtin (m4)} substr (@var{string}, @var{from}, @ovar{length})
-Expands to the substring of @var{string}, which starts at index
address@hidden, and extends for @var{length} characters, or to the end of
address@hidden, if @var{length} is omitted.  The starting index of a
-is always 0.  The expansion is empty if there is an error parsing
address@hidden or @var{length}, if @var{from} is beyond the end of
address@hidden, or if @var{length} is negative.
address@hidden {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
address@hidden; if it is positive, @var{length} is added to the starting
+index to determine the ending index.
+
address@hidden @acronym{GNU} extensions
+As a @acronym{GNU} extension, if @var{from} is negative, it is added to
+the length of @var{string} to determine the starting index; if it is
+empty, the start of the string is used.  Likewise, if @var{length} is
+negative, it is added to the length of @var{string} to determine the
+ending index, and an emtpy @var{length} behaves like an omitted
address@hidden  It is not an error if either of the resulting indices lie
+outside the string, but the selected substring only contains the bytes
+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.
+
+If @var{replace} is omitted, then the expansion is only the selected
+substring, which may be empty.  As a @acronym{GNU} extension,if
address@hidden is provided, then the expansion is the original
address@hidden 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, 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
@@ -7029,15 +7049,160 @@ substr(`gnus, gnats, and armadillos', `6', `5')
 @result{}gnats
 @end example
 
-Omitting @var{from} evokes a warning, but still produces output.
+Omitting @var{from} evokes a warning, but still produces output.  On the
+other hand, selecting a @var{from} or @var{length} that lies beyond
address@hidden is not a problem.
 
 @example
 substr(`abc')
 @error{}m4:stdin:1: Warning: substr: too few arguments: 1 < 2
 @result{}abc
-substr(`abc',)
address@hidden:stdin:2: Warning: substr: empty string treated as 0
+substr(`abc', `')
 @result{}abc
+substr(`abc', `4')
address@hidden
+substr(`abc', `1', `4')
address@hidden
address@hidden example
+
+Using negative values for @var{from} or @var{length} are @acronym{GNU}
+extensions, useful for accessing a fixed size tail of an
+arbitrary-length string.  Prior to M4 1.6, using these values would
+silently result in the empty string.  Some other implementations crash
+on negative values, and many treat an explicitly empty @var{length} as
+0, which is different from the omitted @var{length} implying the rest of
+the original @var{string}.
+
address@hidden
+substr(`abcde', `2', `')
address@hidden
+substr(`abcde', `-3')
address@hidden
+substr(`abcde', `', `-3')
address@hidden
+substr(`abcde', `-6')
address@hidden
+substr(`abcde', `-6', `5')
address@hidden
+substr(`abcde', `-7', `1')
address@hidden
+substr(`abcde', `1', `-2')
address@hidden
+substr(`abcde', `-4', `-1')
address@hidden
+substr(`abcde', `4', `-3')
address@hidden
+substr(`abcdefghij', `-09', `08')
address@hidden
address@hidden 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.
+
address@hidden
+substr(`abcde', `1', `3', `t')
address@hidden
+substr(`abcde', `5', `', `f')
address@hidden
+substr(`abcde', `-3', `-4', `f')
address@hidden
+substr(`abcde', `-6', `1', `f')
address@hidden
+substr(`abcde', `-7', `1', `f')
address@hidden:stdin:5: Warning: substr: substring out of range
address@hidden
+substr(`abcde', `6', `', `f')
address@hidden:stdin:6: Warning: substr: substring out of range
address@hidden
address@hidden 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
+as an exercise to the reader).
+
address@hidden
+define(`substr', `ifelse(`$#', `0', ``$0'',
+  eval(`2 < $#')`$3', `1', `',
+  index(`$2$3', `-'), `-1', `builtin(`$0', `$1', `$2', `$3')')')
address@hidden
+substr(`abcde', `3')
address@hidden
+substr(`abcde', `3', `')
address@hidden
+substr(`abcde', `-1')
address@hidden
+substr(`abcde', `1', `-1')
address@hidden
+substr(`abcde', `2', `1', `C')
address@hidden
address@hidden example
+
+On the other hand, it is possible to portably emulate the @acronym{GNU}
+extension of negative @var{from} and @var{length} arguments across all
address@hidden implementations, albeit with a lot more overhead.  This
+example uses @code{incr} and @code{decr} to normalize @samp{-08} to
+something that a later @code{eval} will treat as a decimal value, rather
+than looking like an invalid octal number, while avoiding using these
+macros on an empty string.  The helper macro @code{_substr_normalize} is
+recursive, since it is easier to fix @var{length} after @var{from} has
+been normalized, with the final iteration supplying two non-negative
+arguments to the original builtin, now named @code{_substr}.
+
address@hidden options: -daq -t_substr
address@hidden
+$ @kbd{m4 -daq -t _substr}
+define(`_substr', defn(`substr'))dnl
+define(`substr', `ifelse(`$#', `0', ``$0'',
+  `_$0(`$1', _$0_normalize(len(`$1'),
+    ifelse(`$2', `', `0', `incr(decr(`$2'))'),
+    ifelse(`$3', `', `', `incr(decr(`$3'))')))')')dnl
+define(`_substr_normalize', `ifelse(
+  eval(`$2 < 0 && $1 + $2 >= 0'), `1',
+    `$0(`$1', eval(`$1 + $2'), `$3')',
+  eval(`$2 < 0')`$3', `1', ``0', `$1'',
+  eval(`$2 < 0 && $3 - 0 >= 0 && $1 + $2 + $3 - 0 >= 0'), `1',
+    `$0(`$1', `0', eval(`$1 + $2 + $3 - 0'))',
+  eval(`$2 < 0 && $3 - 0 >= 0'), `1', ``0', `0'',
+  eval(`$2 < 0'), `1', `$0(`$1', `0', `$3')',
+  `$3', `', ``$2', `$1'',
+  eval(`$3 - 0 < 0 && $1 - $2 + $3 - 0 >= 0'), `1',
+    ``$2', eval(`$1 - $2 + $3')',
+  eval(`$3 - 0 < 0'), `1', ``$2', `0'',
+  ``$2', `$3'')')dnl
+substr(`abcde', `2', `')
address@hidden: -1- _substr(`abcde', `2', `5')
address@hidden
+substr(`abcde', `-3')
address@hidden: -1- _substr(`abcde', `2', `5')
address@hidden
+substr(`abcde', `', `-3')
address@hidden: -1- _substr(`abcde', `0', `2')
address@hidden
+substr(`abcde', `-6')
address@hidden: -1- _substr(`abcde', `0', `5')
address@hidden
+substr(`abcde', `-6', `5')
address@hidden: -1- _substr(`abcde', `0', `4')
address@hidden
+substr(`abcde', `-7', `1')
address@hidden: -1- _substr(`abcde', `0', `0')
address@hidden
+substr(`abcde', `1', `-2')
address@hidden: -1- _substr(`abcde', `1', `2')
address@hidden
+substr(`abcde', `-4', `-1')
address@hidden: -1- _substr(`abcde', `1', `3')
address@hidden
+substr(`abcde', `4', `-3')
address@hidden: -1- _substr(`abcde', `4', `0')
address@hidden
+substr(`abcdefghij', `-09', `08')
address@hidden: -1- _substr(`abcdefghij', `1', `8')
address@hidden
 @end example
 
 @node Translit
diff --git a/modules/m4.c b/modules/m4.c
index f578261..b7d23d0 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -1,6 +1,6 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 2000, 2002, 2003, 2004, 2006, 2007, 2008 Free Software
-   Foundation, Inc.
+   Copyright (C) 2000, 2002, 2003, 2004, 2006, 2007, 2008, 2009 Free
+   Software Foundation, Inc.
 
    This file is part of GNU M4.
 
@@ -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 )    \
@@ -924,17 +924,21 @@ M4BUILTIN_HANDLER (index)
   m4_shipout_int (obs, retval);
 }
 
-/* The macro "substr" extracts substrings from the first argument, starting
-   from the index given by the second argument, extending for a length
-   given by the third argument.  If the third argument is missing, the
-   substring extends to the end of the first argument.  */
+/* The macro "substr" extracts substrings from the first argument,
+   starting from the index given by the second argument, extending for
+   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.  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);
   const char *str = M4ARG (1);
   int start = 0;
+  int end;
   int length;
-  int avail;
 
   if (argc <= 2)
     {
@@ -942,19 +946,53 @@ M4BUILTIN_HANDLER (substr)
       return;
     }
 
-  length = avail = M4ARGLEN (1);
-  if (!m4_numeric_arg (context, me, M4ARG (2), &start))
+  length = M4ARGLEN (1);
+  if (!m4_arg_empty (argv, 2)
+      && !m4_numeric_arg (context, me, M4ARG (2), &start))
     return;
+  if (start < 0)
+    start += length;
 
-  if (argc >= 4 && !m4_numeric_arg (context, me, M4ARG (3), &length))
-    return;
+  if (m4_arg_empty (argv, 3))
+    end = length;
+  else
+    {
+      if (!m4_numeric_arg (context, me, M4ARG (3), &end))
+       return;
+      if (end < 0)
+       end += length;
+      else
+       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 || length <= 0 || start >= avail)
+  if (start < 0)
+    start = 0;
+  if (length < end)
+    end = length;
+  if (end <= start)
     return;
 
-  if (start + length > avail)
-    length = avail - start;
-  obstack_grow (obs, str + start, length);
+  obstack_grow (obs, str + start, end - start);
 }
 
 


hooks/post-receive
--
GNU M4 source repository




reply via email to

[Prev in Thread] Current Thread [Next in Thread]