cotn25/area/
cotn25/src/
#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;
         }
      }
   }
}