#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; } } } }