diff --git a/src/iocsh/Makefile b/src/iocsh/Makefile index ba44c20a3..848f4f852 100644 --- a/src/iocsh/Makefile +++ b/src/iocsh/Makefile @@ -5,6 +5,7 @@ include $(TOP)/configure/CONFIG # INC += ioccrf.h +INC += iocUtilRegister.h INC += dbStaticRegister.h INC += dbTestRegister.h INC += dbBkptRegister.h @@ -23,6 +24,7 @@ INC += asTestRegister.h # LIBSRCS += ioccrf.c +LIBSRCS += iocUtil.c LIBSRCS += dbStaticRegister LIBSRCS += dbTestRegister LIBSRCS += dbBkptRegister diff --git a/src/iocsh/dbAccessRegister.c b/src/iocsh/dbAccessRegister.c index 8273b8cda..876570bc3 100644 --- a/src/iocsh/dbAccessRegister.c +++ b/src/iocsh/dbAccessRegister.c @@ -19,6 +19,11 @@ of this distribution. #include "dbAccessRegister.h" #include "ioccrf.h" +#ifdef __rtems__ +# define dbLoadDatabase dbLoadDatabaseRTEMS +# define dbLoadRecords dbLoadRecordsRTEMS +#endif + /* dbLoadDatabase */ static ioccrfArg dbLoadDatabaseArg0 = { "file name",ioccrfArgString,0}; static ioccrfArg dbLoadDatabaseArg1 = { "path",ioccrfArgString,0}; diff --git a/src/iocsh/iocUtil.c b/src/iocsh/iocUtil.c new file mode 100644 index 000000000..b4ef47d6e --- /dev/null +++ b/src/iocsh/iocUtil.c @@ -0,0 +1,121 @@ +/* iocUtil.c */ +/* Author: W. Eric Norum Date: 02MAY2000 */ + +#include +#include +#include +#include +#include + +#include + +#include "ioccrf.h" +#define epicsExportSharedSymbols + + +/* < (runScript) command */ +static ioccrfArg runScriptArg0 = { "file name",ioccrfArgString,0}; +static ioccrfArg *runScriptArgs[1] = {&runScriptArg0}; +static ioccrfFuncDef runScriptFuncDef = {"<",1,runScriptArgs}; +static void runScriptCallFunc(ioccrfArg **args) +{ +#ifdef __rtems__ + runScriptRTEMS ((char *)args[0]->value); +#else + char *cp; + FILE *fp; + + cp = (char *)args[0]->value; + fp = fopen (cp, "r"); + if (fp == NULL) { + printf ("Can't open script (%s)\n", cp); + } + else { + ioccrf (fp, cp); + fclose (fp); + } +#endif +} + +/* chdir */ +static ioccrfArg chdirArg0 = { "directory name",ioccrfArgString,0}; +static ioccrfArg *chdirArgs[1] = {&chdirArg0}; +static ioccrfFuncDef chdirFuncDef = {"cd",1,chdirArgs}; +static void chdirCallFunc(ioccrfArg **args) +{ + chdir((char *)args[0]->value); +} + +/* show (thread information) */ +static ioccrfArg showArg0 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg1 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg2 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg3 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg4 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg5 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg6 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg7 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg8 = { "task",ioccrfArgString,0}; +static ioccrfArg showArg9 = { "task",ioccrfArgString,0}; +static ioccrfArg *showArgs[10] = { + &showArg0,&showArg1,&showArg2,&showArg3,&showArg4, + &showArg5,&showArg6,&showArg7,&showArg8,&showArg9, +}; +static ioccrfFuncDef showFuncDef = {"show",10,showArgs}; +static void showCallFunc(ioccrfArg **args) +{ + int i = 0; + int first = 1; + int level = 0; + char *cp; + threadId tid; + unsigned long ltmp; + char *endp; + + if (((cp = (char *)args[i]->value) != NULL) + && (*cp == '-')) { + level = atoi (cp + 1); + i++; + } + if ((cp = (char *)args[i]->value) == NULL) { + threadShowAll (level); + return; + } + for ( ; i < 10 ; i++) { + if ((cp = (char *)args[i]->value) == NULL) + return; + ltmp = strtoul (cp, &endp, 16); + if (*endp) { + tid = threadGetId (cp); + if (!tid) { + printf ("*** argument %d (%s) is not a valid task name ***\n", i+1, cp); + continue; + } + } + else { + tid = (threadId)ltmp; + } + if (first) { + threadShow (0, level); + first = 0; + } + threadShow (tid, level); + } +} + +/* threadInit */ +static ioccrfFuncDef threadInitFuncDef = + {"threadInit",0,0}; +static void threadInitCallFunc(ioccrfArg **args) +{ + threadInit(); +} + + +void epicsShareAPI iocUtilRegister(void) +{ + ioccrfRegister(&runScriptFuncDef,runScriptCallFunc); + ioccrfRegister(&chdirFuncDef,chdirCallFunc); + ioccrfRegister(&showFuncDef,showCallFunc); + ioccrfRegister(&threadInitFuncDef,threadInitCallFunc); +} diff --git a/src/iocsh/iocUtilRegister.h b/src/iocsh/iocUtilRegister.h new file mode 100644 index 000000000..733507bc0 --- /dev/null +++ b/src/iocsh/iocUtilRegister.h @@ -0,0 +1,19 @@ +/* iocUtilRegister.h */ +/* Author: W. Eric Norum Date: 03MAY2000 */ + +#ifndef INCiocUtilRegisterH +#define INCiocUtilRegisterH + +#include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +epicsShareFunc void epicsShareAPI iocUtilRegister(void); + +#ifdef __cplusplus +} +#endif + +#endif /*INCiocUtilRegisterH*/ diff --git a/src/iocsh/ioccrf.c b/src/iocsh/ioccrf.c index 810c4f7ad..cccef07ff 100644 --- a/src/iocsh/ioccrf.c +++ b/src/iocsh/ioccrf.c @@ -1,5 +1,6 @@ /* ioccrf.c */ /* Author: Marty Kraimer Date: 27APR2000 */ +/* Heavily modified by Eric Norum Date: 03MAY2000 */ /********************COPYRIGHT NOTIFICATION********************************** This software was developed under a United States Government license @@ -19,176 +20,373 @@ of this distribution. #define epicsExportSharedSymbols #include "ioccrf.h" -#define MAX_BUFFER_SIZE 120 - -static char *ioccrfID = "ioccrf"; -static char inline[MAX_BUFFER_SIZE]; - typedef struct argvalue { struct argvalue *next; union type { int ival; double dval; } type; -}argvalue; - -argvalue *argvalueHead = 0; +} argvalue; typedef struct ioccrfFunc { ioccrfFuncDef *pioccrfFuncDef; ioccrfCallFunc func; -}ioccrfFunc; +} ioccrfFunc; -static int cvtArg(char **pnextchar,argvalue *pargvalue,ioccrfArg *pioccrfArg) +static char ioccrfID[] = "ioccrf"; + +#ifdef IOCSH_USE_READLINE + +#include +#include + +#else + +/* + * Fake versions of some readline/history routines + */ +#define stifle_history(n) do { } while(0) +#define add_history(l) do { } while(0) +#define rl_bind_key(c,f) do { } while(0) + +#endif + +/* + * Register a command + */ +void epicsShareAPI ioccrfRegister (ioccrfFuncDef *pioccrfFuncDef, ioccrfCallFunc func) +{ + ioccrfFunc *pioccrfFunc; + + pioccrfFunc = callocMustSucceed (1, sizeof(ioccrfFunc), "ioccrfRegister"); + pioccrfFunc->pioccrfFuncDef = pioccrfFuncDef; + pioccrfFunc->func = func; + if (!registryAdd(ioccrfID, pioccrfFuncDef->name, (void *)pioccrfFunc)) + errlogPrintf ("ioccrfRegister failed to add %s\n", pioccrfFuncDef->name); +} + +/* + * Read a line of input + */ +static char * +my_readline (FILE *fp, const char *prompt) +{ + char c; + char *line = NULL; + int linelen = 0; + int linesize = 50; + +#ifdef IOCSH_USE_READLINE + if (fp == stdin) + return readline (prompt); +#endif + line = malloc (linesize * sizeof *line); + if (line == NULL) { + printf ("Out of memory!\n"); + return NULL; + } + if (prompt) + printf ("%s", prompt); + while ((c = getc (fp)) != '\n') { + if (c == EOF) { + free (line); + return NULL; + } + if ((linelen + 1) >= linesize) { + char *cp; + + linesize += 50; + cp = realloc (line, linesize * sizeof *line); + if (cp == NULL) { + printf ("Out of memory!\n"); + free (line); + return NULL; + } + line = cp; + } + line[linelen++] = c; + } + line[linelen] = '\0'; + return line; +} + +/* + * Report an error + */ +static void +showError (const char *name, int lineno, const char *msg, ...) +{ + va_list ap; + + va_start (ap, msg); + if (name) + printf ("%s -- Line %d -- ", name, lineno); + vprintf (msg, ap); + printf ("\n"); + va_end (ap); +} + +static int +cvtArg (const char *filename, int lineno, char *arg, argvalue *pargvalue, ioccrfArg *pioccrfArg) { - char *p = *pnextchar; - char *argend; char *endp; - /*skip leading whitespace */ - while(*p && (isspace(*p))) ++p; - argend = p; - /* look for , or ) */ - while(*argend && (*argend!=',') && (*argend!=')') ) { - /* If quote then look for matching quote */ - if(*argend == '\"') { - ++argend; - while(*argend && (*argend!='\"') ) ++argend; - if(!*argend) { - printf("Illegal string: %s\n",p); - return(0); + + switch (pioccrfArg->type) { + case ioccrfArgInt: + if (arg && *arg) { + pargvalue->type.ival = strtol (arg, &endp, 0); + if (*endp) { + showError (filename, lineno, "Illegal integer `%s'", arg); + return 0; } } - ++argend; - } - if(*argend) { - *argend = 0; - *pnextchar = argend + 1; - } - /*remove trailing spaces*/ - while(*p && isspace(p[strlen(p)-1])) p[strlen(p)-1] = 0; - switch(pioccrfArg->type) { - case ioccrfArgInt: - if(*p) { - pargvalue->type.ival = strtol(p,&endp,0); - if(*endp) { - printf("Illegal integer %s\n",p); - return(0); - } - } else { + else { pargvalue->type.ival = 0; } pioccrfArg->value = &pargvalue->type.ival; break; + case ioccrfArgDouble: - if(*p) { - pargvalue->type.dval = strtod(p,&endp);; - if(*endp) { - printf("Illegal double %s\n",p); - return(0); + if (arg && *arg) { + pargvalue->type.dval = strtod (arg, &endp); + if (*endp) { + showError (filename, lineno, "Illegal double `%s'", arg); + return 0; } - } else { - pargvalue->type.ival = 0.0; + } + else { + pargvalue->type.dval = 0.0; } pioccrfArg->value = &pargvalue->type.dval; break; + case ioccrfArgString: - /*if argument is missing just assume null*/ - if(!*p) { - pioccrfArg->value = 0; - break; - } - /*first and last char should be quote */ - if( (*p != '\"') || (p[strlen(p)-1] != '\"') ) { - /*if just character 0 accept it*/ - if(strcmp(p,"0")==0) { - pioccrfArg->value = 0; - break; - } - printf("Illegal string argument %s\n",p); - return(0); - } - /* strip off trailing quote */ - p[strlen(p)-1] = 0; - pioccrfArg->value = p+1; + pioccrfArg->value = arg; break; + case ioccrfArgPdbbase: - /*field must missing or 0 or pdbbase*/ - if( !*p || (*p == '0') || (strcmp(p,"pdbbase")==0) ) { + /* Argumenmt must be missing or 0 or pdbbase */ + if(!arg || !*arg || (*arg == '0') || (strcmp(arg, "pdbbase") == 0)) { pioccrfArg->value = pdbbase; break; } - printf("Expecting pdbbase; got %s\n",p); - return(0); + showError (filename, lineno, "Expecting `pdbbase' got `%s'", arg); + return 0; + default: - printf("Illegal argument type\n"); - return(0); + showError (filename, lineno, "Illegal argument type %d", pioccrfArg->type); + return 0; } - return(1); -} - - -void epicsShareAPI ioccrfRegister(ioccrfFuncDef *pioccrfFuncDef,ioccrfCallFunc func) -{ - ioccrfFunc *pioccrfFunc; - - pioccrfFunc = callocMustSucceed(1,sizeof(ioccrfFunc),"ioccrfRegister"); - pioccrfFunc->pioccrfFuncDef = pioccrfFuncDef; - pioccrfFunc->func = func; - if(!registryAdd((void *)ioccrfID,pioccrfFuncDef->name,(void *)pioccrfFunc)) - errlogPrintf("ioccrfRegister failed to add %s\n", pioccrfFuncDef->name); + return 1; } -void epicsShareAPI ioccrf(FILE *fp) +/* + * The body of the command interpreter + */ +void epicsShareAPI +ioccrf (FILE *fp, const char *filename) { - char *p; - char *command = 0; + int icin, icout; + int c, quote, inword, backslash; + char *line = NULL; + int lineno = 0; + int argc; + char **argv = NULL; + int argvsize = 0; + int sep; + const char *prompt; + const char *ifs; + const char *historySize; ioccrfFunc *pioccrfFunc; ioccrfFuncDef *pioccrfFuncDef; - argvalue *pargvalue; - ioccrfArg *pioccrfArg; - argvalue *prevArgvalue; int arg; + argvalue *pargvalue, *prevargvalue, *argvalueHead = NULL; + ioccrfArg *pioccrfArg; + + /* + * Pick up items from environment + */ + if ((prompt = getenv ("PS1")) == NULL) + prompt = "-> "; + if ((ifs = getenv ("IFS")) == NULL) + ifs = " \t(),"; - while(1) { - if(fp==stdin) printf("ioccrf: "); - p= fgets(inline,MAX_BUFFER_SIZE-1,fp); - if(!p) break; - if(strlen(p)==1) continue; /* null line */ - inline[strlen(inline)-1] = 0; /*strip newline*/ - if(fp!=stdin) printf("%s\n",inline); - if(strncmp(p,"exit",4)==0) break; - /*skip whitespace at beginning of line*/ - while(*p && (isspace(*p))) ++p; - if(!p) continue; - command = p; - /*look for ( and replace with null*/ - while(*p && (*p != '(') ) ++p; - if(*p) *p++ = 0; - /*remove trailing spaces from command*/ - while(isspace(command[strlen(command)-1])) - command[strlen(command)-1]=0; - pioccrfFunc = (ioccrfFunc *)registryFind(ioccrfID,command); - if(!pioccrfFunc) { - printf("command %s not found\n",command); + /* + * See if command interpreter is interactive + */ + if (fp == NULL) + fp = stdin; + if (fp == stdin) { + filename = NULL; + if ((historySize = getenv ("HISTSIZE")) == NULL) + historySize="10"; + stifle_history (atoi (historySize)); + /* + * FIXME: Could enable tab-completion of commands here + */ + rl_bind_key ('\t', rl_insert); + } + else { + prompt = NULL; + } + + /* + * Read commands till EOF + */ + for (;;) { + /* + * Get a line + */ + lineno++; + free (line); + line = my_readline (fp, prompt); + if (line == NULL) + break; + + /* + * If interactive, add non-blank lines to history + */ + if ((fp == stdin) && *line) + add_history (line); + + /* + * Ignore comment lines + */ + if (*line == '#') + continue; + + /* + * Break line into words + */ + icout = icin = 0; + inword = 0; + quote = EOF; + backslash = 0; + argc = 0; + for (;;) { + if (argc >= argvsize) { + char **av; + argvsize += 50; + av = realloc (argv, argvsize * sizeof *argv); + if (av == NULL) { + printf ("Out of memory!\n"); + argc = -1; + break; + } + argv = av; + } + c = line[icin++]; + if (c == '\0') + break; + if ((quote == EOF) && !backslash && (strchr (ifs, c))) + sep = 1; + else + sep = 0; + if ((quote == EOF) && (c == '\\') && !backslash) { + backslash = 1; + continue; + } + if (inword) { + if (c == quote) { + quote = EOF; + } + else { + if ((quote == EOF) && !backslash) { + if (sep) { + inword = 0; + line[icout++] = '\0'; + } + else if ((c == '"') || (c == '\'')) { + quote = c; + } + else { + line[icout++] = c; + } + } + else { + line[icout++] = c; + } + } + } + else { + if (!sep) { + if (((c == '"') || (c == '\'')) && !backslash) + quote = c; + argv[argc++] = line + icout; + if (quote == EOF) + line[icout++] = c; + inword = 1; + } + } + backslash = 0; + } + if (argc < 0) + break; + if (quote != EOF) { + showError (filename, lineno, "Unbalanced quote."); continue; } - pioccrfFuncDef = pioccrfFunc->pioccrfFuncDef; - pargvalue = argvalueHead; - prevArgvalue = 0; - for(arg=0;argnargs; arg++) { - pioccrfArg = pioccrfFuncDef->arg[arg]; - if(!pargvalue) { - pargvalue = callocMustSucceed(1,sizeof(argvalue),"ioccrf"); - if(prevArgvalue) prevArgvalue->next = pargvalue; - argvalueHead = pargvalue; - } - if(!cvtArg(&p,pargvalue,pioccrfArg)) goto badline; - prevArgvalue = pargvalue; - pargvalue = prevArgvalue->next; + if (backslash) { + showError (filename, lineno, "Trailing backslash."); + continue; } - (*pioccrfFunc->func)(pioccrfFuncDef->arg); - continue; -badline: - printf("illegal line\n"); + if (inword) + line[icout++] = '\0'; + argv[argc] = NULL; + + /* + * Look up command + */ + if (argc) { + /* + * Special command? + */ + if (strncmp (argv[0], "exit", 4) == 0) + break; + + /* + * Look up command + */ + pioccrfFunc = (ioccrfFunc *)registryFind (ioccrfID, argv[0]); + if (!pioccrfFunc) { + showError (filename, lineno, "Command %s not found.", argv[0]); + continue; + } + + /* + * Process arguments + */ + pioccrfFuncDef = pioccrfFunc->pioccrfFuncDef; + pargvalue = argvalueHead; + prevargvalue = NULL; + for (arg = 0 ; ; arg++) { + char *p = (arg < argc) ? argv[arg+1] : NULL; + + if (arg == pioccrfFuncDef->nargs) { + (*pioccrfFunc->func)(pioccrfFuncDef->arg); + break; + } + pioccrfArg = pioccrfFuncDef->arg[arg]; + if (!pargvalue) { + pargvalue = callocMustSucceed(1, sizeof(argvalue), "ioccrf"); + if(prevargvalue) + prevargvalue->next = pargvalue; + argvalueHead = pargvalue; + } + if (!cvtArg (filename, lineno, p, pargvalue, pioccrfArg)) + break; + prevargvalue = pargvalue; + pargvalue = prevargvalue->next; + } + } + } + free (line); + free (argv); + while (argvalueHead) { + pargvalue = argvalueHead->next; + free (argvalueHead); + argvalueHead = pargvalue; } } + +/* Readline automatic completion code could go here! */ diff --git a/src/iocsh/ioccrf.h b/src/iocsh/ioccrf.h index 3a0062756..27950c88b 100644 --- a/src/iocsh/ioccrf.h +++ b/src/iocsh/ioccrf.h @@ -17,7 +17,6 @@ of this distribution. extern "C" { #endif - typedef enum { ioccrfArgInt, ioccrfArgDouble, @@ -43,7 +42,7 @@ epicsShareFunc void epicsShareAPI ioccrfRegister( ioccrfFuncDef *pioccrfFuncDef,ioccrfCallFunc func); -epicsShareFunc void epicsShareAPI ioccrf(FILE *); +epicsShareFunc void epicsShareAPI ioccrf(FILE *, const char *filename); #ifdef __cplusplus }