home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / rpos2101.zip / RPILOT.C < prev    next >
C/C++ Source or Header  |  1998-07-03  |  44KB  |  1,687 lines

  1. /*
  2.  * rpilot.c -- A simple PILOT interpretor in ANSI C
  3.  * Copyright 1998 Rob Linwood (auntfloyd@biosys.net)
  4.  * Visit http://auntfloyd.home.ml.org/ for more cool stuff
  5.  *
  6.  * See the file rpilot.txt/README.rpilot for user documentation
  7.  *
  8.  * Ignore all compiler warnings
  9.  */
  10.  
  11.    /**********************************************************************
  12.     RPilot: Rob's PILOT Interpreter
  13.     Copyright 1998 Rob Linwood
  14.  
  15.     This program is free software; you can redistribute it and/or modify
  16.     it under the terms of the GNU General Public License as published by
  17.     the Free Software Foundation; either version 2 of the License, or
  18.     (at your option) any later version.
  19.  
  20.     This program is distributed in the hope that it will be useful,
  21.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.     GNU General Public License for more details.
  24.  
  25.     You should have received a copy of the GNU General Public License
  26.     along with this program; if not, write to the Free Software
  27.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  28.     **********************************************************************/
  29.  
  30.  
  31.  
  32. /* Tells Turbo C++ not to give warnings when functions don't return
  33.    a value, other compilers will probably give us a warning */
  34. #ifdef __TURBOC__
  35. #pragma warn -rvl
  36. #endif
  37. /* __TURBOC__ */
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <ctype.h>
  43. #include <time.h>
  44. #include "parse.h"
  45.  
  46. /* If Turbo/Borland C++ is not being used, we'll need the rstring library */
  47. #ifndef __TURBOC__
  48. #ifndef __BORLANDC__
  49. #include "rstring.h"
  50. #endif
  51. /* __BORLANDC__ */
  52. #endif
  53. /* __TURBOC__ */
  54.  
  55. /* Arbitrary constants.  Change at will.  Some of these are fixed by the
  56.    PILOT Standard (IEEE 1154-1991)   */
  57. #define MAXLINE 128         /* Max length of a source line */
  58. #define MAXVARN 11            /* Max length of a variable name */
  59. #define MAXVARV 80            /* Max length of a variable string value */
  60. #define MAXLBLN 11            /* Max length of a label name */
  61. #define MAXSUBR 20            /* Max number of subroutine calls */
  62.  
  63. /* Error message number definitions -- see err() for more */
  64. #define DUP_LABEL 0            /* If there are two labels with the same name */
  65. #define NO_FILE 1            /* If no file was given on the command line */
  66. #define ERR_FILE 2            /* If the file given can't be opened */
  67. #define UNKWN_CMD 3            /* If there is an unknown command in the source */
  68. #define NO_MEM 4            /* If we run out of memory */
  69. #define DUP_VAR 5            /* If there are two variables that share a name */
  70. #define BAD_VAR 6            /* If a non-existantant variable is used */
  71. #define EXP_MATH 7            /* When a non-math symbol where it shouldn't */
  72. #define NO_RELAT 8            /* When a relational op is missing */
  73.  
  74. /* Used to determine whether the program will halt on an error */
  75. #define FATAL 1                /* Used when the error causes a call to exit() */
  76. #define NONFATAL 2            /* Used when we can still go on */
  77.  
  78. /* Used to check conditional values */
  79. #define NO 0
  80. #define YES 1
  81.  
  82. /* What char is displayed for an accept command? */
  83. #define ACCEPT_CHAR '>'
  84.  
  85. /* Remove a terminating newline */
  86. #define chop( str )    if(str[strlen(str)-1] == '\n') str[strlen(str)-1] = '\0'
  87. /* Trim leading and trailing whitespace   */
  88. #define trim( str ) ltrim(str); rtrim(str);
  89. /* Initialize randon number based on time */
  90. #define srandom() srand( (unsigned)time(NULL) );
  91.  
  92. /* The version number, of course */
  93. #define VERSION "1.01"
  94.  
  95.  
  96. /* The first group of functions are those that perform some action which
  97.    is called directly by handle(), and correspond to the PILOT functions    */
  98.  
  99. /* use() implememnts PILOT's version of GOSUB                               */
  100. void use( char *str );
  101. /* Handles variable assignment                                              */
  102. void compute( char *str );
  103. /* Handles user input                                                       */
  104. void accept( char *str );
  105. /* Displays data                                                            */
  106. void type( char *str );
  107. /* Marks the end of a subroutine                                            */
  108. void endit( char *str );
  109. /* Does string matching                                                     */
  110. void match( char *str );
  111. /* PILOT's version of GOTO                                                  */
  112. void jump( char *str );
  113. /* Displays text if #matched equals YES                                     */
  114. void yes( char *str );
  115. /* Displays text if #matched equals NO                                      */
  116. void no( char *str );
  117.  
  118.  
  119. /* The following are nonstandard functions available in rpilot programs     */
  120.  
  121. /* Executes a line of PILOT code in                                         */
  122. void execute( char *str );
  123. /* Allows access to the operating system                                    */
  124. void shell( char *str );
  125. /* Gives debugging info from inside a PILOT program                         */
  126. void debug( char *str );
  127. /* Puts a random number in a given variable */
  128. void gen( char *str);
  129.  
  130. /* All the following functions are support functions called by those listed
  131.    above.  They are not directly available in PILOT programs */
  132.  
  133. /* Label-related functions                                                  */
  134.  
  135. /* this is called at startup to generate a list of labels & their locations */
  136. void scanlbl();
  137. /* addlbl() adds a label to the label list                                  */
  138. int addlbl( char *str );
  139. /* returns the seek address of a given label */
  140. long getlbl( char *name );
  141.  
  142.  
  143. /* Variable functions */
  144.  
  145. /* Sets the value of a given string variable */
  146. int setsvar( char *name, char *val );
  147. /* Sets the value of a given numeric variable */
  148. int setnvar( char *name, int val );
  149. /* Returns the value of a given numeric variable */
  150. int getnvar( char *name );
  151. /* Stores the value of variable "name" in dest */
  152. char *getsvar( char *dest, char *name );
  153.  
  154. /* Misc. functions */
  155.  
  156. /* Displays a given error message and optionally halts execution         */
  157. int err( int errnum, int qfatal, char *msg );
  158. /* Handles processing of input by passing it off to the proper func     */
  159. void handle( char *str );
  160. /* Find the colon (:) in a string                                         */
  161. int findcol( char *str );
  162. /* Determines whether a given conditional expression is true or not        */
  163. int test( char *buffer );
  164. /* Splits an input string into its seperate parts                       */
  165. void split( char *str, char *exp, char *args );
  166. /* Parses a mathematic formula into a more easily readable form         */
  167. void explode( char *dest, char *src );
  168. /* Returns the value of a given mathematical formula                    */
  169. int express( char *form );
  170. /* Returns the value of a given number or variable                      */
  171. int getval( char *str );
  172. /* Returns the value of a given string or variable                      */
  173. char *getstr( char *dest, char *src );
  174.  
  175. #ifdef __DJGPP__
  176. int _stklen = 0x200000;
  177. #endif
  178.  
  179.  
  180. FILE *in;                  /* Input file */
  181. int line = 0;              /* Line number.  Isn't accurate after a use */
  182. char last;                 /* Last used PILOT function */
  183. long substack[MAXSUBR];    /* subroutine stack */
  184. int scount=0;              /* first free space in substack */
  185. char lastacc[MAXVARN];     /* last string variable that was accept()'d */
  186.  
  187. struct var {
  188.         char name[MAXVARN];    /* The variable's name */
  189.         char str[MAXVARV];     /* The string value */
  190.         int num;               /* The numeric value */
  191.         struct var *next;      /* A pointer to the next variable */
  192. } *var1, *lastvar;
  193.  
  194. struct lbl {
  195.     char name[MAXLBLN];         /* The label's name */
  196.         long line;                  /* The seek value of the label */
  197.         struct lbl *next;           /* A pointer to the next label */
  198. } *lbl1, *lastlbl;
  199.  
  200. /*
  201.  * Name    : main
  202.  * Descrip : This is the place where execution begins
  203.  * Input   : argc = number of arguments
  204.  *           argv[] = pointers to the arguments
  205.  * Output  : returns errorcodes listed in #define's
  206.  * Notes   : none
  207.  * Example : n/a
  208.  */
  209.  
  210. int main( int argc, char *argv[] )
  211. {
  212.     char fname[80];             /* Name of the input file */
  213.     char inbuf[MAXLINE];        /* Input buffer           */
  214.  
  215.     if( argc == 1) {    /* If no file name is given   */
  216.         printf( "\nRPilot: Rob's PILOT Interpreter Version %s \n", VERSION );
  217.         printf( "Copyright 1998 Rob Linwood (auntfloyd@biosys.net)\n" );
  218.         printf( "RPilot is Free Software and comes with ABSOLUTELY NO WARRANTY!\n\n" );
  219.         printf( "Usage: %s filename[.p]\n\n", argv[0] );
  220.         exit( 0 );
  221.     }
  222.  
  223.     printf( "\n" );
  224.     strcpy( fname, argv[1] );
  225.  
  226.     if( (in = fopen( fname, "rt" ) ) == NULL ) {
  227.         strcat( fname, ".p" );
  228.         if( (in = fopen( fname, "rt" ) ) == NULL )
  229.             err( ERR_FILE, FATAL, fname );
  230.     }
  231.  
  232.     scanlbl();          /* Add all labels to the label list */
  233.  
  234.     rewind( in );
  235.  
  236.     do {                /* Main input loop */
  237.         fgets( inbuf, MAXLINE+1, in );
  238.         line++;
  239.         chop( inbuf );
  240.         if( strlen( inbuf ) > 0 )
  241.             handle( inbuf );
  242.         /* Clear the input buffer */
  243.         strset( inbuf, 0 );
  244.     } while( !feof( in ) );
  245.  
  246.     fclose( in );
  247.  
  248.     return 0;
  249. }
  250.  
  251. /*
  252.  * Name    : handle
  253.  * Descrip : Takes input and figures which PILOT function to call based on
  254.  *           first character of the string
  255.  * Input   : str = pointer to the input string
  256.  * Output  : none
  257.  * Notes   : none
  258.  * Example : handle( "T(33>#count): 33 is more than count" ) calls type()
  259.  */
  260.  
  261. void handle( char *str )
  262. {
  263.     int i;
  264.  
  265.     i = ws( str );      /* Strip the leading whitespace */
  266.         if( i == -1 )       /* If there is nothing but wspace, exit */
  267.         return;
  268.  
  269.     ltrim( str );
  270.  
  271.     switch( toupper( str[0] ) ) {
  272.         case 'R' : last = 'R';
  273.                    break;    /* comment */
  274.         case 'D' : last = 'D';
  275.                    debug( str );
  276.                    break;
  277.         case 'U' : last = 'U';
  278.                    use( str );
  279.                    break;
  280.         case 'C' : last = 'C';
  281.                    compute( str );
  282.                    break;
  283.         case 'T' : last = 'T';
  284.                    type( str );
  285.                    break;
  286.         case 'A' : last = 'A';
  287.                    accept( str );
  288.                    break;
  289.         case 'E' : last = 'E';
  290.                    endit( str );
  291.                    break;
  292.         case 'M' : last = 'M';
  293.                    match( str );
  294.                    break;
  295.         case 'J' : last = 'J';
  296.                    jump( str );
  297.                    break;
  298.         case 'X' : last = 'X';
  299.                    execute( str );
  300.                    break;
  301.         case 'Y' : last = 'Y';
  302.                    yes( str );
  303.                    break;
  304.         case 'N' : last = 'N';
  305.                    no( str );
  306.                    break;
  307.         case 'S' : last = 'S';
  308.                    shell( str );
  309.                    break;
  310.         case 'G' : last = 'G';
  311.                    gen( str );
  312.                    break;
  313.         case '*' : break;    /* label */
  314.         case ':' : switch( last ) {
  315.                         case 'R' : break;
  316.                         case 'D' : debug( str );
  317.                                    break;
  318.                         case 'U' : use( str );
  319.                                    break;
  320.                         case 'C' : compute( str );
  321.                                    break;
  322.                         case 'T' : type( str );
  323.                                    break;
  324.                         case 'A' : accept( str );
  325.                                    break;
  326.                         case 'E' : endit( str );
  327.                                    break;
  328.                         case 'M' : match( str );
  329.                                    break;
  330.                         case 'J' : jump( str );
  331.                                    break;
  332.                         case 'X' : execute( str );
  333.                                    break;
  334.                         case 'Y' : yes( str );
  335.                                    break;
  336.                         case 'N' : no( str );
  337.                                    break;
  338.                         case 'S' : shell( str );
  339.                                    break;
  340.                         case 'G' : gen( str );
  341.                                    break;
  342.                    }
  343.                    break;
  344.         default  : err( UNKWN_CMD, NONFATAL, str );
  345.                    break;
  346.     }
  347. }
  348.  
  349. /*
  350.  * Name    : err
  351.  * Descrip : Prints an error message based on the number passed to it and
  352.  *           optionally exits on fatal errors
  353.  * Input   : errnum = the error code for the erro (see #define's above)
  354.  *           qfatal = FATAL if the error is fatal, and NONFATAL if it isn't
  355.  * Output  : Will either return the error number, or exit
  356.  * Notes   : none
  357.  * Example : err( ERR_FILE, FATAL, "figment.p" ) prints:
  358.  *           "rpilot(0) Fatal Error - Can't open file figment.p"
  359.  */
  360.  
  361. int err( int errnum, int qfatal, char *msg )
  362. {
  363.     char buf[80];
  364.     char *errlist[] = {
  365.                 /* DUP_LABEL */     "Duplicate label `%s'",
  366.                 /* NO_FILE   */     "No file name specified",
  367.                 /* ERR_FILE  */     "Can't open file `%s'",
  368.                 /* UNKWN_CMD */     "Unknown command `%s'",
  369.                 /* NO_MEM    */     "Out of memory!",
  370.         /* DUP_VAR   */     "Duplicate variable `%s'",
  371.                 /* BAD_VAR   */     "Unknown variable `%s'",
  372.         /* EXP_MATH  */     "Expected math symbol, not `%s'",
  373.                 /* NO_RELAT  */     "Missing relational operator"
  374.  
  375.     };
  376.  
  377.     if( qfatal == FATAL )
  378.         sprintf( buf, "rpilot(%d): Fatal Error - %s\n", line, errlist[errnum]);
  379.     else
  380.         sprintf( buf, "rpilot(%d): Error - %s\n", line, errlist[errnum] );
  381.  
  382.     printf( buf, msg );
  383.  
  384.     if( qfatal == FATAL )
  385.         exit( errnum );
  386.     return errnum;
  387. }
  388.  
  389. /*
  390.  * Name    : addlbl
  391.  * Descrip : Adds a given label to the label list.  It gets the position via
  392.  *           a call to ftell()
  393.  * Input   : str = a pointer to the label name
  394.  * Output  : returns a nonzero error message (see error code table) on an
  395.  *           error, and zero on success
  396.  * Notes   : Don't include the initial "*" in the label name.  Capitializes
  397.  *           label names and strips all leadinf & trailing whitespace.  Using
  398.  *           the same label name twice results in an error.
  399.  * Example : addlbl( "bob" )  adds "BOB" to the label list
  400.  */
  401.  
  402. int addlbl( char *str )
  403. {
  404.     struct lbl *prev;
  405.  
  406.     prev = lbl1;
  407.     lastlbl = lbl1;
  408.  
  409.     trim( str );
  410.     strupr( str );
  411.     while( lastlbl != NULL ) {
  412.         if( strcmp(lastlbl->name, str) == 0 )
  413.             return( err( DUP_LABEL, NONFATAL, str ) );
  414.         prev = lastlbl;
  415.         lastlbl = lastlbl->next;
  416.     }
  417.  
  418.  
  419.     if ((lastlbl = (struct lbl *) malloc(sizeof *lastlbl)) == NULL)
  420.       err( NO_MEM, FATAL, str );     /* no memory! */
  421.  
  422.     strncpy(lastlbl->name, str, MAXLBLN);
  423.     lastlbl->line = ftell( in );
  424.     lastlbl->next = NULL;
  425.  
  426.     if (prev == NULL)
  427.       lbl1 = lastlbl;    /* first element in list */
  428.     else
  429.       prev->next = lastlbl;
  430.     return 0;
  431. }
  432.  
  433. /*
  434.  * Name    : scanlbl
  435.  * Descrip : Scans the file at startup for all the labels (any line beggining
  436.  *           with a "*"), and calls addlbl() to add them to the list
  437.  * Input   : none
  438.  * Output  : none
  439.  * Notes   : This needs to be called only once
  440.  * Example : n/a
  441.  */
  442.  
  443. void scanlbl()
  444. {
  445.     char trash[MAXLINE];
  446.     char buffer[MAXLINE];
  447.     int i;
  448.  
  449.     do {
  450.         fgets( buffer, MAXLINE + 1, in );
  451.         line++;
  452.         chop( buffer );
  453.         if( strlen( buffer ) > 0 ) {
  454.             i = ws( buffer );
  455.             if( i != -1 ) {
  456.                 if( buffer[i] == '*' ) {
  457.                     scopy( trash, buffer, i+1, rws( buffer ) - i  );
  458.                     addlbl( trash );
  459.                 }
  460.             }
  461.         }
  462.     } while( !feof( in ) );
  463.     line = 0;
  464.     rewind( in );
  465. }
  466.  
  467. /*
  468.  * Name    : use
  469.  * Descrip : Implements the U command in PILOT programs. See rpilot.txt for
  470.  *           info on PILOT 
  471.  * Input   : str = pointer to the entire line taken from the source file
  472.  * Output  : none
  473.  * Notes   : none
  474.  * Example : use( "U: dogbert" )
  475.  */
  476.  
  477. void use( char *str )
  478. {
  479.     char args[MAXLINE];
  480.     char exp[MAXLINE];
  481.  
  482.     split( str, exp, args );
  483.     if( ws(exp) != -1 ) {
  484.         if( test( exp ) == NO )
  485.             return;
  486.     }
  487.  
  488.         if( scount < MAXSUBR ) {   /* Push ftell() value on stack */
  489.         substack[scount] = ftell( in );
  490.         scount++;
  491.     }
  492.  
  493.     trim( args );
  494.  
  495.     /* And now handle the jump to the specified label */
  496.     if( args[0] == '*' ) {
  497.         strset( exp, '\0' );
  498.         scopy( exp, args, 1, strlen( args ) - 1 );
  499.         fseek( in, getlbl(exp), SEEK_SET );
  500.     }
  501.     else
  502.         fseek( in, getlbl(args), SEEK_SET );
  503.  
  504. }
  505.  
  506. /*
  507.  * Name    : compute
  508.  * Descrip : Implements the C command in PILOT programs. See rpilot.txt for
  509.  *           info on PILOT 
  510.  * Input   : str = pointer to the entire line taken from the source file
  511.  * Output  : none
  512.  * Notes   : none
  513.  * Example : compute( "C: $dog = Rex" )
  514.  */
  515.  
  516. void compute( char *str )
  517. {
  518.     char args[MAXLINE];
  519.     char exp[MAXLINE];
  520.     char buffer[MAXLINE];
  521.     char buf2[MAXVARV];         /* conatins value of varibale */
  522.     char name[MAXVARN];
  523.     int i, n;
  524.  
  525.     split( str, exp, args );
  526.     if( ws(exp) != -1 ) {
  527.         if( test( exp ) == NO )
  528.             return;
  529.     }
  530.     strset( buffer, 0 );
  531.     for(i=0; i<strlen(args); i++) {
  532.         if( args[i] == '=' ) {
  533.                         scopy( name, args, 0, i-1 );  /* holds var name */
  534.                         /* get value */
  535.                         scopy( buffer, args, i+1, strlen(args) - i ); 
  536.         }
  537.     }
  538.         trim( name );           /* Contains variable name */
  539.     trim( buffer );         /* Contains right side    */
  540.     n = numstr( buffer );
  541.         strset( buf2, 0 );
  542.  
  543.     if( name[0] == '$' ) {        /* String variable */
  544.         for(i=1; i<=n; i++) {
  545.             strset( args, 0 );
  546.             parse( buffer, i, args );
  547.             if( args[0] == '$' ) {
  548.                 strset( exp, 0 );
  549.                 getsvar( exp, args );
  550.                 strcat( buf2, exp );
  551.             }
  552.             else
  553.                 strcat( buf2, args );
  554.  
  555.             strcat( buf2, " " );
  556.         }
  557.         setsvar( name, buf2 );
  558.     }
  559.     else
  560.         setnvar( name, express( buffer ) );
  561. }
  562.  
  563. /*
  564.  * Name    : accept
  565.  * Descrip : Implements the A command in PILOT programs. See rpilot.txt for
  566.  *           info on PILOT 
  567.  * Input   : str = pointer to the entire line taken from the source file
  568.  * Output  : none
  569.  * Notes   : none
  570.  * Example : accept( "A: $name" )
  571.  */
  572.  
  573. void accept( char *str )
  574. {
  575.     char args[MAXLINE];
  576.     char exp[MAXLINE];
  577.     int i;
  578.  
  579.     fflush(stdin);
  580.  
  581.     split( str, exp, args );
  582.     if( ws(exp) != -1 ) {
  583.         if( test( exp ) == NO )
  584.             return;
  585.     }
  586.     strset( exp, '\0' );
  587.     if( ws(args) == -1 ) {    /* no variable name was given, so we put it in */
  588.         printf( "%c ", ACCEPT_CHAR ); /*  $answer */
  589.         gets( exp );
  590.         setsvar( "$ANSWER", exp );
  591.         strcpy( lastacc, "$ANSWER" );
  592.     }
  593.     else {
  594.         trim( args );
  595.         if( args[0] == '$' ) {    /* String variable */
  596.             printf( "%c ", ACCEPT_CHAR );
  597.             gets( exp );
  598.             setsvar( args, exp );
  599.             strcpy( lastacc, args );
  600.         }
  601.         if( args[0] != '$' ) {    /* Numeric variable */
  602.             printf( "%c ", ACCEPT_CHAR );
  603.             scanf( "%d", &i );
  604.             setnvar( args, i );
  605.         }
  606.     }
  607.  
  608. }
  609.  
  610. /*
  611.  * Name    : type
  612.  * Descrip : Implements the T command in PILOT programs. See rpilot.txt for
  613.  *           info on PILOT
  614.  * Input   : str = pointer to the entire line taken from the source file
  615.  * Output  : none
  616.  * Notes   : none
  617.  * Example : type( "T: Bonjour, $name" )
  618.  */
  619.  
  620. void type( char *str )
  621. {
  622.     char args[MAXLINE];
  623.     char exp[MAXLINE];
  624.     char buffer[MAXLINE];
  625.     int i, c;
  626.  
  627.     split( str, exp, args );
  628.  
  629.     if( ws(exp) != -1 ) {
  630.         if( test( exp ) == NO )
  631.             return;
  632.     }
  633.     strset( exp, '\0' );
  634.     ltrim( args );
  635.  
  636.     if( ws(args) == -1 ) {      /* Blank  Line */
  637.         printf( "\n" );
  638.         return;
  639.     }
  640.  
  641.     for(c=0; c<strlen(args); c++) {
  642.         if( args[c] == '$' ) {
  643.             i = find( args, " \t\n", c );    /* find whitespace */
  644.                         if( i == -1 )                   /* No ws=EOL */
  645.                 i = strlen( args );
  646.             scopy( exp, args, c, i - c );
  647.             trim( exp );
  648.             strset( buffer, '\0' );
  649.             getsvar( buffer, exp );
  650.             printf( "%s", buffer );
  651.             c = i;
  652.         }
  653.         if( args[c] == '#' ) {
  654.             i = find( args, " \t\n", c );    /* find whitespace */
  655.                         if( i == -1 )                   /* No ws=EOL */
  656.                 i = strlen( args );
  657.             scopy( exp, args, c, i - c );
  658.             printf( "%d", getnvar(exp) );
  659.             c = i;
  660.         }
  661.         if( (args[c] != '$') && (args[c] != '#') )
  662.             putchar( args[c] );
  663.     }
  664.     if( c >= strlen(args) )
  665.         printf( "\n" );
  666. }
  667.  
  668. /*
  669.  * Name    : endit
  670.  * Descrip : Implements the E command in PILOT programs. See rpilot.txt for
  671.  *           info on PILOT
  672.  * Input   : str = pointer to the entire line taken from the source file
  673.  * Output  : none
  674.  * Notes   : none
  675.  * Example : endit( "E:" )
  676.  */
  677.  
  678. void endit( char *str )
  679. {
  680.     char args[MAXLINE];
  681.     char exp[MAXLINE];
  682.  
  683.  
  684.     split( str, exp, args );
  685.     if( ws(exp) != -1 ) {
  686.         if( test( exp ) == NO )
  687.             return;
  688.     }
  689.  
  690.     if( scount == 0 )          /* End the program */
  691.         exit( 0 );
  692.     fseek( in, substack[--scount], SEEK_SET );
  693.  
  694. }
  695.  
  696. /*
  697.  * Name    : match
  698.  * Descrip : Implements the M command in PILOT programs. See rpilot.txt for
  699.  *           info on PILOT 
  700.  * Input   : str = pointer to the entire line taken from the source file 
  701.  * Output  : none
  702.  * Notes   : none
  703.  * Example : match( "M: yes y yep ok sure" )
  704.  */
  705.  
  706. void match( char *str )
  707. {
  708.     char args[MAXLINE];
  709.     char exp[MAXLINE];
  710.     char buffer[MAXLINE];
  711.     int i, c;
  712.  
  713.     split( str, exp, args );
  714.     if( ws(exp) != -1 ) {
  715.         if( test( exp ) == NO )
  716.             return;
  717.     }
  718.  
  719. /*    strcat( args, " " ); */
  720.     i = numstr( args );
  721.  
  722.     getsvar( buffer, lastacc );
  723.     strupr( buffer );
  724.  
  725.     for(c=1;c<=i;c++) {
  726.         strset( exp, 0 );
  727.         parse( args, c, exp );
  728.         strupr( exp );
  729.         if( !strcmp( exp, buffer ) ) {
  730.             setnvar( "#MATCHED", YES );
  731.             setnvar( "#WHICH", c );
  732.             break;
  733.         }
  734.     }
  735.     if( c > i ) {    /* Nothing matched */
  736.         setnvar( "#MATCHED", NO );
  737.         setnvar( "#WHICH", 0 );
  738.     }
  739.  
  740. }
  741.  
  742. /*
  743.  * Name    : jump
  744.  * Descrip : Implements the J command in PILOT programs. See rpilot.txt for
  745.  *           info on PILOT 
  746.  * Input   : str = pointer to the entire line taken from the source file 
  747.  * Output  : none
  748.  * Notes   : none
  749.  * Example : jump( "J: *menu" )
  750.  */
  751.  
  752. void jump( char *str )
  753. {
  754.     char args[MAXLINE];
  755.     char exp[MAXLINE];
  756.  
  757.     split( str, exp, args );
  758.     if( ws(exp) != -1 ) {
  759.         if( test( exp ) == NO )
  760.             return;
  761.     }
  762.  
  763.     trim( args );
  764.  
  765.     /* And now handle the jump to the specified label */
  766.     if( args[0] == '*' ) {
  767.         strset( exp, '\0' );
  768.         scopy( exp, args, 1, strlen( args ) - 1 );
  769.         fseek( in, getlbl(exp), SEEK_SET );
  770.     }
  771.     else
  772.         fseek( in, getlbl(args), SEEK_SET );
  773.  
  774. }
  775.  
  776. /*
  777.  * Name    : execute
  778.  * Descrip : Implements the X command in PILOT programs. See rpilot.txt for
  779.  *           info on PILOT 
  780.  * Input   : str = pointer to the entire line taken from the source file 
  781.  * Output  : none
  782.  * Notes   : none
  783.  * Example : execute( "X: T: Hello!" )
  784.  */
  785.  
  786. void execute( char *str )
  787. {
  788.     char args[MAXLINE];
  789.     char exp[MAXLINE];
  790.  
  791.     split( str, exp, args );
  792.     if( ws(exp) != -1 ) {
  793.         if( test( exp ) == NO )
  794.             return;
  795.     }
  796.     ltrim( args );
  797.     strset( exp, 0 );
  798.     getstr( exp, args );
  799.     handle( exp );
  800.  
  801. }
  802.  
  803. /*
  804.  * Name    : yes
  805.  * Descrip : Implements the Y command in PILOT programs. See rpilot.txt for
  806.  *           info on PILOT 
  807.  * Input   : str = pointer to the entire line taken from the source file
  808.  * Output  : none
  809.  * Notes   : none
  810.  * Example : yes( "Y: I thought you'd agree" )
  811.  */
  812.  
  813. void yes( char *str )
  814. {
  815.     char args[MAXLINE];
  816.     char exp[MAXLINE];
  817.     char buffer[MAXLINE];
  818.     int i, c;
  819.  
  820.     split( str, exp, args );
  821.     if( ws(exp) != -1 ) {
  822.         if( test( exp ) == NO )
  823.             return;
  824.     }
  825.  
  826.     if( getnvar("#MATCHED") == YES ) {
  827.         strset( exp, '\0' );
  828.         ltrim( args );
  829.         for(c=0; c<strlen(args); c++) {
  830.                         if( args[c] == '$' ) {  /* find whitespace */
  831.                                 i = find( args, " \t\n", c );   
  832.                                 if( i == -1 )    /* No ws=EOL */
  833.                     i = strlen( args );
  834.                 scopy( exp, args, c, i - c );
  835.                 trim( exp );
  836.                 strset( buffer, '\0' );
  837.                 getsvar( buffer, exp );
  838.                 printf( "%s", buffer );
  839.                 c = i;
  840.             }
  841.             if( args[c] == '#' ) {
  842.                 i = find( args, " \t\n", c );    /* find whitespace */
  843.                                 if( i == -1 )                   /* No ws=EOL */
  844.                     i = strlen( args );
  845.                 scopy( exp, args, c, i - c );
  846.                 printf( "%d", getnvar(exp) );
  847.                 c = i;
  848.             }
  849.             if( (args[c] != '$') && (args[c] != '#') )
  850.                 putchar( args[c] );
  851.         }
  852.         if( c >= strlen(args) )
  853.             printf( "\n" );
  854.     }
  855. }
  856.  
  857. /*
  858.  * Name    : no
  859.  * Descrip : Implements the N command in PILOT programs. See rpilot.txt for
  860.  *           info on PILOT 
  861.  * Input   : str = pointer to the entire line taken from the source file 
  862.  * Output  : none
  863.  * Notes   : none
  864.  * Example : no( "N: You don't like reptiles?  Wierdo!" )
  865.  */
  866.  
  867. void no( char *str )
  868. {
  869.     char args[MAXLINE];
  870.     char exp[MAXLINE];
  871.     char buffer[MAXLINE];
  872.     int i, c;
  873.  
  874.     split( str, exp, args );
  875.     if( ws(exp) != -1 ) {
  876.         if( test( exp ) == NO )
  877.             return;
  878.     }
  879.  
  880.     if( getnvar("#MATCHED") == NO ) {
  881.         strset( exp, '\0' );
  882.         ltrim( args );
  883.         for(c=0; c<strlen(args); c++) {
  884.                         if( args[c] == '$' ) {   /* find whitespace */
  885.                                 i = find( args, " \t\n", c );
  886.                                 if( i == -1 )    /* No ws=EOL */
  887.                     i = strlen( args );
  888.                 scopy( exp, args, c, i - c );
  889.                 trim( exp );
  890.                 strset( buffer, '\0' );
  891.                 getsvar( buffer, exp );
  892.                 printf( "%s", buffer );
  893.                 c = i;
  894.             }
  895.                         if( args[c] == '#' ) {  /* find whitespace */
  896.                                 i = find( args, " \t\n", c );   
  897.                                 if( i == -1 )   /* No ws=EOL */
  898.                     i = strlen( args );
  899.                 scopy( exp, args, c, i - c );
  900.                 printf( "%d", getnvar(exp) );
  901.                 c = i;
  902.             }
  903.             if( (args[c] != '$') && (args[c] != '#') )
  904.                 putchar( args[c] );
  905.         }
  906.         if( c >= strlen(args) )
  907.             printf( "\n" );
  908.     }
  909. }
  910.  
  911. /*
  912.  * Name    : shell
  913.  * Descrip : Implements the S command in PILOT programs. See rpilot.txt for
  914.  *           info on PILOT
  915.  * Input   : str = pointer to the entire line taken from the source file 
  916.  * Output  : none
  917.  * Notes   : none
  918.  * Example : shell( "rm -rf /" )
  919.  */
  920.  
  921. void shell( char *str )
  922. {
  923.     char args[MAXLINE];
  924.     char exp[MAXLINE];
  925.  
  926.     split( str, exp, args );
  927.     if( ws(exp) != -1 ) {
  928.         if( test( exp ) == NO )
  929.             return;
  930.     }
  931.     trim( args );
  932.     strset( exp, 0 );
  933.     getstr( exp, args );
  934.     system( exp );
  935. }
  936.  
  937. /*
  938.  * Name    : debug
  939.  * Descrip : Implements the D command in PILOT programs. See rpilot.txt for
  940.  *           info on PILOT
  941.  * Input   : str = pointer to the entire line taken from the source file
  942.  * Output  : none
  943.  * Notes   : none
  944.  * Example : debug( "lv" )
  945.  */
  946.  
  947. void debug( char *str )
  948. {
  949.     struct lbl *prev;
  950.     struct var *vprev;
  951.     char buffer[MAXVARN];
  952.     char args[MAXLINE];
  953.     char exp[MAXLINE];
  954.     int i;
  955.  
  956.     split( str, exp, args );
  957.     if( ws(exp) != -1 ) {
  958.         if( test( exp ) == NO )
  959.             return;
  960.     }
  961.  
  962.     trim( args );
  963.     puts( "==============================================================================" );
  964.     for(i=0;i<strlen(args);i++) {
  965.         if( toupper(args[i]) == 'L' ) {
  966.             puts( "Label Dump:" );
  967.             prev = lbl1;
  968.             while( prev != NULL ) {
  969.                 printf( "%s : %d\n", prev->name, prev->line );
  970.                 prev = prev->next;
  971.             }
  972.         }
  973.         if( toupper(args[i]) == 'V' ) {
  974.             puts( "Variable Dump:" );
  975.             vprev = var1;
  976.             while( vprev != NULL ) {
  977.                 printf( "%s : ", vprev->name );
  978.                 strcpy( buffer, vprev->name );
  979.                 if( buffer[0] == '$' )      /* String variable */
  980.                     printf( "%s\n", vprev->str );
  981.                 else
  982.                     printf( "%d\n", vprev->num );
  983.                 vprev = vprev->next;
  984.             }
  985.         }
  986.     }
  987.     puts( "==============================================================================" );
  988. }
  989.  
  990. /*
  991.  * Name    : gen
  992.  * Descrip : Implements the G command in PILOT programs. See rpilot.txt for
  993.  *           info on PILOT
  994.  * Input   : str = pointer to the entire line taken from the source file
  995.  * Output  : none
  996.  * Notes   : none
  997.  * Example : gen( "$random 0 100" )
  998.  */
  999.  
  1000. void gen( char *str)
  1001. {
  1002.     char args[MAXLINE];
  1003.     char exp[MAXLINE];
  1004.     int r, i, k;
  1005.  
  1006.     split( str, exp, args );
  1007.     if( ws(exp) != -1 ) {
  1008.         if( test( exp ) == NO )
  1009.             return;
  1010.     }
  1011.     trim( args );
  1012.     strset( exp, 0 );
  1013.     parse( args, 2, exp );
  1014.     i = getval( exp );
  1015.     strset( exp, 0 );
  1016.     parse( args, 3, exp );
  1017.     k = getval( exp );
  1018.     srandom();
  1019.     r = ((rand() % (k+1)) +  i);
  1020.     strset( exp, 0 );
  1021.     parse( args, 1, exp );
  1022.     setnvar( exp, r );
  1023. }
  1024.  
  1025.  
  1026. /*
  1027.  * Name    : setsvar
  1028.  * Descrip : Sets string variable "name" to "val"
  1029.  * Input   :  name = pointer to the name of the variable with leading "$"
  1030.  *            val = pointer to the string to store
  1031.  * Output  : nonzero error code on error (see error code table above), and
  1032.  *           zero on success
  1033.  * Notes   : Leave the initial "$" on the variable name.  Setting a variable
  1034.  *           more than once overwrites the old values
  1035.  * Example : setsvar( "$name", "Floyd" ) - sets variable "$NAME" to "Floyd"
  1036.  */
  1037.  
  1038. int setsvar( char *name, char *val )
  1039. {
  1040.     struct var *prev;
  1041.  
  1042.     prev = var1;
  1043.     lastvar = var1;
  1044.  
  1045.     trim( name );
  1046.     strupr( name );
  1047.     while( lastvar != NULL ) {
  1048.         if( strcmp(lastvar->name, name) == 0 ) {
  1049.             strcpy( lastvar->str, val );
  1050.             return 0;
  1051.         }
  1052.         prev = lastvar;
  1053.         lastvar = lastvar->next;
  1054.     }
  1055.  
  1056.  
  1057.     if ((lastvar = (struct var *) malloc(sizeof *lastvar)) == NULL)
  1058.       err( NO_MEM, FATAL, name );     /* no memory! */
  1059.  
  1060.     strncpy(lastvar->name, name, MAXVARN);
  1061.     strcpy( lastvar->str, val );
  1062.     lastvar->next = NULL;
  1063.  
  1064.     if (prev == NULL)
  1065.       var1 = lastvar;    /* first element in list */
  1066.     else
  1067.       prev->next = lastvar;
  1068.     return 0;
  1069. }
  1070.  
  1071. /*
  1072.  * Name    : setnvar
  1073.  * Descrip : Sets numeric variable "name" to val
  1074.  * Input   :  name = pointer to the name of the variable with leading "#"
  1075.  *            val = pointer to the number to store
  1076.  * Output  : nonzero error code on error (see error code table above), and
  1077.  *           zero on success  
  1078.  * Notes   : Leave the initial "#" on the variable name.  Setting a variable
  1079.  *           more than once overwrites the old values
  1080.  * Example : setnvar( "#age", 73 ) - sets variable "$AGE" to 73
  1081.  */
  1082.  
  1083. int setnvar( char *name, int val )
  1084. {
  1085.     struct var *prev;
  1086.  
  1087.     prev = var1;
  1088.     lastvar = var1;
  1089.  
  1090.     trim( name );
  1091.     strupr( name );
  1092.     while( lastvar != NULL ) {
  1093.         if( strcmp(lastvar->name, name) == 0 ) {
  1094.             lastvar->num = val;
  1095.             return 0;
  1096.         }
  1097.           /*    return( err( DUP_VAR, NONFATAL, name ) ); */
  1098.         prev = lastvar;
  1099.         lastvar = lastvar->next;
  1100.     }
  1101.  
  1102.  
  1103.     if ((lastvar = (struct var *) malloc(sizeof *lastvar)) == NULL)
  1104.       err( NO_MEM, FATAL, name );     /* no memory! */
  1105.  
  1106.     strncpy(lastvar->name, name, MAXVARN);
  1107.     lastvar->num = val;
  1108.     lastvar->next = NULL;
  1109.  
  1110.     if (prev == NULL)
  1111.       var1 = lastvar;    /* first element in list */
  1112.     else
  1113.       prev->next = lastvar;
  1114.     return 0;
  1115. }
  1116.  
  1117. /*
  1118.  * Name    : getnvar
  1119.  * Descrip : Returns the value of the given numeric variable
  1120.  * Input   : name = pointer to the variable's name
  1121.  * Output  : Returns the value of "name", or an error code on errors
  1122.  * Notes   : Leave the initial "#" in the variable name
  1123.  * Example : getnvar( "#score" ) returns the current value of "#score"
  1124.  */
  1125.  
  1126. int getnvar( char *name )
  1127. {
  1128.     struct var *prev;
  1129.  
  1130.     trim( name );
  1131.     strupr( name );
  1132.  
  1133.     prev = var1;
  1134.     while( prev != NULL ) {
  1135.         if( strcmp( prev->name, name ) == 0 )
  1136.             return prev->num;
  1137.         prev = prev->next;
  1138.     }
  1139.     return( err( BAD_VAR, FATAL, name ) );
  1140. }
  1141.  
  1142. /*
  1143.  * Name    : findcol
  1144.  * Descrip : Finds the position of the colon ":" in a PILOT statement
  1145.  * Input   : str = pointer to the line of input
  1146.  * Output  : returns position of the first colon in the string, or -1 if
  1147.  *           isn't one
  1148.  * Notes   : none
  1149.  * Example : findcol( "T : Say Cheese!" ) returns 2
  1150.  */
  1151.                     
  1152. int findcol( char *str )
  1153. {
  1154.     int i;
  1155.  
  1156.     for(i=0;i<strlen(str);i++) {
  1157.         if( str[i] == ':' )
  1158.             return i;
  1159.     }
  1160.     return -1;
  1161. }
  1162.  
  1163. /*
  1164.  * Name    : split
  1165.  * Descrip : Takes a string and splits it into the conditional expression and
  1166.  *           the arguments
  1167.  * Input   : str = pointer to the string to be split
  1168.  *           exp = pointer to string where the conditional expression will be
  1169.  *                 stored
  1170.  *           args = pointer to string where the arguments will be stored
  1171.  * Output  : Stores cond. expression in exp and arguments in args
  1172.  * Notes   : Called by all the PILOT functions (use, type, shell, etc.)
  1173.  * Example : split( "T(33 > #count): Jeepers!", exp, args ) - puts
  1174.  *           "(33> #count)" in exp and " Jeepers!" in args
  1175.  */
  1176.  
  1177. void split( char *str, char *exp, char *args )
  1178. {
  1179.     char buffer[MAXLINE];
  1180.  
  1181.     strset( buffer, '\0' );
  1182.     if( findcol(str) > 1 ) {    /* There is some expression */
  1183.         scopy( buffer, str, 1, findcol(str)-2 );
  1184.         if( ws(buffer) == -1 )
  1185.             strset( exp, '\0' );
  1186.         else {
  1187.             strcpy( exp, buffer );
  1188.             rtrim( exp );
  1189.         }
  1190.     }
  1191.     else
  1192.         strset( exp, 0 );     /* clear the expression */
  1193.  
  1194.     strcpy( buffer, str );
  1195.     rtrim( buffer );
  1196.     if( findcol(str) != strlen(str) )
  1197.         scopy( args, str, findcol(str)+1, strlen(str) - findcol(str) -1);
  1198.     else
  1199.         strset( args, '\0' );   /* clear the arguments */
  1200. }
  1201.  
  1202. /*
  1203.  * Name    : getsvar
  1204.  * Descrip : Gets the value of the string variable "name", and puts it in
  1205.  *           dest.
  1206.  * Input   : dest = pointer to string where the value of "name" will be put
  1207.  *           name = pointer to the name of the variable to look up
  1208.  * Output  : Copies value of "name" into buffer pointed to by dest
  1209.  * Notes   : Leave the initial "$" on the variable name.
  1210.  * Example : getsvar( name, "$name" ) - stores value of "$NAME" in name
  1211.  */
  1212.  
  1213. char *getsvar( char *dest, char *name )
  1214. {
  1215.     struct var *prev;
  1216.  
  1217.     trim( name );
  1218.     strupr( name );
  1219.  
  1220.     prev = var1;
  1221.     while( prev != NULL ) {
  1222.         if( strcmp(prev->name, name) == 0 )
  1223.             return( strcpy(dest, prev->str) );
  1224.  
  1225.         prev = prev->next;
  1226.     }
  1227.  
  1228.     err(BAD_VAR, FATAL, name);
  1229.  
  1230. }
  1231.  
  1232. /*
  1233.  * Name    : explode
  1234.  * Descrip : Takes a string and seperates into into tokens seperated by
  1235.  *           spaces
  1236.  * Input   : dest = pointer to buffer where output will be stored
  1237.  *           src = pointer to string to use as input
  1238.  * Output  : Stores parsed form of str in dest
  1239.  * Notes   : This function makes life easier on the expression handler,
  1240.  *           express().  It was written with clarity in mind, and handles
  1241.  *           all valid relational and math operators
  1242.  * Example : explode( dest, "4+5%6<6" ) - stores "4 + 5 % 6 < 6" in dest
  1243.  */
  1244.  
  1245. void explode( char *dest, char *src )
  1246. {
  1247.     int k, i;
  1248.  
  1249.     i = 0;
  1250.     for(k=0;k<strlen(src);k++) {
  1251.         switch( src[k] ) {
  1252.             case '+' : if( dest[i-1] != ' ' ) {
  1253.                             dest[i] = ' ';
  1254.                             dest[++i] = '+';
  1255.                             dest[++i] = ' ';
  1256.                             i++;
  1257.                        }
  1258.                        else {
  1259.                             dest[i] = '+';
  1260.                             dest[++i] = ' ';
  1261.                             i++;
  1262.                        }
  1263.                        break;
  1264.             case '-' : if( dest[i-1] != ' ' ) {
  1265.                             dest[i] = ' ';
  1266.                             dest[++i] = '-';
  1267.                             dest[++i] = ' ';
  1268.                             i++;
  1269.                        }
  1270.                        else {
  1271.                             dest[i] = '-';
  1272.                             dest[++i] = ' ';
  1273.                             i++;
  1274.                        }
  1275.                        break;
  1276.             case '*' : if( dest[i-1] != ' ' ) {
  1277.                             dest[i] = ' ';
  1278.                             dest[++i] = '*';
  1279.                             dest[++i] = ' ';
  1280.                             i++;
  1281.                        }
  1282.                        else {
  1283.                             dest[i] = '*';
  1284.                             dest[++i] = ' ';
  1285.                             i++;
  1286.                        }
  1287.                        break;
  1288.             case '/' : if( dest[i-1] != ' ' ) {
  1289.                             dest[i] = ' ';
  1290.                             dest[++i] = '/';
  1291.                             dest[++i] = ' ';
  1292.                             i++;
  1293.                        }
  1294.                        else {
  1295.                             dest[i] = '/';
  1296.                             dest[++i] = ' ';
  1297.                             i++;
  1298.                        }
  1299.                        break;
  1300.             case '^' : if( dest[i-1] != ' ' ) {
  1301.                             dest[i] = ' ';
  1302.                             dest[++i] = '^';
  1303.                             dest[++i] = ' ';
  1304.                             i++;
  1305.                        }
  1306.                        else {
  1307.                             dest[i] = '^';
  1308.                             dest[++i] = ' ';
  1309.                             i++;
  1310.                        }
  1311.                        break;
  1312.             case '%' : if( dest[i-1] != ' ' ) {
  1313.                             dest[i] = ' ';
  1314.                             dest[++i] = '%';
  1315.                             dest[++i] = ' ';
  1316.                             i++;
  1317.                        }
  1318.                        else {
  1319.                             dest[i] = '%';
  1320.                             dest[++i] = ' ';
  1321.                             i++;
  1322.                        }
  1323.                        break;
  1324.             case '&' : if( dest[i-1] != ' ' ) {
  1325.                             dest[i] = ' ';
  1326.                             dest[++i] = '&';
  1327.                             dest[++i] = ' ';
  1328.                             i++;
  1329.                        }
  1330.                        else {
  1331.                             dest[i] = '&';
  1332.                             dest[++i] = ' ';
  1333.                             i++;
  1334.                        }
  1335.                        break;
  1336.             case '|' : if( dest[i-1] != ' ' ) {
  1337.                             dest[i] = ' ';
  1338.                             dest[++i] = '|';
  1339.                             dest[++i] = ' ';
  1340.                             i++;
  1341.                        }
  1342.                        else {
  1343.                             dest[i] = '|';
  1344.                             dest[++i] = ' ';
  1345.                             i++;
  1346.                        }
  1347.                        break;
  1348.             case ')' : dest[i] = ' ';
  1349.                        i++;
  1350.                        break;
  1351.             case '(' : dest[i] = ' ';
  1352.                        i++;
  1353.                        break;
  1354.             case '=' : if( (src[k-1] == '<') || (src[k-1] == '>') ) {
  1355.                            dest[i] = '=';
  1356.                            dest[++i] = ' ';
  1357.                            i++;
  1358.                        }
  1359.                        else {
  1360.                            if( dest[i-1] != ' ' ) {
  1361.                                 dest[i] = ' ';
  1362.                                 dest[++i] = '=';
  1363.                                 dest[++i] = ' ';
  1364.                                 i++;
  1365.                            }
  1366.                            else {
  1367.                                 dest[i] = '=';
  1368.                                 dest[++i] = ' ';
  1369.                                 i++;
  1370.                            }
  1371.                        }
  1372.                        break;
  1373.             case '<' : if( src[k+1] == '>' ) {
  1374.                             if( dest[i-1] != ' ' ) {
  1375.                                 dest[i] = ' ';
  1376.                                 dest[++i] = '<';
  1377.                                 dest[++i] = '>';
  1378.                                 dest[++i] = ' ';
  1379.                                 i++;
  1380.                             }
  1381.                             else {
  1382.                                 dest[i] = '<';
  1383.                                 dest[++i] = '>';
  1384.                                 dest[++i] = ' ';
  1385.                                 i++;
  1386.                             }
  1387.                        }
  1388.                        if( src[k+1] == '=' ) {
  1389.                             if( dest[i-1] != ' ' ) {
  1390.                                 dest[i] = ' ';
  1391.                                 dest[++i] = '<';
  1392.                                 dest[++i] = '=';
  1393.                                 dest[++i] = ' ';
  1394.                                 i++;
  1395.                             }
  1396.                             else {
  1397.                                 dest[i] = '<';
  1398.                                 dest[++i] = '=';
  1399.                                 dest[++i] = ' ';
  1400.                                 i++;
  1401.                             }
  1402.                        }
  1403.                        if( (src[k+1] != '>') && (src[k+1] != '=') ) {
  1404.                             if( dest[i-1] != ' ' ) {
  1405.                                 dest[i] = ' ';
  1406.                                 dest[++i] = '<';
  1407.                                 dest[++i] = ' ';
  1408.                                 i++;
  1409.                             }
  1410.                             else {
  1411.                                 dest[i] = '<';
  1412.                                 dest[++i] = ' ';
  1413.                                 i++;
  1414.                             }
  1415.                        }
  1416.                        break;
  1417.             case '>' : if( src[k+1] == '=' ) {
  1418.                             if( dest[i-1] != ' ' ) {
  1419.                                 dest[i] = ' ';
  1420.                                 dest[++i] = '>';
  1421.                                 dest[++i] = '=';
  1422.                                 dest[++i] = ' ';
  1423.                                 i++;
  1424.                             }
  1425.                             else {
  1426.                                 dest[i] = '>';
  1427.                                 dest[++i] = '=';
  1428.                                 dest[++i] = ' ';
  1429.                                 i++;
  1430.                             }
  1431.                        }
  1432.                        else {
  1433.                             if( dest[i-1] != ' ' ) {
  1434.                                 dest[i] = ' ';
  1435.                                 dest[++i] = '>';
  1436.                                 dest[++i] = ' ';
  1437.                                 i++;
  1438.                             }
  1439.                             else {
  1440.                                 dest[i] = '>';
  1441.                                 dest[++i] = ' ';
  1442.                                 i++;
  1443.                             }
  1444.                        }
  1445.                        break;
  1446.                 default  : dest[i] = src[k];
  1447.                        i++;
  1448.                        break;
  1449.         }
  1450.     }
  1451.     dest[i] = ' ';
  1452.     dest[i+1] = '\0';
  1453. }
  1454.  
  1455. /*
  1456.  * Name    : express
  1457.  * Descrip : This is the math expression handler.  It takes a string and
  1458.  *           returns the numeric result, substituting variables as needed
  1459.  * Input   : form = pointer to a string to use as input
  1460.  * Output  : Returns the result on success, and calls err() on errors
  1461.  * Notes   : This is pretty simple, there is no operator precedence, and
  1462.  *           parenthesis are thrown away
  1463.  * Example : express( "3+3" ) - returns 6
  1464.  */
  1465.  
  1466. int express( char *form )
  1467. {
  1468.         int result = 0;             /* To hold the mathematical result */
  1469.     int i;
  1470.         char temp[MAXVARN];         /* To hold the parse()'d output ); */
  1471.     char buffer[MAXLINE];
  1472.         char op[2];                 /* Holds math operator (+,-,/,*) */
  1473.  
  1474.     explode( buffer, form );
  1475.     parse( buffer, 1, temp );
  1476.     result = getval( temp );
  1477.     if( numstr(buffer) > 1 ) {
  1478.         parse( buffer, 2, temp );
  1479.         strncpy( op, temp, 2 );
  1480.         for(i=3; i<=numstr(buffer); i+=2) {
  1481.             strset( temp, '\0' );
  1482.             parse( buffer, i, temp );
  1483.             switch( op[0] ) {
  1484.                 case '+' : result += getval( temp );
  1485.                            break;
  1486.                 case '-' : result -= getval( temp );
  1487.                            break;
  1488.                 case '/' : result /= getval( temp );
  1489.                            break;
  1490.                 case '*' : result *= getval( temp );
  1491.                            break;
  1492.                 case '%' : result %= getval( temp );
  1493.                            break;
  1494.                 case '&' : result &= getval( temp );
  1495.                            break;
  1496.                 case '|' : result |= getval( temp );
  1497.                            break;
  1498.                 case '^' : result ^= getval( temp );
  1499.                            break;
  1500.                 default  : return( err( EXP_MATH, FATAL, op ) );
  1501.             }
  1502.             parse( buffer, i+1, op );
  1503.         }
  1504.     }
  1505.     return result;
  1506. }
  1507.  
  1508. /*
  1509.  * Name    : getval
  1510.  * Descrip : Gets the value of any numeric string, including variables
  1511.  * Input   : str = pointer to a string which either contains a variable name
  1512.  *           or the ASCII representation of a number
  1513.  * Output  : Returns the numeric version of the string
  1514.  * Notes   : Very simple.  Make sure variables start with a "#"
  1515.  * Example : getval( "#num" ) - returns value of "#num"
  1516.  *           getval( "998" )  - retruns 998 
  1517.  */
  1518.  
  1519. int getval( char *str )
  1520. {
  1521.     if( str[0] == '#' )
  1522.         return( getnvar(str) );
  1523.     return( atoi( str ) );
  1524. }
  1525.  
  1526. /*
  1527.  * Name    : test
  1528.  * Descrip : This is the conditional expression handler.  it checks all
  1529.  *           conditional expressions to see if they are true or not.
  1530.  * Input   : buffer = pointer to a string to use as input
  1531.  * Output  : Returns YES if the expression is true; NO if it isn't
  1532.  * Notes   : Handles all boolean expressions and numeric variables.
  1533.  * Example : test( "33 != 34" )     - returns YES
  1534.  *           test( "#score >= 10" ) - returns YES if "#score" is more than or
  1535.  *                                    equal to 10, otherwise NO
  1536.  */
  1537.  
  1538. int test( char *buffer )
  1539. {
  1540.     int i;
  1541.     int i2=0;
  1542.     int r1;
  1543.     int r2;
  1544.     char buf2[MAXLINE];
  1545.     char op[3];
  1546.  
  1547.     strset( buf2, '\0' );
  1548.     i = ws( buffer );
  1549.     if( toupper(buffer[i]) == 'Y' ) {
  1550.         if( getnvar("#MATCHED") == YES )
  1551.             return YES;
  1552.         else
  1553.             return NO;
  1554.     }
  1555.     if( toupper(buffer[i]) == 'N' ) {
  1556.         if( getnvar("#MATCHED") == NO )
  1557.             return YES;
  1558.         else
  1559.             return NO;
  1560.     }
  1561.  
  1562.     for(i=0; i<strlen(buffer); i++) {
  1563.         if( (buffer[i] == '=') || (buffer[i] == '>') || (buffer[i] == '<') ) {
  1564.             if( (buffer[i+1] == '=') || (buffer[i+1] == '>') ) {
  1565.                 scopy( op, buffer, i, 2 );
  1566.                 i2 = 1;
  1567.             }
  1568.             else {
  1569.                 op[0] = buffer[i];
  1570.                 op[1] = '\0';
  1571.             }
  1572.             break;
  1573.         }
  1574.     }
  1575.     if( i == strlen(buffer) )
  1576.         return( err( NO_RELAT, FATAL, "" ) );
  1577.     scopy( buf2, buffer, 0, i-1 );
  1578.     r1 = express( buf2 );
  1579.     if( i2 )
  1580.         scopy( buf2, buffer, i+2, strlen(buffer) - i+1 );
  1581.     else
  1582.         scopy( buf2, buffer, i+1, strlen(buffer) - i );
  1583.     r2 = express( buf2 );
  1584.     trim( op );
  1585.  
  1586.     if( strcmp("=", op) == 0 ) {
  1587.         if( r1 == r2 )
  1588.             return YES;
  1589.         else
  1590.             return NO;
  1591.     }
  1592.     if( strcmp(">", op) == 0 ) {
  1593.         if( r1 > r2 )
  1594.             return YES;
  1595.         else
  1596.             return NO;
  1597.     }
  1598.     if( strcmp("<", op) == 0 ) {
  1599.         if( r1 < r2 )
  1600.             return YES;
  1601.         else
  1602.             return NO;
  1603.     }
  1604.     if( strcmp("<>", op) == 0 ) {
  1605.         if( r1 != r2 )
  1606.             return YES;
  1607.         else
  1608.             return NO;
  1609.     }
  1610.     if( strcmp("<=", op) == 0 ) {
  1611.         if( r1 <= r2 )
  1612.             return YES;
  1613.         else
  1614.             return NO;
  1615.     }
  1616.     if( strcmp(">=", op) == 0 ) {
  1617.         if( r1 >= r2 )
  1618.             return YES;
  1619.         else
  1620.             return NO;
  1621.     }
  1622. }
  1623.  
  1624. /*
  1625.  * Name    : getstr
  1626.  * Descrip : Gets the value of the string variable "src"
  1627.  * Input   : dest = pointer to a string to store value of "src" in
  1628.  *           src = pointer to the string to use as the input
  1629.  * Output  : Puts the value of "src" into the string pointed to by dest
  1630.  * Notes   : This works just like getval(), but for strings
  1631.  * Example : 
  1632.  */
  1633.  
  1634. char *getstr( char *dest, char *src )
  1635. {
  1636. /*    int k;*/
  1637.  
  1638.     dest[0] = '\0';
  1639.  
  1640.     if( src[0] == '$' ) {
  1641.         getsvar( dest, src );
  1642.         return dest;
  1643.     }
  1644.     strcpy( dest, src );
  1645. /*
  1646.     for(k=0; k<strlen(src); k++) {
  1647.         if( src[k] == '\\' ) {
  1648.             switch( src[k+1] ) {
  1649.                 case '\\' : strcat( dest, "\\" );
  1650.                             break;
  1651.                 case 'n'  : strcat( dest, "\n" );
  1652.                             break;
  1653.                 case '\"' : strcat( dest, "\"" );
  1654.                             break;
  1655.                 case 't'  : strcat( dest, "\t" );
  1656.                             break;
  1657.             }
  1658.         }
  1659.     }*/
  1660.     return src;
  1661. }
  1662.  
  1663. /*
  1664.  * Name    : getlbl
  1665.  * Descrip : This gets the seek value of the label "name"
  1666.  * Input   : name = pointer to the name of a label
  1667.  * Output  : Returns the seek address of the label
  1668.  * Notes   : This is used with fseek() to implement jumps
  1669.  * Example : getlbl( "end" ) - returns offset of the "END" label
  1670.  */
  1671.  
  1672. long getlbl( char *name )
  1673. {
  1674.     struct lbl *prev;
  1675.  
  1676.     prev = lbl1;
  1677.  
  1678.     trim( name );
  1679.     strupr( name );
  1680.     while( prev != NULL ) {
  1681.         if( strcmp(prev->name, name) == 0 )
  1682.             return prev->line;
  1683.         prev = prev->next;
  1684.     }
  1685. }
  1686.  
  1687.