summaryrefslogtreecommitdiff
path: root/function.c
diff options
context:
space:
mode:
Diffstat (limited to 'function.c')
-rw-r--r--function.c263
1 files changed, 145 insertions, 118 deletions
diff --git a/function.c b/function.c
index 90ab76a..ca66b91 100644
--- a/function.c
+++ b/function.c
@@ -33,9 +33,10 @@ Boston, MA 02111-1307, USA. */
struct function_table_entry
{
const char *name;
- int len;
- int required_args;
- int expand_args;
+ unsigned char len;
+ unsigned char minimum_args;
+ unsigned char maximum_args;
+ char expand_args;
char *(*func_ptr) PARAMS((char *output, char **argv, const char*funcname));
};
@@ -815,9 +816,9 @@ func_foreach (o, argv, funcname)
const char *funcname;
{
/* expand only the first two. */
- char *varname = expand_argument (argv[0], argv[1] - 1);
- char *list = expand_argument (argv[1], argv[2] -1);
- char *body = savestring (argv[2], argv[3] - argv[2] - 1);
+ char *varname = expand_argument (argv[0], NULL);
+ char *list = expand_argument (argv[1], NULL);
+ char *body = argv[2];
int doneany = 0;
char *list_iterator = list;
@@ -857,7 +858,6 @@ func_foreach (o, argv, funcname)
pop_variable_scope ();
free (varname);
free (list);
- free (body);
return o;
}
@@ -1090,7 +1090,7 @@ func_if (o, argv, funcname)
const char *funcname;
{
char *begp = argv[0];
- char *endp = argv[1]-1;
+ char *endp = begp + strlen (argv[0]);
int result = 0;
/* Find the result of the condition: if we have a value, and it's not
@@ -1101,7 +1101,7 @@ func_if (o, argv, funcname)
if (begp < endp)
{
- char *expansion = expand_argument (begp, endp);
+ char *expansion = expand_argument (begp, NULL);
result = strlen (expansion);
free (expansion);
@@ -1113,20 +1113,14 @@ func_if (o, argv, funcname)
argv += 1 + !result;
- if (argv[0] != NULL && argv[1] != NULL)
+ if (argv[0])
{
char *expansion;
- char **argend = argv+1;
- /* If we're doing the else-clause, make sure we concatenate any
- potential extra arguments into the last argument. */
- if (!result)
- while (argend[1])
- ++argend;
-
- expansion = expand_argument (*argv, *argend-1);
+ expansion = expand_argument (argv[0], NULL);
o = variable_buffer_output (o, expansion, strlen (expansion));
+
free (expansion);
}
@@ -1634,11 +1628,8 @@ func_not (char* o, char **argv, char *funcname)
some efficiency by moving most often used functions to the start of the
table.
- If REQUIRED_ARGS is positive, the function takes exactly that many
- arguments. All subsequent text is included with the last argument. So,
- since $(sort a,b,c) takes only one argument, it will be the full string
- "a,b,c". If the value is negative, it's the minimum number of arguments.
- A function can have more, but if it has less an error is generated.
+ If MAXIMUM_ARGS is 0, that means there is no maximum and all
+ comma-separated values are treated as arguments.
EXPAND_ARGS means that all arguments should be expanded before invocation.
Functions that do namespace tricks (foreach) don't automatically expand. */
@@ -1648,36 +1639,36 @@ static char *func_call PARAMS((char *o, char **argv, const char *funcname));
static struct function_table_entry function_table[] =
{
- /* Name/size */ /* ARG EXP? Function */
- { STRING_SIZE_TUPLE("addprefix"), 2, 1, func_addsuffix_addprefix},
- { STRING_SIZE_TUPLE("addsuffix"), 2, 1, func_addsuffix_addprefix},
- { STRING_SIZE_TUPLE("basename"), 1, 1, func_basename_dir},
- { STRING_SIZE_TUPLE("dir"), 1, 1, func_basename_dir},
- { STRING_SIZE_TUPLE("notdir"), 1, 1, func_notdir_suffix},
- { STRING_SIZE_TUPLE("subst"), 3, 1, func_subst},
- { STRING_SIZE_TUPLE("suffix"), 1, 1, func_notdir_suffix},
- { STRING_SIZE_TUPLE("filter"), 2, 1, func_filter_filterout},
- { STRING_SIZE_TUPLE("filter-out"), 2, 1, func_filter_filterout},
- { STRING_SIZE_TUPLE("findstring"), 2, 1, func_findstring},
- { STRING_SIZE_TUPLE("firstword"), 1, 1, func_firstword},
- { STRING_SIZE_TUPLE("join"), 2, 1, func_join},
- { STRING_SIZE_TUPLE("patsubst"), 3, 1, func_patsubst},
- { STRING_SIZE_TUPLE("shell"), 1, 1, func_shell},
- { STRING_SIZE_TUPLE("sort"), 1, 1, func_sort},
- { STRING_SIZE_TUPLE("strip"), 1, 1, func_strip},
- { STRING_SIZE_TUPLE("wildcard"), 1, 1, func_wildcard},
- { STRING_SIZE_TUPLE("word"), 2, 1, func_word},
- { STRING_SIZE_TUPLE("wordlist"), 3, 1, func_wordlist},
- { STRING_SIZE_TUPLE("words"), 1, 1, func_words},
- { STRING_SIZE_TUPLE("origin"), 1, 1, func_origin},
- { STRING_SIZE_TUPLE("foreach"), 3, 0, func_foreach},
- { STRING_SIZE_TUPLE("call"), -1, 1, func_call},
- { STRING_SIZE_TUPLE("error"), 1, 1, func_error},
- { STRING_SIZE_TUPLE("warning"), 1, 1, func_error},
- { STRING_SIZE_TUPLE("if"), -2, 0, func_if},
+ /* Name/size */ /* MIN MAX EXP? Function */
+ { STRING_SIZE_TUPLE("addprefix"), 2, 2, 1, func_addsuffix_addprefix},
+ { STRING_SIZE_TUPLE("addsuffix"), 2, 2, 1, func_addsuffix_addprefix},
+ { STRING_SIZE_TUPLE("basename"), 1, 1, 1, func_basename_dir},
+ { STRING_SIZE_TUPLE("dir"), 1, 1, 1, func_basename_dir},
+ { STRING_SIZE_TUPLE("notdir"), 1, 1, 1, func_notdir_suffix},
+ { STRING_SIZE_TUPLE("subst"), 3, 3, 1, func_subst},
+ { STRING_SIZE_TUPLE("suffix"), 1, 1, 1, func_notdir_suffix},
+ { STRING_SIZE_TUPLE("filter"), 2, 2, 1, func_filter_filterout},
+ { STRING_SIZE_TUPLE("filter-out"), 2, 2, 1, func_filter_filterout},
+ { STRING_SIZE_TUPLE("findstring"), 2, 2, 1, func_findstring},
+ { STRING_SIZE_TUPLE("firstword"), 1, 1, 1, func_firstword},
+ { STRING_SIZE_TUPLE("join"), 2, 2, 1, func_join},
+ { STRING_SIZE_TUPLE("patsubst"), 3, 3, 1, func_patsubst},
+ { STRING_SIZE_TUPLE("shell"), 1, 1, 1, func_shell},
+ { STRING_SIZE_TUPLE("sort"), 1, 1, 1, func_sort},
+ { STRING_SIZE_TUPLE("strip"), 1, 1, 1, func_strip},
+ { STRING_SIZE_TUPLE("wildcard"), 1, 1, 1, func_wildcard},
+ { STRING_SIZE_TUPLE("word"), 2, 2, 1, func_word},
+ { STRING_SIZE_TUPLE("wordlist"), 3, 3, 1, func_wordlist},
+ { STRING_SIZE_TUPLE("words"), 1, 1, 1, func_words},
+ { STRING_SIZE_TUPLE("origin"), 1, 1, 1, func_origin},
+ { STRING_SIZE_TUPLE("foreach"), 3, 3, 0, func_foreach},
+ { STRING_SIZE_TUPLE("call"), 1, 0, 0, func_call},
+ { STRING_SIZE_TUPLE("error"), 1, 1, 1, func_error},
+ { STRING_SIZE_TUPLE("warning"), 1, 1, 1, func_error},
+ { STRING_SIZE_TUPLE("if"), 2, 3, 0, func_if},
#ifdef EXPERIMENTAL
- { STRING_SIZE_TUPLE("eq"), 2, 1, func_eq},
- { STRING_SIZE_TUPLE("not"), 1, 1, func_not},
+ { STRING_SIZE_TUPLE("eq"), 2, 2, 1, func_eq},
+ { STRING_SIZE_TUPLE("not"), 1, 1, 1, func_not},
#endif
{ 0 }
};
@@ -1692,11 +1683,7 @@ expand_builtin_function (o, argc, argv, entry_p)
char **argv;
struct function_table_entry *entry_p;
{
- int min = (entry_p->required_args > 0
- ? entry_p->required_args
- : -entry_p->required_args);
-
- if (argc < min)
+ if (argc < entry_p->minimum_args)
fatal (reading_file,
_("Insufficient number of arguments (%d) to function `%s'"),
argc, entry_p->name);
@@ -1721,39 +1708,36 @@ handle_function (op, stringp)
const struct function_table_entry *entry_p;
char openparen = (*stringp)[0];
char closeparen = openparen == '(' ? ')' : '}';
- char *beg = *stringp + 1;
- char *endref;
+ char *beg;
+ char *end;
int count = 0;
- char *argbeg;
register char *p;
char **argv, **argvp;
int nargs;
+ beg = *stringp + 1;
+
entry_p = lookup_function (function_table, beg);
if (!entry_p)
return 0;
- /* We have found a call to a builtin function. Find the end of the
- arguments, and do the function. */
-
- endref = beg + entry_p->len;
+ /* We found a builtin function. Find the beginning of its arguments (skip
+ whitespace after the name). */
- /* Space after function name isn't part of the args. */
- p = next_token (endref);
- argbeg = p;
+ beg = next_token (beg + entry_p->len);
/* Find the end of the function invocation, counting nested use of
whichever kind of parens we use. Since we're looking, count commas
to get a rough estimate of how many arguments we might have. The
count might be high, but it'll never be low. */
- for (nargs=1; *p != '\0'; ++p)
- if (*p == ',')
+ for (nargs=1, end=beg; *end != '\0'; ++end)
+ if (*end == ',')
++nargs;
- else if (*p == openparen)
+ else if (*end == openparen)
++count;
- else if (*p == closeparen && --count < 0)
+ else if (*end == closeparen && --count < 0)
break;
if (count >= 0)
@@ -1761,47 +1745,63 @@ handle_function (op, stringp)
_("unterminated call to function `%s': missing `%c'"),
entry_p->name, closeparen);
+ *stringp = end;
+
/* Get some memory to store the arg pointers. */
argvp = argv = (char **) alloca (sizeof(char *) * (nargs + 2));
- /* Chop the string into arguments, then store the end pointer and a nul.
- If REQUIRED_ARGS is positive, as soon as we hit that many assume the
- rest of the string is part of the last argument. */
- *argvp = argbeg;
- nargs = 1;
- while (entry_p->required_args < 0 || nargs < entry_p->required_args)
+ /* Chop the string into arguments, then a nul. As soon as we hit
+ MAXIMUM_ARGS (if it's >0) assume the rest of the string is part of the
+ last argument.
+
+ If we're expanding, store pointers to the expansion of each one. If
+ not, make a duplicate of the string and point into that, nul-terminating
+ each argument. */
+
+ if (!entry_p->expand_args)
{
- char *next = find_next_argument (openparen, closeparen, *argvp, p);
+ int len = end - beg;
- if (!next)
- break;
+ p = xmalloc (len+1);
+ memcpy (p, beg, len);
+ p[len] = '\0';
+ beg = p;
+ end = beg + len;
+ }
+
+ p = beg;
+ nargs = 0;
+ for (p=beg, nargs=0; p < end; ++argvp)
+ {
+ char *next;
- *(++argvp) = next+1;
++nargs;
- }
- *(++argvp) = p+1;
- *(++argvp) = 0;
+ if (nargs == entry_p->maximum_args
+ || (! (next = find_next_argument (openparen, closeparen, p, end))))
+ next = end;
- /* If we should expand, do it. */
- if (entry_p->expand_args)
- {
- for (argvp=argv; argvp[1] != 0; ++argvp)
- *argvp = expand_argument (*argvp, argvp[1]-1);
+ if (entry_p->expand_args)
+ *argvp = expand_argument (p, next);
+ else
+ {
+ *argvp = p;
+ *next = '\0';
+ }
- /* end pointer doesn't make sense for expanded stuff. */
- *argvp = 0;
+ p = next + 1;
}
+ *argvp = NULL;
/* Finally! Run the function... */
*op = expand_builtin_function (*op, nargs, argv, entry_p);
- /* If we allocated memory for the expanded args, free it again. */
+ /* Free memory. */
if (entry_p->expand_args)
for (argvp=argv; *argvp != 0; ++argvp)
free (*argvp);
-
- *stringp = p;
+ else
+ free (beg);
return 1;
}
@@ -1818,47 +1818,73 @@ func_call (o, argv, funcname)
const char *funcname;
{
char *fname;
+ char *cp;
int flen;
char *body;
int i;
const struct function_table_entry *entry_p;
- /* Calling nothing is a no-op. */
- if (*argv[0] == '\0')
- return o;
+ fname = expand_argument (argv[0], NULL);
/* There is no way to define a variable with a space in the name, so strip
- trailing whitespace as a favor to the user. */
-
- flen = strlen (argv[0]);
- fname = argv[0] + flen - 1;
- while (isspace ((unsigned char)*fname))
- --fname;
- fname[1] = '\0';
-
- flen = fname - argv[0] + 1;
- fname = argv[0];
+ leading and trailing whitespace as a favor to the user. */
+ cp = fname;
+ while (*cp != '\0' && isspace ((unsigned char)*cp))
+ ++cp;
+ argv[0] = cp;
+
+ cp += strlen(cp) - 1;
+ while (cp > argv[0] && isspace ((unsigned char)*cp))
+ --cp;
+ cp[1] = '\0';
+
+ /* Calling nothing is a no-op */
+ if (*argv[0] == '\0')
+ {
+ free (fname);
+ return o;
+ }
/* Are we invoking a builtin function? */
- entry_p = lookup_function (function_table, fname);
+ entry_p = lookup_function (function_table, argv[0]);
if (entry_p)
{
+ char **av;
+
+ free (fname);
+
+ /* How many arguments do we have? */
for (i=0; argv[i+1]; ++i)
- ;
+ ;
+
+ /* If we need to expand arguments, do it now. */
+ if (entry_p->expand_args)
+ for (av=argv+1; *av; ++av)
+ *av = expand_argument (*av, NULL);
+
+ o = expand_builtin_function (o, i, argv+1, entry_p);
- return expand_builtin_function (o, i, argv + 1, entry_p);
+ /* What we expanded we must free... */
+ if (entry_p->expand_args)
+ for (av=argv+1; *av; ++av)
+ free (*av);
+
+ return o;
}
- /* No, so the first argument is the name of a variable to be expanded and
- interpreted as a function. Create the variable reference. */
+ /* Not a builtin, so the first argument is the name of a variable to be
+ expanded and interpreted as a function. Create the variable
+ reference. */
+ flen = strlen (argv[0]);
+
body = alloca (flen + 4);
- body[0]='$';
- body[1]='(';
- strcpy (body + 2, fname);
- body[flen+2]=')';
- body[flen+3]= '\0';
+ body[0] = '$';
+ body[1] = '(';
+ memcpy (body + 2, fname, flen);
+ body[flen+2] = ')';
+ body[flen+3] = '\0';
/* Set up arguments $(1) .. $(N). $(0) is the function name. */
@@ -1869,7 +1895,7 @@ func_call (o, argv, funcname)
char num[11];
sprintf (num, "%d", i);
- define_variable (num, strlen (num), *argv, o_automatic, 0);
+ define_variable (num, strlen (num), *argv, o_automatic, 1);
}
/* Expand the body in the context of the arguments, adding the result to
@@ -1879,5 +1905,6 @@ func_call (o, argv, funcname)
pop_variable_scope ();
+ free (fname);
return o + strlen(o);
}