📄 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;
char *appcmdUlvl;
extern struct monCommand cmdlist[];
extern char cmdUlvl[];
void
showusage(struct monCommand *cmdptr)
{
char *usage;
usage = cmdptr->helptxt[1];
printf("Usage: %s %s\n",
cmdptr->name,*usage ? usage : "(no args/opts)");
}
void
paramerr(struct monCommand *cmdptr)
{
printf("Command parameter error...\n");
showusage(cmdptr);
}
int
addcommand(struct monCommand *cmdlist, char *cmdlvl)
{
appCmdlist = cmdlist;
appcmdUlvl = cmdlvl;
return(0);
}
#if INCLUDE_SHELLVARS
char *
shellsym_chk(char type, char *string,int *size,char *buf,int bufsize)
{
char *p1, *p2, varname[CMDLINESIZE], *val;
p1 = string;
p2 = varname;
/* If incoming check is for a symbol, we apply a somewhat more
* flexible syntax check for the symbol name...
*/
if (type == '%') {
while(*p1 && (*p1 != '}') && (*p1 != ' ') && (*p1 != '\t'))
*p2++ = *p1++;
}
else {
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))
*size = strlen(varname);
return(val);
}
/* 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 int
braceimbalance(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 int
processprefixes(char *src)
{
int namesize, srclen;
char *base, *varname, *value;
char buf[CMDLINESIZE], buf1[CMDLINESIZE];
base = src;
srclen = strlen(src);
while(*src) {
if (((*src == '$') || (*src == '%')) && (*(src-1) != '\\')) {
varname = src+1;
value = shellsym_chk(*src,varname,&namesize,buf1,sizeof(buf1));
if (value) {
if (((srclen - namesize) + strlen(value)) >= CMDLINESIZE) {
printf("Cmd line expansion overflow\n");
return(-1);
}
strcpy(buf,varname+namesize);
sprintf(varname-1,"%s%s",value,buf);
return(1);
}
}
src++;
}
return(0);
}
/* processbraces():
* Look into the incoming string for the deepest set of braces and
* substitute that with the value stored in the corresponding shell
* variable. Return 1 if a set of braces was processed; else 0 indicating
* that all braces have been processed. Return -1 if there is some kind
* of processing error (buffer overflow).
*/
static int
processbraces(char *src)
{
int namesize, srclen, result;
char *base, *cp1, *cp2, *varname, *value, type;
char buf[CMDLINESIZE], buf1[CMDLINESIZE], buf2[CMDLINESIZE];
type = 0;
base = src;
varname = src;
srclen = strlen(src);
while(*src) {
if (((*src == '$') || (*src == '%')) && (*(src+1) == '{')) {
type = *src;
varname = src+2;
src++;
}
else if (*src == '}') {
cp1 = varname;
cp2 = buf1;
while(cp1 < src)
*cp2++ = *cp1++;
*cp2 = 0;
while((result = processprefixes(buf1)) == 1);
if (result == -1)
return(-1);
strcpy(buf,src);
sprintf(varname,"%s%s",buf1,buf);
value = shellsym_chk(type,varname,&namesize,buf2,sizeof(buf2));
/* If the shellvar or symbol exists, replace it; else remove it. */
if (value) {
if (((srclen-(namesize+3))+strlen(value)+1) > CMDLINESIZE) {
printf("Cmd line expansion overflow\n");
return(-1);
}
strcpy(buf1,varname+namesize+1);
sprintf(varname-2,"%s%s",value,buf1);
}
else {
strcpy(varname-2,src+1);
}
return(1);
}
else if (*src == '\\') {
if ((*(src+1) == '$') || (*(src+1) == '%') ||
(*(src+1) == '\\') ||
(*(src+1) == '{') || (*(src+1) == '}')) {
src++;
}
}
src++;
}
return(0);
}
/* expandshellvars():
* Passed a string that is to be expanded with all shell variables converted.
* This function supports variables of type $VARNAME and ${VARNAME}.
* It also allows variables to be embedded within variables. For example...
* ${VAR${NAME}} will be a 2-pass expansion in which ${NAME} is evaluated
* and then ${VARXXX} (where XXX is whatever was in variable NAME) is
* processed.
*/
static int
expandshellvars(char *newstring)
{
char *cp;
int result, cno, ndp;
/* Verify that there is a balanced set of braces in the incoming
* string...
*/
ndp = 0;
if (braceimbalance(newstring,&cno,&ndp)) {
printf("Brace imbalance @ %d%s.\n",
cno,ndp ? " ({ missing $ or %)" : "");
return(-1);
}
/* Process the variable names within braces... */
while((result = processbraces(newstring)) == 1);
if (result == -1)
return(-1);
/* Process dollar signs (left-most first)... */
while((result = processprefixes(newstring)) == 1);
if (result == -1)
return(-1);
/* Cleanup any remaining "\{", "\}" or "\$" strings... */
cp = newstring+1;
while(*cp) {
if (*cp == '{' || *cp == '}' || *cp == '$' || *cp == '%') {
if (*(cp-1) == '\\') {
strcpy(cp-1,cp);
cp -= 2;
}
}
cp++;
}
return(0);
}
#else
static int
expandshellvars(char *newstring)
{
return(0);
}
#endif
/* tokenize():
* Take the incoming string and create an argv[] array from that. The
* incoming string is assumed to be writeable. The argv[] array is simple
* a set of pointers into that string, where the whitespace delimited
* character sets are each NULL terminated.
*/
int
tokenize(char *string,char *argv[])
{
int argc, done;
/* Null out the incoming argv array. */
for(argc=0;argc<ARGCNT;argc++)
argv[argc] = (char *)0;
argc = 0;
while(1) {
while ((*string == ' ') || (*string == '\t'))
string++;
if (*string == 0)
break;
argv[argc] = string;
while ((*string != ' ') && (*string != '\t')) {
if ((*string == '\\') && (*(string+1) == '"')) {
strcpy(string,string+1);
}
else if (*string == '"') {
strcpy(string,string+1);
while(*string != '"') {
if ((*string == '\\') && (*(string+1) == '"'))
strcpy(string,string+1);
if (*string == 0)
return(-1);
string++;
}
strcpy(string,string+1);
continue;
}
if (*string == 0)
break;
string++;
}
if (*string == 0)
done = 1;
else {
done = 0;
*string++ = 0;
}
argc++;
if (done)
break;
if (argc >= ARGCNT) {
argc = -1;
break;
}
}
return(argc);
}
/* showhelp():
* Called by Help() when it is time to print out some verbosity level of
* a command's help text.
* if...
* verbose == 2, then print all the help text;
* verbose == 1, then print the command name and abstract;
* verbose == 0, then print only the command name;
*/
int
showhelp(struct monCommand *list,int index,int verbose)
{
char **hp, *lvltbl;
struct monCommand *cptr;
cptr = &list[index];
/* Get command list in sync with user-level table:
*/
if (list == cmdlist)
lvltbl = cmdUlvl;
else if (list == appCmdlist)
lvltbl = appcmdUlvl;
else
return(-1);
/* Verify user level:
*/
if ((lvltbl[index] > getUsrLvl()))
return(0);
if (verbose == 2) {
printf("%s\n", cptr->helptxt[0]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -