--- /dev/null
+
+To compile RPilot, run `make'.
+
+To install it, run `make install'. To install under a directory other than
+/usr/local/, run `make install INSTALL_DIR=/the/new/dir'.
--- /dev/null
+CC = sdcc
+ASM = sdasz80
+AR = sdar
+LINKER = sdcc
+FCC = ../../Library/tools/fcc -O2
+PLATFORM =
+#PLATFORM = -tzx128
+
+.SUFFIXES: .c .rel
+
+SRCS = bind.c calc.c cmds.c condex.c debug.c err.c interact.c label.c \
+ line.c main.c math.c rpilot.c rpinfo.c rstring.c stack.c var.c
+
+INCS = bind.h calc.h cmds.h condex.h debug.h err.h interact.h label.h \
+ line.h main.h math.h rpilot.h rpinfo.h rstring.h stack.h var.h
+
+
+OBJS = $(SRCS:.c=.rel)
+
+LIBS = ../../Library/libs/syslib.lib
+
+all: rpilot
+
+rpilot: $(OBJS)
+ $(FCC) $(PLATFORM) $(OBJS) -o $@
+
+$(OBJS): $(INCS)
+
+.c.rel:
+ $(FCC) $(PLATFORM) -DNO_INTER -DIGNORE_HASH -c $<
+
+%: %.rel
+ $(FCC) $(PLATFORM) $< -o $@
+
+clean:
+ rm -f $(OBJS) rpilot $(SRCS:.c=) core *~ *.asm *.lst *.sym *.map *.noi *.lk *.ihx *.tmp *.bin
+
+rmbak:
+ rm -f *~ core
+
--- /dev/null
+.SUFFIXES: .c .o
+
+SRCS = bind.c calc.c cmds.c condex.c debug.c err.c interact.c label.c \
+ line.c main.c math.c rpilot.c rpinfo.c rstring.c stack.c var.c
+
+INCS = bind.h calc.h cmds.h condex.h debug.h err.h interact.h label.h \
+ line.h main.h math.h rpilot.h rpinfo.h rstring.h stack.h var.h
+
+
+OBJS = $(SRCS:.c=.o)
+
+all: rpilotgcc
+
+rpilotgcc: $(OBJS)
+ $(CC) $(PLATFORM) $(OBJS) -o $@
+
+$(OBJS): $(INCS)
+
+.c.o:
+ $(CC) $(PLATFORM) -DNO_INTER -DIGNORE_HASH -c $<
+
+%: %.o
+ $(CC) $(PLATFORM) $< -o $@
+
+clean:
+ rm -f $(OBJS) rpilot $(SRCS:.c=) core *~ *.asm *.lst *.sym *.map *.noi *.lk *.ihx *.tmp *.bin
+
+rmbak:
+ rm -f *~ core
+
--- /dev/null
+#include "rpilot.h"
+#include "bind.h"
+#include <string.h>
+
+char *filebase( char *filename )
+{
+ int dotpos, i;
+
+ dotpos = -1;
+ for( i=strlen(filename)-1; i>=0; i-- ) {
+ if( filename[i] == '.' ) {
+ dotpos = i;
+ break;
+ }
+ }
+
+ if( dotpos == -1 ) {
+ return filename;
+ } else {
+ return new_string_from( filename, 0, dotpos );
+ }
+}
+
+void bindfile( char *filename, char *outfile, char *dataname, char *funcname,
+ int mainfunc )
+{
+ FILE *header, *source;
+ char *base, *hfile, *srcfile;
+ line *curr;
+ char *buffer;
+ int i;
+
+ if( outfile == NULL ) {
+ base = filebase( filename );
+ } else {
+ base = outfile;
+ }
+
+
+ hfile = (char *)malloc(strlen(base)+3);
+ strcpy( hfile, base );
+ strcat( hfile, ".h" );
+ srcfile = (char *)malloc(strlen(base)+3);
+ strcpy( srcfile, base );
+ strcat( srcfile, ".c" );
+
+ if( (header = fopen(hfile, "w")) == NULL ) {
+ err( ERR_FILE, hfile );
+ }
+ if( (source = fopen(srcfile, "w")) == NULL ) {
+ err( ERR_FILE, srcfile );
+ }
+
+ if( dataname == NULL ) {
+ dataname = new_string( "pilot_data" );
+ }
+ if( funcname == NULL ) {
+ funcname = new_string( "run_pilot" );
+ }
+
+
+ init();
+ readfile( filename );
+
+
+ // start outputting to files
+
+ fprintf( header, "/* PILOT code datafile - generated by RPilot %s */\n\n",
+ VERSION );
+ fprintf( header, "#ifndef _%s_h_\n#define _%s_h_\n\n", base, base );
+ fprintf( header, "#include <stdio.h>\n\n" );
+
+ fprintf( header, "void %s(void);\n", funcname );
+ fprintf( header, "\n\n#endif" );
+
+ fclose( header );
+
+
+ fprintf( source, "/* PILOT code source file - generated by RPilot %s */\n\n",
+ VERSION );
+ fprintf( source, "#include \"%s\"\n\n", hfile );
+ fprintf( source, "extern void run_bound( char *code[] );\n\n" );
+ fprintf( source, "void %s(void)\n{\n", funcname );
+
+ fprintf( source, "char *%s[] = {\n", dataname );
+
+ curr = (line *)rpi->linehead;
+ curr = (line *)curr->next; // first entry is always blank, so skip it
+
+ while( curr != NULL ) {
+
+ print_line( curr );
+ printf( "\n" );
+
+ buffer = get_line( curr );
+ fprintf( source, "\"" );
+ for( i = 0; i<strlen(buffer); i++ ) {
+ switch( buffer[i] ) {
+ case '\"' :
+ fprintf( source, "\\\"" );
+ break;
+ case '\'' :
+ fprintf( source, "\\\'" );
+ break;
+ case '\\' :
+ fprintf( source, "\\\\" );
+ break;
+ default:
+ fprintf( source, "%c", buffer[i] );
+ break;
+ }
+ }
+ fprintf( source, "\",\n" );
+ free( buffer );
+ // fprintf( source, " \"" );
+ // print_line_to( curr, source );
+ // fprintf( source, "\",\n" );
+ curr = (line *)curr->next;
+ }
+
+ fprintf( source, "NULL\n};\n\n" );
+
+ fprintf( source, "run_bound( %s );\n}\n\n", dataname );
+
+ if( mainfunc == TRUE ) {
+ fprintf( source, "int main( int argc, char *argv[] )\n{\n" );
+ fprintf( source, " %s();\n return 0;\n}\n\n", funcname );
+ }
+
+ fclose( source );
+
+}
+
+
+// run some bound code
+void run_bound( char *code[] )
+{
+ line *curr;
+ int i = 0;
+
+ init();
+ rpi->filename = new_string( "<<Bound Code>>" );
+
+ curr = (line *)rpi->linehead;
+
+ while( code[i] != NULL ) {
+ printf( "code[%d] is \"%s\"\n", i, code[i] );
+ curr->next = (struct line *)new_line( code[i], '!', i+1 );
+ curr = (line *)curr->next;
+ i++;
+ }
+
+ curr = (line *)rpi->linehead;
+ rpi->linehead = curr->next;
+ interp();
+}
+
--- /dev/null
+// header for bind.c
+
+#ifndef _bind_h_
+#define _bind_h_
+
+#define BIND_HEADER "bind.h"
+
+void bindfile( char *filename, char *outfile, char *dataname, char *funcname,
+ int manifunc );
+
+void run_bound( char *code[] );
+
+
+#endif
--- /dev/null
+/*
+ * calc.c - handle simple mathematical expressions
+ * rob - started july.25.2000
+ *
+ * updates:
+ * - got around to finishing it - aug.11.2000
+ * - RPilot special code - aug.11.2000
+ */
+
+#include "rpilot.h"
+#include "rstring.h"
+#include "calc.h"
+#include "var.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+int next_num( char *str, int *pos, int *status );
+char next_tok( char *str, int *pos );
+int find_match( char *str, int pos, char what, char match );
+int read_num( char *str, int *pos );
+int read_var( char *str, int *pos );
+
+int calc( char *expr, int *status )
+{
+ int pos = 0;
+ int num = 0, result = 0;
+ char op = 0;
+
+ total_trim( expr );
+
+ result = next_num( expr, &pos, status );
+
+ while( pos < strlen(expr) ) {
+
+
+ op = next_tok( expr, &pos );
+ num = next_num( expr, &pos, status );
+
+
+ switch( op ) {
+ case 0 : // invalid operand
+ *status = CALC_NO_OP;
+ return 0;
+ break;
+ case '+' :
+ result += num;
+ break;
+ case '-' :
+ result -= num;
+ break;
+ case '/' :
+ result /= num;
+ break;
+ case '*' :
+ result *= num;
+ break;
+ case '%' :
+ result %= num;
+ break;
+ case '&' :
+ result &= num;
+ break;
+ case '|' :
+ result |= num;
+ break;
+ case '^' :
+ result ^= num;
+ break;
+ default:
+ *status = CALC_BAD_OP;
+ return 0;
+ break;
+ }
+ }
+
+ *status = CALC_SUCCESS;
+ return result;
+}
+
+
+
+
+int next_num( char *str, int *pos, int *status )
+{
+ char *inparen, *tempstr;
+ int result, rparen;
+ int mult = 1;
+
+ *pos = wspace( str, *pos );
+
+ if( str[*pos] == '-' ) {
+ mult = -1;
+ *pos += 1;
+ }
+ if( str[*pos] == '(' ) {
+ rparen = find_match( str, *pos+1, ')', '(' );
+ inparen = new_string_from( str, *pos+1, rparen-*pos-1 );
+
+ *pos = rparen+1;
+
+ result = calc( inparen, status );
+ free( inparen );
+ } else if( str[*pos] == '#' ) { // variable
+ result = read_var( str, pos );
+ } else {
+ result = read_num( str, pos );
+ }
+
+ return result * mult;
+}
+
+/*
+ * find_match()
+ * Returns the position in the string `str' of the matching character.
+ * Example: find_match( "((8*8)+9)/2", 1, ')', '(' ) => 8
+ */
+int find_match( char *str, int pos, char what, char match )
+{
+ int levels = 1;
+ int i = pos;
+
+ do {
+ if( str[i] == what ) {
+ levels--;
+ } else if( str[i] == match ) {
+ levels++;
+ }
+ i++;
+ } while( levels != 0 );
+
+ return i-1;
+}
+
+
+int read_num( char *str, int *pos )
+{
+ int start;
+ int numchars;
+ char *num;
+ int result;
+
+ start = wspace( str, *pos );
+ numchars = start;
+
+ while( isdigit(str[numchars]) ) {
+ numchars++;
+ }
+
+ num = new_string_from( str, start, numchars - start );
+
+ *pos = numchars;
+
+ result = atoi( num );
+ free( num );
+
+ return result;
+}
+
+
+char next_tok( char *str, int *pos )
+{
+ int nows = wspace( str, *pos );
+ *pos = nows;
+
+ *pos += 1; // increment position counter
+ return str[nows];
+}
+
+
+
+int read_var( char *str, int *pos )
+{
+ int start;
+ int numchars;
+ char *var;
+ int result;
+
+ start = *pos;
+ numchars = start + 1;
+
+ while( isalpha(str[numchars]) ) {
+ numchars++;
+ }
+
+ var = new_string_from( str, start, numchars - start );
+
+ // printf( "*** read_var(): var = \"%s\"\n", var );
+
+ *pos = numchars;
+
+ result = get_numvar( var );
+ free( var );
+
+ return result;
+}
--- /dev/null
+/*
+ * calc.h - header file for the calc package
+ * rob linwood (rcl211@nyu.edu)
+ * see README for more information
+ */
+
+#ifndef _calc_h_
+#define _calc_h_
+
+#define CALC_SUCCESS 0 /* Indicates success */
+#define CALC_NO_OP 1 /* No mathematical operator in expression */
+#define CALC_BAD_OP 2 /* Unknown mathematical operator in expression */
+
+int calc( char *expr, int *status );
+
+#endif
--- /dev/null
+/*
+ cmds.c - RPilot commands functions
+*/
+
+
+#include "rpilot.h"
+#include "math.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef isblank
+#define isblank(ch) (ch==' ' || ch == '\t')
+#endif
+
+/* FIXME: move this into the C headers where it belongs */
+#ifndef RAND_MAX
+#define RAND_MAX 32767
+#endif
+
+/*
+ * internal_type takes a string and formats it like it would be for a T:
+ * statement, but returning a string rather than printing it to the screen
+ */
+char *internal_type( char *str )
+{
+ int i;
+ int nextsp;
+ char *varname;
+ char output[500], *ret;
+
+
+ if( str == NULL ) {
+ return new_string("");
+ }
+
+
+ // output = (char *)malloc(5000);
+ strcpy( output, "" );
+
+ for( i=0; i<strlen(str); i++ ) {
+ if( (str[i] == '$') && (!isblank(str[i+1])) ) {
+ if( str[i+1] == '$' ) {
+ i+=2;
+ } else {
+ nextsp = find( str, " \t", i ); // find next space
+ if( nextsp == -1 ) { // no more spaces, use the rest of the line
+ varname = new_string_from( str, i, strlen(str)-i );
+ } else {
+ varname = new_string_from( str, i, nextsp-i );
+ }
+ sprintf( output, "%s%s ", output, get_strvar( varname) );
+ i+=strlen( varname );
+ free( varname );
+ }
+ } else if( (str[i] == '#') && (!isblank(str[i+1])) ) {
+ if( str[i+1] == '#' ) {
+ i+=2;
+ } else {
+ nextsp = find( str, " \t", i ); // find next space;
+ if( nextsp == -1 ) { // no more spaces, use the rest of the line
+ varname = new_string_from( str, i, strlen(str)-i );
+ } else {
+ varname = new_string_from( str, i, nextsp-i );
+ }
+ sprintf( output, "%s%d ", output, get_numvar( varname) );
+ i+=strlen( varname );
+ free( varname );
+ }
+ } else {
+ sprintf( output, "%s%c", output, str[i] );
+ }
+ // printf( "output=\"%s\"\n", output );
+
+ }
+
+ ret = new_string( output );
+ // free( output );
+ // printf("!!output=\"%s\", len=%d\n", output, strlen(output) );
+ // printf("!!ret=\"%s\", len=%d\n", ret, strlen(ret) );
+
+ return ret;
+}
+
+
+/*
+ * the cmd_ functions implement the PILOT statements that they're named after
+ */
+
+void cmd_use( char *str )
+{
+ use( str );
+}
+
+void cmd_compute( char *str )
+{
+ char *lside, *rside;
+ int eqlpos;
+ int i;
+
+ if( str == NULL ) {
+ return;
+ }
+
+ trim( str );
+
+ for( eqlpos=0; eqlpos<strlen(str); eqlpos++ ) {
+ if( str[eqlpos] == '=' ) {
+ break;
+ }
+ }
+
+ if( eqlpos == strlen(str) ) {
+ err( NO_EQL, str );
+ }
+
+ lside = new_string_from( str, 0, eqlpos );
+ rside = new_string_from( str, eqlpos+1, strlen(str)-eqlpos-1 );
+ trim( lside );
+ trim( rside );
+
+ if( lside[0] == '#' ) { // numeric variable, so a simple assignment
+ set_numvar( lside, express(rside) );
+ } else if( lside[0] == '$' ) { // string var, copy all strings on the right
+ set_strvar( lside, internal_type(rside) );
+ } else {
+ err( CONS_ASGN, lside );
+ }
+
+
+ free( lside );
+ free( rside );
+}
+
+
+
+void cmd_accept( char *str )
+{
+ char inbuf[MAXLINE];
+ int i;
+
+ fflush( stdin );
+ printf( "%s ", get_strvar("$PROMPT") ); // print the prompt
+
+ trim( str );
+
+ if( !strcmp(str, "") ) { // blank args, so we put it in $accept
+ fgets( inbuf, MAXLINE-1, stdin );
+ chop( inbuf ); // remove trailing LF
+ set_strvar( "$ACCEPT", inbuf );
+ free( rpi->lastacc );
+ rpi->lastacc = new_string( "$ACCEPT" );
+ } else if( str[0] == '$' ) { // we need to read a string variable
+ fgets( inbuf, MAXLINE-1, stdin );
+ chop( inbuf );
+ if( !strcmp(inbuf, "") ) { // did the user enter a blank line?
+ strcpy( inbuf, "[BLANK]" ); // FIXME ....maybe
+ }
+ set_strvar( str, inbuf );
+ free( rpi->lastacc );
+ rpi->lastacc = new_string( str );
+ } else if( str[0] == '#' ) { // read a numeric var
+ fgets( inbuf, MAXLINE-1, stdin );
+ chop( inbuf );
+ i = atoi( inbuf );
+ // scanf( "%d", &i );
+ set_numvar( str, i );
+ free( rpi->lastacc );
+ rpi->lastacc = new_string( str );
+ }
+
+ fflush(stdin);
+}
+
+
+void cmd_type( char *str )
+{
+/* int i; */
+/* int nextsp; */
+/* char *varname; */
+
+/* if( str == NULL ) { */
+/* //puts( "T: empty arguments (str == NULL)" ); */
+/* return; */
+/* } */
+
+/* for( i=0; i<strlen(str); i++ ) { */
+/* if( (str[i] == '$') && (!isblank(str[i+1])) ) { */
+/* if( str[i+1] == '$' ) { */
+/* i+=2; */
+/* } else { */
+/* nextsp = find( str, " \t", i ); // find next space */
+/* if( nextsp == -1 ) { // no more spaces, use the rest of the line */
+/* varname = new_string_from( str, i, strlen(str)-i ); */
+/* } else { */
+/* varname = new_string_from( str, i, nextsp-i ); */
+/* } */
+/* printf( "%s ", get_strvar( varname) ); */
+/* i+=strlen( varname ); */
+/* free( varname ); */
+/* } */
+/* } else if( (str[i] == '#') && (!isblank(str[i+1])) ) { */
+/* if( str[i+1] == '#' ) { */
+/* i+=2; */
+/* } else { */
+/* nextsp = find( str, " \t", i ); // find next space; */
+/* if( nextsp == -1 ) { // no more spaces, use the rest of the line */
+/* varname = new_string_from( str, i, strlen(str)-i ); */
+/* } else { */
+/* varname = new_string_from( str, i, nextsp-i ); */
+/* } */
+/* printf( "%d ", get_numvar( varname) ); */
+/* i+=strlen( varname ); */
+/* free( varname ); */
+/* } */
+/* } else { */
+/* putchar( str[i] ); */
+/* } */
+/* } */
+
+ char *output;
+
+ output = internal_type( str );
+ printf( "%s\n", output );
+ free( output );
+
+}
+
+
+void cmd_end( char *str )
+{
+
+ rpi->currline = (struct line *)stk_pop( (stack *)rpi->stk );
+
+}
+
+
+void cmd_match( char *str )
+{
+ int count = numstr( str );
+ int i;
+ // char *temp = (char *)malloc( strlen(str)+1 );
+ char *temp = NULL;
+
+ strupr( str );
+ for( i=1; i<count+1; i++ ) { // count;
+ // strset( temp, 0 );
+ temp = parse( str, i );
+ if( !strcmp(strupr(get_strvar(rpi->lastacc)), temp) ) {
+ set_numvar( "#MATCHED", 1 );
+ set_numvar( "#WHICH", i );
+ return;
+ }
+ }
+
+ free( temp );
+
+ set_numvar( "#MATCHED", 0 );
+ set_numvar( "#WHICH", 0 );
+}
+
+
+
+void cmd_jump( char *str )
+{
+ jump( str );
+}
+
+
+void cmd_execute( char *str )
+{
+ execute( str );
+}
+
+// Types a line if #matched == TRUE
+void cmd_yes( char *str )
+{
+
+ if( get_numvar( "#MATCHED") == TRUE ) {
+ cmd_type( str );
+ }
+}
+
+
+// Types a line if #matched == FALSE
+void cmd_no( char *str )
+{
+
+ if( get_numvar("#MATCHED") == FALSE ) {
+ cmd_type( str );
+ }
+}
+
+
+
+// call a shell
+void cmd_shell( char *str )
+{
+ int retcode;
+
+ retcode = system( get_strval(str) );
+ set_numvar( "#RETCODE", retcode );
+}
+
+
+
+void cmd_debug( char *str )
+{
+ debug();
+}
+
+
+void cmd_generate( char *str )
+{
+ int upper, lower, rnd;
+ char *exp, *var;
+
+ if( !strcmp(str, "") ) {
+ // do what?
+ } else {
+ trim( str );
+ }
+
+ var = parse( str, 1 );
+ exp = parse( str, 2 );
+ lower = get_numval( exp );
+ free( exp );
+ exp = parse( str, 3 );
+ upper = get_numval( exp );
+
+ srand( (unsigned)time(NULL) );
+
+ // rnd = lower + (int)( (upper * rand()) / RAND_MAX );
+ rnd = lower+(int) ((float)upper*rand()/(RAND_MAX+1.0));
+
+ set_numvar( var, rnd );
+ free( exp );
+ free( var );
+}
--- /dev/null
+/*
+ cmds.h - header for cmds.c
+*/
+
+#ifndef _cmds_h_
+#define _cmds_h_
+
+#include "rpilot.h"
+
+// use() implememnts PILOT's version of GOSUB
+void cmd_use( char *str );
+// Handles variable assignment
+void cmd_compute( char *str );
+// Handles user input
+void cmd_accept( char *str );
+// Displays data
+void cmd_type( char *str );
+// Marks the end of a subroutine
+void cmd_end( char *str );
+// Does string matching
+void cmd_match( char *str );
+// PILOT's version of GOTO
+void cmd_jump( char *str );
+// Displays text if #matched equals YES
+void cmd_yes( char *str );
+// Displays text if #matched equals NO
+void cmd_no( char *str );
+
+
+// The following are nonstandard functions available in rpilot programs
+
+// Executes a line of PILOT code
+void cmd_execute( char *str );
+// Allows access to the operating system
+void cmd_shell( char *str );
+// Gives debugging info from inside a PILOT programs
+void cmd_debug( char *str );
+// Puts a random number in a given variable
+void cmd_generate( char *str );
+
+
+#endif
+
--- /dev/null
+// condex.c - conditional expression handling
+
+#include "rpilot.h"
+#include <string.h>
+#include <stdio.h>
+
+
+condex *new_condex( char *str )
+{
+ int i = -1;
+ condex *c;
+
+ c = (condex *)malloc( sizeof(condex) );
+ c->next = NULL;
+
+ if( !strcmp(str, "") ) {
+ c->lside = NULL;
+ c->rside = NULL;
+ c->op = OP_NULL;
+ return c;
+ }
+
+ if( !strcmp(str, "Y") ) {
+ c->op = OP_YES;
+ return c;
+ } else if( !strcmp(str, "N") ) {
+ c->op = OP_NO;
+ return c;
+ }
+
+ for(i=0; i<strlen(str); i++) {
+ if( (str[i]=='=') || (str[i]=='>') || (str[i]=='<') || (str[i]=='!') ) {
+ break;
+ }
+ }
+
+ // we can't find a relational operator
+ if( i == strlen(str) ) {
+ printf("str=\"%s\"\n", str );
+ err( NO_RELAT, str );
+ return NULL;
+ }
+
+ if( str[i] == '=' ) {
+ c->op = OP_EQL;
+ } else if( (str[i] == '>') && (str[i+1] != '=') ) {
+ c->op = OP_GT;
+ } else if( (str[i] == '<') && (str[i+1] != '=') && (str[i+1] != '>') ) {
+ c->op = OP_LT;
+ } else if( (str[i] == '>') && (str[i+1] == '=') ) {
+ c->op = OP_GE;
+ } else if( (str[i] == '<') && (str[i+1] == '=') ) {
+ c->op = OP_LE;
+ } else if( (str[i] == '<') && (str[i+1] == '>') ) {
+ c->op = OP_NEQL;
+ } else { // Unknown operation
+ err( BAD_RELAT, str );
+ }
+
+ if( (c->op==OP_EQL) || (c->op==OP_GT) || (c->op==OP_LT) ) {
+ c->lside = new_string_from( str, 0, i );
+ c->rside = new_string_from( str, i+1, strlen(str)-i );
+ } else {
+ c->lside = new_string_from( str, 0, i );
+ c->rside = new_string_from( str, i+2, strlen(str)-i-1 );
+ }
+
+ return c;
+}
+
+/* hack to support binding */
+void print_condex_to( condex *curr, FILE *stream )
+{
+ fprintf( stream, "%s ", curr->lside );
+ switch( curr->op ) {
+ case OP_EQL : fprintf( stream, "=" );
+ break;
+ case OP_NEQL : fprintf( stream, "<>" );
+ break;
+ case OP_GT : fprintf( stream, ">" );
+ break;
+ case OP_LT : fprintf( stream, "<" );
+ break;
+ case OP_GE : fprintf( stream, ">=" );
+ break;
+ case OP_LE : fprintf( stream, "<=" );
+ break;
+ case OP_YES : fprintf( stream, "Y" );
+ break;
+ case OP_NO : fprintf( stream, "N" );
+ break;
+ }
+ fprintf( stream, " %s", curr->rside );
+}
+
+
+char *get_condex( condex *curr )
+{
+ char *buffer;
+
+ buffer = (char *)malloc(1024);
+
+ sprintf( buffer, "%s ", curr->lside );
+
+ switch( curr->op ) {
+ case OP_EQL : strcat( buffer, "=" );
+ break;
+ case OP_NEQL : strcat( buffer, "<>" );
+ break;
+ case OP_GT : strcat( buffer, ">" );
+ break;
+ case OP_LT : strcat( buffer, "<" );
+ break;
+ case OP_GE : strcat( buffer, ">=" );
+ break;
+ case OP_LE : strcat( buffer, "<=" );
+ break;
+ case OP_YES : strcat( buffer, "Y" );
+ break;
+ case OP_NO : strcat( buffer, "N" );
+ break;
+ }
+ sprintf( buffer, " %s", curr->rside );
+
+ return buffer;
+}
+
+void print_condex( condex *curr )
+{
+ print_condex_to( curr, stdout );
+}
+
+
+void print_condex_list( condex *head )
+{
+ condex *curr = head;
+
+ while( curr ) {
+ print_condex( curr );
+ printf( "\n" );
+ curr = (condex *)curr->next;
+ }
+}
+
+
+#ifdef TEST
+
+int main( int argc, char *argv[] )
+{
+
+ FILE *f;
+ char buf[256];
+ condex *head, *curr;
+
+ if( argc < 2 ) {
+ puts( "condex: Usage condex filename" );
+ return 0;
+ }
+
+ f = fopen( argv[1], "r" );
+
+ head = new_condex("");
+ curr = head;
+
+ do {
+ strset( buf, 0 );
+ fgets( buf, 255, f );
+ chop( buf );
+ if( strcmp(buf, "") ) {
+ curr->next = (struct condex *)new_condex( buf );
+ curr = (condex *)curr->next;
+ }
+ } while( !feof(f) );
+
+
+ print_condex_list( head );
+
+ return 0;
+}
+
+#endif
+
--- /dev/null
+// condex.h - condex type and functions
+
+#ifndef _condex_h_
+#define _condex_h_
+
+#include "rpilot.h"
+#include <stdio.h>
+
+#define OP_NULL 0
+#define OP_EQL 1
+#define OP_LT 2
+#define OP_GT 3
+#define OP_NEQL 4
+#define OP_LE 5
+#define OP_GE 6
+#define OP_YES 7
+#define OP_NO 8
+
+typedef struct {
+ int op;
+ char *rside;
+ char *lside;
+ struct condex *next;
+} condex;
+
+condex *new_condex( char *str );
+
+void print_condex_to( condex *curr, FILE *stream );
+void print_condex( condex *curr );
+void print_condex_list( condex *head );
+char *get_condex( condex *curr );
+
+#endif
--- /dev/null
+// debug.c - RPilot's interactive debugger
+
+#include <string.h>
+
+#include "rpilot.h"
+#include "debug.h"
+
+void debug(void)
+{
+ char inbuf[MAXLINE];
+ char lastcmd[MAXLINE];
+
+ do {
+ strset( inbuf, 0 );
+ printf( "debug> " );
+ fgets( inbuf, MAXLINE-1, stdin );
+ proc( inbuf, lastcmd );
+ } while( strcasecmp(inbuf, "exit") );
+
+}
+
+void proc( char *inbuf, char *lastcmd )
+{
+
+ char *tok;
+
+ if( !strcmp(inbuf, "" ) ) {
+ strncpy( inbuf, lastcmd, MAXLINE-1 );
+ }
+
+ tok = parse( inbuf, 1 );
+
+ if( !strcasecmp(tok, "step") ) {
+ // step( rpi );
+ } else if( !strcasecmp(tok, "skip") ) {
+ // skip( rpi );
+ } else if( !strcasecmp(tok, "print") ) {
+ // print( rpi, inbuf );
+ } else if( !strcasecmp(tok, "set") ) {
+ // set( rpi, inbuf );
+ } else if( !strcasecmp(tok, "list") ) {
+ // list( rpi, inbuf );
+ } else if( !strcasecmp(tok, "run") ) {
+ // run( rpi, inbuf );
+ } else if( !strcasecmp(tok, "stop") ) {
+ // stop( rpi );
+ } else if( !strcasecmp(tok, "help") ) {
+ // help();
+ } else if( !strcasecmp(tok, "jump") ) {
+ // jump( rpi, inbuf );
+ } else if( !strcasecmp(tok, "exec" ) ) {
+ // exec( rpi, inbuf );
+ } else if( !strcasecmp(tok, "use") ) {
+ // use( rpi, inbuf );
+ } else if( !strcasecmp(tok, "restart") ) {
+ // restart( rpi );
+ }
+
+ free( tok );
+
+}
+
+
+void dump_numvars(void)
+{
+ numvar *n = (numvar *)rpi->numhead;
+
+ while( n != NULL ) {
+ printf( "\"%s\" = %d\n", n->name, n->val );
+ n = (numvar *)n->next;
+ }
+
+}
--- /dev/null
+#ifndef _debug_h_
+#define _debug_h_
+
+#include "rpilot.h"
+
+void debug(void);
+void proc( char *inbuf, char *lastcmd );
+void dump_numvars(void);
+
+#endif
--- /dev/null
+Change log for RPilot
+---------------------
+
+1.4.2 (Released June 21st, 2002)
+ - Fix usage of `isblank()', a GNU extension (Thanks to Patrick Eaton)
+ - Add some #defines to rpilot.h to replace a few hard-coded constants
+ - RPilot is over 4 years old. Wow.
+
+1.4.1 (Released August 13th, 2000)
+ - New math system! I think that was the only remaining code from the 1.0
+ releases, so the 1.4 versions now represent a complete rewrite.
+ - Added Unix man page.
+ - First version to use RPM and BSD packages.
+
+1.4: (Released July 4th, 2000)
+ - Rewrote everything except the math system (which needs it bad!)
+ - Merged parse.c and rstring.c
+ - Fixed a few examples.
+ - Added an interactive mode.
+ - Added the special variables $prompt, #rpilot, and #retcode
+ - Revised documentation.
+ - Changed contact info in all files.
+
+1.01: (Released July 4th, 1998)
+ - Fixed two bugs in rpilot.c, so it will now work when compiled by gcc. The
+ lines read "strcpy( string, '\0')" when that should have been
+ "strset( string, 0)". Thanks to Ken M who pointed this out.
+ - Fixed a few bugs in parse.c - see that file for more info.
+ - Revised documentation to point out differences in the size of numbers based
+ on what compiler the program was compiled with, and correct a few typos.
+ - Added a new example program, fact.p, for calculating factorials.
+ - Included a DJGPP-compiled version of RPilot in the DOS distribution.
+ - Released the first native OS/2 version.
+ - Added this file.
+
+1.0: (Released Apr 17th, 1998)
+ - First version for DOS and Linux.
+
+
+
+
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
--- /dev/null
+The following examples are included with RPilot:
+dosmenu.p - A program which displays a menu of commands for DOS users
+unixmenu.p - The same as above, only it's for Linux users
+french.p - A quiz on your knowledge of French
+guess.p - A simple number-guessing game
+hello.p - "Hello World!", the cannonical first trial program
+jump-use.p - An example of Jumps and Using subroutines
+math.p - A demonstration of RPilot's mathematical capabilities
+name.p - A simple program which asks for your name and age
+recurse.p - A recursive PILOT program which calls itself
+crazy.p - An example of overusing the "X" command
+fact.p - A program which recursively solves factorials
+inter.p - Run RPilot interactively, by reading statements and running them
--- /dev/null
+.\" RPilot man page
+.TH RPILOT 1
+
+.SH NAME
+rpilot \- Rob's PILOT interpreter
+
+
+.SH SYNOPSIS
+.B rpilot
+.RI [ -options ]
+.I file
+
+
+.SH DESCRIPTION
+
+.BR rpilot
+is an intepreter for the IEEE-standard language PILOT.
+
+.SH OPTIONS
+
+.TP
+.BI \-b \
+Don't print the banner when starting up
+.BR rpilot
+
+.TP
+.B \-i
+Enters an interactive mode when no file names are given on the command line.
+To do so, it first looks for a file called
+.B interact.p
+in the current directory. If that cannot be found, the file pointed to by the
+.B RPILOT_INTERACT
+variable will be tried. If either of these can be found, they will be loaded
+and run. Finally, if neither of these can be loaded, an error will be
+reported.
+
+.TP
+.B \-?
+Prints a short summary of command line options.
+
+.SH SEE ALSO
+The RPilot web site at http://rpilot.sourceforge.net/
+
+.SH BUGS
+Please report any bugs to the author at rcl211@nyu.edu
+
+.SH COPYING
+.B RPilot
+is Copyright 1998,2002 Rob Linwood
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+
+.SH AUTHOR
+Rob Linwood <rcl211@nyu.edu>
+.br
+http://homepages.nyu.edu/~rcl211/
--- /dev/null
+
+ -- RPilot: Rob's PILOT Version 1.4.2 --
+ -- Copyright 1998,2002 Rob Linwood (rcl211@nyu.edu) --
+ -- WWW: http://rpilot.sourceforge.net/ --
+
+Intro::
+ RPilot is an interpreter for the PILOT programming language. PILOT,
+ the Programmed Inquiry, Learning, Or Teaching language, was originally
+ designed to be used by teachers as an aid in instruction. PILOT is
+ easy to learn, and most people should be able to in a very short amount
+ of time. PILOT was first developed in 1962, and was standardized by
+ the IEEE in 1991. RPilot probably isn't completely standard, but it
+ is very close. It also adds a few extensions not found in standard
+ PILOT interpretors, such as rudimentry debugging and the ability to
+ call other programs. RPilot was written in 100% ANSI standard C, and
+ should be easily portable to any platform with a standard C compiler.
+
+
+Programming::
+ PILOT programs consist of a series of statements, which are either
+ labels or function calls. PILOT statements all end with a newline, and
+ the lines themselves may be no longer than 127 characters long. PILOT
+ is case insensitive when it comes to label and variable names, $name,
+ $NaMe, and $NAME all refer to the same variable. Speaking of variables,
+ PILOT has only two different types: string, and numeric.
+
+ Variables::
+ String variables consist of a list of characters which can be up to
+ 127 bytes long. Numeric variables are equivilent to C's int. They
+ can be any number in the range of -2,147,483,648 to 2,147,483,648
+ (with 32 bit rpilot) or -32,768 to 32,768 (with 16 bit DOS rpilot).
+ Variables are referenced by their names, which can be up to 10
+ characters in length, and consist of a type designator followed by
+ any non-whitespace characters. When I say "type designator", I mean
+ that all string variables have a "$" as their first character, and all
+ numerics use "#". Thus, $count refers to a string, and #count to
+ a number. This leads to another point: a string variable and a
+ numeric one can have the same name, so both $count and #count could
+ exist at the same time. They are independent of each other, however.
+
+ PILOT also implements labels, which are used just like in any other
+ language, and are declared in the following way:
+
+ *labelname
+
+ This would define a label called "labelname". All label definitions
+ start with an asterisk (the "*"), and follow that with the label name.
+ Label names, like variable names, are case insensitive.
+
+ PILOT statements that do not declare labels have the following syntax:
+
+ <command>[conditional] : [arguments]
+
+ <command> is any of RPilot's internal commands, which I will cover
+ shortly. [conditional] is an optional conditional expression which
+ determines whether the statement will be executed. This is different
+ from more contemporary languages which use "if" clauses and the like, in
+ that the "if" clause is implemented in every function, in a way.
+ [arguments] is an optional list of arguments to be passed to the function.
+ Some functions require arguments; others don't.
+
+ Commands::
+ Commands in RPilot are exactly one character long. This may seem
+ a little wierd, but that's the way things are. Even if you are a
+ PILOT expert, you will find it beneficial to read ALL of the command
+ descriptions, to learn the nuances of RPilot. On to the commands:
+
+ R ::
+ The "R" (Remark) command flags the rest of the line as a comment,
+ and therefore the interpreter ignores it. This is a good way to
+ add reminders to yourself about what you have typed. Example:
+
+ R: This is a comment
+
+ A ::
+ The "A" (Accept) command takes input from the user. It can
+ take the name of a string or numeric variable as an argument, in
+ which case it will store the input into the given variable. If
+ no arguments are given, it stores input into the string variable
+ "$answer". Examples:
+
+ R: The next line gets a string from the user and puts it in
+ : "$answer"
+ A:
+
+ R: This gets a number and stores it in "#group"
+ A: #group
+
+ Note that you can only name one variable for each A command
+
+ T ::
+ The "T" (Type) command is used to display information. If any
+ arguments are given, it displays the string, substituting
+ variables as needed. With no arguments, it prints a blank line.
+ Examples:
+
+ R: The next line prints the contents of the variables "$name",
+ : "$rank", and "#serialnum"
+ T: Name: $name Rank: $rank Serial Number: #serialnum
+
+ T: Note that instead of using the same command over and over
+ T: again, as I have just done, you can skip the command name
+ T: and just use the colon, as I have done in a few examples,
+ : like this.
+ : It saves time, and makes things look nicer.
+
+ J ::
+ The "J" (Jump) command is like GOTO in BASIC and other languages.
+ It causes the interpreter to jump to the label given to it as
+ an argument. When giving a label name, do not add on the
+ initial "*". Example:
+
+ R: The next line causes a jump to the label "done"
+ J: done
+
+ U ::
+ The "U" (Use) command is used to implement a sort of primitive
+ subroutine. It causes the interpreter to jump to the given
+ label, just like J, but first it pushes to current file offset
+ onto a stack. When the E command is reached, that value is
+ popped off and jumped to. This is like GOSUB in BASIC.
+ Example:
+
+ U: sub
+ T: Back from the sub!
+ J: done
+
+ *sub
+ T: Now we're in the sub.
+ R: We'll look at the "E" command next
+ E:
+
+ *done
+
+ E ::
+ The "E" (End) command is used with U to return from subroutines.
+ If no subroutines were called, E ends the program. Example:
+
+ T: The next line ends this program
+ E:
+ T: This is never executed
+
+ Also note the example for the U command.
+
+ M ::
+ The "M" (Match) command is used to handle user input. It
+ compares a given list of strings to the last string which was
+ used to hold input from the A command. This also is very wierd,
+ and it would probably help to check some of the example programs.
+ If RPilot finds a match, it sets the variable "#matched" to 1,
+ and the variable "#which" to the position of the matched string
+ in the argument list. Example:
+
+ T: What is your favorite flavor of ice cream?
+ A: $icecream
+
+ R: The next line checks to see if "vanilla" or "mint" were
+ : entered during the last A command
+ M: vanilla mint
+
+ If $icecream = "vanilla" then #which would equal 1. If the answer
+ was "mint", then #which would equal 2. In either case, #matched
+ would be set to 1. If neither matched what the user typed, then
+ #matched would be set to 0, and so would #which
+
+ C ::
+ The "C" (Compute) command sets variables. The argument string
+ contains a variable name followed by an equal sign ("="),
+ followed by a value to assign tot he variable. For numerics,
+ this is a mathematical expression which can contain one or more
+ terms, and variables as well as constants. See the section on
+ math for more info on expressions. For strings, it is a list
+ of strings and variables which will be copied into the given
+ variable. For example:
+
+ R: This causes "#number" to be incremented by 5
+ C: #number = 5 + #number
+
+ R: This copies the contents of "$firstname" and "$lastname"
+ : to the variable "$fullname"
+ C: $fullname = $firstname $lastname
+
+ Y ::
+ The "Y" (Yes) command works like T, except that it only prints
+ if the variable "#matched" equals 1. This is usually used in
+ conjunction with M. Example:
+
+ A:
+ M: Herbert Floyd
+ Y: You typed "Herbert" or "Floyd"
+ N: You entered some other name.
+
+ N ::
+ The "N" (No) command is just the opposite of Y, it only prints
+ if "#matched" equals 0. For an example, see above.
+
+ That's it for the standard PILOT. Next we take a look at RPilot's
+ extensions.
+
+ X ::
+ The "X" (eXecute) command runs a line of PILOT code which you
+ pass to it. The argument(s) are either a constant string,
+ (ie, "T: Hello!"), or a string variable. Try the following:
+
+ A:
+ X: $answer
+
+ It will wait for you to input a string, and then will try to run
+ it. If you were to type "T: Boo!", that command would take
+ place, and "Boo!" would be displayed
+
+ S ::
+ The "S" (Shell) command allows you to execute other programs.
+ This gives you access to the operating system and all other
+ programs on the user's machine. For example:
+
+ S: dir
+ OR
+ S: /bin/ls
+
+ will display a list of files, depending on what operating system
+ you are running.
+
+ The return code of the program which you ran is stored in the
+ variable `#retcode'. If a program runs succesfully, this should
+ be zero. If not, it usually means that something went wrong.
+
+ D ::
+ The "D" (Debug) command is used as a way to quickly and easily
+ get a list of all variables and labels. It takes a string as an
+ argument, and checks for two characters. If it sees an "l" or
+ an "L" (case is unimportant), it will dump a list of all labels
+ and their offsets. If it sees a "v" or a "V", it will do a
+ variable dump, listing all variables and their values. This is
+ useful when something goes wrong, and you need to check
+ everything at once. Example:
+
+ D: Lv
+
+ Lists all labels, followed by all variables
+
+ G ::
+ The "G" (Generate) command is used to generate random numbers,
+ and place them in a variable. It takes three arguments, first
+ a numeric variable, then two numbers. It randomly creates a
+ number between the second and third arguments, and places it
+ in the variable specified by the first. Example:
+
+ G: #rand 23 56
+
+ This generates a number between 23 and 56, and stores it in #rand
+
+ This is especially useful when making things that require random
+ values, such as games. (See the example programs for a few games
+ that use G)
+
+
+ Math::
+ RPilot supports the following mathematical operators (math ops):
+
+ Standard:
+ + :: Adds two things together
+ - :: Subtracts one number from another
+ * :: Multiplies two numbers
+ / :: Divides one number by another
+
+ RPilot Extensions:
+ % :: Gets the modulo (remainder after division) of two numbers
+ & :: Gets the bitwise AND of two numbers
+ | :: Bitwise OR of two numbers
+ ^ :: Bitwise XOR of two numbers
+
+ I'm not sure how useful all the bitwise operators are, but they
+ were easy enough to add, so why not? RPilot works all expressions
+ from left to right, and currently ignores operator precedence.
+
+
+ Conditionals::
+ RPilot statements can contain "conditional expressions" (condexs),
+ which are evaluated and checked to see if they are true. If so,
+ the rest of the statement is run. They are placed after the command,
+ such as in this example:
+
+ J(#answer > 45): menu1
+
+ In this case, the condex is "(#answer > 45)" The J (Jump) will only
+ take place if the value of "#answer" is more than 45. If not, RPilot
+ goes on to the next line. RPilot understands the following
+ "relational operators" (relat ops):
+
+ = :: True if two numbers are equal
+ < :: True if the first number is less than the second
+ > :: True if the first is greater than the second
+ <> :: True if the two numbers are not equal
+ <= :: True if the first is less than or equal to the second
+ >= :: True if the first is greater than or equal to the second
+
+ Of course, you are free to use all the math ops in a condex, such as:
+
+ T(#score + 10 >= 50): You made it by at least 10 points!
+
+ Note, however, that you can have only one relational operator per
+ condex.
+
+ In addition to standard condexs, there are also two other methods
+ of testing a condition, Y and N. If the condex of a statement is
+ a captial "Y", then RPilot checks to see if "#matched" is equal to
+ 1. If so, the condition is true, and is then executed. "N" is the
+ opposite, and checks whether "#matched" equals 0. If so, the
+ statement is executed. These are ususally used after an "M" command,
+ for example:
+
+ A: $answer
+ M: 1776 1812 1968 1998
+ R: The following line jumps to "correct" if "#matched" equals 1.
+ : That would be true if "M" matched any dates listed
+ JY: correct
+ R: If "#matched" equals 0, then "N" statements are true, and are
+ : then executed
+ TN: You did not answer correctly
+
+
+ Special Variables::
+ RPilot has two special variables which you can use. They are special
+ because they are set by the interpreter itself, so you can use them
+ without assigning a value first. The two special variables are:
+
+ $prompt - This is the prompt which is printed out for an A: (Accept)
+ command. The default value is ">". If you run the following
+ program:
+
+ T: Please enter a number
+ C: $prompt = rpilot>
+ A: #number
+
+ You would see that when you are asked for a number, the
+ prompt is "rpilot>" rather than ">".
+
+ #rpilot - This is the version number of RPilot. For version 1.4,
+ it's value is 14. RPilot 1.5 would be 15, and 2.0 would
+ be 20.
+
+
+ Interactive Mode::
+ If RPilot is invoked with the "-i" command line switch, it will
+ attempt to enter an interactive mode, where you type commands in, and
+ have them executed immediately.
+
+ Interactive mode is not a part of the `rpilot' program, but rather
+ it should be written as an external PILOT program. Therefore, in
+ order for RPilot to use interactive mode, it needs a program to run.
+ It will find one in one of two ways:
+
+ 1) Look for a program called "interact.p" in the current directory.
+ 2) Run the program specified by the RPILOT_INTERACT environment
+ variable.
+
+ The `inter.p' file located in the examples directory is a good
+ program to use. Feel free to customize it by editing the source code.
+
+ Note::
+ I think that the best way to learn RPilot is to look through all the
+ example programs after reading this, and hopefully it will make more
+ sense. They are all fully commented, and are meant to serve as
+ learning aids.
+
+
+Where to get RPilot::
+
+ The RPilot web site is located at http://rpilot.sourceforge.net/ All
+ new versions are released there first.
+
+ RPilot for DOS will (hopefully) be found at the following places:
+ Note that the XX stands for the version number, ie rpilot10.zip for
+ version 1.0.
+
+ ftp.simtel.net/pub/simtelnet/msdos/misclang/rpilotXX.zip
+ and it's many mirrors
+
+ RPilot for Linux will be found at
+
+ sunsite.unc.edu/pub/Linux/devel/lang/misc/rpilot-XX.tar.gz
+ and it's many mirrors
+
+ RPilot for OS/2 2.0 and above wil l be at
+
+ hobbes.nmsu.edu/pub/os2/dev/misc/rpos2xx.zip
+ and it's many mirrors
+
+ The source code will in be all of the packages, along with makefiles and
+ tips relevant to the particular platform. Since RPilot is portable, all
+ of the versions were built from the exact same source.
+
+ Also, check out my home page at http://auntfloyd.home.ml.org/ Updates
+ will always be available there, along with other cool stuff.
+
+
+Contacting the Author::
+
+ If you find any bugs or have any questions/comments, write me at
+ rcl211@nyu.edu
+
+
+Special Thanks to::
+
+ Ken Martwick - for sending me a bug report. So now you can run gcc-
+ compiled versions of RPilot.
+
+
+License::
+ Since Linux people seem to be big on licenses and garbage like that,
+ here's info on RPilot's license:
+
+ **********************************************************************
+ RPilot: Rob's PILOT Interpreter
+ Copyright 1998 Rob Linwood
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ **********************************************************************
+
+ See the COPYING file for the full text.
+
+----------
+Rob Linwood (rcl211@nyu.edu)
+http://homepages.nyu.edu/~rcl211/
+
--- /dev/null
+/*
+ err.c - Error handling code for RPilot
+*/
+
+#include "rpilot.h"
+#include <string.h>
+
+int yesno( char *msg )
+{
+ char buf[MAXLINE];
+
+ printf( "%s (Y/N) ", msg );
+ fgets( buf, MAXLINE-1, stdin );
+
+ chop( buf );
+ if( (!strcmp(strupr(buf), "Y")) || (!strcmp(strupr(buf), "YES")) ) {
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
+int err( int errnum, char *msg )
+{
+ char *errbuf;
+ int linenum;
+ line *l;
+
+ if( rpi != NULL ) {
+ l = (line *)rpi->currline;
+ linenum = l->linenum;
+ } else {
+ linenum = -1;
+ }
+
+ errbuf = (char *)malloc( strlen(errstr(errnum)) + strlen(msg) );
+ sprintf( errbuf, errstr(errnum), msg );
+
+ if( rpi != NULL ) {
+ printf( "RPilot Error in %s, line %d\n %s\n",
+ rpi->filename, linenum, errbuf );
+ } else {
+ printf( "RPilot Error : %s\n", errbuf );
+ }
+
+
+
+ exit( errnum );
+}
+
+char *errstr( int errnum )
+{
+
+ char *errlist[] = {
+ "Duplicate label `%s'", // DUP_LABEL
+ "No file name specified", // NO_FILE
+ "Can't open file `%s'", // ERR_FILE
+ "Unknown command `%s'", // UNKNWN_CMD
+ "Out of memory!", // NO_MEM
+ "Duplicate variable `%s'", // DUP_VAR
+ "Unknown variable `%s'", // BAD_VAR
+ "Expected math symbol, not `%s'", // EXP_MATH
+ "Missing relational operator", // NO_RELAT
+ "Missing colon in statement", // NO_COLON
+ "Unknown label: `%s'", // BAD_LABEL
+ "Unknown relational operator: `%s'", // BAD_RELAT
+ "No equal sign in assignment", // NO_EQL
+ "Missing right parentheses in conditional expression", // NO_RPAREN
+ "Cannot assign value to constant `%s'", // CONS_ASGN
+ "Missing command line argument after `%s'" // NO_CLARG
+ };
+
+ if( errnum >= 0 ) {
+ return errlist[errnum];
+ } else {
+ return "";
+ }
+}
+
--- /dev/null
+/*
+ err.h - prototypes and #defines for err.c
+*/
+
+#ifndef _err_h_
+#define _err_h_
+
+#include "rpilot.h"
+
+/* Error message number definitions -- see err() for more */
+#define ERR_NONE -1 // No error
+#define DUP_LABEL 0 // If there are two labels with the same name
+#define NO_FILE 1 // If no file was given on the command line
+#define ERR_FILE 2 // If the file given can't be opened
+#define UNKWN_CMD 3 // If there is an unknown command in the source
+#define NO_MEM 4 // If we run out of memory
+#define DUP_VAR 5 // If there are two variables that share a name
+#define BAD_VAR 6 // If a non-existantant variable is used
+#define EXP_MATH 7 // When a non-math symbol where it shouldn't
+#define NO_RELAT 8 // When a relational op is missing
+#define NO_COLON 9 // statement is missing a colon
+#define BAD_LABEL 10 // when an unknown label is called
+#define BAD_RELAT 11 // a bad relational operator is used
+#define NO_EQL 12 // no equal sign in an assignment
+#define NO_RPAREN 13 // a condex is missing a right parenthese
+#define CONS_ASGN 14 // attempt to assign a constant a value
+#define NO_CLARGS 15
+
+// Used to determine whether the program will halt on an error
+#define FATAL 1 // Used when the error causes a call to exit()
+#define NONFATAL 2 // Used when we can still go on
+
+#define YES TRUE
+#define NO FALSE
+
+// Displays a given error message and optionally halts execution
+//int err( rpinfo *rpi, int errnum );
+int err( int errnum, char *msg );
+char *errstr( int errnum );
+
+#endif
--- /dev/null
+R: crazy.p - A wierd way of printing stuff
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:T:Hi!
--- /dev/null
+R: dosmenu.p - A simple DOS menu program
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+R: We put this label here so we can jump back to it later
+*menu
+
+R: Print out the menu
+T: ÿÿÿÿÿDOS Menu
+ : ==================
+ : 1. List Files
+ : 2. Edit some Files
+ : 3. Play Ultima VI
+ : 4. Find a file
+ : 5. Delete a file
+ : 6. Rename a file
+ : 7. Copy a file
+ : 8. Move a file
+ : 9. Quit
+ :
+ : What to do? (Enter 1, 2, 3, 4, 5, 6, 7, 8, or 9)
+
+R: Get the user's response
+A: #what
+
+R: Jump to the specified labels
+
+J(#what = 1): list
+J(#what = 2): edit
+J(#what = 3): play
+J(#what = 4): find
+J(#what = 5): delete
+J(#what = 6): rename
+J(#what = 7): copy
+J(#what = 8): move
+J(#what = 9): quit
+
+R: If nothing above works, print an error message
+T:
+ : I don't understand!
+ :
+J: menu
+
+*list
+R: First off, list the files
+S: dir
+R: then return
+J: menu
+
+*edit
+T: Edit which File?
+A: $file
+
+R: Here we make $command equal to "edit" plus whatever is in $files
+C: $command = edit $file
+
+T: $command
+
+R: Run the newly-constructed command
+S: $command
+J: menu
+
+*play
+S: C:\ULTIMA\U6\ULTIMA6
+J: menu
+
+*find
+R: Requires "Whereis" of some sort
+ : This is just like what happens in "edit"
+
+T: Find which file?
+A: $file
+C: $command = whereis $file
+S: $command
+J: menu
+
+*delete
+T: Delete which file?
+A: $file
+C: $command = del $file
+S: $command
+J: menu
+
+*rename
+T: Rename which file?
+A: $file
+T: To what?
+A: $newname
+C: $command = ren $file $newname
+S: $command
+J: menu
+
+*copy
+T: Copy which file?
+A: $file
+T: To where?
+A: $newname
+C: $command = copy $file $newname
+S: $command
+J: menu
+
+*move
+T: Move which file?
+A: $file
+T: To where?
+A: $newname
+C: $command = move $file $newname
+S: $command
+J: menu
+
+*quit
+E:
+
--- /dev/null
+R: fact.p - A recursive PILOT program for solving factorials
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+R: A factorial of number n is written as n! It is the equal to the expression
+ : n! = n * (n-1) * (n-2) * (n - 3) * ... * (n - (n-1))
+ : For example, 4! = 4 * 3 * 2 * 1 = 24. The way we solve this in PILOT is to
+ : use a programming technique called "recursion". In a recursive program,
+ : one part of the program (generally a subroutine) calls itself. This a
+ : powerful technique which is crucial in handling numerical sequences. Note
+ : that this is a simple example of recursion, but a useful one.
+
+T: This program can generate factorials of a number (n!) which you give it.
+ : Because the value of n! rises very rapidly with respect to n, RPilot will
+ : not be able to handle the result of n! for values of n larger than a
+ : certain number. On 32-bit systems, this number is 16.
+ :
+ : So please give me a number.
+A: #num
+
+R: If #num is 0, 1, or 2, we don't need to solve. Instead, we go straight to
+ : the end.
+ : These are "special cases" which can be handled more quickly than others
+J( #num = 0 ): zero
+J( #num = 1): one
+J( #num = 2): two
+
+R: Initialize the result (#res) to 0
+C: #res = #num
+
+*bang
+J( #num = 1 ): done
+C: #tmp = #num - 1
+C: #res = #tmp * #res
+C: #num = #num -1
+J: bang
+
+*zero
+T: The answer is Zero
+E:
+
+*one
+T: The answer is One
+E:
+
+*two
+T: The answer is Two
+E:
+
+*done
+T: The answer is #res
+
+
--- /dev/null
+R: french.p - A quiz on your skills in the French language
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+T: Welcome to the French Quiz!
+ : You will be given a word in French, and asked to pick the BEST
+ : translation for it.
+ :
+ : Example:
+ :
+ : Fromage
+ :
+ : 1. Cat
+ : 2. Dog
+ : 3. Cheese
+ : 4. Mouse
+ :
+ : Here you would enter 1, 2, 3, or 4 depending on what you think
+ : the best translation for the word "Fromage" is. (btw, the answer is 3)
+ :
+ : Hit "Enter" to get started!
+ :
+A: $junk
+
+R: Initialize the variables
+C: #right = 0
+C: #wrong = 0
+
+R: Let's get started with the quiz...
+
+T:
+ : Q1. Porte
+ :
+ : 1. Ring
+ : 2. Cup
+ : 3. Belt
+ : 4. Door
+U: answer
+C(#ans = 4): #right = #right + 1
+C(#ans <> 4): #wrong = #wrong + 1
+
+T:
+ : Q2. Ceinture
+ :
+ : 1. Helmet
+ : 2. Belt
+ : 3. Bicycle
+ : 4. Cat
+U: answer
+C(#ans = 2): #right = #right + 1
+C(#ans <> 2): #wrong = #wrong + 1
+
+T:
+ : Q3. Cambriolage
+ :
+ : 1. Floor wax
+ : 2. Robbery
+ : 3. Bus station
+ : 4. Expression
+U: answer
+C(#ans = 2): #right = #right + 1
+C(#ans <> 2): #wrong = #wrong + 1
+
+T:
+ : Q4. Chapeau
+ :
+ : 1. Hat
+ : 2. Chair
+ : 3. Earring
+ : 4. Wig
+U: answer
+C(#ans = 1): #right = #right + 1
+C(#ans <> 1): #wrong = #wrong + 1
+
+T:
+ : Q5. Conduire
+ :
+ : 1. To run
+ : 2. To remove
+ : 3. To drive
+ : 4. To type
+U: answer
+C(#ans = 3): #right = #right + 1
+C(#ans <> 3): #wrong = #wrong + 1
+
+T:
+ : Q6. Chien
+ :
+ : 1. Cat
+ : 2. Rabbit
+ : 3. Mouse
+ : 4. Dog
+U: answer
+C(#ans = 4): #right = #right + 1
+C(#ans <> 4): #wrong = #wrong + 1
+
+T:
+ : Q7. Jeterai
+ :
+ : 1. Will speak
+ : 2. Will run
+ : 3. Will throw
+ : 4. Will eat
+U: answer
+C(#ans = 3): #right = #right + 1
+C(#ans <> 3): #wrong = #wrong + 1
+
+T:
+ : Q8. Irais
+ :
+ : 1. Will go
+ : 2. Will become
+ : 3. Will have
+ : 4. Will be
+U: answer
+C(#ans = 1): #right = #right + 1
+C(#ans <> 1): #wrong = #wrong + 1
+
+T:
+ : Q9. Zut Alors!
+ :
+ : 1. Shucks!
+ : 2. Darn!
+ : 3. Oh my!
+ : 4. Sacre' Bleu!
+U: answer
+C: #right = #right + 1
+
+T:
+ : Q10. Parlez-vous anglais?
+ :
+ : 1. I am lost.
+ : 2. I am a tourist.
+ : 3. I am looking to be mugged.
+ : 4. Do you speak English?
+U: answer
+C(#ans = 4): #right = #right + 1
+C(#ans <> 4): #wrong = #wrong + 1
+J: done
+
+*answer
+A: #ans
+T(#ans > 4): Please enter a number between 1 and 4
+T(#ans < 1): Please enter a number between 1 and 4
+J(#ans < 1): answer
+J(#ans > 4): answer
+E:
+
+*done
+
+C: #percent = #right * 10
+T: You got #right out of 10. This is #percent percent correct.
+
--- /dev/null
+brtR: guess.p - A simple number guessing game
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+*start
+
+T: I will think of a random number between 1 and 100. Can you guess it?
+ :
+
+R: Get a random number between 1 and 100 and put it in #rand
+G: #rand 1 100
+r:T: #rand
+R: Initialize the #tries variable, which holds the number of tries
+C: #tries = 0
+
+*guess
+
+R: Get the player's guess
+T: Guess!
+A: #guess
+
+R: Increase the number of tries
+C: #tries = #tries + 1
+
+R: Jump to the proper place based on whether the player guessed the number,
+ : guessed too high, or guessed too low
+J(#guess = #rand): win
+J(#guess > #rand): toobig
+J(#guess < #rand): toosmall
+
+*toobig
+T: Too big!
+ :
+J: guess
+
+*toosmall
+T: Too small!
+ :
+J: guess
+
+*win
+T(#tries > 1): Congratulations! You guessed it in #tries guesses!
+T(#tries = 1): Congratulations! You guessed it in 1 guess! Lucky!
+T: Play again? (Y/N)
+A:
+M: y yes yep sure
+R: If any of the above match, (ie #matched = 1), jump to start
+JY: start
+E:
+
+
--- /dev/null
+R: hello.p - Classic first program in any language
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+R: The next line simply displays "Hello, World!"
+
+T: Hello, World!
--- /dev/null
+R: -*- Text -*-
+
+T: Welcome to interactive RPilot!
+ :
+ : Simply enter your commands, or `quit' to exit.
+
+*input
+A: $command
+M: quit
+JY: done
+X: $command
+J: input
+
+*done
+
+
+
--- /dev/null
+R: jump-use.p - An example of J and U
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+T: We are about to jump far away to label1
+J: label1
+T: This text is never seen! If you can see this, you've got problems!
+E:
+
+*label1
+
+T: Now, we're going to call the subroutine "Woof"
+U: woof
+T: We're back from the subroutine!
+E:
+
+*woof
+T: Now we're in "Woof"
+E:
+
+
+
+
+
+
+
+
--- /dev/null
+R: math.p - A demonstration of RPilot's math features
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+T: This program is meant to show how good RPILOT is at math. I want
+ : you to give me two numbers, and I'll show you what I can do with them
+ :
+ : Ok, I'm ready for the first number
+ :
+
+A: #first
+
+T:
+ : Now the second
+ :
+
+A: #second
+
+C: #add = #first + #second
+C: #sub = #first - #second
+C: #mul = #first * #second
+C: #div = #first / #second
+C: #mod = #first % #second
+C: #and = #first & #second
+C: #or = #first | #second
+C: #xor = #first ^ #second
+
+T:
+ : #first + #second = #add
+ : #first - #second = #sub
+ : #first * #second = #mul
+ : #first / #second = #div
+ : #first modulo #second = #mod
+ : #first AND #second = #and
+ : #first OR #second = #or
+ : #first XOR #second = #xor
+ :
+
--- /dev/null
+R: name.p - Simple question & answer type program
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+R: Ask the user what their name is
+T: What is your name?
+
+R: Get their answer and put it in $name
+A: $name
+
+R: Ask for their age
+T: How old are you? I won't tell!
+
+R: Get their answer to that question, and put it in #age
+A: #age
+
+R: Display the information
+T: Your name is $name and you are #age years old.
+
+R: We don't need an E: here because the file ends
+
+
+
--- /dev/null
+R: recures.p - an example of a recursive PILOT program
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+R: Ask a question
+
+T: Would you like to recurse again? (Y/N)
+
+R: Get the answer and put it in $answer,
+ : because no variable name was given
+
+A:
+
+R: Try to match any of the strings listed after the "M:"
+
+M: y yes sure yep
+
+R: If any of them matched, then #matched was set to 1
+ : Next we Jump to "*recurse" if #matched equals 1
+
+JY: recurse
+
+R: If nothing matched, we end the program
+
+E:
+
+R: Define a label called "recurse"
+
+*recurse
+
+R: Call rpilot again, and start running this file again
+ : Note: whether this will work or not depends on where the `recurse.p' file
+ : is located. We'll check in two locations.
+
+S: rpilot examples/recurse.p
+J( #retcode = 0 ): done
+S: rpilot recurse.p
+J( #retcode = 0 ): done
+
+T: Sorry, I can't run the program! Return code: #retcode
+
+*done
--- /dev/null
+R: unixmenu.p - A simple Unix menu program
+ : Written by Rob Linwood (auntfloyd@biosys.net)
+
+R: We put this label here so we can jump back to it later
+*menu
+
+R: Print out the menu
+T: Unix Menu
+ : ==================
+ : 1. List Files
+ : 2. Edit some Files
+ : 3. Play Hack
+ : 4. Find a file
+ : 5. Delete a file
+ : 6. Rename a file
+ : 7. Copy a file
+ : 8. Move a file
+ : 9. Quit
+ :
+ : What to do? (Enter 1, 2, 3, 4, 5, 6, 7, 8, or 9)
+
+R: Get the user's response
+A: #what
+
+R: Jump to the specified labels
+
+J(#what = 1): list
+J(#what = 2): edit
+J(#what = 3): play
+J(#what = 4): find
+J(#what = 5): delete
+J(#what = 6): rename
+J(#what = 7): copy
+J(#what = 8): move
+J(#what = 9): quit
+
+R: If nothing above works, print an error message
+T:
+ : I don't understand!
+ :
+J: menu
+
+*list
+R: First off, list the files
+S: /bin/ls -la
+R: then return
+J: menu
+
+*edit
+T: Edit which File?
+A: $file
+
+R: Here we make $command equal to "edit" plus whatever is in $files
+C: $command = /bin/vi $file
+
+T: $command
+
+R: Run the newly-constructed command
+S: $command
+J: menu
+
+*play
+R: You may have to change this, perhaps to /usr/local/games/hack
+S: /usr/games/hack
+J: menu
+
+*find
+R: This is just like what happens in "edit"
+
+T: Find which file?
+A: $file
+C: $command = find / -name $file
+S: $command
+J: menu
+
+*delete
+T: Delete which file?
+A: $file
+C: $command = rm -f $file
+S: $command
+J: menu
+
+*rename
+T: Rename which file?
+A: $file
+T: What's its new name?
+A: $newname
+C: $command = mv $file $newname
+S: $command
+J: menu
+
+*copy
+T: Copy which file?
+A: $file
+T: To where?
+A: $newname
+C: $command = cp $file $newname
+S: $command
+J: menu
+
+*move
+T: Move which file?
+A: $file
+T: To where?
+A: $newname
+C: $command = mv $file $newname
+S: $command
+J: menu
+
+*quit
+E:
+
--- /dev/null
+/* PILOT code source file - generated by RPilot 1.4 */
+
+#include "foo.h"
+
+extern void run_bound( char *code[] );
+
+void run_pilot(void)
+{
+char *pilot_data[] = {
+": Welcome to interactive RPilot!",
+": ",
+": Simply enter your commands, or `quit\' to exit.",
+": $command",
+": quit",
+": done",
+": $command",
+": input",
+NULL
+};
+
+run_bound( pilot_data );
+}
+
+int main( int argc, char *argv[] )
+{
+ run_pilot();
+ return 0;
+}
+
--- /dev/null
+/* PILOT code datafile - generated by RPilot 1.4 */
+
+#ifndef _foo_h_
+#define _foo_h_
+
+#include <stdio.h>
+
+void run_pilot(void);
+
+
+#endif
\ No newline at end of file
--- /dev/null
+// interact.c - handle interactive mode
+
+#include "rpilot.h"
+
+#ifndef NO_INTER
+
+ #include "inter.h"
+
+#endif
+
+void interact()
+{
+ FILE *f;
+
+ if( (f = fopen("interact.p", "r")) == NULL ) {
+ if( (f = fopen(getenv(ENV_VAR), "r")) == NULL ) {
+#ifndef NO_INTER
+ inter();
+#else
+ puts( "Can't run interactive mode. RPilot was compiled with NO_INTER." );
+ exit( 1 );
+#endif
+ } else {
+ run( getenv(ENV_VAR) );
+ }
+ } else {
+ run( "interact.p" );
+ }
+}
+
+
--- /dev/null
+#ifndef _interact_h_
+#define _interact_h_
+
+#define ENV_VAR "RPILOT_INTERACT"
+
+void interact();
+
+#endif
--- /dev/null
+/*
+ * label.c - label handling code
+ */
+
+#include "rpilot.h"
+
+#include <string.h>
+
+label *new_label( char *name, line *lne, int linenum )
+{
+ label *l;
+
+ l = (label *)malloc( sizeof(label) );
+ l->linenum = linenum;
+ l->stmnt = lne;
+ l->name = new_string( name );
+ l->next = NULL;
+
+ return l;
+}
+
+
+label *get_label( char *name )
+{
+ label *l = (label *)rpi->lblhead;
+
+ while( l != NULL ) {
+ if( !strcasecmp(l->name, name) ) {
+ return l;
+ }
+ l = (label *)l->next;
+ }
+
+ err( BAD_LABEL, name );
+}
+
+
+void print_label( label *l )
+{
+ printf( "[line %d] %s: ", l->linenum, l->name );
+ print_line( l->stmnt );
+ printf( "\n" );
+}
+
+void print_label_list()
+{
+ label *l = (label *)rpi->lblhead;
+
+ while( l != NULL ) {
+ print_label( l );
+ l = (label *)l->next;
+ }
+
+}
+
+
+
--- /dev/null
+/*
+ label.h - header for label.c
+*/
+
+#ifndef _label_h_
+#define _label_h_
+
+/* #include "line.h" */
+#include "rpilot.h"
+
+typedef struct {
+ char *name;
+ line *stmnt;
+ int linenum;
+ struct label *next;
+} label;
+
+label *get_label( char *name );
+label *new_label( char *name, line *lne, int linenum );
+void print_label( label *l );
+void print_label_list();
+
+#endif
--- /dev/null
+/*
+ * line.c - RPilot syntax handling routines
+ */
+
+#include "rpilot.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+
+// the input str should already be trim()ed
+
+line *new_line( char *str, char lastcmd, int linenum )
+{
+ line *l = (line *)malloc( sizeof(line) );
+ int colon;
+ int rparen, lparen;
+ int i;
+ char *contemp = NULL; // temp variable for condex string
+
+
+ colon = findchar( str, ':' ); // get the position of the colon
+ l->next = NULL;
+ l->linenum = linenum;
+
+ // is it a blank string?
+ if( !strcmp(str, "") ) {
+ l->cmd = lastcmd;
+ l->args = NULL;
+ l->cond = NULL;
+ return l;
+ }
+
+ if( colon == -1 ) { // if there is no colon, it's an error
+ err( NO_COLON, str );
+ }
+
+
+ /* Notes for the 3/3/00 rewrite
+ * There are 3 different possiblities for what will be the first character
+ * in the line:
+ *
+ * 1) A letter signifing the command name (this includes 'Y' and 'N')
+ * 2) A colon, meaning that we should use the last command for this one, too
+ * 3) A left parentheses, like above, but with a conditional expression
+ *
+ */
+
+ if( colon != strlen(str)-1 ) {
+ l->args = new_string_from( str, colon+1, strlen(str)-colon+1 );
+ ltrim( l->args );
+ } else {
+ l->args = new_string( "" );
+ }
+
+
+ /*
+ * Here, we'll handle the second case first, because it is the easiest.
+ * The command is the same as the last command, and everything after the
+ * first character constitutes the arguments.
+ */
+
+ if( str[0] == ':' ) {
+ l->cmd = lastcmd;
+ l->cond = NULL;
+ return l;
+ }
+
+
+ /*
+ * Now the third case. Like the second case, everything after the colon
+ * forms the arguments. But we have to find the right parentheses in order
+ * to create a conditional expression. The command is the same as the
+ * previous one.
+ */
+
+ if( str[0] == '(' ) {
+ l->cmd = lastcmd;
+
+ rparen = findchar( str, ')' );
+ if( rparen == -1 ) {
+ // If there is no right parentheses, we signal an error
+ err( NO_RPAREN, str );
+ }
+ // otherwise, create a temporary string, and make a new condex
+ // contemp = new_string_from( str, 1, rparen-1 );
+ contemp = new_string_from( str, 1, rparen-1 );
+ l->cond = new_condex( contemp );
+ free( contemp );
+
+ return l;
+ }
+
+
+ /*
+ * Finally, the first case. This itself has four possibilities:
+ *
+ * 1) There is no conditional expression
+ * 2) There is a conditional expression in parentheses
+ * 3) There is a 'Y' as the conditional
+ * 4) There is an 'N' as the conditional
+ */
+
+ l->cmd = str[0];
+ // l->args = new_string_from( str, colon+1, strlen(str)-colon+1 );
+
+ lparen = findchar( str, '(' );
+ if( (lparen == -1)|| (lparen > colon) ) {
+ // Now, we can see if there is a Y or N somehwere..
+ for( i=1; i<colon; i++ ) {
+ if( toupper(str[i]) == 'Y' ) {
+ l->cond = new_condex( "Y" );
+ return l;
+ } else if( toupper(str[i]) == 'N' ) {
+ l->cond = new_condex( "N" );
+ return l;
+ }
+ }
+ // If we didn't find Y or N, there is no condex, so just return
+ l->cond = NULL;
+ return l;
+
+ }
+
+ // Now we have a conditional expression, so create a new condex and return
+ rparen = findchar( str, ')' );
+ if( rparen == -1 ) {
+ err( NO_RPAREN, str );
+ }
+ // contemp = new_string_from( str, lparen+1, rparen-1 );
+ contemp = new_string_from( str, lparen+1, rparen-2 );
+ l->cond = new_condex( contemp );
+ free( contemp );
+
+ return l;
+}
+
+/* support binding */
+void print_line_to( line *curr, FILE *stream )
+{
+ if( curr == NULL ) {
+ fprintf( stream, "[NULL]" );
+ return;
+ }
+ fprintf( stream, "%c", curr->cmd );
+ if( curr->cond != NULL ) {
+ if( (curr->cond->op == OP_YES) || (curr->cond->op == OP_NO) ) {
+ print_condex_to( curr->cond, stream );
+ } else {
+ fprintf( stream, "(" );
+ print_condex_to( curr->cond, stream );
+ fprintf( stream, ")" );
+ }
+ }
+ fprintf( stream, ": %s", curr->args );
+}
+
+char *get_line( line *curr )
+{
+ char *buffer;
+ char *cond;
+
+ buffer = (char *)malloc(1024);
+
+ if( curr == NULL ) {
+ return "(null)";
+ }
+
+ sprintf( buffer, "%c", curr->cmd );
+ if( curr->cond != NULL ) {
+ if( (curr->cond->op == OP_YES) || (curr->cond->op == OP_NO) ) {
+ sprintf( buffer, "%c", curr->cond->op );
+ } else {
+ cond = get_condex( curr->cond );
+ sprintf( buffer, "(%s)", cond );
+ free( cond );
+ }
+ }
+
+ sprintf( buffer, ": %s", curr->args );
+
+ return buffer;
+}
+
+
+void print_line( line *curr )
+{
+ print_line_to( curr, stdout );
+}
+
+
+void print_line_list( line *head )
+{
+ line *curr = head;
+
+ while( curr ) {
+ printf( "#%d ", curr->linenum );
+ print_line( curr );
+ printf( "\n" );
+ curr = (line *)curr->next;
+ }
+}
+
+
+#ifdef TEST
+
+int main( int argc, char *argv[] )
+{
+
+ FILE *f;
+ char buf[256];
+ line *head, *curr;
+ int linenum = 0;
+
+ if( argc < 2 ) {
+ puts( "line: Usage line filename" );
+ return 0;
+ }
+
+ f = fopen( argv[1], "r" );
+
+ head = new_line("", ' ', 0 );
+ curr = head;
+
+ do {
+ strset( buf, 0 );
+ fgets( buf, 255, f );
+ chop( buf );
+ trim( buf );
+puts( buf );
+ if( strcmp(buf, "") ) {
+ curr->next = (struct line *)new_line( buf, 'Q', ++linenum );
+ curr = (line *)curr->next;
+ }
+ } while( !feof(f) );
+
+
+ print_line_list( head );
+
+ return 0;
+}
+
+
+#endif
--- /dev/null
+#ifndef _line_h_
+#define _line_h_
+
+#include "condex.h"
+#include "rpilot.h"
+#include <stdio.h>
+
+typedef struct {
+ char cmd; // name of the command (C,A,M, etc)
+ condex *cond; // Conditional expression, w/o the outer parens
+ char *args; // argument to the command
+ int linenum; // line number (from the source file)
+ struct line *next; // next line
+} line;
+
+line *new_line( char *str, char lastcmd, int linenum );
+void print_line_to( line *curr, FILE *stream );
+void print_line( line *curr );
+void print_line_list( line *head );
+char *get_line( line *curr );
+
+#endif
--- /dev/null
+/*
+ * main.c - main() function for RPilot
+ */
+
+#include "rpilot.h"
+#include "main.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+int main( int argc, char *argv[] )
+{
+ int i;
+ int showban = TRUE, inter = FALSE, bind = FALSE, mainfunc = FALSE,
+ showhelp = FALSE;
+ char *filename=NULL, *outfile=NULL, *dataname=NULL, *funcname=NULL;
+
+ for( i=1; i<argc; i++ ) {
+
+ /* printf("argv[%d] = %s\n", i, argv[i] ); */
+
+ if( !strcasecmp(argv[i], "-b") ) {
+ showban = FALSE;
+ } else if( !strcasecmp(argv[i], "-i") ) {
+ inter = TRUE;
+ } else if( !strcasecmp(argv[i], "-?") ) {
+ showhelp = TRUE;
+ } else if( !strcasecmp(argv[i], "-c") ) {
+ bind = TRUE;
+ } else if( !strcasecmp(argv[i], "-o") ) {
+
+ if( argc == i+1 ) {
+ err( NO_CLARGS, "-o" );
+ } else {
+ outfile = new_string( argv[i+1] );
+ i++;
+ }
+ } else if( !strcasecmp(argv[i], "-d") ) {
+ if( argc == i+1 ) {
+ err( NO_CLARGS, "-d" );
+ } else {
+ dataname = new_string( argv[i+1] );
+ i++;
+ }
+ } else if( !strcasecmp(argv[i], "-f") ) {
+ if( argc == i+1 ) {
+ err( NO_CLARGS, "-f" );
+ } else {
+ funcname = new_string( argv[i+1] );
+ i++;
+ }
+ } else if( !strcasecmp(argv[i], "-m") ) {
+ mainfunc = TRUE;
+ } else {
+ filename = new_string( argv[i] );
+ }
+ }
+
+/* printf("filename=\"%s\", outfile=\"%s\", dataname=\"%s\", funcname=\"%s\"\n", */
+/* filename, outfile, dataname, funcname ); */
+/* printf("showban=%d, inter=%d, mainfunc=%d\n", showban, inter, mainfunc ); */
+
+
+ if( argc == 1 ) { // no arguments
+ banner();
+ } else { // there were arguments
+ if( showhelp == TRUE ) {
+ if( showban == TRUE ) { banner(); }
+ help();
+ } else if( inter == TRUE ) {
+ if( showban == TRUE ) { banner(); }
+ interact();
+ } else if( filename == NULL ) {
+ if( showban == TRUE ) { banner(); }
+ err( NO_FILE, "" );
+ } else if( bind == TRUE ) {
+ bindfile( filename, outfile, dataname, funcname, mainfunc );
+ } else {
+ run( filename );
+ }
+ }
+
+ return 0;
+}
+
+
+void help()
+{
+ printf( "Usage: rpilot [switch] filename\n" );
+ printf( "Switch \t Action\n" );
+ printf( "-b \t Suppress banner printing on startup\n" );
+ printf( "-i \t Enter interactive mode when no file names are given\n");
+ // printf( "-c \t Bind a file as a C program\n" );
+ printf( "-? \t Print this help message, then exit\n\n" );
+
+}
+
+void banner()
+{
+ printf( "RPilot: Rob's PILOT Interpreter, version %s\n", VERSION );
+ printf( "Copyright 1998,2002 Rob Linwood (rcl211@nyu.edu)\n" );
+ printf( "RPilot is Free Software. Please see http://rpilot.sf.net/\n" );
+ printf( "For help, try `rpilot -?'\n\n" );
+}
+
--- /dev/null
+/*
+ * main.h - prototypes for main.c
+ */
+
+#ifndef _main_h_
+#define _main_h_
+
+void help();
+void banner();
+
+#endif
--- /dev/null
+/*
+ * math.c - mathematical functions for RPilot
+ *
+ * major update - aug.11.2000
+ * - remove all garbage, express() remains only as a wrapper to calc()
+ */
+
+#include "rpilot.h"
+#include "calc.h"
+
+#include <string.h>
+
+int express( char *form )
+{
+ int result, status;
+
+ result = calc( form, &status );
+
+ if( status != 0 ) { // error
+ err( EXP_MATH, "" );
+ }
+
+ return result;
+
+}
+
--- /dev/null
+/*
+ * math.h - header for math.c
+ */
+
+#ifndef _math_h_
+#define _math_h_
+
+
+// Returns the value of a given mathematical formula
+int express( char *form );
+
+#endif
--- /dev/null
+/*
+ * rpilot.c -- A simple PILOT interpretor in ANSI C
+ * Copyright 1998, 2000 Rob Linwood (rob@auntfloyd.com)
+ * Visit http://www.auntfloyd.com/ for more cool stuff
+ *
+ * See the file rpilot.txt for user documentation.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "rpilot.h"
+#include "math.h"
+
+rpinfo *rpi;
+
+int readfile( char *filename )
+{
+ char inbuf[MAXLINE]; // 256-char limit on line width
+ line *currline;
+ line *templine = NULL;
+ label *currlbl;
+ label *templbl = NULL;
+ int linenum = 0;
+ char lastcmd = '!';
+ FILE *f;
+
+
+ if( (f = fopen(filename, "r")) == NULL ) {
+ rpi = NULL; /* kludge around the error printing */
+ err( ERR_FILE, filename );
+ }
+
+ rpi->filename = new_string( filename );
+
+ currline = (line *)rpi->linehead;
+ currlbl = (label *)rpi->lblhead;
+ do {
+ strset( inbuf, 0 );
+ fgets( inbuf, MAXLINE-1, f );
+ chop( inbuf );
+ linenum++;
+ trim( inbuf );
+ if( strcmp(inbuf, "") ) { // if the line isn't blank
+
+#ifdef IGNORE_HASH
+ if( (linenum == 1) && (inbuf[0] == '#') ) {
+ break;
+ }
+#endif
+
+ if( inbuf[0] == '*' ) { // label
+ currlbl->next = (struct label *)new_label( inbuf+1, NULL, linenum );
+ templbl = (label *)currlbl->next;
+ currlbl = (label *)currlbl->next;
+ } else if( (toupper(inbuf[0]) != 'R') &&
+ !((inbuf[0] == ':') && (lastcmd == 'R')) ) {
+ *(line **)&currline->next = new_line( inbuf, currline->cmd, linenum );
+ currline = (line *)currline->next;
+ if( templbl != NULL ) {
+ templbl->stmnt = (line *)currline;
+ templbl = NULL;
+ }
+ lastcmd = currline->cmd; // next->cmd;
+ } else {
+ lastcmd = 'R';
+ }
+ }
+ } while( !feof(f) );
+}
+
+
+
+
+void handle( line *l )
+{
+
+ switch( toupper(l->cmd) ) {
+ case 'A' : cmd_accept( l->args );
+ break;
+ case 'T' : cmd_type( l->args );
+ break;
+ case 'J' : cmd_jump( l->args );
+ break;
+ case 'U' : cmd_use( l->args );
+ break;
+ case 'E' : cmd_end( l->args );
+ break;
+ case 'M' : cmd_match( l->args );
+ break;
+ case 'C' : cmd_compute( l->args );
+ break;
+ case 'Y' : cmd_yes( l->args );
+ break;
+ case 'N' : cmd_no( l->args );
+ break;
+ case 'X' : cmd_execute( l->args );
+ break;
+ case 'S' : cmd_shell( l->args );
+ break;
+ case 'D' : cmd_debug( l->args );
+ break;
+ case 'G' : cmd_generate( l->args );
+ break;
+ }
+}
+
+
+
+int test( condex *cond )
+{
+
+ if( (cond->op == OP_YES) && (get_numvar("#MATCHED") == TRUE) ) {
+ return TRUE;
+ } else if( (cond->op == OP_NO) && (get_numvar("#MATCHED")==FALSE) ) {
+ return TRUE;
+ } else if( cond->op == OP_EQL ) {
+ if( express(cond->lside) == express(cond->rside) ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if( cond->op == OP_LT ) {
+ if( express(cond->lside) < express(cond->rside) ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if( cond->op == OP_GT ) {
+ if( express(cond->lside) > express(cond->rside) ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if( cond->op == OP_NEQL ) {
+ if( express(cond->lside) != express(cond->rside) ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if( cond->op == OP_LE ) {
+ if( express(cond->lside) <= express(cond->rside) ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if( cond->op == OP_GE ) {
+ if( express(cond->lside) >= express(cond->rside) ) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+
+void init()
+{
+ line *linehead;
+ label *lblhead;
+ strvar *svar;
+ numvar *nvar;
+
+ rpi = NULL;
+
+ linehead = new_line( "", ' ', -1 );
+ lblhead = new_label( "", NULL, -1 );
+ rpi = (rpinfo *)malloc( sizeof(rpinfo) );
+
+ rpi->linehead = (struct line *)linehead;
+ rpi->lblhead = (struct label *)lblhead;
+ rpi->numhead = (struct numvar *)new_numvar( "", -1 );
+ rpi->strhead = (struct strvar *)new_strvar( "", "" );
+ rpi->stk = (struct stack *)new_stack( NULL );
+ rpi->status = STAT_RUN;
+ rpi->error = -1;
+ rpi->strict = TRUE;
+ rpi->currline = rpi->linehead;
+
+ svar = (strvar *)rpi->strhead;
+ nvar = (numvar *)rpi->numhead;
+ nvar->next = (struct numvar *)new_numvar( "#RPILOT", RP_VERSION );
+ svar->next = (struct strvar *)new_strvar( "$PROMPT", ACCEPT_STR );
+
+}
+
+int interp()
+{
+ line *curr;
+
+ while( rpi->currline != NULL ) {
+ curr = (line *)rpi->currline;
+ if( curr->cond != NULL ) { // is there a conditional expression?
+ if( test(curr->cond) == TRUE ) { // if so, test it
+ handle( curr );
+ }
+ } else {
+ handle( curr );
+ }
+ // have any other functions changed the value of rpi->currline?
+ if( (line *)rpi->currline == curr ) {
+ rpi->currline = (struct line *)curr->next;
+ } // Otherwise, keep the value of rpi->currline, cuz it's been modified
+ }
+}
+
+
+int run( char *filename )
+{
+
+ init();
+ readfile( filename );
+ interp();
+}
+
+
+/*
+ * the routines below are used in both commands (cmds.c) and the debugger
+ * (debug.c), so are made as common procedures to both.
+ */
+
+void set_var( char *name, char *val )
+{
+
+ if( name[0] == '$' ) { // string variable
+ set_strvar( name, val );
+ } else if( name[0] == '#' ) { // numeric variable
+ set_numvar( name, atoi(val) );
+ } else {
+ err( BAD_VAR, name );
+ }
+
+}
+
+
+int get_numval( char *str )
+{
+ if( str[0] == '#' ) {
+ return( get_numvar(str) );
+ } else {
+ return( atoi( str ) );
+ }
+}
+
+char *get_strval( char *str )
+{
+ if( str[0] == '$' ) {
+ return get_strvar(str);
+ } else {
+ return str;
+ }
+}
+
+
+void jump( char *str )
+{
+ label *l;
+
+ l = get_label( get_strval(str) );
+
+ rpi->currline = (struct line *)l->stmnt;
+}
+
+
+void use( char *str )
+{
+ label *l;
+ line *curr;
+
+ l = get_label( trim(get_strval(str)) );
+
+ // push next command onto stack
+ curr = (line *)rpi->currline;
+ curr = (line *)curr->next;
+ stk_push( (stack *)rpi->stk, curr );
+ rpi->currline = (struct line *)l->stmnt;
+}
+
+
+void execute( char *str )
+{
+ line *lne = new_line( trim(get_strval(str)), ' ', -1 );
+
+ lne->cmd = toupper( lne->cmd );
+ handle( lne );
+}
+
--- /dev/null
+/*
+ rpilot.h - universal macros and the like.
+*/
+
+#ifndef _rpilot_h_
+#define _rpilot_h_
+
+#include "line.h"
+#include "stack.h"
+#include "label.h"
+#include "var.h"
+#include "cmds.h"
+#include "condex.h"
+#include "debug.h"
+#include "err.h"
+#include "rstring.h"
+#include "rpinfo.h"
+#include "bind.h"
+#include "interact.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MAXLINE 256 // Max length of a source line
+
+// Status indicators
+#define STAT_RUN 1
+#define STAT_HALT 2
+#define STAT_END 3
+
+
+// Used to check conditional values
+#define FALSE 0
+#define TRUE 1
+
+// What string is displayed for an accept command?
+#define ACCEPT_STR ">"
+
+
+// Remove a terminating newline
+#define chop( str ) if(str[strlen(str)-1] == '\n') str[strlen(str)-1] = '\0'
+
+// Initialize randon number based on time
+//#define srandom() srand( (unsigned)time(NULL) );
+
+
+// The version number, of course
+#define VERSION "1.4.2"
+// The version number which can be gotten with the #RPILOT variable
+#define RP_VERSION 14
+
+// exported functions
+int get_numval( char *str );
+void set_var( char *name, char *val );
+int run( char *filename );
+void jump( char *str );
+void use( char *str );
+void execute( char *str );
+char *get_strval( char *str );
+void init();
+int readfile( char *filename );
+extern rpinfo *rpi;
+
+#endif
--- /dev/null
+#include "rpinfo.h"
+#include <stdio.h>
+#include "err.h"
+#include "rpilot.h"
+
+rpinfo *new_rpinfo()
+{
+ rpinfo *r;
+
+ r = (rpinfo *)malloc( sizeof(rpinfo) );
+
+ r->currline = NULL;
+ r->linehead = NULL;
+ r->lblhead = NULL;
+ r->numhead = NULL;
+ r->strhead = NULL;
+ r->stk = NULL;
+ r->error = ERR_NONE;
+ r->status = 0;
+ r->lastacc = NULL;
+ r->strict = TRUE;
+ r->filename = NULL;
+
+ return r;
+}
--- /dev/null
+#ifndef _rpinfo_h_
+#define _rpinfo_h_
+
+//#include "line.h"
+//#include "label.h"
+//#include "var.h"
+//#include "stack.h"
+
+// contains info about the currently running interpreter
+typedef struct {
+ struct line *currline; // the line of code that is currently being executed
+ struct line *linehead; // the head of the line list
+ struct label *lblhead; // head of the label list
+ struct numvar *numhead;
+ struct strvar *strhead;
+ struct stack *stk;
+ int error; // the last error that occured
+ int status; // the status of the program (one of the STAT_ values)
+ char *lastacc; // the name of the last variable to be accepted
+ int strict; // should we be strict about undeclared variables?
+ char *filename; // name of file being run
+} rpinfo;
+
+//rpinfo *new_rpinfo();
+
+#endif
--- /dev/null
+/*
+ * rstring.c - generic string-handling functions
+ * as of version 1.49, this contains the contents of the `parse' library
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "rstring.h"
+
+/*
+ * Name : strupr
+ * Descrip : Changes s to all uppercase
+ * Input : s = pointer to a string to uppercase
+ * Output : returns a pointer to s
+ * Notes : none
+ * Example : strupr( "proper-noun" ) - returns "PROPER-NOUN"
+ */
+
+char *strupr( char *s )
+{
+ int i;
+
+ for(i=0; i<strlen(s); i++ ) {
+ s[i] = toupper(s[i]);
+ }
+
+ return s;
+}
+
+/*
+ * Name : strset
+ * Descrip : Sets all characters in s to ch
+ * Input : s = pointer to a string to set
+ * ch = character to set all positions in s to
+ * Output : returns a pointer to s
+ * Notes : None
+ * Example : char cstring[10];
+ strset( cstring, 'C' ) - returns "CCCCCCCCC"
+ */
+
+char *strset( char *s, int ch )
+{
+ unsigned char c;
+
+ for(c=0; s[c] != 0; c++)
+ s[c] = ch;
+
+ return s;
+}
+
+// make a copy of a string
+char *new_string( char *src )
+{
+ char *str;
+
+ str = (char *)malloc( strlen(src)+1 );
+ strncpy( str, src, strlen(src) );
+
+ // prevent junk from being tacked on the end
+ if( strlen(str) > strlen(src) ) {
+ str[strlen(src)] = 0;
+ }
+
+ return str;
+}
+
+// make a new string from src, starting at char index and going for count chars
+char *new_string_from( char *src, int index, int count )
+{
+ char *str;
+
+ str = (char *)malloc( count + 1 );
+ memset( str, 0, count+1 );
+ strncpy( str, src+index, count );
+
+ // str[strlen(str)+1] = 0;
+ // str[count+1] = 0;
+
+ return str;
+}
+
+/*
+ * Name: firstnot - Finds first instance of a character which is not the
+ * one specified
+ * Input: d - Pointer to string to search through
+ * e - Char to search against
+ * first - Position in d to start the search at
+ * Output: Returns the position of the first character which is not e.
+ * Returns -1 if there was an error
+ * Example: firstnot( "ggggXgggX", "g", 0 ) returns 4
+ */
+
+int firstnot( const char *d, const char e, int first )
+{
+ char k;
+
+ for(k=first; k<strlen(d); k++) {
+ if( d[k] != e )
+ return k;
+ }
+ return -1;
+}
+
+/*
+ * Name: neither - Finds the first character after the two specified
+ * Input: d - Pointer to the string to search through
+ * e - The first char to search against
+ * f - The second char to search against
+ * first - The location in d to start searching at
+ * Output: Returns the location of the first char which is not e or f.
+ * Returns -1 on errors
+ * Notes: This is just like firstnot() except it takes to chars as args.
+ * Example: neither( "ggggXgggXzgg", 'g', 'X', 0 ) returns 9.
+ */
+
+int neither( const char *d, const char e, const char f, char first )
+{
+ char k;
+
+ for(k=first; k<strlen(d); k++) {
+ if( (d[k] != e) && (d[k] != f) )
+ return k;
+ }
+ return -1;
+}
+
+/*
+ * Name: find - Search for any chars in the string e in string d
+ * Input: d - pointer to a string to search through
+ * e - pointer to a list of chars to search for
+ * first - location in d to start search at
+ * Output: Returns the location of the first occurence of a char in e in d.
+ * Returns -1 on errors
+ * Example: find( "xrcedfg", "dg", 0 ) returns 4.
+ */
+
+int find( const char *d, const char *e, int first )
+{
+ int k, k2;
+
+ for(k=first; k<strlen(d); k++) {
+ for(k2=0; k2<strlen(e); k2++) {
+ if( d[k] == e[k2] )
+ return k;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Name : scopy
+ * Descrip : Like the Pascal Copy function, scopy copies a portion of a
+ * string from src to dest, starting at index, and going for
+ * count characters.
+ * Input : dest - pointer to a string to recieve the copied portion
+ * src - pointer to a string to use as input
+ * index - character to start copying at
+ * count - number of characters to copy
+ * Output : dest contains the slice of src[index..index+count]
+ * Notes : None
+ * Example : scopy( last, "Charlie Brown", 8, 5 ) - puts "Brown" in last.
+ * History : the parse() function was originally coded in Pascal. To support
+ * the translation, this function was implemented, but now its proved
+ * useful on its own.
+ */
+
+char *scopy( char *dest, char *src, int index, int count )
+{
+ int k;
+
+ for(k=0;k<=count;k++) {
+ dest[k] = src[k+index];
+ }
+ dest[k] = '\0';
+ return dest;
+}
+
+/*
+ * Name: numstr - Returns number of substrings in a string
+ * Input : d - a pointer to the string to search through
+ * Output: returns number of substrings in string d
+ * Example: numstr( "bob and Figment are THE Bombz " ) returns 6
+ */
+int numstr( const char *d )
+{
+
+ int k2, k3;
+ int cnt = 0;
+
+ k3 = -1;
+
+ /* new version */
+ do {
+ k2 = wspace( d, k3+1 ); /* find start of substring */
+ if( k2 == -1 ) /* if there is no start, we return */
+ return cnt;
+ k3 = find( d, " \t", k2 ); /* find end of substring */
+ if( k3 == -1 )
+ return ++cnt;
+ ++cnt; /* increase counter if there is a start & a finish */
+ } while( k3 != -1 );
+ return -1;
+}
+
+/*
+ * Name: parse - Returns specified substrings seperated by whitespace
+ * Input: d - a pointer to the string to parse
+ * i - the number of the substring you want
+ * c - a pointer to the string where we place the substring
+ * Output: Returns nonzero on errors and zero when there are no errors
+ * Example: parse( " bob ate cheese", 3, buffer ) places "cheese" in buffer
+ */
+
+char *parse( const char *src, int num )
+{
+ char *srccopy;
+ char *ret = NULL;
+ int currws, nextws;
+ int i;
+
+ srccopy = (char *)malloc(strlen(src)+1);
+ strcpy( srccopy, src );
+
+ total_trim( srccopy );
+
+ if( !strcmp(srccopy, "") ) {
+ return NULL;
+ }
+
+ currws = find( srccopy, " \t", 1 );
+
+ if( currws == -1 ) { // no spaces found, so only one string available
+ return srccopy;
+ }
+
+ if( num == 1 ) {
+ ret = new_string_from( srccopy, 0, currws );
+ free( srccopy );
+ return ret;
+ }
+
+ /*
+ 01234567890123456789
+ "hello said the fig"
+ */
+
+ for( i=1; i<num; i++ ) {
+ nextws = find( srccopy, " \t", currws+1 );
+ if( i+1 != num ) {
+ currws = nextws;
+ }
+ }
+
+ if( nextws == -1 ) { // last bit in src, no whitespace after
+ ret = new_string_from( srccopy, currws+1, strlen(srccopy)-currws-1 );
+ } else {
+ ret = new_string_from( srccopy, currws+1, nextws-currws-1 );
+ }
+
+ free( srccopy );
+ return ret;
+}
+
+/*
+ * Name : rtrim
+ * Descrip : Removes all trailing whitespace from a string
+ * Input : str = pointer to a string to strip
+ * Output : Returns a pointer to str
+ * Notes : None.
+ * Example : rtrim( "Bob was busy " ) - returns "Bob was busy"
+ */
+
+char *rtrim( char *str )
+{
+
+ int i = strlen( str ) - 1;
+
+ while( (isspace(str[i])) && (i>=0) )
+ str[i--] = '\0';
+
+ return str;
+}
+
+/*
+ * Name : ltrim
+ * Descrip : Removes all leading whitespace from a string
+ * Input : str = pointer to a string to strip
+ * Output : Retruns a pointer to str
+ * Notes : None
+ * Example : ltrim( " Woof! " ) - returns "Woof! "
+ */
+
+char *ltrim( char *str )
+{
+ int i;
+ int spc = ws( str );
+
+ if( spc == -1 ) { // blank line
+ return "";
+ }
+
+ for( i=0; i<strlen(str); i++ ) {
+ str[i] = str[i+spc];
+ }
+ str[i] = 0;
+
+ return str;
+}
+
+/*
+ * Name : rws
+ * Descrip : Reverse WhiteSpace: Finds the last charater in a string which
+ * is not a space or a tab
+ * Input : str = pointer to a string to search through
+ * Output : Returns the position of the last non-whitespace character
+ * Notes : Just like, ws(), but backwards
+ * Example : rws( "Hey, you! " ) - returns 8
+ */
+
+int rws( const char *str)
+{
+ int k;
+
+ for(k=strlen(str);k>-1;k--) {
+ if( (str[k] != ' ') && (str[k] != '\t') )
+ return k;
+ }
+ return -1;
+}
+
+
+/*
+ * Name : ws
+ * Descrip : WhiteSpace: finds the first character which isn't a tab or space
+ * Input : str = pointer to string to use as input
+ * Output : Returns position of fitsrt non-whitespace character
+ * Notes : none
+ * Example : ws( " Howdy, world!" ) - returns 3
+ */
+
+int ws( const char *str)
+{
+ int k;
+
+ for(k=0;k<strlen(str);k++) {
+ if( (str[k] != ' ') && (str[k] != '\t') )
+ return k;
+ }
+ return -1;
+}
+
+
+int wspace( const char *str, int first )
+{
+ return neither( str, ' ', '\t', first );
+}
+
+
+char *trim( char *str )
+{
+ if( !strcmp(str, "") ) {
+ return "";
+ }
+
+ ltrim( str );
+ rtrim( str );
+
+ return str;
+}
+
+
+
+int findchar( const char *str, char c )
+{
+ int i;
+
+ for(i=0; i<strlen(str); i++) {
+ if( str[i] == c )
+ return i;
+ }
+ return -1;
+}
+
+
+
+/*
+** total_trim() - Remove leading, trailing, & excess embedded spaces
+** from the Snippets collection (TRIM.C)
+** public domain by Bob Stout & Michael Dehlwes
+*/
+char *total_trim( char *str )
+{
+ char *ibuf, *obuf;
+
+ if( !strcmp(str, "") ) {
+ return str;
+ }
+
+ if( str ) {
+ for( ibuf = obuf = str; *ibuf; ){
+ while (*ibuf && (isspace (*ibuf))) {
+ ibuf++;
+ }
+ if (*ibuf && (obuf != str)) {
+ *(obuf++) = ' ';
+ }
+ while (*ibuf && (!isspace (*ibuf))) {
+ *(obuf++) = *(ibuf++);
+ }
+ }
+ *obuf = 0;
+ }
+ return str;
+}
+
+
+#ifdef STANDALONE
+
+int main( int argc, char *argv[] )
+{
+ char *tmp;
+ const char *text = " hello, said the happy figment! ";
+ int i;
+ int num = numstr( text );
+
+ printf( "%d bits in `text'\n", num );
+
+ for( i=1; i<=num; i++ ) {
+ tmp = parse( text, i );
+ puts( tmp );
+ free( tmp );
+ }
+
+ return 0;
+}
+
+#endif
--- /dev/null
+#ifndef _RSTRING_H_
+#define _RSTRING_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+char *strupr( char *s );
+char *strset( char *s, int ch );
+char *new_string( char *src );
+char *new_string_from( char *src, int index, int count );
+
+extern int firstnot( const char *d, const char e, int first );
+extern int neither( const char *d, const char e, const char f, char first );
+extern int find( const char *d, const char *e, int first );
+extern char *parse( const char *src, int num );
+extern int numstr( const char *d );
+extern char *rtrim( char *str );
+extern int rws( const char *str);
+extern char *scopy( char *dest, char *src, int index, int count );
+extern int ws( const char *str );
+extern char *ltrim( char *str );
+char *trim( char *str );
+int wspace( const char *str, int first );
+int findchar( const char *str, char c );
+char *total_trim( char *str );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef _RSTRING_H_ */
--- /dev/null
+
+/* #include "stack.h" */
+/* #include "line.h" */
+#include "rpilot.h"
+
+#include <stdlib.h>
+
+stkitem *new_stkitem( line *lne )
+{
+ stkitem *si;
+
+ si = (stkitem *)malloc( sizeof(stkitem) );
+ si->item = lne;
+ si->prev = NULL;
+
+}
+
+
+stack *new_stack( line *lne )
+{
+ stack *s;
+ stkitem *si;
+
+ s = (stack *)malloc( sizeof(stack) );
+ si = new_stkitem( lne );
+
+ s->head = si;
+ s->tail = si;
+
+ return s;
+}
+
+
+// returns the new tail of the list
+stack *stk_push( stack *stk, line *lne )
+{
+ stkitem *si;
+
+ si = new_stkitem( lne );
+ *(stkitem **)&si->prev = stk->tail; // worthless cast
+ stk->tail = si;
+
+ return stk;
+}
+
+
+line *stk_pop( stack *stk )
+{
+ stkitem *si;
+ line *lne;
+
+ si = stk->tail;
+
+ stk->tail = (stkitem *)stk->tail->prev; // worthless cast
+ lne = si->item;
+ free( si );
+
+ return lne;
+}
--- /dev/null
+#ifndef _stack_h_
+#define _stack_h_
+
+/* #include "line.h" */
+#include "rpilot.h"
+
+
+typedef struct {
+ line *item;
+ struct stkitem *prev;
+} stkitem;
+
+typedef struct {
+ stkitem *head, *tail;
+} stack;
+
+stkitem *new_stkitem( line *lne );
+stack *new_stack( line *lne );
+stack *stk_push( stack *stk, line *lne );
+line *stk_pop( stack *stk );
+
+
+
+#endif
--- /dev/null
+/*
+ var.c - RPilot variable support
+*/
+
+#include <string.h>
+#include "rpilot.h"
+
+strvar *new_strvar( char *name, char *val )
+{
+ strvar *ret;
+
+ if( (ret = (strvar *)malloc(sizeof(strvar))) == NULL ) {
+ err( NO_MEM, "" );
+ }
+
+ ret->name = new_string( name );
+ ret->val = new_string( val );
+ ret->next = NULL;
+
+ return ret;
+}
+
+numvar *new_numvar( char *name, int val )
+{
+ numvar *ret;
+
+ if( (ret = (numvar *)malloc(sizeof(numvar))) == NULL ) {
+ err( NO_MEM, "" );
+ }
+
+ ret->name = new_string_from( name, 0, strlen(name) );
+ ret->val = val;
+ ret->next = NULL;
+ return ret;
+}
+
+void set_strvar( char *name, char *val )
+{
+ strvar *s = (strvar *)rpi->strhead;
+ strvar *prev;
+
+ while( s != NULL ) {
+ if( !strcasecmp(s->name, name) ) {
+ free( s->val );
+ s->val = new_string( val );
+ return;
+ }
+ prev = s;
+ s = (strvar *)s->next;
+ }
+
+ // if we can't find the variable, make a new one
+ *(strvar **)&prev->next = new_strvar( name, val );
+}
+
+void set_numvar( char *name, int val )
+{
+ numvar *n = (numvar *)rpi->numhead;
+ numvar *prev;
+
+ while( n != NULL ) {
+ if( !strcasecmp(n->name, name) ) {
+ n->val = val;
+ return;
+ }
+ prev = n;
+ n = (numvar *)n->next;
+ }
+
+ *(numvar **)&prev->next = new_numvar( name, val );
+}
+
+char *get_strvar( char *name )
+{
+ strvar *s = (strvar *)rpi->strhead;
+
+ while( s != NULL ) {
+ if( !strcasecmp(s->name, name) ) {
+ return s->val;
+ } else {
+ s = (strvar *)s->next;
+ }
+ }
+
+ if( rpi->strict == TRUE ) {
+ err( BAD_VAR, name );
+ } else {
+ set_strvar( name, "" );
+ return "";
+ }
+
+ return NULL;
+}
+
+int get_numvar( char *name )
+{
+ numvar *n = (numvar *)rpi->numhead;
+
+ while( n != NULL ) {
+ if( !strcasecmp(n->name, name) ) {
+ return n->val;
+ } else {
+ n = (numvar *)n->next;
+ }
+ }
+
+ if( rpi->strict == TRUE ) {
+ err( BAD_VAR, name );
+ } else {
+ set_numvar( name, 0 );
+ return 0;
+ }
+
+}
+
+void print_strvar( strvar *var )
+{
+ printf( "%s = \"%s\"\n", var->name, var->val );
+}
+
+void print_numvar( numvar *var )
+{
+ printf( "%s = %d\n", var->name, var->val );
+}
+
+void print_strvar_list( void )
+{
+ strvar *var = (strvar *)rpi->strhead;
+
+ while( var != NULL ) {
+ print_strvar( var );
+ var = (strvar *)var->next;
+ }
+}
+
+void print_numvar_list( void )
+{
+ numvar *var = (numvar *)rpi->numhead;
+
+ while( var != NULL ) {
+ print_numvar( var );
+ var = (numvar *)var->next;
+ }
+}
--- /dev/null
+/*
+ var.h - variable datatypes and prototypes for var.c
+*/
+
+#ifndef _var_h_
+#define _var_h_
+
+#include "rpilot.h"
+
+// string variables
+typedef struct {
+ char *name;
+ char *val;
+ struct strvar *next;
+} strvar;
+
+// numeric variables
+typedef struct {
+ char *name;
+ int val;
+ struct numvar *next;
+} numvar;
+
+
+// make new variables
+strvar *new_strvar( char *name, char *val );
+numvar *new_numvar( char *name, int val );
+
+// Sets the value of a given variable
+void set_strvar( char *name, char *val );
+void set_numvar( char *name, int val );
+
+// Returns the value of a given variable
+int get_numvar( char *name );
+char *get_strvar( char *name );
+
+void print_strvar( strvar *var );
+void print_numvar( numvar *var );
+void print_strvar_list( void );
+void print_numvar_list( void );
+
+#endif