#include "make.h"
#include "filedef.h"
#include "variable.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
#include "debug.h"
#ifdef _AMIGA
#include "amiga.h"
#endif
struct function_table_entry
{
const char *name;
unsigned char len;
unsigned char minimum_args;
unsigned char maximum_args;
char expand_args;
char *(*func_ptr) PARAMS ((char *output, char **argv, const char *fname));
};
static unsigned long
function_table_entry_hash_1 (const void *keyv)
{
struct function_table_entry const *key = (struct function_table_entry const *) keyv;
return_STRING_N_HASH_1 (key->name, key->len);
}
static unsigned long
function_table_entry_hash_2 (const void *keyv)
{
struct function_table_entry const *key = (struct function_table_entry const *) keyv;
return_STRING_N_HASH_2 (key->name, key->len);
}
static int
function_table_entry_hash_cmp (const void *xv, const void *yv)
{
struct function_table_entry const *x = (struct function_table_entry const *) xv;
struct function_table_entry const *y = (struct function_table_entry const *) yv;
int result = x->len - y->len;
if (result)
return result;
return_STRING_N_COMPARE (x->name, y->name, x->len);
}
static struct hash_table function_table;
char *
subst_expand (char *o, char *text, char *subst, char *replace,
unsigned int slen, unsigned int rlen, int by_word)
{
char *t = text;
char *p;
if (slen == 0 && !by_word)
{
o = variable_buffer_output (o, t, strlen (t));
if (rlen > 0)
o = variable_buffer_output (o, replace, rlen);
return o;
}
do
{
if (by_word && slen == 0)
p = end_of_token (next_token (t));
else
{
p = strstr (t, subst);
if (p == 0)
{
o = variable_buffer_output (o, t, strlen (t));
return o;
}
}
if (p > t)
o = variable_buffer_output (o, t, p - t);
if (by_word
&& ((p > text && !isblank ((unsigned char)p[-1]))
|| (p[slen] != '\0' && !isblank ((unsigned char)p[slen]))))
o = variable_buffer_output (o, subst, slen);
else if (rlen > 0)
o = variable_buffer_output (o, replace, rlen);
{
char *nt = p + slen;
t = nt;
}
} while (*t != '\0');
return o;
}
char *
patsubst_expand (char *o, char *text, char *pattern, char *replace,
char *pattern_percent, char *replace_percent)
{
unsigned int pattern_prepercent_len, pattern_postpercent_len;
unsigned int replace_prepercent_len, replace_postpercent_len;
char *t;
unsigned int len;
int doneany = 0;
if (!replace_percent)
{
replace_percent = find_percent (replace);
if (replace_percent)
++replace_percent;
}
if (replace_percent)
{
replace_prepercent_len = replace_percent - replace - 1;
replace_postpercent_len = strlen (replace_percent);
}
else
{
replace_prepercent_len = strlen (replace);
replace_postpercent_len = 0;
}
if (!pattern_percent)
{
pattern_percent = find_percent (pattern);
if (pattern_percent)
++pattern_percent;
}
if (!pattern_percent)
return subst_expand (o, text, pattern, replace,
strlen (pattern), strlen (replace), 1);
pattern_prepercent_len = pattern_percent - pattern - 1;
pattern_postpercent_len = strlen (pattern_percent);
while ((t = find_next_token (&text, &len)) != 0)
{
int fail = 0;
if (len < pattern_prepercent_len + pattern_postpercent_len)
fail = 1;
if (!fail && pattern_prepercent_len > 0
&& (*t != *pattern
|| t[pattern_prepercent_len - 1] != pattern_percent[-2]
|| !strneq (t + 1, pattern + 1, pattern_prepercent_len - 1)))
fail = 1;
if (!fail && pattern_postpercent_len > 0
&& (t[len - 1] != pattern_percent[pattern_postpercent_len - 1]
|| t[len - pattern_postpercent_len] != *pattern_percent
|| !strneq (&t[len - pattern_postpercent_len],
pattern_percent, pattern_postpercent_len - 1)))
fail = 1;
if (fail)
o = variable_buffer_output (o, t, len);
else
{
o = variable_buffer_output (o, replace, replace_prepercent_len);
if (replace_percent != 0)
{
o = variable_buffer_output (o, t + pattern_prepercent_len,
len - (pattern_prepercent_len
+ pattern_postpercent_len));
o = variable_buffer_output (o, replace_percent,
replace_postpercent_len);
}
}
if (fail || replace_prepercent_len > 0
|| (replace_percent != 0 && len + replace_postpercent_len > 0))
{
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
}
if (doneany)
--o;
return o;
}
static const struct function_table_entry *
lookup_function (const char *s)
{
const char *e = s;
while (*e && ( (*e >= 'a' && *e <= 'z') || *e == '-'))
e++;
if (*e == '\0' || isblank ((unsigned char) *e))
{
struct function_table_entry function_table_entry_key;
function_table_entry_key.name = s;
function_table_entry_key.len = e - s;
return hash_find_item (&function_table, &function_table_entry_key);
}
return 0;
}
int
pattern_matches (char *pattern, char *percent, char *str)
{
unsigned int sfxlen, strlength;
if (percent == 0)
{
unsigned int len = strlen (pattern) + 1;
char *new_chars = (char *) alloca (len);
bcopy (pattern, new_chars, len);
pattern = new_chars;
percent = find_percent (pattern);
if (percent == 0)
return streq (pattern, str);
}
sfxlen = strlen (percent + 1);
strlength = strlen (str);
if (strlength < (percent - pattern) + sfxlen
|| !strneq (pattern, str, percent - pattern))
return 0;
return !strcmp (percent + 1, str + (strlength - sfxlen));
}
static char *
find_next_argument (char startparen, char endparen,
const char *ptr, const char *end)
{
int count = 0;
for (; ptr < end; ++ptr)
if (*ptr == startparen)
++count;
else if (*ptr == endparen)
{
--count;
if (count < 0)
return NULL;
}
else if (*ptr == ',' && !count)
return (char *)ptr;
return NULL;
}
static char *
string_glob (char *line)
{
static char *result = 0;
static unsigned int length;
register struct nameseq *chain;
register unsigned int idx;
chain = multi_glob (parse_file_seq
(&line, '\0', sizeof (struct nameseq),
0),
sizeof (struct nameseq));
if (result == 0)
{
length = 100;
result = (char *) xmalloc (100);
}
idx = 0;
while (chain != 0)
{
register char *name = chain->name;
unsigned int len = strlen (name);
struct nameseq *next = chain->next;
free ((char *) chain);
chain = next;
if (file_exists_p (name))
{
if (idx + len + 1 > length)
{
length += (len + 1) * 2;
result = (char *) xrealloc (result, length);
}
bcopy (name, &result[idx], len);
idx += len;
result[idx++] = ' ';
}
free (name);
}
if (idx == 0)
result[0] = '\0';
else
result[idx - 1] = '\0';
return result;
}
static char *
func_patsubst (char *o, char **argv, const char *funcname UNUSED)
{
o = patsubst_expand (o, argv[2], argv[0], argv[1], (char *) 0, (char *) 0);
return o;
}
static char *
func_join (char *o, char **argv, const char *funcname UNUSED)
{
int doneany = 0;
register char *tp;
register char *pp;
char *list1_iterator = argv[0];
char *list2_iterator = argv[1];
do
{
unsigned int len1, len2;
tp = find_next_token (&list1_iterator, &len1);
if (tp != 0)
o = variable_buffer_output (o, tp, len1);
pp = find_next_token (&list2_iterator, &len2);
if (pp != 0)
o = variable_buffer_output (o, pp, len2);
if (tp != 0 || pp != 0)
{
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
}
while (tp != 0 || pp != 0);
if (doneany)
--o;
return o;
}
static char *
func_origin (char *o, char **argv, const char *funcname UNUSED)
{
register struct variable *v = lookup_variable (argv[0], strlen (argv[0]));
if (v == 0)
o = variable_buffer_output (o, "undefined", 9);
else
switch (v->origin)
{
default:
case o_invalid:
abort ();
break;
case o_default:
o = variable_buffer_output (o, "default", 7);
break;
case o_env:
o = variable_buffer_output (o, "environment", 11);
break;
case o_file:
o = variable_buffer_output (o, "file", 4);
break;
case o_env_override:
o = variable_buffer_output (o, "environment override", 20);
break;
case o_command:
o = variable_buffer_output (o, "command line", 12);
break;
case o_override:
o = variable_buffer_output (o, "override", 8);
break;
case o_automatic:
o = variable_buffer_output (o, "automatic", 9);
break;
}
return o;
}
static char *
func_flavor (char *o, char **argv, const char *funcname UNUSED)
{
register struct variable *v = lookup_variable (argv[0], strlen (argv[0]));
if (v == 0)
o = variable_buffer_output (o, "undefined", 9);
else
if (v->recursive)
o = variable_buffer_output (o, "recursive", 9);
else
o = variable_buffer_output (o, "simple", 6);
return o;
}
#ifdef VMS
# define IS_PATHSEP(c) ((c) == ']')
#else
# ifdef HAVE_DOS_PATHS
# define IS_PATHSEP(c) ((c) == '/' || (c) == '\\')
# else
# define IS_PATHSEP(c) ((c) == '/')
# endif
#endif
static char *
func_notdir_suffix (char *o, char **argv, const char *funcname)
{
char *list_iterator = argv[0];
char *p2 =0;
int doneany =0;
unsigned int len=0;
int is_suffix = streq (funcname, "suffix");
int is_notdir = !is_suffix;
while ((p2 = find_next_token (&list_iterator, &len)) != 0)
{
char *p = p2 + len;
while (p >= p2 && (!is_suffix || *p != '.'))
{
if (IS_PATHSEP (*p))
break;
--p;
}
if (p >= p2)
{
if (is_notdir)
++p;
else if (*p != '.')
continue;
o = variable_buffer_output (o, p, len - (p - p2));
}
#ifdef HAVE_DOS_PATHS
else if (streq (funcname, "notdir") && p2[0] && p2[1] == ':')
{
p = p2 + 2;
o = variable_buffer_output (o, p, len - (p - p2));
}
#endif
else if (is_notdir)
o = variable_buffer_output (o, p2, len);
if (is_notdir || p >= p2)
{
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
}
if (doneany)
--o;
return o;
}
static char *
func_basename_dir (char *o, char **argv, const char *funcname)
{
char *p3 = argv[0];
char *p2=0;
int doneany=0;
unsigned int len=0;
char *p=0;
int is_basename= streq (funcname, "basename");
int is_dir= !is_basename;
while ((p2 = find_next_token (&p3, &len)) != 0)
{
p = p2 + len;
while (p >= p2 && (!is_basename || *p != '.'))
{
if (IS_PATHSEP (*p))
break;
--p;
}
if (p >= p2 && (is_dir))
o = variable_buffer_output (o, p2, ++p - p2);
else if (p >= p2 && (*p == '.'))
o = variable_buffer_output (o, p2, p - p2);
#ifdef HAVE_DOS_PATHS
else if (p2[0] && p2[1] == ':' && is_dir)
o = variable_buffer_output (o, p2, 2);
#endif
else if (is_dir)
#ifdef VMS
o = variable_buffer_output (o, "[]", 2);
#else
#ifndef _AMIGA
o = variable_buffer_output (o, "./", 2);
#else
;
#endif
#endif
else
o = variable_buffer_output (o, p2, len);
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
if (doneany)
--o;
return o;
}
static char *
func_addsuffix_addprefix (char *o, char **argv, const char *funcname)
{
int fixlen = strlen (argv[0]);
char *list_iterator = argv[1];
int is_addprefix = streq (funcname, "addprefix");
int is_addsuffix = !is_addprefix;
int doneany = 0;
char *p;
unsigned int len;
while ((p = find_next_token (&list_iterator, &len)) != 0)
{
if (is_addprefix)
o = variable_buffer_output (o, argv[0], fixlen);
o = variable_buffer_output (o, p, len);
if (is_addsuffix)
o = variable_buffer_output (o, argv[0], fixlen);
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
if (doneany)
--o;
return o;
}
static char *
func_subst (char *o, char **argv, const char *funcname UNUSED)
{
o = subst_expand (o, argv[2], argv[0], argv[1], strlen (argv[0]),
strlen (argv[1]), 0);
return o;
}
static char *
func_firstword (char *o, char **argv, const char *funcname UNUSED)
{
unsigned int i;
char *words = argv[0];
char *p = find_next_token (&words, &i);
if (p != 0)
o = variable_buffer_output (o, p, i);
return o;
}
static char *
func_lastword (char *o, char **argv, const char *funcname UNUSED)
{
unsigned int i;
char *words = argv[0];
char *p = 0;
char *t;
while ((t = find_next_token (&words, &i)))
p = t;
if (p != 0)
o = variable_buffer_output (o, p, i);
return o;
}
static char *
func_words (char *o, char **argv, const char *funcname UNUSED)
{
int i = 0;
char *word_iterator = argv[0];
char buf[20];
while (find_next_token (&word_iterator, (unsigned int *) 0) != 0)
++i;
sprintf (buf, "%d", i);
o = variable_buffer_output (o, buf, strlen (buf));
return o;
}
char *
strip_whitespace (const char **begpp, const char **endpp)
{
while (*begpp <= *endpp && isspace ((unsigned char)**begpp))
(*begpp) ++;
while (*endpp >= *begpp && isspace ((unsigned char)**endpp))
(*endpp) --;
return (char *)*begpp;
}
static void
check_numeric (const char *s, const char *message)
{
const char *end = s + strlen (s) - 1;
const char *beg = s;
strip_whitespace (&s, &end);
for (; s <= end; ++s)
if (!ISDIGIT (*s))
break;
if (s <= end || end - beg < 0)
fatal (*expanding_var, "%s: '%s'", message, beg);
}
static char *
func_word (char *o, char **argv, const char *funcname UNUSED)
{
char *end_p=0;
int i=0;
char *p=0;
check_numeric (argv[0], _("non-numeric first argument to `word' function"));
i = atoi (argv[0]);
if (i == 0)
fatal (*expanding_var,
_("first argument to `word' function must be greater than 0"));
end_p = argv[1];
while ((p = find_next_token (&end_p, 0)) != 0)
if (--i == 0)
break;
if (i == 0)
o = variable_buffer_output (o, p, end_p - p);
return o;
}
static char *
func_wordlist (char *o, char **argv, const char *funcname UNUSED)
{
int start, count;
check_numeric (argv[0],
_("non-numeric first argument to `wordlist' function"));
check_numeric (argv[1],
_("non-numeric second argument to `wordlist' function"));
start = atoi (argv[0]);
if (start < 1)
fatal (*expanding_var,
"invalid first argument to `wordlist' function: `%d'", start);
count = atoi (argv[1]) - start + 1;
if (count > 0)
{
char *p;
char *end_p = argv[2];
while (((p = find_next_token (&end_p, 0)) != 0) && --start)
;
if (p)
{
while (--count && (find_next_token (&end_p, 0) != 0))
;
o = variable_buffer_output (o, p, end_p - p);
}
}
return o;
}
static char*
func_findstring (char *o, char **argv, const char *funcname UNUSED)
{
if (strstr (argv[1], argv[0]) != 0)
o = variable_buffer_output (o, argv[0], strlen (argv[0]));
return o;
}
static char *
func_foreach (char *o, char **argv, const char *funcname UNUSED)
{
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;
char *p;
unsigned int len;
register struct variable *var;
push_new_variable_scope ();
var = define_variable (varname, strlen (varname), "", o_automatic, 0);
while ((p = find_next_token (&list_iterator, &len)) != 0)
{
char *result = 0;
{
char save = p[len];
p[len] = '\0';
free (var->value);
var->value = (char *) xstrdup ((char*) p);
p[len] = save;
}
result = allocated_variable_expand (body);
o = variable_buffer_output (o, result, strlen (result));
o = variable_buffer_output (o, " ", 1);
doneany = 1;
free (result);
}
if (doneany)
--o;
pop_variable_scope ();
free (varname);
free (list);
return o;
}
struct a_word
{
struct a_word *next;
struct a_word *chain;
char *str;
int length;
int matched;
};
static unsigned long
a_word_hash_1 (const void *key)
{
return_STRING_HASH_1 (((struct a_word const *) key)->str);
}
static unsigned long
a_word_hash_2 (const void *key)
{
return_STRING_HASH_2 (((struct a_word const *) key)->str);
}
static int
a_word_hash_cmp (const void *x, const void *y)
{
int result = ((struct a_word const *) x)->length - ((struct a_word const *) y)->length;
if (result)
return result;
return_STRING_COMPARE (((struct a_word const *) x)->str,
((struct a_word const *) y)->str);
}
struct a_pattern
{
struct a_pattern *next;
char *str;
char *percent;
int length;
int save_c;
};
static char *
func_filter_filterout (char *o, char **argv, const char *funcname)
{
struct a_word *wordhead;
struct a_word **wordtail;
struct a_word *wp;
struct a_pattern *pathead;
struct a_pattern **pattail;
struct a_pattern *pp;
struct hash_table a_word_table;
int is_filter = streq (funcname, "filter");
char *pat_iterator = argv[0];
char *word_iterator = argv[1];
int literals = 0;
int words = 0;
int hashing = 0;
char *p;
unsigned int len;
pattail = &pathead;
while ((p = find_next_token (&pat_iterator, &len)) != 0)
{
struct a_pattern *pat = (struct a_pattern *) alloca (sizeof (struct a_pattern));
*pattail = pat;
pattail = &pat->next;
if (*pat_iterator != '\0')
++pat_iterator;
pat->str = p;
pat->length = len;
pat->save_c = p[len];
p[len] = '\0';
pat->percent = find_percent (p);
if (pat->percent == 0)
literals++;
}
*pattail = 0;
wordtail = &wordhead;
while ((p = find_next_token (&word_iterator, &len)) != 0)
{
struct a_word *word = (struct a_word *) alloca (sizeof (struct a_word));
*wordtail = word;
wordtail = &word->next;
if (*word_iterator != '\0')
++word_iterator;
p[len] = '\0';
word->str = p;
word->length = len;
word->matched = 0;
word->chain = 0;
words++;
}
*wordtail = 0;
hashing = (literals >= 2 && (literals * words) >= 10);
if (hashing)
{
hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2, a_word_hash_cmp);
for (wp = wordhead; wp != 0; wp = wp->next)
{
struct a_word *owp = hash_insert (&a_word_table, wp);
if (owp)
wp->chain = owp;
}
}
if (words)
{
int doneany = 0;
for (pp = pathead; pp != 0; pp = pp->next)
{
if (pp->percent)
for (wp = wordhead; wp != 0; wp = wp->next)
wp->matched |= pattern_matches (pp->str, pp->percent, wp->str);
else if (hashing)
{
struct a_word a_word_key;
a_word_key.str = pp->str;
a_word_key.length = pp->length;
wp = (struct a_word *) hash_find_item (&a_word_table, &a_word_key);
while (wp)
{
wp->matched |= 1;
wp = wp->chain;
}
}
else
for (wp = wordhead; wp != 0; wp = wp->next)
wp->matched |= (wp->length == pp->length
&& strneq (pp->str, wp->str, wp->length));
}
for (wp = wordhead; wp != 0; wp = wp->next)
if (is_filter ? wp->matched : !wp->matched)
{
o = variable_buffer_output (o, wp->str, strlen (wp->str));
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
if (doneany)
--o;
}
for (pp = pathead; pp != 0; pp = pp->next)
pp->str[pp->length] = pp->save_c;
if (hashing)
hash_free (&a_word_table, 0);
return o;
}
static char *
func_strip (char *o, char **argv, const char *funcname UNUSED)
{
char *p = argv[0];
int doneany =0;
while (*p != '\0')
{
int i=0;
char *word_start=0;
while (isspace ((unsigned char)*p))
++p;
word_start = p;
for (i=0; *p != '\0' && !isspace ((unsigned char)*p); ++p, ++i)
{}
if (!i)
break;
o = variable_buffer_output (o, word_start, i);
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
if (doneany)
--o;
return o;
}
static char *
func_error (char *o, char **argv, const char *funcname)
{
char **argvp;
char *msg, *p;
int len;
for (len=0, argvp=argv; *argvp != 0; ++argvp)
len += strlen (*argvp) + 2;
p = msg = (char *) alloca (len + 1);
for (argvp=argv; argvp[1] != 0; ++argvp)
{
strcpy (p, *argvp);
p += strlen (*argvp);
*(p++) = ',';
*(p++) = ' ';
}
strcpy (p, *argvp);
switch (*funcname) {
case 'e':
fatal (reading_file, "%s", msg);
case 'w':
error (reading_file, "%s", msg);
break;
case 'i':
printf ("%s\n", msg);
fflush(stdout);
break;
default:
fatal (*expanding_var, "Internal error: func_error: '%s'", funcname);
}
return o;
}
static char *
func_sort (char *o, char **argv, const char *funcname UNUSED)
{
char **words = 0;
int nwords = 0;
register int wordi = 0;
char *t = argv[0];
char *p;
unsigned int len;
int i;
while ((p = find_next_token (&t, &len)) != 0)
{
if (wordi >= nwords - 1)
{
nwords = (2 * nwords) + 5;
words = (char **) xrealloc ((char *) words,
nwords * sizeof (char *));
}
words[wordi++] = savestring (p, len);
}
if (!wordi)
return o;
qsort ((char *) words, wordi, sizeof (char *), alpha_compare);
for (i = 0; i < wordi; ++i)
{
len = strlen (words[i]);
if (i == wordi - 1 || strlen (words[i + 1]) != len
|| strcmp (words[i], words[i + 1]))
{
o = variable_buffer_output (o, words[i], len);
o = variable_buffer_output (o, " ", 1);
}
free (words[i]);
}
--o;
free (words);
return o;
}
static char *
func_if (char *o, char **argv, const char *funcname UNUSED)
{
const char *begp = argv[0];
const char *endp = begp + strlen (argv[0]) - 1;
int result = 0;
strip_whitespace (&begp, &endp);
if (begp <= endp)
{
char *expansion = expand_argument (begp, endp+1);
result = strlen (expansion);
free (expansion);
}
argv += 1 + !result;
if (argv[0])
{
char *expansion;
expansion = expand_argument (argv[0], NULL);
o = variable_buffer_output (o, expansion, strlen (expansion));
free (expansion);
}
return o;
}
static char *
func_or (char *o, char **argv, const char *funcname UNUSED)
{
for ( ; *argv ; ++argv)
{
const char *begp = *argv;
const char *endp = begp + strlen (*argv) - 1;
char *expansion;
int result = 0;
strip_whitespace (&begp, &endp);
if (begp > endp)
continue;
expansion = expand_argument (begp, endp+1);
result = strlen (expansion);
if (!result)
{
free (expansion);
continue;
}
o = variable_buffer_output (o, expansion, result);
free (expansion);
break;
}
return o;
}
static char *
func_and (char *o, char **argv, const char *funcname UNUSED)
{
char *expansion;
int result;
while (1)
{
const char *begp = *argv;
const char *endp = begp + strlen (*argv) - 1;
strip_whitespace (&begp, &endp);
if (begp > endp)
return o;
expansion = expand_argument (begp, endp+1);
result = strlen (expansion);
if (!result)
break;
if (*(++argv))
free (expansion);
else
{
o = variable_buffer_output (o, expansion, result);
break;
}
}
free (expansion);
return o;
}
static char *
func_wildcard (char *o, char **argv, const char *funcname UNUSED)
{
#ifdef _AMIGA
o = wildcard_expansion (argv[0], o);
#else
char *p = string_glob (argv[0]);
o = variable_buffer_output (o, p, strlen (p));
#endif
return o;
}
static char *
func_eval (char *o, char **argv, const char *funcname UNUSED)
{
char *buf;
unsigned int len;
install_variable_buffer (&buf, &len);
eval_buffer (argv[0]);
restore_variable_buffer (buf, len);
return o;
}
static char *
func_value (char *o, char **argv, const char *funcname UNUSED)
{
struct variable *v = lookup_variable (argv[0], strlen (argv[0]));
if (v)
o = variable_buffer_output (o, v->value, strlen(v->value));
return o;
}
static void
fold_newlines (char *buffer, unsigned int *length)
{
char *dst = buffer;
char *src = buffer;
char *last_nonnl = buffer -1;
src[*length] = 0;
for (; *src != '\0'; ++src)
{
if (src[0] == '\r' && src[1] == '\n')
continue;
if (*src == '\n')
{
*dst++ = ' ';
}
else
{
last_nonnl = dst;
*dst++ = *src;
}
}
*(++last_nonnl) = '\0';
*length = last_nonnl - buffer;
}
int shell_function_pid = 0, shell_function_completed;
#ifdef WINDOWS32
#include <windows.h>
#include <io.h>
#include "sub_proc.h"
void
windows32_openpipe (int *pipedes, int *pid_p, char **command_argv, char **envp)
{
SECURITY_ATTRIBUTES saAttr;
HANDLE hIn;
HANDLE hErr;
HANDLE hChildOutRd;
HANDLE hChildOutWr;
HANDLE hProcess;
saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (DuplicateHandle (GetCurrentProcess(),
GetStdHandle(STD_INPUT_HANDLE),
GetCurrentProcess(),
&hIn,
0,
TRUE,
DUPLICATE_SAME_ACCESS) == FALSE) {
fatal (NILF, _("create_child_process: DuplicateHandle(In) failed (e=%ld)\n"),
GetLastError());
}
if (DuplicateHandle(GetCurrentProcess(),
GetStdHandle(STD_ERROR_HANDLE),
GetCurrentProcess(),
&hErr,
0,
TRUE,
DUPLICATE_SAME_ACCESS) == FALSE) {
fatal (NILF, _("create_child_process: DuplicateHandle(Err) failed (e=%ld)\n"),
GetLastError());
}
if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0))
fatal (NILF, _("CreatePipe() failed (e=%ld)\n"), GetLastError());
hProcess = process_init_fd(hIn, hChildOutWr, hErr);
if (!hProcess)
fatal (NILF, _("windows32_openpipe (): process_init_fd() failed\n"));
sync_Path_environment();
if (!process_begin(hProcess, command_argv, envp, command_argv[0], NULL)) {
process_register(hProcess);
*pid_p = (int) hProcess;
pipedes[0] = _open_osfhandle((long) hChildOutRd, O_RDONLY);
pipedes[1] = _open_osfhandle((long) hChildOutWr, O_APPEND);
} else {
process_cleanup(hProcess);
CloseHandle(hIn);
CloseHandle(hErr);
CloseHandle(hChildOutRd);
CloseHandle(hChildOutWr);
pipedes[0] = pipedes[1] = -1;
*pid_p = -1;
}
}
#endif
#ifdef __MSDOS__
FILE *
msdos_openpipe (int* pipedes, int *pidp, char *text)
{
FILE *fpipe=0;
struct variable *sh = lookup_variable ("SHELL", 5);
int e;
extern int dos_command_running, dos_status;
while (isblank ((unsigned char)*text))
++text;
if (*text == '\0')
return 0;
if (sh)
{
char buf[PATH_MAX + 7];
sprintf (buf, "SHELL=%s", sh->value);
putenv (buf);
}
e = errno;
errno = 0;
dos_command_running = 1;
dos_status = 0;
fpipe = popen (text, "rt");
dos_command_running = 0;
if (!fpipe || dos_status)
{
pipedes[0] = -1;
*pidp = -1;
if (dos_status)
errno = EINTR;
else if (errno == 0)
errno = ENOMEM;
shell_function_completed = -1;
}
else
{
pipedes[0] = fileno (fpipe);
*pidp = 42;
errno = e;
shell_function_completed = 1;
}
return fpipe;
}
#endif
#ifdef VMS
#define func_shell 0
#else
#ifndef _AMIGA
static char *
func_shell (char *o, char **argv, const char *funcname UNUSED)
{
char* batch_filename = NULL;
#ifdef __MSDOS__
FILE *fpipe;
#endif
char **command_argv;
char *error_prefix;
char **envp;
int pipedes[2];
int pid;
#ifndef __MSDOS__
command_argv = construct_command_argv (argv[0],
(char **) NULL, (struct file *) 0,
&batch_filename);
if (command_argv == 0)
return o;
#endif
envp = environ;
if (reading_file && reading_file->filenm)
{
error_prefix = (char *) alloca (strlen (reading_file->filenm)+11+4);
sprintf (error_prefix,
"%s:%lu: ", reading_file->filenm, reading_file->lineno);
}
else
error_prefix = "";
#ifdef WINDOWS32
windows32_openpipe (pipedes, &pid, command_argv, envp);
if (pipedes[0] < 0) {
shell_function_completed = -1;
return o;
} else
#elif defined(__MSDOS__)
fpipe = msdos_openpipe (pipedes, &pid, argv[0]);
if (pipedes[0] < 0)
{
perror_with_name (error_prefix, "pipe");
return o;
}
#else
if (pipe (pipedes) < 0)
{
perror_with_name (error_prefix, "pipe");
return o;
}
# ifdef __EMX__
CLOSE_ON_EXEC(pipedes[1]);
CLOSE_ON_EXEC(pipedes[0]);
pid = child_execute_job (0, pipedes[1], command_argv, envp);
if (pid < 0)
perror_with_name (error_prefix, "spawn");
# else
pid = vfork ();
if (pid < 0)
perror_with_name (error_prefix, "fork");
else if (pid == 0)
child_execute_job (0, pipedes[1], command_argv, envp);
else
# endif
#endif
{
char *buffer;
unsigned int maxlen, i;
int cc;
shell_function_pid = pid;
#ifndef __MSDOS__
shell_function_completed = 0;
free (command_argv[0]);
free ((char *) command_argv);
(void) close (pipedes[1]);
#endif
maxlen = 200;
buffer = (char *) xmalloc (maxlen + 1);
for (i = 0; ; i += cc)
{
if (i == maxlen)
{
maxlen += 512;
buffer = (char *) xrealloc (buffer, maxlen + 1);
}
EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i));
if (cc <= 0)
break;
}
buffer[i] = '\0';
#ifdef __MSDOS__
if (fpipe)
(void) pclose (fpipe);
#else
(void) close (pipedes[0]);
#endif
while (shell_function_completed == 0)
reap_children (1, 0);
if (batch_filename) {
DB (DB_VERBOSE, (_("Cleaning up temporary batch file %s\n"),
batch_filename));
remove (batch_filename);
free (batch_filename);
}
shell_function_pid = 0;
if (shell_function_completed == -1)
{
fputs (buffer, stderr);
fflush (stderr);
}
else
{
fold_newlines (buffer, &i);
o = variable_buffer_output (o, buffer, i);
}
free (buffer);
}
return o;
}
#else
static char *
func_shell (char *o, char **argv, const char *funcname)
{
#include <dos/dos.h>
#include <proto/dos.h>
BPTR child_stdout;
char tmp_output[FILENAME_MAX];
unsigned int maxlen = 200, i;
int cc;
char * buffer, * ptr;
char ** aptr;
int len = 0;
char* batch_filename = NULL;
command_argv = construct_command_argv (argv[0], (char **) NULL,
(struct file *) 0, &batch_filename);
if (command_argv == 0)
return o;
strcpy (tmp_output, "t:MakeshXXXXXXXX");
mktemp (tmp_output);
child_stdout = Open (tmp_output, MODE_NEWFILE);
for (aptr=command_argv; *aptr; aptr++)
len += strlen (*aptr) + 1;
buffer = xmalloc (len + 1);
ptr = buffer;
for (aptr=command_argv; *aptr; aptr++)
{
strcpy (ptr, *aptr);
ptr += strlen (ptr) + 1;
*ptr ++ = ' ';
*ptr = 0;
}
ptr[-1] = '\n';
Execute (buffer, NULL, child_stdout);
free (buffer);
Close (child_stdout);
child_stdout = Open (tmp_output, MODE_OLDFILE);
buffer = xmalloc (maxlen);
i = 0;
do
{
if (i == maxlen)
{
maxlen += 512;
buffer = (char *) xrealloc (buffer, maxlen + 1);
}
cc = Read (child_stdout, &buffer[i], maxlen - i);
if (cc > 0)
i += cc;
} while (cc > 0);
Close (child_stdout);
fold_newlines (buffer, &i);
o = variable_buffer_output (o, buffer, i);
free (buffer);
return o;
}
#endif
#endif
#ifdef EXPERIMENTAL
static char *
func_eq (char *o, char **argv, char *funcname)
{
int result = ! strcmp (argv[0], argv[1]);
o = variable_buffer_output (o, result ? "1" : "", result);
return o;
}
static char *
func_not (char *o, char **argv, char *funcname)
{
char *s = argv[0];
int result = 0;
while (isspace ((unsigned char)*s))
s++;
result = ! (*s);
o = variable_buffer_output (o, result ? "1" : "", result);
return o;
}
#endif
static char *
abspath (const char *name, char *apath)
{
char *dest;
const char *start, *end, *apath_limit;
if (name[0] == '\0' || apath == NULL)
return NULL;
apath_limit = apath + GET_PATH_MAX;
if (name[0] != '/')
{
if (!starting_directory)
return NULL;
strcpy (apath, starting_directory);
dest = strchr (apath, '\0');
}
else
{
apath[0] = '/';
dest = apath + 1;
}
for (start = end = name; *start != '\0'; start = end)
{
unsigned long len;
while (*start == '/')
++start;
for (end = start; *end != '\0' && *end != '/'; ++end)
;
len = end - start;
if (len == 0)
break;
else if (len == 1 && start[0] == '.')
;
else if (len == 2 && start[0] == '.' && start[1] == '.')
{
if (dest > apath + 1)
while ((--dest)[-1] != '/');
}
else
{
if (dest[-1] != '/')
*dest++ = '/';
if (dest + len >= apath_limit)
return NULL;
dest = memcpy (dest, start, len);
dest += len;
*dest = '\0';
}
}
if (dest > apath + 1 && dest[-1] == '/')
--dest;
*dest = '\0';
return apath;
}
static char *
func_realpath (char *o, char **argv, const char *funcname UNUSED)
{
char *p = argv[0];
char *path = 0;
int doneany = 0;
unsigned int len = 0;
PATH_VAR (in);
PATH_VAR (out);
while ((path = find_next_token (&p, &len)) != 0)
{
if (len < GET_PATH_MAX)
{
strncpy (in, path, len);
in[len] = '\0';
if
(
#ifdef HAVE_REALPATH
realpath (in, out)
#else
abspath (in, out)
#endif
)
{
o = variable_buffer_output (o, out, strlen (out));
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
}
}
if (doneany)
--o;
return o;
}
static char *
func_abspath (char *o, char **argv, const char *funcname UNUSED)
{
char *p = argv[0];
char *path = 0;
int doneany = 0;
unsigned int len = 0;
PATH_VAR (in);
PATH_VAR (out);
while ((path = find_next_token (&p, &len)) != 0)
{
if (len < GET_PATH_MAX)
{
strncpy (in, path, len);
in[len] = '\0';
if (abspath (in, out))
{
o = variable_buffer_output (o, out, strlen (out));
o = variable_buffer_output (o, " ", 1);
doneany = 1;
}
}
}
if (doneany)
--o;
return o;
}
static char *func_call PARAMS ((char *o, char **argv, const char *funcname));
static struct function_table_entry function_table_init[] =
{
{ STRING_SIZE_TUPLE("abspath"), 0, 1, 1, func_abspath},
{ STRING_SIZE_TUPLE("addprefix"), 2, 2, 1, func_addsuffix_addprefix},
{ STRING_SIZE_TUPLE("addsuffix"), 2, 2, 1, func_addsuffix_addprefix},
{ STRING_SIZE_TUPLE("basename"), 0, 1, 1, func_basename_dir},
{ STRING_SIZE_TUPLE("dir"), 0, 1, 1, func_basename_dir},
{ STRING_SIZE_TUPLE("notdir"), 0, 1, 1, func_notdir_suffix},
{ STRING_SIZE_TUPLE("subst"), 3, 3, 1, func_subst},
{ STRING_SIZE_TUPLE("suffix"), 0, 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"), 0, 1, 1, func_firstword},
{ STRING_SIZE_TUPLE("flavor"), 0, 1, 1, func_flavor},
{ STRING_SIZE_TUPLE("join"), 2, 2, 1, func_join},
{ STRING_SIZE_TUPLE("lastword"), 0, 1, 1, func_lastword},
{ STRING_SIZE_TUPLE("patsubst"), 3, 3, 1, func_patsubst},
{ STRING_SIZE_TUPLE("realpath"), 0, 1, 1, func_realpath},
{ STRING_SIZE_TUPLE("shell"), 0, 1, 1, func_shell},
{ STRING_SIZE_TUPLE("sort"), 0, 1, 1, func_sort},
{ STRING_SIZE_TUPLE("strip"), 0, 1, 1, func_strip},
{ STRING_SIZE_TUPLE("wildcard"), 0, 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"), 0, 1, 1, func_words},
{ STRING_SIZE_TUPLE("origin"), 0, 1, 1, func_origin},
{ STRING_SIZE_TUPLE("foreach"), 3, 3, 0, func_foreach},
{ STRING_SIZE_TUPLE("call"), 1, 0, 1, func_call},
{ STRING_SIZE_TUPLE("info"), 0, 1, 1, func_error},
{ STRING_SIZE_TUPLE("error"), 0, 1, 1, func_error},
{ STRING_SIZE_TUPLE("warning"), 0, 1, 1, func_error},
{ STRING_SIZE_TUPLE("if"), 2, 3, 0, func_if},
{ STRING_SIZE_TUPLE("or"), 1, 0, 0, func_or},
{ STRING_SIZE_TUPLE("and"), 1, 0, 0, func_and},
{ STRING_SIZE_TUPLE("value"), 0, 1, 1, func_value},
{ STRING_SIZE_TUPLE("eval"), 0, 1, 1, func_eval},
#ifdef EXPERIMENTAL
{ STRING_SIZE_TUPLE("eq"), 2, 2, 1, func_eq},
{ STRING_SIZE_TUPLE("not"), 0, 1, 1, func_not},
#endif
};
#define FUNCTION_TABLE_ENTRIES (sizeof (function_table_init) / sizeof (struct function_table_entry))
static char *
expand_builtin_function (char *o, int argc, char **argv,
const struct function_table_entry *entry_p)
{
if (argc < (int)entry_p->minimum_args)
fatal (*expanding_var,
_("insufficient number of arguments (%d) to function `%s'"),
argc, entry_p->name);
if (!argc)
return o;
if (!entry_p->func_ptr)
fatal (*expanding_var,
_("unimplemented on this platform: function `%s'"), entry_p->name);
return entry_p->func_ptr (o, argv, entry_p->name);
}
int
handle_function (char **op, char **stringp)
{
const struct function_table_entry *entry_p;
char openparen = (*stringp)[0];
char closeparen = openparen == '(' ? ')' : '}';
char *beg;
char *end;
int count = 0;
register char *p;
char **argv, **argvp;
int nargs;
beg = *stringp + 1;
entry_p = lookup_function (beg);
if (!entry_p)
return 0;
beg = next_token (beg + entry_p->len);
for (nargs=1, end=beg; *end != '\0'; ++end)
if (*end == ',')
++nargs;
else if (*end == openparen)
++count;
else if (*end == closeparen && --count < 0)
break;
if (count >= 0)
fatal (*expanding_var,
_("unterminated call to function `%s': missing `%c'"),
entry_p->name, closeparen);
*stringp = end;
argvp = argv = (char **) alloca (sizeof (char *) * (nargs + 2));
if (!entry_p->expand_args)
{
int len = end - beg;
p = xmalloc (len+1);
memcpy (p, beg, len);
p[len] = '\0';
beg = p;
end = beg + len;
}
for (p=beg, nargs=0; p <= end; ++argvp)
{
char *next;
++nargs;
if (nargs == entry_p->maximum_args
|| (! (next = find_next_argument (openparen, closeparen, p, end))))
next = end;
if (entry_p->expand_args)
*argvp = expand_argument (p, next);
else
{
*argvp = p;
*next = '\0';
}
p = next + 1;
}
*argvp = NULL;
*op = expand_builtin_function (*op, nargs, argv, entry_p);
if (entry_p->expand_args)
for (argvp=argv; *argvp != 0; ++argvp)
free (*argvp);
else
free (beg);
return 1;
}
static char *
func_call (char *o, char **argv, const char *funcname UNUSED)
{
static int max_args = 0;
char *fname;
char *cp;
char *body;
int flen;
int i;
int saved_args;
const struct function_table_entry *entry_p;
struct variable *v;
fname = argv[0];
while (*fname != '\0' && isspace ((unsigned char)*fname))
++fname;
cp = fname + strlen (fname) - 1;
while (cp > fname && isspace ((unsigned char)*cp))
--cp;
cp[1] = '\0';
if (*fname == '\0')
return o;
entry_p = lookup_function (fname);
if (entry_p)
{
for (i=0; argv[i+1]; ++i)
;
return expand_builtin_function (o, i, argv+1, entry_p);
}
flen = strlen (fname);
v = lookup_variable (fname, flen);
if (v == 0)
warn_undefined (fname, flen);
if (v == 0 || *v->value == '\0')
return o;
body = (char *) alloca (flen + 4);
body[0] = '$';
body[1] = '(';
memcpy (body + 2, fname, flen);
body[flen+2] = ')';
body[flen+3] = '\0';
push_new_variable_scope ();
for (i=0; *argv; ++i, ++argv)
{
char num[11];
sprintf (num, "%d", i);
define_variable (num, strlen (num), *argv, o_automatic, 0);
}
for (; i < max_args; ++i)
{
char num[11];
sprintf (num, "%d", i);
define_variable (num, strlen (num), "", o_automatic, 0);
}
v->exp_count = EXP_COUNT_MAX;
saved_args = max_args;
max_args = i;
o = variable_expand_string (o, body, flen+3);
max_args = saved_args;
v->exp_count = 0;
pop_variable_scope ();
return o + strlen (o);
}
void
hash_init_function_table (void)
{
hash_init (&function_table, FUNCTION_TABLE_ENTRIES * 2,
function_table_entry_hash_1, function_table_entry_hash_2,
function_table_entry_hash_cmp);
hash_load (&function_table, function_table_init,
FUNCTION_TABLE_ENTRIES, sizeof (struct function_table_entry));
}