#include "irc.h"
#include <math.h>
#undef PANA_EXP
#undef PANA_EXP1
static void TruncateAndQuote(char **, const char *, int, const char *, char);
static void do_alias_string (char *, char *);
char *alias_string = NULL;
static char *canon_number (char *input)
{
int end = strlen(input);
if (end)
end--;
else
return input;
if (get_int_var(FLOATING_POINT_MATH_VAR))
{
while (input[end] == '0')
end--;
if (input[end] == '.')
end--;
input[end+1] = 0;
}
else
{
char *dot = strchr(input, '.');
if (dot)
*dot = 0;
}
return input;
}
static char *lastop (char *ptr)
{
while (ptr[1] && strchr("!=<>&^|#+/%,-* ", ptr[1]))
ptr++;
return ptr;
}
#define NU_EXPR 0
#define NU_ASSN 1
#define NU_TERT 2
#define NU_CONJ 3
#define NU_BITW 4
#define NU_COMP 5
#define NU_ADD 6
#define NU_MULT 7
#define NU_UNIT 8
char *BX_next_unit (char *str, const char *args, int *arg_flag, int stage)
{
register char *ptr;
char *ptr2,
*right,
*lastc,
*tmp = NULL,
op;
int got_sloshed = 0,
display;
char *result1 = NULL,
*result2 = NULL,
*varname = NULL;
long value1 = 0,
value2 = 0,
value3 = 0;
double dvalue1 = 0.0,
dvalue2 = 0.0,
dvalue3 = 0.0;
#ifdef PANA_EXP
union
{
char s[4];
unsigned long t;
} strlong;
#endif
#define SETUP_IMPLIED(var1, var2, func) \
{ \
\
op = *ptr; \
*ptr++ = '\0'; \
ptr++; \
\
\
varname = expand_alias(str, args, arg_flag, NULL); \
lastc = varname + strlen(varname) - 1; \
while (lastc > varname && *lastc == ' ') \
*lastc-- = '\0'; \
while (my_isspace(*varname)) \
varname++; \
\
\
result1 = get_variable(varname); \
var1 = (result1 && *result1) ? func (result1) : 0; \
new_free(&result1); \
\
\
result2 = next_unit(ptr, args, arg_flag, stage); \
var2 = func (result2); \
new_free(&result2); \
}
#define CLEANUP_IMPLIED() \
{ \
\
if (ptr[-1] == '=' && stage == NU_ASSN) \
{ \
\
display = window_display; \
window_display = 0; \
\
\
if (*varname) \
add_var_alias(varname, tmp); \
else \
debugyell("Invalid assignment: No lvalue"); \
\
\
window_display = display; \
} \
new_free(&varname); \
}
#define SETUP_BINARY(var1, var2, func) \
{ \
\
op = *ptr; \
*ptr++ = '\0'; \
\
\
result1 = next_unit(str, args, arg_flag, stage); \
result2 = next_unit(ptr, args, arg_flag, stage); \
\
\
var1 = func (result1); \
var2 = func (result2); \
\
\
new_free(&result1); \
new_free(&result2); \
}
#define SETUP(var1, var2, func, STAGE) \
{ \
\
if (ptr[1] == '=' && stage == NU_ASSN) \
SETUP_IMPLIED(var1, var2, func) \
\
\
else if (ptr[1] != '=' && stage == STAGE) \
SETUP_BINARY(var1, var2, func) \
\
\
else \
{ \
ptr = lastop(ptr); \
break; \
} \
}
#define SETUP_FLOAT_OPERATION(STAGE) \
SETUP(dvalue1, dvalue2, atof, STAGE)
#define SETUP_INTEGER_OPERATION(STAGE) \
SETUP(value1, value2, my_atol, STAGE)
while (my_isspace(*str))
++str;
if (!*str)
return m_strdup(empty_string);
if ((lastc = str+strlen(str)) > str)
lastc--;
while (my_isspace(*lastc))
*lastc-- = '\0';
if (!args)
args = empty_string;
if (stage == NU_UNIT && *lastc == ')' && *str == '(')
{
str++, *lastc-- = '\0';
return next_unit(str, args, arg_flag, NU_EXPR);
}
for (ptr = str; *ptr; ptr++)
{
if (got_sloshed)
{
got_sloshed = 0;
continue;
}
switch(*ptr)
{
case '\\':
{
got_sloshed = 1;
continue;
}
case '(':
{
int savec = 0;
if (stage != NU_UNIT || ptr == str)
{
if (!(ptr2 = MatchingBracket(ptr+1, '(', ')')))
ptr = ptr + strlen(ptr) - 1;
else
{
#ifdef PANA_EXP1
if ((ptr+1) == ptr2 && stage > NU_ASSN)
stage = NU_UNIT-1;
#endif
ptr = ptr2;
}
break;
}
if ((ptr2 = MatchingBracket(ptr + 1, '(', ')')))
{
ptr2++;
savec = *ptr2;
*ptr2 = 0;
}
result1 = call_function(str, args, arg_flag);
if (savec)
*ptr2 = savec;
if (ptr && *ptr)
{
malloc_strcat(&result1, ptr);
result2 = next_unit(result1, args, arg_flag, stage);
new_free(&result1);
result1 = result2;
}
return result1;
}
case '{':
{
display = window_display;
ptr2 = MatchingBracket(ptr + 1, LEFT_BRACE, RIGHT_BRACE);
if (!ptr2)
ptr2 = ptr + strlen(ptr) - 1;
if (stage != NU_UNIT)
{
ptr = ptr2;
break;
}
*ptr2++ = 0;
*ptr++ = 0;
make_local_stack(NULL);
window_display = 0;
add_local_alias("FUNCTION_RETURN", empty_string);
window_display = display;
will_catch_return_exceptions++;
parse_line(NULL, ptr, args, 0, 1, 1);
will_catch_return_exceptions--;
return_exception = 0;
result1 = get_variable("FUNCTION_RETURN");
destroy_local_stack();
if (!result1)
result1 = m_strdup(empty_string);
return result1;
}
case '[':
{
#ifdef PANA_EXP
int got_it = 0;
#endif
if (stage != NU_UNIT)
{
if (!(ptr2 = MatchingBracket(ptr+1, LEFT_BRACKET, RIGHT_BRACKET)))
ptr = ptr+strlen(ptr)-1;
else
{
#ifdef PANA_EXP1
if ((ptr+1) == ptr2 && stage > NU_ASSN)
stage = NU_UNIT-1;
#endif
ptr = ptr2;
}
break;
}
#ifdef PANA_EXP
strlong.t = 0;
{
#if 0
<hop> if little endian is ABCD and big endian is DCBA
<hop> ive heard of middle enddian which is CDAB
#endif
memcpy(&strlong.t, ptr, 4);
if ((strlong.t & 0xfff0ffff) == 0x5d30245b)
{
unsigned int k;
if (!(k = ((strlong.t & 0x000f0000) >> 16) & 0x07))
{
result1 = extract2(args, k, k);
got_it = *arg_flag = 1;
*ptr = 0;
ptr = ptr + 4;
}
}
}
if (!got_it)
#endif
{
*ptr++ = '\0';
right = ptr;
if ((ptr = MatchingBracket(right, LEFT_BRACKET, RIGHT_BRACKET)))
*ptr++ = '\0';
#ifndef NO_CHEATING
if (*right == '$')
{
char *end = NULL;
long j = strtol(right + 1, &end, 10);
if (end && !*end)
{
if (j < 0)
result1 = extract2(args, SOS, -j);
else
result1 = extract2(args, j, j);
*arg_flag = 1;
}
else if (*end == '-' && !end[1])
{
result1 = extract2(args, j, EOS);
*arg_flag = 1;
}
else
result1 = expand_alias(right, args, arg_flag, NULL);
}
else if (!strchr(right, '$') && !strchr(right, '\\'))
result1 = m_strdup(right);
else
#endif
result1 = expand_alias(right, args, arg_flag, NULL);
}
if (*str)
{
int size = strlen(str) + (result1 ? strlen(result1) : 0) + (ptr ? strlen(ptr) : 0) + 2;
result2 = alloca(size);
strcpy(result2, str);
strcat(result2, ".");
strcat(result2, result1);
new_free(&result1);
if (ptr && *ptr)
{
strcat(result2, ptr);
result1 = next_unit(result2, args, arg_flag, stage);
}
else
{
if (!(result1 = get_variable(result2)))
malloc_strcpy(&result1, empty_string);
}
}
else if (ptr && *ptr)
{
malloc_strcat(&result1, ptr);
result2 = next_unit(result1, args, arg_flag, stage);
new_free(&result1);
result1 = result2;
}
if (!*result1)
malloc_strcpy(&result1, empty_string);
return result1;
}
case '-':
#if 0
if (ptr[1] && (ptr[1] == '>'))
{
char *ptr3;
char savec;
varname = str, *ptr = 0;
ptr++; ptr++;
if (!*ptr)
break;
if ((ptr3 = MatchingBracket(varname + 1, '(', ')')))
{
ptr3++;
savec = *ptr3;
*ptr3 = 0;
}
if (!(ptr2 = lookup_member(varname, ptr3, ptr, args)))
break;
}
#endif
case '+':
{
if (ptr[1] == ptr[0])
{
int prefix;
long r;
if (stage != NU_UNIT)
{
ptr++;
break;
}
if (ptr == str)
prefix = 1, ptr2 = ptr + 2;
else
prefix = 0, ptr2 = str, *ptr++ = 0;
varname = expand_alias(ptr2, args, arg_flag, NULL);
upper(varname);
if (!(result1 = get_variable(varname)))
malloc_strcpy(&result1,zero);
r = my_atol(result1);
if (*ptr == '+')
r++;
else
r--;
display = window_display;
window_display = 0;
add_var_alias(varname,ltoa(r));
window_display = display;
if (!prefix)
r--;
new_free(&result1);
new_free(&varname);
return m_strdup(ltoa(r));
}
else if (ptr == str)
break;
#if 0
if (get_int_var(FLOATING_POINT_MATH_VAR))
#endif
{
SETUP_FLOAT_OPERATION(NU_ADD)
if (op == '-')
dvalue3 = dvalue1 - dvalue2;
else
dvalue3 = dvalue1 + dvalue2;
tmp = m_sprintf("%f", dvalue3);
canon_number(tmp);
}
#if 0
else
{
SETUP_INTEGER_OPERATION(NU_ADD)
if (op == '-')
value3 = value1 - value2;
else
value3 = value1 + value2;
tmp = m_strdup(ltoa(value3));
}
#endif
CLEANUP_IMPLIED()
return tmp;
}
case '/':
case '*':
case '%':
{
if (ptr == str)
break;
dvalue3 = 0.0;
if (ptr[0] == '*' && ptr[1] == '*' && stage == NU_MULT)
{
*ptr++ = '\0';
SETUP_BINARY(dvalue1, dvalue2, atof)
return m_sprintf("%f", pow(dvalue1, dvalue2));
}
SETUP_FLOAT_OPERATION(NU_MULT)
if (op == '*')
dvalue3 = dvalue1 * dvalue2;
else
{
if (dvalue2 == 0.0)
debugyell("Division by zero!");
else if (op == '/')
dvalue3 = dvalue1 / dvalue2;
else
dvalue3 = (int)dvalue1 % (int)dvalue2;
}
tmp = m_sprintf("%f", dvalue3);
canon_number(tmp);
CLEANUP_IMPLIED()
return tmp;
}
case '#':
{
if (ptr[1] == '#' && stage == NU_ADD)
{
*ptr++ = '\0';
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
malloc_strcat(&result1, result2);
new_free(&result2);
return result1;
}
else if (ptr[1] == '~' && stage == NU_ASSN)
{
char *sval1, *sval2;
ptr[1] = '=';
SETUP_IMPLIED(sval1, sval2, m_strdup);
malloc_strcat(&sval2, sval1);
new_free(&sval1);
tmp = sval2;
CLEANUP_IMPLIED()
return sval2;
}
else if (ptr[1] == '=' && stage == NU_ASSN)
{
char *sval1, *sval2;
SETUP_IMPLIED(sval1, sval2, m_strdup)
malloc_strcat(&sval1, sval2);
new_free(&sval2);
tmp = sval1;
CLEANUP_IMPLIED()
return sval1;
}
else
{
ptr = lastop(ptr);
break;
}
}
case '&':
{
if (ptr[0] == ptr[1] && stage == NU_CONJ)
{
*ptr++ = '\0';
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
if (check_val(result1))
{
result2 = next_unit(ptr, args, arg_flag, stage);
value3 = check_val(result2);
}
else
value3 = 0;
new_free(&result1);
new_free(&result2);
return m_strdup(value3 ? one : zero);
}
else if (ptr[1] == '=' && stage == NU_ASSN)
{
SETUP_IMPLIED(value1, value2, my_atol)
value1 &= value2;
tmp = m_strdup(ltoa(value1));
CLEANUP_IMPLIED();
return tmp;
}
else if (ptr[1] != ptr[0] && ptr[1] != '=' && stage == NU_BITW)
{
SETUP_BINARY(value1, value2, my_atol)
return m_strdup(ltoa(value1 & value2));
}
else
{
ptr = lastop(ptr);
break;
}
}
case '|':
{
if (ptr[0] == ptr[1] && stage == NU_CONJ)
{
*ptr++ = '\0';
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
if (!check_val(result1))
{
result2 = next_unit(ptr, args, arg_flag, stage);
value3 = check_val(result2);
}
else
value3 = 1;
new_free(&result1);
new_free(&result2);
return m_strdup(value3 ? one : zero);
}
else if (ptr[1] == '=' && stage == NU_ASSN)
{
SETUP_IMPLIED(value1, value2, my_atol)
value1 |= value2;
tmp = m_strdup(ltoa(value1));
CLEANUP_IMPLIED();
return tmp;
}
else if (ptr[1] != ptr[0] && ptr[1] != '=' && stage != NU_BITW)
{
SETUP_BINARY(value1, value2, my_atol)
return m_strdup(ltoa(value1 | value2));
}
else
{
ptr = lastop(ptr);
break;
}
}
case '^':
{
if (ptr[0] == ptr[1] && stage == NU_CONJ)
{
*ptr++ = '\0';
ptr++;
value1 = check_val((result1 = next_unit(str, args, arg_flag, stage)));
value2 = check_val((result2 = next_unit(ptr, args, arg_flag, stage)));
new_free(&result1);
new_free(&result2);
return m_strdup((value1 ^ value2) ? one : zero);
}
else if (ptr[1] == '=' && stage == NU_ASSN)
{
SETUP_IMPLIED(value1, value2, my_atol)
value1 ^= value2;
tmp = m_strdup(ltoa(value1));
CLEANUP_IMPLIED();
return tmp;
}
else if (ptr[1] != ptr[0] && ptr[1] != '=' && stage == NU_BITW)
{
SETUP_BINARY(value1, value2, my_atol)
return m_strdup(ltoa(value1 ^ value2));
}
else
{
ptr = lastop(ptr);
break;
}
}
case '?':
{
if (stage == NU_TERT)
{
*ptr++ = '\0';
result1 = next_unit(str, args, arg_flag, stage);
ptr2 = MatchingBracket(ptr, '?', ':');
if (!ptr2)
{
ptr = lastop(ptr);
break;
}
*ptr2++ = '\0';
if ( check_val(result1) )
result2 = next_unit(ptr, args, arg_flag, stage);
else
result2 = next_unit(ptr2, args, arg_flag, stage);
ptr2[-1] = ':';
new_free(&result1);
return result2;
}
else
{
ptr = lastop(ptr);
break;
}
}
case '=':
{
if (ptr[1] == '~' && stage == NU_COMP)
{
*ptr++ = 0;
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
if (wild_match(result2, result1))
malloc_strcpy(&result1, one);
else
malloc_strcpy(&result1, zero);
new_free(&result2);
return result1;
}
if (ptr[1] != '=' && ptr[1] != '~' && stage == NU_ASSN)
{
*ptr++ = '\0';
upper(str);
result1 = expand_alias(str, args, arg_flag, NULL);
result2 = next_unit(ptr, args, arg_flag, stage);
lastc = result1 + strlen(result1) - 1;
while (lastc > result1 && *lastc == ' ')
*lastc-- = '\0';
for (varname = result1; my_isspace(*varname);)
varname++;
display = window_display;
window_display = 0;
upper(varname);
if (*varname)
add_var_alias(varname, result2);
else
debugyell("Invalid assignment: no lvalue");
window_display = display;
new_free(&result1);
return result2;
}
else if (ptr[1] == '=' && stage == NU_COMP)
{
*ptr++ = '\0';
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
if (!my_stricmp(result1, result2))
malloc_strcpy(&result1, one);
else
malloc_strcpy(&result1, zero);
new_free(&result2);
return result1;
}
else
{
ptr = lastop(ptr);
break;
}
}
case '>':
case '<':
{
if (ptr[1] == ptr[0] && stage == NU_BITW)
{
op = *ptr;
*ptr++ = 0;
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
value1 = my_atol(result1);
value2 = my_atol(result2);
if (op == '>')
value3 = value1 >> value2;
else
value3 = value1 << value2;
new_free(&result1);
new_free(&result2);
return m_strdup(ltoa(value3));
break;
}
else if (ptr[1] != ptr[0] && stage == NU_COMP)
{
op = *ptr;
if (ptr[1] == '=')
value3 = 1, *ptr++ = '\0';
else
value3 = 0;
*ptr++ = '\0';
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
if ((my_isdigit(result1)) && (my_isdigit(result2)))
{
dvalue1 = atof(result1);
dvalue2 = atof(result2);
value1 = (dvalue1 == dvalue2) ? 0 : ((dvalue1 < dvalue2) ? -1 : 1);
}
else
value1 = my_stricmp(result1, result2);
if (value1)
{
value2 = (value1 > 0) ? 1 : 0;
if (op == '<')
value2 = 1 - value2;
}
else
value2 = value3;
new_free(&result1);
new_free(&result2);
return m_strdup(ltoa(value2));
}
else
{
ptr = lastop(ptr);
break;
}
}
case '~':
{
if (ptr == str && stage == NU_UNIT)
{
result1 = next_unit(str+1, args, arg_flag, stage);
if (isdigit((unsigned char)*result1))
value1 = ~my_atol(result1);
else
value1 = 0;
return m_strdup(ltoa(value1));
}
else
{
ptr = lastop(ptr);
break;
}
}
case '!':
{
if (ptr == str && stage == NU_UNIT)
{
result1 = next_unit(str+1, args, arg_flag, stage);
if (my_isdigit(result1))
{
value1 = my_atol(result1);
value2 = value1 ? 0 : 1;
}
else
value2 = ((*result1)?0:1);
new_free(&result1);
return m_strdup(ltoa(value2));
}
else if (ptr != str && ptr[1] == '~' && stage == NU_COMP)
{
*ptr++ = 0;
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
if (!wild_match(result2, result1))
malloc_strcpy(&result1, one);
else
malloc_strcpy(&result1, zero);
new_free(&result2);
return result1;
}
else if (ptr != str && ptr[1] == '=' && stage == NU_COMP)
{
*ptr++ = '\0';
ptr++;
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
if (!my_stricmp(result1, result2))
malloc_strcpy(&result1, zero);
else
malloc_strcpy(&result1, one);
new_free(&result2);
return result1;
}
else
{
ptr = lastop(ptr);
break;
}
}
case ',':
{
if (stage == NU_EXPR)
{
*ptr++ = '\0';
result1 = next_unit(str, args, arg_flag, stage);
result2 = next_unit(ptr, args, arg_flag, stage);
new_free(&result1);
return result2;
}
else
{
ptr = lastop(ptr);
break;
}
}
}
}
if (stage != NU_UNIT)
return next_unit(str, args, arg_flag, stage + 1);
if (my_isdigit(str))
return m_strdup(str);
if (*str == '#' || *str == '@')
op = *str++;
else
op = '\0';
if (!*str)
result1 = m_strdup(args);
else if (!(result1 = get_variable(str)))
return m_strdup(empty_string);
if (op)
{
if (op == '#')
value1 = word_count(result1);
else if (op == '@')
value1 = strlen(result1);
new_free(&result1);
return m_strdup(ltoa(value1));
}
return result1;
}
char *BX_parse_inline(char *str, const char *args, int *args_flag)
{
#ifndef WINNT
if (x_debug & DEBUG_NEW_MATH)
return matheval(str, args, args_flag);
else
#endif
return next_unit(str, args, args_flag, NU_EXPR);
}
char *BX_expand_alias (const char *string, const char *args, int *args_flag, char **more_text)
{
char *buffer = NULL,
*ptr,
*stuff = NULL,
*free_stuff,
*quote_str = NULL;
char quote_temp[2];
char ch;
int is_quote = 0;
int unescape = 1;
if (!string || !*string)
return m_strdup(empty_string);
if (*string == '@' && more_text)
{
unescape = 0;
*args_flag = 1;
}
quote_temp[1] = 0;
ptr = free_stuff = stuff = LOCAL_COPY(string);
if (more_text)
*more_text = NULL;
while (ptr && *ptr)
{
if (is_quote)
{
is_quote = 0;
++ptr;
continue;
}
switch(*ptr)
{
case '$':
{
if (more_text && *string == '@')
{
ptr++;
break;
}
*ptr++ = 0;
if (!*ptr)
break;
m_strcat_ues(&buffer, stuff, unescape);
for (; *ptr == '^'; ptr++)
{
ptr++;
if (!*ptr)
break;
quote_temp[0] = *ptr;
malloc_strcat("e_str, quote_temp);
}
stuff = alias_special_char(&buffer, ptr, args, quote_str, args_flag);
if (quote_str)
new_free("e_str);
ptr = stuff;
break;
}
case ';':
{
if (!more_text)
{
ptr++;
break;
}
*more_text = (char *)(string + (ptr - free_stuff) + 1);
*ptr = '\0';
break;
}
case LEFT_PAREN:
case LEFT_BRACE:
{
ch = *ptr;
*ptr = '\0';
m_strcat_ues(&buffer, stuff, unescape);
stuff = ptr;
*args_flag = 1;
if (!(ptr = MatchingBracket(stuff + 1, ch,
(ch == LEFT_PAREN) ?
RIGHT_PAREN : RIGHT_BRACE)))
{
debugyell("Unmatched %c", ch);
ptr = stuff + strlen(stuff+1)+1;
}
else
ptr++;
*stuff = ch;
ch = *ptr;
*ptr = '\0';
malloc_strcat(&buffer, stuff);
stuff = ptr;
*ptr = ch;
break;
}
case '\\':
{
is_quote = 1;
ptr++;
break;
}
default:
ptr++;
break;
}
}
if (stuff)
m_strcat_ues(&buffer, stuff, unescape);
if (internal_debug & DEBUG_EXPANSIONS && !in_debug_yell)
debugyell("Expanded [%s] to [%s]", string, buffer);
#if 0
if ((internal_debug & DEBUG_CMDALIAS) && alias_debug)
debugyell("%d %s", debug_count++, string);
#endif
return buffer;
}
extern char *call_structure_internal(char *, const char *, char *, char *);
char *call_structure(char *name, const char *args, int *args_flag, char *rest, char *rest1)
{
char *ret = NULL, *tmp = NULL;
char *lparen, *rparen;
if ((lparen = strchr(name, '(')))
{
if ((rparen = MatchingBracket(lparen + 1, '(', ')')))
*rparen++ = 0;
else
debugyell("Unmatched lparen in function call [%s]", name);
*lparen++ = 0;
}
else
lparen = empty_string;
tmp = expand_alias(lparen, args, args_flag, NULL);
if ((internal_debug & DEBUG_STRUCTURES) && !in_debug_yell)
debugyell("%s->%s %d", name, rest, *args_flag);
ret = call_structure_internal(name, tmp ? tmp : "0", rest, rest1);
new_free(&tmp);
return m_strdup(ret ? ret : empty_string);
}
char *BX_alias_special_char(char **buffer, char *ptr, const char *args, char *quote_em, int *args_flag)
{
char *tmp,
*tmp2,
pad_char = 0;
register unsigned char c;
int length;
length = 0;
if ((c = *ptr) == LEFT_BRACKET)
{
ptr++;
if ((tmp = MatchingBracket(ptr, '[', ']')))
{
*tmp = 0;
if (*ptr == '$')
{
char *str;
size_t slen;
str = expand_alias(ptr, args, args_flag, NULL);
slen = strlen(str);
if (slen &&
!isdigit((unsigned char)str[slen - 1]))
pad_char = str[slen - 1];
length = my_atol(str);
new_free(&str);
}
else
{
if (!isdigit((unsigned char)*(tmp - 1)))
pad_char = *(tmp - 1);
length = my_atol(ptr);
}
ptr = ++tmp;
c = *ptr;
}
else
{
say("Missing %c", RIGHT_BRACKET);
return (ptr);
}
}
tmp = ptr+1;
switch (c)
{
case LEFT_PAREN:
{
char *sub_buffer = NULL,
*tmp2 = NULL,
*tmpsav = NULL,
*ph = ptr + 1;
if ((ptr = MatchingBracket(ph, '(', ')')) ||
(ptr = strchr(ph, ')')))
*ptr++ = 0;
else
debugyell("Unmatched ( (continuing anyways)");
do
{
tmp2 = expand_alias(tmp, args, args_flag, NULL);
if (tmpsav)
new_free(&tmpsav);
tmpsav = tmp = tmp2;
}
while (*tmp == '$');
alias_special_char(&sub_buffer, tmp, args,
quote_em, args_flag);
if (sub_buffer == NULL)
sub_buffer = m_strdup(empty_string);
TruncateAndQuote(buffer, sub_buffer, length, quote_em, pad_char);
new_free(&sub_buffer);
new_free(&tmpsav);
*args_flag = 1;
return (ptr);
}
case '!':
{
if ((ptr = (char *) strchr(tmp, '!')) != NULL)
*(ptr++) = (char) 0;
if ((tmp = do_history(tmp, empty_string)) != NULL)
{
TruncateAndQuote(buffer, tmp, length, quote_em, pad_char);
new_free(&tmp);
}
return (ptr);
}
case LEFT_BRACE:
{
char *ph = ptr + 1;
if ((ptr = MatchingBracket(ph, '{', '}')) ||
(ptr = strchr(ph, '}')))
*ptr++ = 0;
else
debugyell("Unmatched { (continuing anyways)");
if ((tmp = parse_inline(tmp, args, args_flag)) != NULL)
{
TruncateAndQuote(buffer, tmp, length, quote_em, pad_char);
new_free(&tmp);
}
return (ptr);
}
case DOUBLE_QUOTE:
case '\'':
{
if ((ptr = strchr(tmp, c)))
*ptr++ = 0;
alias_string = NULL;
add_wait_prompt(tmp, do_alias_string, NULL,
(c == DOUBLE_QUOTE) ? WAIT_PROMPT_LINE
: WAIT_PROMPT_KEY, 1);
while (!alias_string)
io("Input Prompt");
TruncateAndQuote(buffer, alias_string, length,quote_em, pad_char);
new_free(&alias_string);
return (ptr);
}
case '*':
{
TruncateAndQuote(buffer, args, length, quote_em, pad_char);
*args_flag = 1;
return (ptr + 1);
}
case '#':
case '@':
{
char c2 = 0;
char *sub_buffer = NULL;
char *rest = NULL, *val;
int dummy;
rest = after_expando(ptr + 1, 0, &dummy);
if (rest == ptr + 1)
{
sub_buffer = m_strdup(args);
*args_flag = 1;
}
else
{
c2 = *rest;
*rest = 0;
alias_special_char(&sub_buffer, ptr + 1,
args, quote_em, args_flag);
*rest = c2;
}
if (c == '#')
val = m_strdup(ltoa(word_count(sub_buffer)));
else
val = m_strdup(ltoa(sub_buffer?strlen(sub_buffer):0));
TruncateAndQuote(buffer, val, length, quote_em, pad_char);
new_free(&val);
new_free(&sub_buffer);
if (rest)
*rest = c2;
return rest;
}
case '$':
{
TruncateAndQuote(buffer, "$", length, quote_em, pad_char);
return ptr + 1;
}
default:
{
if (isdigit(c) || (c == '-') || c == '~')
{
int first, last;
*args_flag = 1;
if (c == '~')
{
first = last = EOS;
ptr++;
}
else if (c == '-')
{
first = SOS;
ptr++;
last = parse_number(&ptr);
if (last == -1)
return empty_string;
}
else
{
first = parse_number(&ptr);
if (*ptr == '-')
{
ptr++;
last = parse_number(&ptr);
if (last == -1)
last = EOS;
}
else
last = first;
}
if (!args)
tmp2 = m_strdup(empty_string);
else
tmp2 = extract2(args, first, last);
TruncateAndQuote(buffer, tmp2, length, quote_em, pad_char);
new_free(&tmp2);
return (ptr ? ptr : empty_string);
}
else
{
char *rest, d = 0;
char *rest1 = NULL;
int function_call = 0;
int struct_call = 0;
rest = after_expando(ptr, 0, &function_call);
if (*rest)
{
d = *rest;
*rest = 0;
}
if ((d == '-') && *(rest + 1) == '>')
{
struct_call = 1;
rest = rest + 2;
function_call = 0;
d = 0;
}
if (function_call)
tmp = call_function(ptr, args, args_flag);
else if (struct_call)
{
rest1 = after_expando(rest, 0, &function_call);
if (*rest1)
{
d = *rest1;
if (*rest1)
{
*rest1 = 0;
rest1++;
}
}
tmp = call_structure(ptr, args, args_flag, rest, rest1);
if ((d == '-') && (*rest1 == '>'))
rest1 = strchr(rest1, ' '), d = 0;
}
else
tmp = get_variable_with_args(ptr, args, args_flag);
if (!tmp)
tmp = m_strdup(empty_string);
TruncateAndQuote(buffer, tmp, length, quote_em, pad_char);
new_free(&tmp);
if (struct_call)
{
if (d)
rest = rest1 - 1;
else
rest = rest1;
}
if (d)
*rest = d;
return(rest);
}
}
}
return NULL;
}
static void TruncateAndQuote(char **buff, const char *add, int length, const char *quote_em, char pad_char)
{
if (length)
{
char *buffer = NULL;
buffer = alloca(abs(length)+1);
strformat(buffer, add, length, pad_char ? pad_char:get_int_var(PAD_CHAR_VAR));
add = buffer;
}
if (quote_em && add)
{
char *ptr = alloca(strlen(add) * 2 + 2);
add = double_quote(add, quote_em, ptr);
}
if (buff)
malloc_strcat(buff, add);
return;
}
static void do_alias_string (char *unused, char *input)
{
malloc_strcpy(&alias_string, input);
}