📄 docmd.c
字号:
/* docmd: * This code supports the command line interface (CLI) portion of the * monitor. It is a table-driven CLI that uses the table in cmdtbl.c. * A limited amount of "shell-like" capabilities are supported... * shell variables, symbol-table lookup, command history, * command line editiing, command output redirection, etc... * * General notice: * This code is part of a boot-monitor package developed as a generic base * platform for embedded system designs. As such, it is likely to be * distributed to various projects beyond the control of the original * author. Please notify the author of any enhancements made or bugs found * so that all may benefit from the changes. In addition, notification back * to the author will allow the new user to pick up changes that may have * been made by other users after this version of the code was distributed. * * Note1: the majority of this code was edited with 4-space tabs. * Note2: as more and more contributions are accepted, the term "author" * is becoming a mis-representation of credit. * * Original author: Ed Sutter * Email: esutter@lucent.com * Phone: 908-582-2351 */#include "config.h"#include "genlib.h"#include "tfs.h"#include "tfsprivate.h"#include "cli.h"/* appCmdlist: * This is a pointer to a list of commands that can be added to the * monitor's list by the application using addcommand(). */struct monCommand *appCmdlist;void paramerr(struct monCommand *);void showusage(struct monCommand *);int showhelp(struct monCommand *,int,int);void shownextarg(struct monCommand *,char *,int,char **);int expandshellvars(char *);int tokenize(char *,char **);extern struct monCommand cmdlist[];extern char cmdUlvl[];/* docommand(): * Assume the incoming string is a null terminated character string * that is made up of whitespace delimited tokens that will be parsed * into command line arguments. The first argument is the command name * and all following arguments (if any) are specific to that command. * Three levels of verbosity are supported: * verbose == 0 no verbosity; * verbose == 1 print the list of arguments after tokenization * verbose == 2 print the incoming string prior to processing AND * print the list of arguments after tokenization; * the print of the unprocessed string is prefixed by * a "+ " string. * The verbosity level is 0 by default, to change the level, the script * should be run with "tfs -v run script" for verbose = 1 or * "tfs -v -v run script" for verbose = 2. */intdocommand(char *cmdline,int verbose){ int ret, argc, i; struct monCommand *cmdptr; char *ps, *argv[ARGCNT], cmdcpy[CMDLINESIZE]; if (verbose == 2) /* Print command line prior to processing */ printf("+ %s\n",cmdline); /* Just in case an upper-level interpreter has the same command as * this monitor, if the first character of the incoming command * string is an underscore, just throw it away. This allows the * user to get to the monitor command that is duplicated in an * upper level interpreter by preceding it with an underscore. */ if (cmdline[0] == '_') cmdline++; /* Copy the incoming command line to a local buffer so that we can * be sure that the line is writeable; plus we do not alter the * incoming buffer. */ strcpy(cmdcpy,cmdline); /* Scan through the string, if '#' is found, terminate line if * it is not preceded by a backslash. If it is preceded by a * backslash, then remove the backslash from the line and leave * the rest of the line as is. */ ps = strchr(cmdcpy,'#'); if (ps) { if (*(ps-1) != '\\') *ps = 0; else strcpy(ps-1,ps); } /* If there are any instances if a dollar or percent sign within the * command line, then expand any shell variables (or symbols) that may * be present. */ if (strpbrk(cmdcpy,"$%")) { if (expandshellvars(cmdcpy) < 0) return(CMD_LINE_ERROR); } /* Do a redirection check after shell variable expansion. * This must be done after the shell variable expansion so that we * can do things like.. * * echo hi >$APPRAMBASE,100 */ if (RedirectionCheck(cmdcpy) == -1) return(CMD_LINE_ERROR); /* Build argc/argv structure based on incoming command line. */ argc = tokenize(cmdcpy,argv); if (argc == 0) return(CMD_LINE_ERROR); if (argc < 0) { printf("Command line error\n"); return(CMD_LINE_ERROR); } /* If verbosity is enabled, print the processed command line. */ if (verbose) { for(i=0;i<argc;i++) printf("%s ",argv[i]); printf("\n"); } /* Initialize static data used by getopt(). */ getoptinit(); /* Step through the command table looking for a match between * the first token of the command line and a command name. */ cmdptr = cmdlist; while(cmdptr->name) { if (strcmp(argv[0],cmdptr->name) == 0) break; cmdptr++; } if (cmdptr->name) { if (cmdUlvl[cmdptr-cmdlist] > getUsrLvl()) { return(CMD_ULVL_DENIED); } if ((argc > 1) && (strcmp(argv[argc-1],"?") == 0)) { shownextarg(cmdptr,cmdline,argc,argv); return(CMD_PREFILL); } ret = cmdptr->func(argc,argv); /* If command returns parameter error, then print the second * string in that commands help text as the usage text. If * the second string is a null pointer, then print a generic * "no arguments" string as the usage message. */ if (ret == CMD_PARAM_ERROR) paramerr(cmdptr); RedirectionCmdDone(); return(ret); } /* If we get here, then the first token does not match on any of * the command names in the standard command table. Next we try * the optional application-provided command table. */ if (appCmdlist) { cmdptr = appCmdlist; while(cmdptr->name) { if (strcmp(argv[0],cmdptr->name) == 0) break; cmdptr++; } if (cmdptr->name) { ret = cmdptr->func(argc,argv); if (ret == CMD_PARAM_ERROR) paramerr(cmdptr); RedirectionCmdDone(); return(ret); } } /* If we get here, then the first token does not match on any of * the command names in ether of the command tables. As a last * resort, we look to see if the first token matches an executable * file name in TFS. */ ret = CMD_NOT_FOUND; if (tfsstat(argv[0])) { int err; err = tfsrun(argv,verbose); if (err == TFS_OKAY) { ret = CMD_SUCCESS; } else { printf("%s: %s\n",argv[0],(char *)tfsctrl(TFS_ERRMSG,err,0)); } } else { printf("Command not found: %s\n",argv[0]); } RedirectionCmdDone(); return(ret);}/* shownextarg(): */voidshownextarg(struct monCommand *cmdptr, char *cmdline, int argc, char **argv){ char *eol; /* Remove the question mark: */ eol = cmdline + strlen(cmdline); while(eol > cmdline) { if (*eol == '?') { *eol = 0; break; } else *eol = 0; eol--; } if (cmdptr->clix) { if (cmdptr->clix->nextarg(cmdline,argc,argv) == -1) showusage(cmdptr); } else showusage(cmdptr);}voidshowusage(struct monCommand *cmdptr){ char *usage; usage = cmdptr->helptxt[1]; printf("Usage: %s %s\n", cmdptr->name,*usage ? usage : "(no args/opts)");}voidparamerr(struct monCommand *cmdptr){ printf("Command line error...\n"); showusage(cmdptr);}intaddcommand(struct monCommand *cmd){ if (appCmdlist) printf("Overwriting appCmdlist pointer.\n"); appCmdlist = cmd; return(0);}static char *shellsym_chk(char type, char *string,int *size,char *buf,int bufsize){ char *p1, *p2, varname[CMDLINESIZE], *val; p1 = string; p2 = varname; while(1) { if (((*p1 >= '0') && (*p1 <= '9')) || ((*p1 >= 'a') && (*p1 <= 'z')) || ((*p1 >= 'A') && (*p1 <= 'Z')) || (*p1 == '_')) { *p2++ = *p1++; } else break; } *p2 = '\0'; if (type == '%') val = getsym(varname,buf,bufsize); else val = getenv(varname); if (val) { *size = strlen(varname); return(val); } else return((char *)0);}/* braceimbalance(): * Return non-zero (the index into the src string at the point of the * imbalance) if the incoming string does not have a balanced set * of braces; else return 0. */static intbraceimbalance(char *src, int *idx, int *ndp){ int bnest; char *base; bnest = 0; base = src; while((*src) && (bnest >= 0)) { if (((*src == '$') || (*src == '%')) && (*(src+1) == '{')) { bnest++; src++; } else if (*src == '}') bnest--; else if (*src == '{') { *ndp += 1; /* Indicate that there is a brace with no '$' prefix */ } else if (*src == '\\') { if ((*(src+1) == '$') || (*(src+1) == '%') || (*(src+1) == '\\') || (*(src+1) == '{') || (*(src+1) == '}')) { src++; } } src++; } /* If there is a '{}' mismatch, bnest will be non-zero... */ *idx = src - base - 1; return(bnest);}/* processprefixes(): * Process the '$' for shell variables and '%' for symbols. * Look for the last '$' (or '%') in the incoming string and attempt to * make a shell variable (or symbol) substitution. Return 0 if no '$' * (or '%') is found. Note that '$' and '%' are processed interchangeably * to support symbols and shell variables in the same way. */static intprocessprefixes(char *src){ int namesize, srclen; char *base, *varname, *value; char buf[CMDLINESIZE], buf1[CMDLINESIZE]; base = src;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -