www.pudn.com > tfs.rar > if.c
/* if.c:
* This file started off as the file for the "if" command in the monitor,
* and has since grown into the file that contains the commands that only
* make sense if they are used in scripts; hence, a prerequisite to these
* commands is that TFS is included in the build.
* It also contains the script runner portion of TFS. The name of this
* file should have been changed to tfsscript.c!
*
* if:
* Supports the monitor's ability to do conditional branching within
* scripts executed through TFS.
*
* goto:
* Tag based jumping in a script.
*
* item:
* A simple way to process a list (similar to KSH's 'for' construct).
*
* 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 "stddefs.h"
#include "tfs.h"
#include "tfsprivate.h"
//#include "ether.h"
//#include "cli.h"
#if INCLUDE_TFSSCRIPT
#define MAXGOSUBDEPTH 15
static long ReturnToTbl[MAXGOSUBDEPTH+1];
static int ReturnToDepth, ReturnToTfd, ScriptIsRunning;
static char *ScriptGotoTag;
int ScriptExitFlag;
/* If:
* A simple test/action statement.
* Currently, the only action supported is "goto tag".
* Syntax:
* if ARG1 compar ARG2 {action} [else action]
* if -t TEST {action} [else action]
*/
char *IfHelp[] = {
"Conditional branching",
"-[t:v] [{arg1} {compar} {arg2}] {action} [else action]",
" Numeric/logic compare:",
" gt lt le ge eq ne and or xor",
" String compare:",
" seq sne",
" Other tests (-t args):",
" gc, ngc, iscmp {filename}",
" Action:",
" goto tag | gosub tag | exit | return",
0,
};
int
If(int argc, char *argv[])
{
int opt, arg, true, if_else, offset, verbose;
void (*iffunc)(), (*elsefunc)();
long var1, var2;
char *testtype, *arg1, *arg2, *iftag, *elsetag;
verbose = 0;
testtype = 0;
while((opt=getopt(argc,argv,"vt:")) != -1) {
switch(opt) {
case 'v':
verbose = 1;
break;
case 't':
testtype = optarg;
break;
default:
return(CMD_PARAM_ERROR);
}
}
elsetag = 0;
elsefunc = 0;
offset = true = if_else = 0;
/* First see if there is an 'else' present... */
for (arg=optind;arg var2)
true = 1;
}
else if (!strcmp(testtype,"lt")) {
if (var1 < var2)
true = 1;
}
else if (!strcmp(testtype,"le")) {
if (var1 <= var2)
true = 1;
}
else if (!strcmp(testtype,"ge")) {
if (var1 >= var2)
true = 1;
}
else if (!strcmp(testtype,"eq")) {
if (var1 == var2)
true = 1;
}
else if (!strcmp(testtype,"ne")) {
if (var1 != var2)
true = 1;
}
else if (!strcmp(testtype,"and")) {
if (var1 & var2)
true = 1;
}
else if (!strcmp(testtype,"xor")) {
if (var1 ^ var2)
true = 1;
}
else if (!strcmp(testtype,"or")) {
if (var1 | var2)
true = 1;
}
else if (!strcmp(testtype,"seq")) {
if (!strcmp(arg1,arg2))
true = 1;
}
else if (!strcmp(testtype,"sne")) {
if (strcmp(arg1,arg2))
true = 1;
}
else
return(CMD_PARAM_ERROR);
}
/* If the true flag is set, call the 'if' function.
* If the true flag is clear, and "else" was found on the command
* line, then call the 'else' function...
*/
if (true) {
if (verbose)
printf("TRUE\n");
iffunc(iftag);
}
else {
if (verbose)
printf("FALSE\n");
if (if_else)
elsefunc(elsetag);
}
return(CMD_SUCCESS);
}
int
InAScript(void)
{
if (ScriptIsRunning)
return(1);
else {
printf("Invalid from outside a script\n");
return(0);
}
}
void
exitscript(char *ignored)
{
if (InAScript()) {
ScriptExitFlag = EXIT_SCRIPT;
}
}
char *ExitHelp[] = {
"Exit a script",
"-[r]",
"Options:",
" -r remove script after exit",
0,
};
int
Exit(int argc, char *argv[])
{
ScriptExitFlag = EXIT_SCRIPT;
if ((argc == 2) && (!strcmp(argv[1],"-r")))
ScriptExitFlag |= REMOVE_SCRIPT;
return(CMD_SUCCESS);
}
char *GotoHelp[] = {
"Branch to file tag",
"{tagname}",
0,
};
int
Goto(int argc, char *argv[])
{
if (argc != 2)
return(CMD_PARAM_ERROR);
gototag(argv[1]);
return(CMD_SUCCESS);
}
char *GosubHelp[] = {
"Call a subroutine",
"{tagname}",
0,
};
int
Gosub(int argc, char *argv[])
{
if (argc != 2)
return(CMD_PARAM_ERROR);
gosubtag(argv[1]);
return(CMD_SUCCESS);
}
char *ReturnHelp[] = {
"Return from subroutine",
"",
0,
};
int
Return(int argc, char *argv[])
{
if (argc != 1)
return(CMD_PARAM_ERROR);
gosubret(0);
return(CMD_SUCCESS);
}
/* Item:
* This is a simple replacement for the KSH "for" construct...
* It allows the user to build a list of strings and retrieve one at a time.
* Basically, the items can be thought of as a table. The value of idx
* (starting with 1) is used to index into the list of items and place
* that item in the shell variable "var".
* Syntax:
* item {idx} {var} {item1} {item2} {item3} ....
*/
char *ItemHelp[] = {
"Extract an item from a list",
"{idx} {stor_var} [item1] [item2] ...",
"Note: idx=1 retrieves item1",
0,
};
int
Item(int argc, char *argv[])
{
int idx;
char *varname;
if (argc < 3)
return(CMD_PARAM_ERROR);
idx = atoi(argv[1]);
varname = argv[2];
if ((idx < 1) || (idx > (argc-3))) {
setenv(varname,0);
return(CMD_SUCCESS);
}
idx += 2;
setenv(varname,argv[idx]);
return(CMD_SUCCESS);
}
/* Read():
* Simple interactive shell variable entry.
* Syntax:
* read [options] [var1] [var2] [...]
* Options:
* -c wait for any character to be received.
* -twww timeout after 'www' milliseconds (approximate) of
* waiting for input.
*
*/
char *ReadHelp[] = {
"Interactive shellvar entry",
"-[ct:] {var1} [var2] ... ",
" -c wait for any input",
" -t ### initial msec timeout",
" -T ### msec timeout per char",
0,
};
int
Read(argc,argv)
int argc;
char *argv[];
{
int i, reached_eol, opt, waitfor1, waitfor2;
char buf[64], *space, *bp;
waitfor1 = waitfor2 = 0;
while((opt=getopt(argc,argv,"ct:T:")) != -1) {
switch(opt) {
case 'c': /* Wait for any character entered (like hitakey). */
while(!gotachar())
#if INCLUDE_ETHERNET
pollethernet()
#endif
;
getchar(); /* Flush it from the input buffer, once received. */
break;
case 't':
waitfor1 = strtol(optarg,(char **)0,0);
waitfor1 *= LoopsPerSecond/1000;
break;
case 'T':
waitfor2 = strtol(optarg,(char **)0,0);
waitfor2 *= LoopsPerSecond/1000;
break;
default:
return(CMD_PARAM_ERROR);
}
}
if (argc == optind)
return(CMD_SUCCESS);
/* Timeout waiting for first character... */
if (waitfor1) {
while(!gotachar()) {
if (waitfor1-- <= 0)
return(CMD_FAILURE);
#if INCLUDE_ETHERNET
pollethernet();
#endif
}
}
/* Timeout waiting for every character... */
if (getline_t(buf,sizeof(buf)-1,waitfor2) == 0)
return(CMD_FAILURE);
bp = buf;
reached_eol = 0;
for(i=optind;i= MAXGOSUBDEPTH) {
printf("Max return-to depth reached\n");
return;
}
ReturnToTbl[ReturnToDepth] = tfstell(ReturnToTfd);
ReturnToDepth++;
gototag(tag);
}
}
void
gosubret(char *ignored)
{
if (InAScript()) {
if (ReturnToDepth <= 0)
printf("Nothing to return to\n");
else {
ReturnToDepth--;
tfsseek(ReturnToTfd, ReturnToTbl[ReturnToDepth], TFS_BEGIN);
}
}
}
/* tfsscript():
* Treat the file as a list of commands that should be executed
* as monitor commands. Step through each line and execute it.
* The tfsDocommand() function pointer is used so that the application
* can assign a different command interpreter to the script capbilities
* of the monitor. To really take advantage of this, the command interpreter
* that is reassigned, should allow monitor commands to run if the command
* does not exist in the application's command list.
*
* Scripts can call other scripts that call other scripts (etc...) and
* that works fine because tfsscript() will just use more stack space but
* it eventually returns through the same function call tree. A script can
* also call a COFF, ELF or AOUT file and expect it to return as long as
* the executable returns through the same point into which it was started
* (the entrypoint). If the executable uses mon_appexit() to terminate,
* then the calling script will not regain control.
*/
int
tfsscript(TFILE *fp,int verbose)
{
char lcpy[CMDLINESIZE], *sv;
int tfd, lnsize, lno, verbosity, rslt;
/* TFS does not support calling a script from within a subroutine. */
if (ReturnToDepth != 0)
return(TFSERR_SCRIPTINSUB);
tfd = tfsopen(fp->name,TFS_RDONLY,0);
if (tfd < 0)
return(tfd);
lno = 0;
ReturnToTfd = tfd;
ScriptIsRunning++;
while(1) {
lno++;
lnsize = tfsgetline(tfd,lcpy,CMDLINESIZE);
if (lnsize == 0) /* end of file? */
break;
if (lnsize < 0) {
printf("tfsscript(): %s\n",tfserrmsg(lnsize));
break;
}
if ((lcpy[0] == '\r') || (lcpy[0] == '\n')) /* empty line? */
continue;
lcpy[lnsize-1] = 0; /* Remove the newline */
/* Just in case the goto tag was set outside a script, */
/* clear it now. */
if (ScriptGotoTag) {
free(ScriptGotoTag);
ScriptGotoTag = (char *)0;
}
ScriptExitFlag = 0;
/* Execute the command line.
* If the shell variable "SCRIPTVERBOSE" is set, then enable
* verbosity for this command; else use what was passed in
* the parameter list of the function. Note that the variable
* is tested for each command so that verbosity can be enabled
* or disabled within a script.
* If the command returns a status that indicates that there was
* some parameter error, then exit the script.
*/
sv = getenv("SCRIPTVERBOSE");
if (sv)
verbosity = atoi(sv);
else
verbosity = verbose;
rslt = tfsDocommand(lcpy,verbosity);
switch(rslt) {
case CMD_PARAM_ERROR:
case CMD_NOT_FOUND:
printf("Terminating script '%s' at line %d\n",
TFS_NAME(fp),lno);
ScriptExitFlag = 1;
break;
}
/* Check for exit flag. If set, then in addition to terminating the
* script, clear the return depth here so that the "missing return"
* warning is not printed. This is done because there is likely
* to be a subroutine with an exit in it and this should not
* cause a warning.
*/
if (ScriptExitFlag) {
ReturnToDepth = 0;
break;
}
/* If ScriptGotoTag is set, then attempt to reposition the line
* pointer to the line that contains the tag.
*/
if (ScriptGotoTag) {
int tlen;
tlen = strlen(ScriptGotoTag);
tfsseek(tfd,0,TFS_BEGIN);
while(1) {
lnsize = tfsgetline(tfd,lcpy,CMDLINESIZE);
if (lnsize == 0) {
printf("Tag '%s' not found\n",ScriptGotoTag+2);
free(ScriptGotoTag);
ReturnToDepth = 0;
ScriptGotoTag = (char *)0;
tfsclose(tfd,0);
return(TFS_OKAY);
}
if (!strncmp(lcpy,ScriptGotoTag,tlen)) {
free(ScriptGotoTag);
ScriptGotoTag = (char *)0;
break;
}
}
}
#if INCLUDE_ETHERNET
/* After each line, poll ethernet interface. */
pollethernet();
#endif
}
tfsclose(tfd,0);
if (ScriptExitFlag & REMOVE_SCRIPT)
tfsunlink(fp->name);
if (ReturnToDepth != 0) {
printf("Warning: '%s' missing return.\n",fp->name);
ReturnToDepth = 0;
}
ScriptIsRunning--;
return(TFS_OKAY);
}
#else /* INCLUDE_TFSSCRIPT */
int
tfsscript(TFILE *fp,int verbose)
{
return(TFSERR_NOTAVAILABLE);
}
#endif