#include /* for getchar */ #include #include /* for isdigit */ #include /* for calloc */ /*********************************************************** Written by: David S. Woodruff, MIT Lab for Nuclear Science, (617)253-6943 dsw@mitlns.mit.edu *********************************************************************** A set of routines for processing a stream of tokens and strings from standard input. The stream is stored in a queue (fifo stack). Contains the following routines. See also the comments in the routines. void getcmd(char *prompt, char *retword) 'prompt' - string issued if command queue is empty. 'retword' - word or string returned from commmand queue Maintains a queue (fifo stack) of tokens. The front token is returned as 'retword'. If the queue is empty, prints the 'prompt', and uses getword to get 'retword' from standard input. int getint(char *prompt, int *retnum) 'prompt' - string printed if the command queue is empty. 'retnum' - number returned from the command queue. Use this to prompt for an integer. Function value is 1 if a number has been entered, 0 if user has entered an 'exit'. In the latter case retnum is undefined. int getdouble(char *prompt, double *retnum) 'prompt' - string printed if the command queue is empty. 'retnum' - number returned from the command queue. Use this to prompt for a real number. Function value is 1 if a number has been entered, 0 if user has entered an 'exit'. In the latter case retnum is undefined. int iscmd (char *entered, char *cmd) 'entered' - a token accepted from the getcmd queue. 'cmd' - the string against which 'entered' is checked. Returns 1 if 'input' is the same as 'cmd', else returns 0. Will accept abbreviations. See the comments with iscmd for details. void flushcmd(char *warning, char *about, int flag) 'warning' - optional string for printing 'about' - second optional string for printing 'flag' - if this is 0 don't print anything Removes everything on the command queue and prints a 'warning' 'about' something if 'flag' is not 0. int morecmd() Returns the number of commands that remain to be processed. int getifint(int *retnum) 'retnum' - number to be returned from the command queue, if there was an integer. Use this to get an optional integer. Function value is 1 if an integer was at the front of the queue, else 0. Example of use. Compare the two streams: 'set value do next job' 'set value 10 do next job' getifint would be used after 'value' is accepted to set a value to 10 if the second stream is entered, or do nothing if the first stream is entered. User could supply a default integer if the returned function value was 0. int getifcmd(char *cmd, char *cmdstr) 'cmd' - string to be returned from the command queue, if it is there 'cmdstr' - returned string. Tests the command queue to see if the next command is 'cmd'. If it is, it is removed from the queue and returned in 'cmdstr', and the function value is 1. If it is not, 'cmdstr' is undefined, and function value is 0. Example of use: 'set trace' and 'set no trace'. getifcmd would be used to detect if the word after 'set' was 'no', with no effect on the word 'trace'. 'cmd' may be abbreviated. See the comments in routine iscmd for how abbreviation is handled. void pushcmd(char *cmd) 'cmd' - a command to be returned to the queue. Puts 'cmd' at the front of the queue. Used for filling the command stack from the program, and for returning commands that should be used during the next invocation of getcmd. void showcmd(char *strn) 'strn' - something to be printed. Use this for debugging purposes. It reports the commands that remain to be processed, and the value of the command pointer and the queue top pointer. int getword(char *token) 'token' - word or string returned from standard input. Used by getcmd. **************************************/ /* for getcmd routines */ #define CMDBUFFSIZE 80 /* maximum number of commands that can be stored. */ #define WORDSIZE 80 /* is big, because it might need to handle strings*/ static char *cmdbuff[CMDBUFFSIZE]; static int cmdptr = 0; /* next token to return from cmdbuff */ static int topptr = -1; /* top token location on cmdbuff */ static int firstcall = 1; /* initialize command buffer at first call */ /* EXTERNS */ void *calloc(); int getword(char*); int atoi(); double atof(); void move_queue() /* used in getcmd and pushcmd to relocate the command queue to the bottom of the stack. */ { int newptr=0; while (cmdptr <= topptr) { if (cmdbuff[newptr] == NULL) { /* probably never used-- since queue is at the top all of the memory must have been allocated already. */ cmdbuff[newptr] = (char *) calloc(WORDSIZE,sizeof(char)); if (cmdbuff[newptr] == NULL) { printf("getcmd: Input not accepted: memory allocation error.\n"); return; } } strcpy( cmdbuff[newptr], cmdbuff[cmdptr]); newptr++; cmdptr++; } cmdptr = 0; topptr = newptr - 1; } void flushcmd(char *warning, char *about, int flag) /*clear the command stack. Issue optional message*/ { if (flag) printf("%s %s\n",warning,about); topptr = -1; cmdptr = 0; } int morecmd() /* returns the number of commands that remain to be processed */ { return(topptr-cmdptr+1); } void showcmd(char *strn) /* use this for debugging. 'strn' is used to print out information about, for example, where the call to showcmd was placed. */ { int i; printf("getcmd: %s: cmdptr=%d, topptr=%d\n",strn,cmdptr,topptr); for (i=cmdptr; i<=topptr; i++) printf(" -- %s\n",cmdbuff[i]); } void getcmd(char *prompt, char *retword) /* Returns string 'retword' from a queue of tokens. If there are no tokens, it issues the string 'prompt' as a prompt and waits for input. Given input, it places each input token into the queue in fifo order. 'topptr' points to the back of the queue, and is incremented every time a new command is entered. 'cmdptr' points to the front of the queue, and is incremented every time a command is processed. getword, which is called by this routine, pushes a string with white space on the queue if a token starts with a double quote. All the following characters are accepted until the next double quote. Processing halts only if white space is encounterd after a new double quote. Pushes 'exit' on the queue if a ^Z is entered (for VMS). */ { int getword(char*); int retnum; char strbuf[WORDSIZE]; int i; /* memory for commands is allocated when needed and then never freed. Number of allocations never exceeds CMDBUFFSIZE. On the first call to getcmd or pushcmd we initialize pointers to this memory. */ if (firstcall) { for ( i=0; i topptr) /* command buffer is empty, get some input*/ { topptr = -1; cmdptr = 0; printf("%s",prompt); while ( (retnum=getword(strbuf)) != 0 ) { if (retnum == -1) /* ^Z was entered (for VMS)*/ { strcpy(retword,"exit"); return; } if (topptr >= CMDBUFFSIZE - 1) /* commands have reached stack top */ { if (cmdptr > 0) /* see if any space is available at the bottom*/ move_queue(); /* if so, then move the queue down.*/ else /* no space is available in the command stack */ { printf("getcmd: command buffer too full. Increase CMDBUFFSIZE\n"); return; } } topptr++; /* there is room for the command on the stack */ if (cmdbuff[topptr] == NULL) { cmdbuff[topptr] = (char *) calloc(WORDSIZE,sizeof(char)); if (cmdbuff[topptr] == NULL) { printf("getcmd: Not accepted: memory allocation error.\n"); return; } } strncpy(cmdbuff[topptr],strbuf,WORDSIZE); } } if (topptr == -1) /* entered a , for example.*/ { strcpy(retword,""); return; } /* once we are here, we know that there is one or more commands in the buffer.*/ strcpy(retword,cmdbuff[cmdptr]); cmdptr++; } void pushcmd(char *cmd) /* A command is returned to the token queue by the calling program.*/ { int i; if (firstcall) { for ( i=0; i= CMDBUFFSIZE - 1 ) /* queue is moving out of stack space*/ { if (cmdptr > 0) /* see if any space is available at the bottom*/ move_queue(); /* if so, move the queue to the stack bottom */ else /* no space is available in the command stack. */ { printf("pushcmd: command buffer is too full. Increase CMDBUFFSIZE.\n"); return; } } topptr++; /* there is room on the stack for the new command */ if (cmdbuff[topptr] == NULL) { cmdbuff[topptr] = (char *) calloc(WORDSIZE,sizeof(char)); if (cmdbuff[topptr] == NULL) { printf("getcmd: Word not accepted: memory allocation error.\n"); return; } } /* the pushed command goes to the front of queue: move the queue back and insert the command at the front. */ for (i=topptr; i>cmdptr; i--) strcpy(cmdbuff[i], cmdbuff[i-1]); strcpy(cmdbuff[cmdptr],cmd); } /* int iscmd (char *input, char *cmd) Returns 1 if 'input' is equal to 'cmd' up to an abbreviation. If any characters in 'input' differ from those in cmd, except for '*', returns 0. If characters match, but input is shorter than cmd location of '*', ambiguous, returns 0. If characters match at least up to '*' in cmd, returns 1. Examples: iscmd(ans,"exit") returns 1 if ans is "exit", else returns 0. iscmd(ans,"ex*it") returns 1 when ans is "ex", "exi" or "exit", else returns 0 (e.g., for "exity", "e", "ey" */ int iscmd (char *input, char *cmd) { int i,j,foundstar=0; i = j = -1; while(1) { i++; j++; if ( input[i] == '\0' && ( cmd[j] == '\0' || foundstar) ) return(1); if (input[i] != cmd[j]) { if (cmd[j] == '*' && !foundstar) { i--; foundstar = 1; } else return(0); } } } /************************************************************************** mgetch, unmgetch used in 'getword' Read standard input a character at a time. Keep each character that is read in a lifo stack so that it can be reread. Adopted from Kernighan and Ritchie. ****************************************************************************/ #define STKSIZE 10 char buf[STKSIZE]; /*buffer for the characters*/ int bufp = 0; /*stack pointer*/ char mgetch() { return( (bufp>0) ? buf[--bufp] : getchar()); } char unmgetch(int c) { if (bufp > STKSIZE) printf("getcmd: unmgetch: too many characters. Increase STKSIZE\n"); else buf[bufp++]=c; return; } /************************************************************************ getword used by getcmd Return a token or a string from standard input. A 'token' is anything delimited by white space. 'Strings' are delimited by double quotes. In a string, If a second quote is followed by white space, terminate the string, else accept second quote. Only if a quote is followed by white space is the string terminated. Commas and semicolons are ignored unless they are internal to strings. Returns: -1 - found ^Z (useful for VMS) 1 -- on success 0 -- no word found ************************************************************************/ int getword(char *token) /* gets 'token' from standard input */ { char c; int retflag=0; /* move past white space*/ while ( (c=mgetch())==' ' || c=='\t' || c==',' || c==';'); if (c==10) return(0); /* encountered newline character*/ else if (c==-1) return(-1); /* encountered ^Z (for VMS)*/ /* string mode: */ if ( c == '\"' ) while(1) { retflag=1; c = mgetch(); if ( c!= '\"' ) *token++ = c; else /* see if the " is followed by white space. */ { c = mgetch(); if ( (c==' ') || (c=='\t') || (c=='\n') || (c==',') || (c==';')) break; else { *token++ = '\"'; unmgetch(c); } } } /* word mode: */ else while( c!='\n' && c!=' ' && c!=',' && c!=';' ) { retflag=1; *token++ = c; c=mgetch(); } *token='\0'; /* end of the token. Terminate the string.*/ unmgetch(c); return (retflag); } /* prompt the user for an integer. Returns: 1 if an integer was entered, then 'response' is the value 0 if 'exit' was entered, then 'response' is not defined. */ int getint(char *prompt, int *response) { char ans[WORDSIZE]; int i,length; int okay; while(1) { getcmd(prompt,ans); if (iscmd(ans,"exit") || iscmd(ans,".") ) return(0); length = strlen(ans); okay = 1; if ( !isdigit(ans[0]) && ans[0] != '-' ) /* check for - sign */ okay = 0; for (i=1; i