summaryrefslogtreecommitdiff
path: root/modules/m4.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/m4.c')
-rw-r--r--modules/m4.c46
1 files changed, 31 insertions, 15 deletions
diff --git a/modules/m4.c b/modules/m4.c
index f578261a..b09510c8 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.
@@ -924,17 +924,19 @@ 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. */
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 +944,33 @@ 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 (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);
}