/* Fido13 -- main function 3 Sep 93 Tom Jennings tomj@wps.com (31 Aug 93) copyright 1993 */ #include #include "fido.h" /* Global static nonsense. */ int output_line = 0; /* lines output so far (reset at pause and input) */ int output_col = 0; /* chars since a newline */ struct _state *current_state; /* ptr to state we're executing */ struct _state *bliss; /* the top of the state-machine */ /* Main state machine execution. */ main() { char c; struct _state *s; unsigned menu; /* current menu (menu) */ char *input(); unsigned load_machine(); bliss= (struct _state *) NULL; /* flag as unallocated */ if (load_machine("fido.dat")) /* load up Fido */ exit(1); /* ERROR! */ current_state= bliss; /* just so I could say that */ while (1) { c= *input(); c= tolower(c); /* get command, */ for (s= current_state, menu= s-> menu; s-> menu == menu; ++s) { if (c == tolower(*s-> input)) { /* (check only first character) */ execute(s-> action); /* it's ours! do it */ current_state= s-> next; /* change state (maybe ourself) */ c= NULL; /* mark input as used */ break; } if (c) output("\"%s\" is not a command\n",c); } } } /* Execute a state; if there is an action exec it. */ execute(a) char *a; { char buff[200]; char *args[64]; parse(a, buff, sizeof(buff), args); /* break it up, */ fork_u(args); /* execute it. */ } /* Parse the command string, for example: Set ptr args[n]: 0 1 2 3 4 | | | | | v v v v v /bin/mail -s "arg with spaces" user@domain.com The last arg[] is a NULL ptr. parse() modifies the input string. */ parse(in, buff, len, args) char *in; /* text we're parsing */ char *buff; /* processed strings... */ unsigned len; /* max. length of string */ char **args; /* ... at these pointers */ { unsigned n; while (*in && (len > 1)) { *args++= buff; /* point to where arg will go */ n= copyqstr(&in, buff, len); /* copy one arg */ buff += n; /* where next one goes */ len -= n; /* how much room left */ } *args= NULL; /* terminate w/ null ptr */ } /* Execute the command. */ fork_u(args) char **args; { int pid, status; if ((pid= fork()) < 0) { /* oops! */ perror("fido: fork:"); exit(1); } if (pid == 0) { /* if child... */ execv(*args, args); perror(*args); exit(1); } while (wait(&status) != pid); /* ... parent */ } /* Get input from the user, returning a pointer to the next token. If none, generate a prompt from the current state table, input a line of text. */ char * input() { char *strtok(); static char linebuff[256] = ""; /* human-input line buffer */ static char *lp = linebuff; /* ptr into it */ char *cp; struct _state *s; while (1) { cp= strtok(lp, ", \t;"); /* see if there's more */ lp= NULL; /* (for 1 -- Nth calls) */ if (cp != NULL) return(cp); /* yup */ display_states(); /* generate the prompt */ output_line= 0; /* reset page pause */ fgets(linebuff, (size_t)sizeof(linebuff), stdin); lp= linebuff; /* repeat, with new input */ } } /* Output text to the console. */ output(s) char *s; { while (*s) switch (*s) { case '\n': output_col= 0; default: fputs(s, stdout); ++output_col; } fflush(stdout); } /* Output all the state names, ie. the prompt. current_state points to the first state in this menu, output all state names in this menu. */ display_states() { struct _state *t; unsigned menu; for (t= current_state, menu= t-> menu;; ) { if (output_col + strlen(t-> name) > 40) /* narrow prompt */ output("\n"); output(t-> name); /* state name */ if (++t-> menu != menu) break; /* if the last one, stop */ output(", "); /* else a comma and space for the next */ } }