#include "config.h"
#if defined (BRACE_EXPANSION)
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "bashansi.h"
#if defined (SHELL)
# include "shell.h"
#endif
#include "general.h"
#include "shmbutil.h"
#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
int brace_arg_separator = ',';
#if defined (__P)
static int brace_gobbler __P((char *, size_t, int *, int));
static char **expand_amble __P((char *, size_t));
static char **array_concat __P((char **, char **));
#else
static int brace_gobbler ();
static char **expand_amble ();
static char **array_concat ();
#endif
char **
brace_expand (text)
char *text;
{
register int start;
size_t tlen;
char *preamble, *postamble, *amble;
size_t alen;
char **tack, **result;
int i, j, c;
DECLARE_MBSTATE;
tlen = strlen (text);
i = 0;
c = brace_gobbler (text, tlen, &i, '{');
preamble = (char *)xmalloc (i + 1);
strncpy (preamble, text, i);
preamble[i] = '\0';
result = (char **)xmalloc (2 * sizeof (char *));
result[0] = preamble;
result[1] = (char *)NULL;
if (c != '{')
return (result);
start = ++i;
c = brace_gobbler (text, tlen, &i, '}');
if (c == 0)
{
#if defined (NOTDEF)
j = start;
while (j < i)
{
if (text[j] == '\\')
{
j++;
ADVANCE_CHAR (text, tlen, j);
continue;
}
if (text[j] == brace_arg_separator)
{
strvec_dispose (result);
report_error ("missing `}'");
throw_to_top_level ();
}
ADVANCE_CHAR (text, tlen, j);
}
#endif
free (preamble);
result[0] = savestring (text);
return (result);
}
#if defined (SHELL)
amble = substring (text, start, i);
alen = i - start;
#else
amble = (char *)xmalloc (1 + (i - start));
strncpy (amble, &text[start], (i - start));
alen = i - start;
amble[alen] = '\0';
#endif
#if defined (SHELL)
INITIALIZE_MBSTATE;
j = 0;
while (amble[j])
{
if (amble[j] == '\\')
{
j++;
ADVANCE_CHAR (amble, alen, j);
continue;
}
if (amble[j] == brace_arg_separator)
break;
ADVANCE_CHAR (amble, alen, j);
}
if (!amble[j])
{
free (amble);
free (preamble);
result[0] = savestring (text);
return (result);
}
#endif
postamble = &text[i + 1];
tack = expand_amble (amble, alen);
result = array_concat (result, tack);
free (amble);
strvec_dispose (tack);
tack = brace_expand (postamble);
result = array_concat (result, tack);
strvec_dispose (tack);
return (result);
}
static char **
expand_amble (text, tlen)
char *text;
size_t tlen;
{
char **result, **partial;
char *tem;
int start, i, c;
DECLARE_MBSTATE;
result = (char **)NULL;
start = i = 0;
c = 1;
while (c)
{
c = brace_gobbler (text, tlen, &i, brace_arg_separator);
#if defined (SHELL)
tem = substring (text, start, i);
#else
tem = (char *)xmalloc (1 + (i - start));
strncpy (tem, &text[start], (i - start));
tem[i- start] = '\0';
#endif
partial = brace_expand (tem);
if (!result)
result = partial;
else
{
register int lr = strvec_len (result);
register int lp = strvec_len (partial);
register int j;
result = strvec_resize (result, lp + lr + 1);
for (j = 0; j < lp; j++)
result[lr + j] = partial[j];
result[lr + j] = (char *)NULL;
free (partial);
}
free (tem);
ADVANCE_CHAR (text, tlen, i);
start = i;
}
return (result);
}
static int
brace_gobbler (text, tlen, indx, satisfy)
char *text;
size_t tlen;
int *indx;
int satisfy;
{
register int i, c, quoted, level, pass_next;
#if defined (SHELL)
int si;
char *t;
#endif
DECLARE_MBSTATE;
level = quoted = pass_next = 0;
i = *indx;
while (c = text[i])
{
if (pass_next)
{
pass_next = 0;
ADVANCE_CHAR (text, tlen, i);
continue;
}
if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
{
pass_next = 1;
i++;
continue;
}
if (quoted)
{
if (c == quoted)
quoted = 0;
ADVANCE_CHAR (text, tlen, i);
continue;
}
if (c == '"' || c == '\'' || c == '`')
{
quoted = c;
i++;
continue;
}
#if defined (SHELL)
if (c == '$' && text[i+1] == '(')
{
si = i + 2;
t = extract_command_subst (text, &si);
i = si;
free (t);
i++;
continue;
}
#endif
if (c == satisfy && level == 0 && quoted == 0)
{
if (c == '{' &&
((!i || brace_whitespace (text[i - 1])) &&
(brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
{
i++;
continue;
}
#if defined (SHELL)
if ((c != '{') || i == 0 || (text[i - 1] != '$'))
#endif
break;
}
if (c == '{')
level++;
else if (c == '}' && level)
level--;
ADVANCE_CHAR (text, tlen, i);
}
*indx = i;
return (c);
}
static char **
array_concat (arr1, arr2)
char **arr1, **arr2;
{
register int i, j, len, len1, len2;
register char **result;
if (arr1 == 0)
return (strvec_copy (arr2));
if (arr2 == 0)
return (strvec_copy (arr1));
len1 = strvec_len (arr1);
len2 = strvec_len (arr2);
result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
len = 0;
for (i = 0; i < len1; i++)
{
int strlen_1 = strlen (arr1[i]);
for (j = 0; j < len2; j++)
{
result[len] =
(char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
strcpy (result[len], arr1[i]);
strcpy (result[len] + strlen_1, arr2[j]);
len++;
}
free (arr1[i]);
}
free (arr1);
result[len] = (char *)NULL;
return (result);
}
#if defined (TEST)
#include <stdio.h>
fatal_error (format, arg1, arg2)
char *format, *arg1, *arg2;
{
report_error (format, arg1, arg2);
exit (1);
}
report_error (format, arg1, arg2)
char *format, *arg1, *arg2;
{
fprintf (stderr, format, arg1, arg2);
fprintf (stderr, "\n");
}
main ()
{
char example[256];
for (;;)
{
char **result;
int i;
fprintf (stderr, "brace_expand> ");
if ((!fgets (example, 256, stdin)) ||
(strncmp (example, "quit", 4) == 0))
break;
if (strlen (example))
example[strlen (example) - 1] = '\0';
result = brace_expand (example);
for (i = 0; result[i]; i++)
printf ("%s\n", result[i]);
free_array (result);
}
}
#endif
#endif