#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include "merc.h"
#include "io.h"
/*********************************************************/
/* VARIABLE TABLE */
/*********************************************************/
const var_type var_table[] =
{
/* Pure string functions */
{ "name", STRING_FUNCTION(get_name) },
/* Pure number functions */
{ "class", NUMBER_FUNCTION(get_class) },
{ "vampire", NUMBER_CONSTANT(CLASS_VAMPIRE) },
{ "werewolf", NUMBER_CONSTANT(CLASS_WEREWOLF) },
{ "mage", NUMBER_CONSTANT(CLASS_MAGE) },
{ "demon", NUMBER_CONSTANT(CLASS_DEMON) },
{ "angel", NUMBER_CONSTANT(CLASS_ANGEL) },
{ "true", NUMBER_CONSTANT(1) },
{ "false", NUMBER_CONSTANT(0) },
{ "animalism", STRING_FUNCTION(get_disc_animalism_text) },
{ "animalism", NUMBER_FUNCTION(get_disc_animalism) },
{ "auspex", STRING_FUNCTION(get_disc_auspex_text) },
{ "auspex", NUMBER_FUNCTION(get_disc_auspex) },
{ "celerity", STRING_FUNCTION(get_disc_celerity_text) },
{ "celerity", NUMBER_FUNCTION(get_disc_celerity) },
{ "chimerstry", STRING_FUNCTION(get_disc_chimerstry_text) },
{ "chimerstry", NUMBER_FUNCTION(get_disc_chimerstry) },
{ "daimoinon", STRING_FUNCTION(get_disc_daimoinon_text) },
{ "daimoinon", NUMBER_FUNCTION(get_disc_daimoinon) },
{ "dominate", STRING_FUNCTION(get_disc_dominate_text) },
{ "dominate", NUMBER_FUNCTION(get_disc_dominate) },
{ "fortitude", STRING_FUNCTION(get_disc_fortitude_text) },
{ "fortitude", NUMBER_FUNCTION(get_disc_fortitude) },
{ "melpominee", STRING_FUNCTION(get_disc_melpominee_text) },
{ "melpominee", NUMBER_FUNCTION(get_disc_melpominee) },
{ "necromancy", STRING_FUNCTION(get_disc_necromancy_text) },
{ "necromancy", NUMBER_FUNCTION(get_disc_necromancy) },
{ "obeah", STRING_FUNCTION(get_disc_obeah_text) },
{ "obeah", NUMBER_FUNCTION(get_disc_obeah) },
{ "obfuscate", STRING_FUNCTION(get_disc_obfuscate_text) },
{ "obfuscate", NUMBER_FUNCTION(get_disc_obfuscate) },
{ "obtenebration", STRING_FUNCTION(get_disc_obtenebration_text) },
{ "obtenebration", NUMBER_FUNCTION(get_disc_obtenebration) },
{ "potence", STRING_FUNCTION(get_disc_potence_text) },
{ "potence", NUMBER_FUNCTION(get_disc_potence) },
{ "presence", STRING_FUNCTION(get_disc_presence_text) },
{ "presence", NUMBER_FUNCTION(get_disc_presence) },
{ "protean", STRING_FUNCTION(get_disc_protean_text) },
{ "protean", NUMBER_FUNCTION(get_disc_protean) },
{ "quietus", STRING_FUNCTION(get_disc_quietus_text) },
{ "quietus", NUMBER_FUNCTION(get_disc_quietus) },
{ "serpentis", STRING_FUNCTION(get_disc_serpentis_text) },
{ "serpentis", NUMBER_FUNCTION(get_disc_serpentis) },
{ "thanatosis", STRING_FUNCTION(get_disc_thanatosis_text) },
{ "thanatosis", NUMBER_FUNCTION(get_disc_thanatosis) },
{ "thaumaturgy", STRING_FUNCTION(get_disc_thaumaturgy_text) },
{ "thaumaturgy", NUMBER_FUNCTION(get_disc_thaumaturgy) },
{ "vicissitude", STRING_FUNCTION(get_disc_vicissitude_text) },
{ "vicissitude", NUMBER_FUNCTION(get_disc_vicissitude) },
{ NULL, END_OF_LIST } /* Always leave this at end */
};
/*********************************************************/
static jmp_buf jBuf;
static int s_iIndex;
static int s_iLevel;
int io_calculate( CHAR_DATA *ch, char *calculation )
{
int iResult;
s_iIndex = -1;
s_iLevel = 0;
if ( setjmp( jBuf ) )
{
return 0; /* Unable to perform calculation */
}
if ( calculation[0] == '\0' )
{
return 0; /* Unable to perform calculation */
}
iResult = main_calc( ch, calculation );
if ( s_iLevel != 1 )
{
char_printf("\nNon-matching brackets.\n", ch );
return 0;
}
s_iIndex = -1;
s_iLevel = 0;
return ( iResult );
}
static int main_calc( CHAR_DATA *ch, char calc_string[] )
{
STATE_TYPE eState = STATE_NONE;
int iLeft = 0;
int iRight = 0;
bool bLeftNeg = FALSE;
bool bRightNeg = FALSE;
char chOperator = 0;
bool bGLEqual = FALSE;
s_iLevel++;
while ( calc_string[++s_iIndex] != '\0' )
{
switch ( calc_string[s_iIndex] )
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
switch ( eState )
{
case STATE_LEFT_SIGN:
bLeftNeg = TRUE;
case STATE_NONE:
case STATE_LEFT:
case STATE_DONE_LEFT: /* TBD - check this */
eState = STATE_LEFT;
if ( bLeftNeg == TRUE ) iLeft = 0 - iLeft; /* Make positive */
iLeft *= 10;
iLeft += (int) (calc_string[s_iIndex] - '0');
if ( bLeftNeg == TRUE ) iLeft = 0 - iLeft; /* Make negative */
break;
case STATE_RIGHT_SIGN:
bRightNeg = TRUE;
case STATE_OPERATOR:
case STATE_RIGHT:
eState = STATE_RIGHT;
if ( bRightNeg == TRUE ) iRight = 0 - iRight; /* Make positive */
iRight *= 10;
iRight += (int) (calc_string[s_iIndex] - '0');
if ( bRightNeg == TRUE ) iRight = 0 - iRight; /* Make negative */
break;
}
break;
case '+': case '-': case '*': case '/':
if ( eState == STATE_RIGHT )
{
switch ( chOperator )
{
case '+':
iLeft = iLeft + iRight;
break;
case '-':
iLeft = iLeft - iRight;
break;
case '*':
iLeft = iLeft * iRight;
break;
case '/':
if ( iRight == 0 )
{
char_printf("\nDivision by zero.\n", ch );
longjmp( jBuf, 1 );
}
iLeft = iLeft / iRight;
break;
default:
char_printf("\nInvalid position of closed bracket.\n", ch );
longjmp( jBuf, 1 );
}
bRightNeg = FALSE;
iRight = 0;
eState = STATE_OPERATOR;
}
else if ( eState == STATE_NONE && calc_string[s_iIndex] == '-' )
{
bLeftNeg = TRUE;
eState = STATE_LEFT_SIGN;
}
else if ( eState == STATE_OPERATOR && calc_string[s_iIndex] == '-' )
{
bRightNeg = TRUE;
eState = STATE_RIGHT_SIGN;
}
else if ( eState > STATE_OPERATOR )
{
char_printf("\nInvalid position of operator.\n", ch );
longjmp( jBuf, 1 );
}
else
{
eState = STATE_OPERATOR;
chOperator = calc_string[s_iIndex];
}
break;
case '=': case '!':
if ( calc_string[s_iIndex+1] != '=' )
{
char_printf("\nInvalid operator '%c'.\n", ch, calc_string[s_iIndex] );
longjmp( jBuf, 1 );
}
++s_iIndex;
if ( eState == STATE_RIGHT )
{
switch ( chOperator )
{
case '=':
iLeft = (iLeft == iRight);
break;
case '!':
iLeft = (iLeft != iRight);
break;
default:
char_printf("\nInvalid position of closed bracket.\n", ch );
longjmp( jBuf, 1 );
}
bRightNeg = FALSE;
iRight = 0;
}
else if ( eState > STATE_OPERATOR )
{
char_printf("\nInvalid position of operator.\n", ch );
longjmp( jBuf, 1 );
}
else
{
eState = STATE_OPERATOR;
chOperator = calc_string[s_iIndex-1];
}
break;
case '<': case '>':
if ( calc_string[s_iIndex+1] == '=' )
{
++s_iIndex;
bGLEqual = TRUE;
}
if ( eState == STATE_RIGHT )
{
switch ( chOperator )
{
case '[':
iLeft = (iLeft <= iRight);
break;
case '<':
iLeft = (iLeft < iRight);
break;
case ']':
iLeft = (iLeft >= iRight);
break;
case '>':
iLeft = (iLeft > iRight);
break;
default:
char_printf("\nInvalid position of closed bracket.\n", ch );
longjmp( jBuf, 1 );
}
bRightNeg = FALSE;
iRight = 0;
}
else if ( eState > STATE_OPERATOR )
{
char_printf("\nInvalid position of operator.\n", ch );
longjmp( jBuf, 1 );
}
else
{
eState = STATE_OPERATOR;
if ( bGLEqual )
{
if ( calc_string[s_iIndex-1] == '<' )
{
chOperator = '[';
}
else /* calc_string[s_iIndex-1] == '>' */
{
chOperator = ']';
}
}
else
{
chOperator = calc_string[s_iIndex];
}
}
bGLEqual = FALSE;
break;
case '&':
if ( calc_string[s_iIndex+1] != '&' )
{
char_printf("\nInvalid operator '%c'.\n", ch, calc_string[s_iIndex]);
longjmp( jBuf, 1 );
}
++s_iIndex;
if ( eState == STATE_RIGHT )
{
switch ( chOperator )
{
case '&':
iLeft = (iLeft && iRight);
break;
default:
char_printf("\nInvalid position of closed bracket.\n",ch );
longjmp( jBuf, 1 );
}
bRightNeg = FALSE;
iRight = 0;
}
else if ( eState > STATE_OPERATOR )
{
char_printf("\nInvalid position of operator.\n",ch );
longjmp( jBuf, 1 );
}
else
{
eState = STATE_OPERATOR;
chOperator = calc_string[s_iIndex-1];
}
break;
case '|':
if ( calc_string[s_iIndex+1] != '|' )
{
char_printf("\nInvalid operator '%c'.\n", ch, calc_string[s_iIndex] );
longjmp( jBuf, 1 );
}
++s_iIndex;
if ( eState == STATE_RIGHT )
{
switch ( chOperator )
{
case '|':
iLeft = (iLeft || iRight);
break;
default:
char_printf("\nInvalid position of closed bracket.\n",ch );
longjmp( jBuf, 1 );
}
bRightNeg = FALSE;
iRight = 0;
}
else if ( eState > STATE_OPERATOR )
{
char_printf("\nInvalid position of operator.\n",ch );
longjmp( jBuf, 1 );
}
else
{
eState = STATE_OPERATOR;
chOperator = calc_string[s_iIndex-1];
}
break;
case ' ':
break;
case '(':
if ( eState == STATE_NONE )
{
iLeft = main_calc( ch, calc_string );
eState = STATE_DONE_LEFT;
}
else if ( eState == STATE_OPERATOR )
{
iRight = main_calc( ch, calc_string );
eState = STATE_RIGHT;
}
else
{
char_printf("\nInvalid position of open bracket.\n",ch );
longjmp( jBuf, 1 );
}
break;
case ')':
s_iLevel--;
if ( eState == STATE_DONE_LEFT || eState == STATE_LEFT )
{
return ( iLeft );
}
if ( eState != STATE_RIGHT )
{
char_printf("\nInvalid position of closed bracket.\n",ch );
longjmp( jBuf, 1 );
}
switch ( chOperator )
{
case '+': return ( iLeft + iRight );
case '-': return ( iLeft - iRight );
case '*': return ( iLeft * iRight );
case '/':
if ( iRight == 0 )
{
char_printf("\nDivision by zero.\n", ch );
longjmp( jBuf, 1 );
}
return ( iLeft / iRight );
case '=': return ( iLeft == iRight );
case '!': return ( iLeft != iRight );
case '<': return ( iLeft < iRight );
case '>': return ( iLeft > iRight );
case '[': return ( iLeft <= iRight );
case ']': return ( iLeft >= iRight );
case '&': return ( iLeft && iRight );
case '|': return ( iLeft || iRight );
}
char_printf("\nInvalid position of closed bracket.\n",ch );
longjmp( jBuf, 1 );
case '\0':
if ( s_iLevel > 1 )
{
char_printf("\nInvalid character '%d'.\n", ch, calc_string[s_iIndex] );
longjmp( jBuf, 1 );
}
char_printf("\nDone.\n",ch );
longjmp( jBuf, 1 );
default: /* zzz */
char_printf("\nInvalid character '%c'.\n", ch, calc_string[s_iIndex] );
longjmp( jBuf, 1 );
}
};
if ( s_iLevel != 1 )
{
char_printf("\nNon-matching brackets.\n", ch );
longjmp( jBuf, 1 );
}
if ( eState != STATE_RIGHT )
{
if ( eState == STATE_DONE_LEFT || eState == STATE_LEFT )
{
return ( iLeft );
}
char_printf("\nInvalid calc_string.\n", ch );
longjmp( jBuf, 1 );
}
switch ( chOperator )
{
case '+': return ( iLeft + iRight );
case '-': return ( iLeft - iRight );
case '*': return ( iLeft * iRight );
case '/':
if ( iRight == 0 )
{
char_printf("\nDivision by zero.\n", ch );
longjmp( jBuf, 1 );
}
return ( iLeft / iRight );
case '=': return ( iLeft == iRight );
case '!': return ( iLeft != iRight );
case '<': return ( iLeft < iRight );
case '>': return ( iLeft > iRight );
case '[': return ( iLeft <= iRight );
case ']': return ( iLeft >= iRight );
case '&': return ( iLeft && iRight );
case '|': return ( iLeft || iRight );
}
char_printf("\nInvalid calculation.\n", ch );
return 0;
}
/*********************************************************/
void io_parse( CHAR_DATA *ch, char *in_ptr, char *out_ptr )
{
char var_buf[256];
int var_count = 0;
bool var_name = FALSE;
char calc_buf[256];
int calc_count = 0;
bool calc_name = FALSE;
int nest_text = 0;
int valid_nest = 0;
you = ch; /* Initialise the 'you' variable used in function table */
setup_variables(ch);
while ( *in_ptr )
{
switch ( *in_ptr )
{
default:
if ( valid_nest != nest_text )
{
in_ptr++;
}
else if ( var_name )
{
var_buf[var_count++] = *in_ptr++;
}
else if ( calc_name )
{
calc_buf[calc_count++] = *in_ptr++;
}
else
{
*out_ptr++ = *in_ptr++;
}
break;
case '{':
if ( valid_nest != nest_text )
{
in_ptr++;
break;
}
in_ptr++;
var_buf[var_count=0] = '\0';
if ( var_name ) char_printf( "Nested variable names not allowed.\n\r", ch );
var_name = TRUE;
break;
case '}':
if ( valid_nest != nest_text )
{
in_ptr++;
break;
}
if ( !var_name ) char_printf( "Variable terminator without variable.\n\r", ch );
var_buf[var_count] = '\0';
in_ptr++;
var_name = FALSE;
if ( calc_name )
{
(void) number_var( &var_buf[0], &calc_buf[calc_count] ); /* Calculator variable */
calc_count = strlen( calc_buf ); /* Nasty hack to recalculate calc_count */
}
else
string_var( &var_buf[0], &out_ptr ); /* String variable */
break;
case '[':
if ( valid_nest != nest_text )
{
in_ptr++;
break;
}
in_ptr++;
calc_buf[calc_count=0] = '\0';
if ( calc_name ) char_printf( "Nested calculations not allowed.\n\r", ch );
calc_name = TRUE;
break;
case ']':
if ( valid_nest != nest_text )
{
nest_text++;
in_ptr++;
break;
}
if ( !calc_name ) char_printf( "Calculation terminator without calculation.\n\r", ch );
calc_buf[calc_count] = '\0';
in_ptr++;
nest_text++;
valid_nest += !!io_calculate( ch, &calc_buf[0] );
calc_name = FALSE;
break;
case '|':
if ( --nest_text < 0 )
{
char_printf( "Conditional terminator without condition.\n\r", ch );
nest_text = 0;
}
if ( valid_nest > nest_text ) valid_nest = nest_text;
in_ptr++;
break;
}
}
*out_ptr = '\0';
}
bool string_var( char *var_ptr, char **out_ptr )
{
int i = -1;
while ( var_table[++i].variable != NULL )
{
if ( !strcmp( var_ptr, var_table[i].variable ) )
{
char *replace_ptr;
switch ( var_table[i].type )
{
case VARIABLE_FUNCTION_STRING:
replace_ptr = ((char*(*)())(var_table[i].replace.text))();
break;
case VARIABLE_CONSTANT_STRING:
replace_ptr = var_table[i].replace.text;
break;
default: continue; /* Cannot resolve numbers */
}
while ( *replace_ptr ) *(*out_ptr)++ = *replace_ptr++;
return TRUE;
}
}
return FALSE;
}
bool number_var( char *var_ptr, char *out_ptr )
{
int i = -1;
while ( var_table[++i].variable != NULL )
{
if ( !strcmp( var_ptr, var_table[i].variable ) )
{
int replace_num;
char replace_buf[64];
char *replace_ptr = &replace_buf[0];
switch ( var_table[i].type )
{
case VARIABLE_FUNCTION_NUMBER:
replace_num = ((int(*)())(var_table[i].replace.number))();
break;
case VARIABLE_CONSTANT_NUMBER:
replace_num = var_table[i].replace.number;
break;
default: continue; /* Cannot resolve strings */
}
sprintf( replace_ptr, "%d", replace_num );
while ( (*out_ptr++ = *replace_ptr++) );
return TRUE;
}
}
return FALSE;
}
void io_display( CHAR_DATA *ch, char text[] )
{
/*
char buf [MAX_STRING_LENGTH] = { '\0' };
*/
int align = 0;
int i;
while ( *text )
{
switch ( *text )
{
default:
char_printf( "%c", ch, *text );
break;
case '[':
char_printf( "\n",ch );
for ( i = 0; i < align; i++ ) char_printf( " ",ch );
char_printf( "[",ch );
break;
case ']':
char_printf( "]\n",ch );
align++;
for ( i = 0; i < align; i++ ) char_printf( " ",ch );
break;
case '|':
char_printf( "\n",ch );
align--;
for ( i = 0; i < align; i++ ) char_printf( " ",ch );
char_printf( "|",ch );
break;
}
text++;
}
char_printf( "\n",ch );
}
void io_main( CHAR_DATA *ch )
{
char in_buf [256];
char out_buf [256];
strcpy( in_buf,
"Hello there!"
"[{str}!=18]How are you?"
"[1]Are you okay?||" );
io_display( ch, in_buf );
io_parse( ch, in_buf, out_buf );
char_printf( "String:[%s]\n\r", ch,out_buf );
}
static void setup_variables ( CHAR_DATA *ch )
{
OBJ_DATA *obj, *obj2;
wpn = NULL;
for ( obj = ch->carrying; obj; obj = obj->next_content )
{
if ( obj->item_type == ITEM_WEAPON )
{
wpn = obj;
break;
}
}
if ( wpn ) return;
for ( obj = ch->carrying; obj; obj = obj->next_content )
{
for ( obj2 = obj->contains; obj2; obj2 = obj2->next_content )
{
if ( obj2->item_type == ITEM_WEAPON )
{
wpn = obj2;
break;
}
}
}
}