home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * COMMAND.C
- * (c) 1992-3 J.Harper
- *
- * Wack(ish) style command processor
- *
- * explanation time,
- * Each command string is built from clauses, the different types of
- * clause are,
- *
- * (symbol [arg clauses]) command or variable clause
- * `string' string clause (quotes nest!), strings can also
- * {string} be surrounded by curly brackets (to help ARexx
- * users :-)
- * number number (hex, octal or decimal) clause,
- * ~x ascii value of char x (number clause)
- * ^x control codes
- * @ clause with no value (a placeholder?)
- *
- * escape sequences supported in strings (and characters) are
- * \n newline
- * \r carriage return
- * \f form feed
- * \t horizontal tab
- * \\ backslash
- * \` ignored open quote
- * \' ignored close quote
- * \0377 octal byte
- * \0xff hex byte
- * \255 decimal byte
- *
- * There are two variable types, strings and numbers (32 bit signed ints),
- * actually command functions are treated as variables, this is not important.
- *
- * In a command clause there can be more clauses representing that command's
- * arguments, so an example command string could be,
- * (settitle (format `%s %ld' `a string' 0x100))
- *
- * If a command string is to be passed as an argument it must be enclosed
- * in quotes to stop it being executed too soon, ie,
- * (if 1 `(req `foo\nbar\n' `go on')')
- *
- * internal notes:
- * Command functions which return NULL are taken as signifying that the macro
- * currently being evaluated is to be aborted, the Value in the RES field
- * of that command is taken as the result of the whole macro (this is to
- * make a (return) command easy :-)
- */
-
- #include "jed.h"
- #include "jed_protos.h"
-
- Prototype GSYM * addgsym (STRPTR, BYTE, VALUE *);
- Prototype LSYM * addlsym (STRPTR, BYTE, VALUE *);
- Prototype BOOL remsym (STRPTR);
- Local VALUE * resolveclause (STRPTR *, VALUE *);
- Local BOOL buildargv (STRPTR *, LONG *, VALUE **);
- Local VALUE * resolvesym (STRPTR, LONG, VALUE *, VALUE *);
- Local VALUE * execsym (SYM *, LONG, VALUE *, VALUE *);
- Local BOOL expandargs (STRPTR, LONG, VALUE *, LONG);
- Prototype VOID releasevalue (VALUE *);
- Prototype BOOL dupvalue (VALUE *, VALUE *);
- Local VOID releaseargs (LONG, VALUE *);
- Prototype BOOL templatecmd (LONG, VALUE *, LONG);
- Prototype VALUE * execstr (STRPTR, VALUE *, BOOL, LONG, VALUE *);
- Prototype LSYM * findlsym (STRPTR);
- Prototype BOOL findsargs (LONG *, VALUE **);
- Prototype VOID rxexecstring (STRPTR, APTR);
- Prototype BOOL scriptfile (STRPTR);
- Local STRPTR nextclause (STRPTR);
- Prototype VALUE * cmd_symboldump (LONG, VALUE *);
- Local VOID dumponesym (SYM *, BPTR);
-
- Prototype const UBYTE NoArgMsg[];
- Prototype const UBYTE NotStringMsg[];
- Prototype const UBYTE NotNumerMsg[];
- Prototype const UBYTE BadArgMsg[];
-
- const UBYTE NoArgMsg[] = "syntax error: no argument specified";
- const UBYTE NotStringMsg[] = "syntax error: not string value";
- const UBYTE NotNumerMsg[] = "syntax error: not numerical value";
- const UBYTE BadArgMsg[] = "syntax error: incorrect argument given";
-
- Prototype HASHNODE *SymbolTab[GSYMTABSIZE];
- Prototype CS CSList[];
- Prototype WORD CSDepth;
-
- HASHNODE *SymbolTab[GSYMTABSIZE];
- CS CSList[MAX_CS_RECURSE];
- WORD CSDepth;
-
- /*
- * value (any strings) will be allocated or whatever.
- */
- GSYM *
- addgsym(STRPTR name, BYTE symType, VALUE *value)
- {
- GSYM *newsym;
- /*
- * if(newsym = (GSYM *)findhash(SymbolTab, name))
- * {
- * releasevalue(&newsym->gs_Sym.sym_Value);
- * newsym->gs_Sym.sym_Type = symType;
- * dupvalue(&newsym->gs_Sym.sym_Value, value);
- * return(newsym);
- * }
- * else
- */
- if(newsym = AllocVec(sizeof(GSYM), MEMF_CLEAR))
- {
- if(newsym->gs_Node.h_Name = savestring(name))
- {
- inserthash(SymbolTab, &newsym->gs_Node, GSYMTABSIZE);
- newsym->gs_Sym.sym_Type = symType;
- dupvalue(&newsym->gs_Sym.sym_Value, value);
- return(newsym);
- }
- FreeVec(newsym);
- }
- settitle(NoMemMsg);
- return(FALSE);
- }
-
- /*
- * value (any strings) will be allocated or whatever.
- */
- LSYM *
- addlsym(STRPTR name, BYTE symType, VALUE *value)
- {
- LSYM *newsym;
- /*
- * if(newsym = findlsym(name))
- * {
- * releasevalue(&newsym->ls_Sym.sym_Value);
- * newsym->ls_Sym.sym_Type = symType;
- * dupvalue(&newsym->ls_Sym.sym_Value, value);
- * return(newsym);
- * }
- * else
- */
- if(newsym = AllocVec(sizeof(LSYM), MEMF_CLEAR))
- {
- if(newsym->ls_Node.ln_Name = savestring(name))
- {
- newsym->ls_Sym.sym_Type = symType;
- dupvalue(&newsym->ls_Sym.sym_Value, value);
- AddTail(&CSList[CSDepth].cs_Locals, &newsym->ls_Node);
- return(newsym);
- }
- FreeVec(newsym);
- }
- settitle(NoMemMsg);
- return(FALSE);
- }
-
- /*
- * symbol's value is automatically discarded
- */
- BOOL
- remsym(STRPTR name)
- {
- BOOL rc = FALSE;
- GSYM *gsym;
- LSYM *lsym;
- if(lsym = findlsym(name))
- {
- Remove(&lsym->ls_Node);
- freestring(lsym->ls_Node.ln_Name);
- releasevalue(&lsym->ls_Sym.sym_Value);
- FreeVec(lsym);
- rc = TRUE;
- }
- else if(gsym = findgsym(name))
- {
- removehash(SymbolTab, &gsym->gs_Node, GSYMTABSIZE);
- releasevalue(&gsym->gs_Sym.sym_Value);
- FreeVec(gsym);
- rc = TRUE;
- }
- else
- settitlefmt("error: unknown symbol %s", (LONG)name);
- return(rc);
- }
-
- /*
- * Evaluate the next clause in the string (deals with all other clauses
- * included in this clause).
- *
- * If this command returns FALSE it means a relatively major problem,
- * normally syntax errors but it could be that the last window was closed
- * in the middle of a command string, or that a clause was screwed up (ie,
- * unknown symbol or something), or we ran out of stack.
- */
- Local VALUE *
- resolveclause(STRPTR *clause, VALUE *result)
- {
- STRPTR symbol = *clause;
- UBYTE c;
- if(stksize() <= MIN_STACK)
- {
- settitle("error: no stack available for deeper recursion");
- goto error;
- }
- symbol = nextclause(symbol);
- c = *symbol;
- if((c == '(') || isalpha(c) || (c == '_'))
- {
- UBYTE name[40], d;
- static const UBYTE dummy[] = ")";
- STRPTR tname = name, dummy_p = dummy;
- VALUE *argv;
- LONG argc;
- if(c == '(')
- symbol = nextclause(symbol + 1);
- while((d = *symbol) && (!isspace(d)) && (d != ')'))
- {
- *tname++ = d;
- symbol++;
- }
- *tname = 0;
- if(c == '(' ? buildargv(&symbol, &argc, &argv) : buildargv(&dummy_p, &argc, &argv))
- {
- result = resolvesym(name, argc, argv, result);
- releaseargs(argc, argv);
- }
- }
- else if((c == '`') || (c == '{'))
- {
- STRPTR tempbuff = AllocVec(1024, 0L);
- LONG buffsize = 1024;
-
- if(tempbuff)
- {
- WORD kg = 0;
- WORD quotecount = 1;
- LONG i = 0;
-
- symbol++;
- while(!kg)
- {
- UBYTE c = *symbol++;
- switch(c)
- {
- case 0:
- kg = -1;
- symbol--;
- settitle("syntax error: unbalanced quotes in string clause");
- break;
- case '`':
- case '{':
- quotecount++;
- break;
- case '\'':
- case '}':
- if(!(--quotecount))
- {
- kg = 1;
- c = 0;
- }
- break;
- case '\\':
- if(quotecount == 1)
- c = escchar(&symbol);
- else
- {
- if(i >= buffsize)
- {
- STRPTR newbuff = AllocVec(buffsize << 1, 0L);
- if(!newbuff)
- {
- settitle(NoMemMsg);
- FreeVec(tempbuff);
- goto error;
- }
- memcpy(newbuff, tempbuff, buffsize);
- FreeVec(tempbuff);
- tempbuff = newbuff;
- buffsize <<= 1;
- }
- tempbuff[i++] = c;
- c = *symbol++;
- }
- break;
- }
- if(i >= buffsize)
- {
- STRPTR newbuff = AllocVec(buffsize << 1, 0L);
- if(!newbuff)
- {
- settitle(NoMemMsg);
- FreeVec(tempbuff);
- goto error;
- }
- memcpy(newbuff, tempbuff, buffsize);
- FreeVec(tempbuff);
- tempbuff = newbuff;
- buffsize <<= 1;
- }
- tempbuff[i++] = c;
- }
- if(kg == 1)
- {
- if(!(result->val_Value.String = savestring(tempbuff)))
- {
- settitle(NoMemMsg);
- FreeVec(tempbuff);
- goto error;
- }
- result->val_Type = VTF_STRING;
- }
- else
- {
- FreeVec(tempbuff);
- goto error;
- }
- FreeVec(tempbuff);
- }
- else
- {
- settitle(NoMemMsg);
- goto error;
- }
- }
- else if((isdigit(c)) || (c == '-'))
- {
- result->val_Value.Number = strtol(symbol, &symbol, 0);
- result->val_Type = VTF_NUMBER;
- }
- else if(c == '~')
- {
- if(symbol[1] == '\\')
- {
- symbol += 2;
- result->val_Value.Number = (LONG)escchar(&symbol);
- }
- else
- {
- result->val_Value.Number = (LONG)symbol[1];
- symbol += 2;
- }
- result->val_Type = VTF_NUMBER;
- }
- else if(c == '^')
- {
- result->val_Value.Number = (LONG)(toupper(symbol[1]) - '@');
- result->val_Type = VTF_NUMBER;
- symbol += 2;
- }
- else if(c == '@')
- {
- result->val_Type = VTF_NONE;
- symbol++;
- }
- else
- {
- settitle("syntax error: unrecognized clause type");
- error:
- /* In a perfect world I'd just step over this clause, but since
- * I'm lazy that can wait and for now I'll skip the whole string.
- */
- symbol += strlen(symbol);
- result->val_Type = VTF_NONE;
- result = FALSE;
- }
- *clause = nextclause(symbol);
- return(result);
- }
-
- /*
- * build up the argv array
- *
- * Format of the argv array is,
- * argv[0] - VALUE structure for result returned from command function,
- * argv[1-n] - VALUE structure of each argument.
- *
- * The argc passed is the number of arguments, doesn't include the
- * result.
- * The number of arguments is only limited by memory availability.
- */
- Local BOOL
- buildargv(STRPTR *args_p, LONG *argc_p, VALUE **argv_p)
- {
- WORD maxargs = 9;
- VALUE *argv = AllocVec(sizeof(VALUE) * maxargs, MEMF_CLEAR);
- if(argv)
- {
- LONG i;
- STRPTR args = *args_p;
- for(i = 0; *args != ')'; i++)
- {
- if(i == (maxargs - 1))
- {
- VALUE *newargv = AllocVec(sizeof(VALUE) * (maxargs << 1), MEMF_CLEAR);
- if(!newargv)
- {
- settitle(NoMemMsg);
- releaseargs(i, argv);
- return(FALSE);
- }
- memcpy(newargv, argv, sizeof(VALUE) * (i + 1));
- FreeVec(argv);
- argv = newargv;
- maxargs <<= 1;
- }
- if(!(resolveclause(&args, &argv[i + 1])))
- {
- releaseargs(i, argv);
- return(FALSE);
- }
- }
- *args_p = args + 1;
- *argv_p = argv;
- *argc_p = i;
- return(TRUE);
- }
- settitle(NoMemMsg);
- return(FALSE);
- }
-
- /*
- * find where a symbol is and resolve it
- */
- Local VALUE *
- resolvesym(STRPTR name, LONG argc, VALUE *argv, VALUE *result)
- {
- LSYM *lsym;
- GSYM *gsym;
- UBYTE tmpbuf[256];
-
- /* Try local symbols first
- */
- if(lsym = findlsym(name))
- result = execsym(&lsym->ls_Sym, argc, argv, result);
-
- /* Look for a global symbol
- */
- else if(gsym = findgsym(name))
- result = execsym(&gsym->gs_Sym, argc, argv, result);
-
- /* See if we can find a DOS variable which fits
- */
- else if(GetVar(name, tmpbuf, 256, 0) > 0)
- {
- if(result->val_Value.String = savestring(tmpbuf))
- result->val_Type = VTF_STRING;
- else
- {
- settitle(NoMemMsg);
- result->val_Type = VTF_NONE;
- result = FALSE;
- }
- }
-
- /* Try for implicit REXX macro
- */
- else
- {
- if(strlen(name) < 200)
- {
- BPTR lock;
- sprintf(tmpbuf, "REXX:%s.jed", name);
- if(lock = Lock(tmpbuf, SHARED_LOCK))
- {
- UnLock(lock);
- strcpy(tmpbuf, name);
- if(expandargs(tmpbuf, argc, argv, 256))
- {
- if(!(result->val_Value.Number = asyncRexxCmd(tmpbuf)))
- goto nosym;
- result->val_Type = VTF_NUMBER;
- }
- else
- {
- settitle("error: buffer overflow");
- result = FALSE;
- }
- }
- else
- goto nosym;
- }
- else
- {
- settitle(NoMemMsg);
- result = FALSE;
- }
- }
- if(FALSE)
- {
- nosym:
- settitlefmt("error: can't find symbol %s", (LONG)name);
- result = FALSE;
- }
- return(result);
- }
-
- /*
- * actually executes (or whatever) a symbol
- */
- Local VALUE *
- execsym(SYM *sym, LONG argc, VALUE *argv, VALUE *result)
- {
- switch(sym->sym_Value.val_Type)
- {
- case VTF_FUNC:
- if(!sym->sym_Value.val_Value.Func(argc, argv))
- {
- *result = RES;
- result = NULL;
- }
- else
- *result = RES;
- refresh();
- break;
- case VTF_STRING:
- if(sym->sym_Type == STF_COMMAND)
- result = execstr(sym->sym_Value.val_Value.String, result, TRUE, argc, argv);
- else
- dupvalue(result, &sym->sym_Value);
- break;
- default:
- dupvalue(result, &sym->sym_Value);
- break;
- }
- return(result);
- }
-
- /*
- * expands a commands argument clauses into a string (for REXX)
- */
- Local BOOL
- expandargs(STRPTR dest, LONG argc, VALUE *argv, LONG maxd)
- {
- LONG i = strlen(dest);
- while(argc--)
- {
- switch(argv->val_Type)
- {
- case VTF_STRING:
- LONG strl = strlen(argv->val_Value.String);
- if(i + strl < maxd)
- {
- strcpy(dest + i, " ");
- strcpy(dest + i + 1, argv->val_Value.String);
- i += strl + 1;
- }
- else
- {
- settitle("error: internal buffer overflow");
- return(FALSE);
- }
- break;
- case VTF_NUMBER:
- UBYTE nbuf[13];
- LONG strl;
- sprintf(nbuf, "%ld", argv->val_Value.Number);
- strl = strlen(nbuf);
- if(i + strl < maxd)
- {
- strcpy(dest + i, " ");
- strcpy(dest + i + 1, nbuf);
- i += strl + 1;
- }
- else
- return(FALSE);
- break;
- }
- argv++;
- }
- return(TRUE);
- }
-
- VOID
- releasevalue(VALUE *value)
- {
- if(value->val_Type == VTF_STRING)
- freestring(value->val_Value.String);
- value->val_Type = VTF_NONE;
- }
-
- BOOL
- dupvalue(VALUE *dst, VALUE *src)
- {
- BOOL rc = TRUE;
- if(src->val_Type == VTF_STRING)
- {
- if(dst->val_Value.String = savestring(src->val_Value.String))
- dst->val_Type = VTF_STRING;
- else
- {
- dst->val_Type = VTF_NONE;
- rc = FALSE;
- }
- }
- else
- *dst = *src;
- return(rc);
- }
-
- /*
- * Doesn't touch the result field
- */
- Local VOID
- releaseargs(LONG argc, VALUE *argv)
- {
- if(argv)
- {
- LONG i;
- for(i = 1; i <= argc; i++)
- {
- if(argv[i].val_Type == VTF_STRING)
- freestring(argv[i].val_Value.String);
- }
- FreeVec(argv);
- }
- }
-
- /*
- * checks the arguments passed to a command against the provided
- * template. template has two bits per argument (ARG1 is LSB)
- * these bits represent,
- * 00 anything
- * 01 string
- * 10 number
- * macros are provided for this function, ie
- * if(TPLATE2(VTF_NUMBER, VTF_STRING))
- */
- BOOL
- templatecmd(LONG argc, VALUE *argv, LONG argTemplate)
- {
- LONG i;
- for (i = 1; i <= argc; i++)
- {
- LONG thismask = argTemplate & 3;
- switch(thismask)
- {
- case 1:
- if(ARG(i).val_Type != VTF_STRING)
- {
- settitlefmt("syntax error: argument %ld should be a string", i);
- return(FALSE);
- }
- break;
- case 2:
- if(ARG(i).val_Type != VTF_NUMBER)
- {
- settitlefmt("syntax error: argument %ld should be a number", i);
- return(FALSE);
- }
- break;
- }
- argTemplate >>= 2;
- }
- if(argTemplate)
- {
- settitle("syntax error: too few arguments");
- return(FALSE);
- }
- return(TRUE);
- }
-
- /*
- * Executes a string of clauses, arguments can be passed and it can return
- * a result.
- *
- * A command in the macro which returns a null VALUE only aborts a macro
- * string (defined as those having arguments) - the result of the macro is
- * the result of the command that returned NULL.
- *
- * internal:
- * If this command returns 0 then it means that the result (in the VALUE
- * passed in) should be propagated back through the strings being executed
- * up to the macro (if available).
- * If a command returns 0 and result type is VTF_BREAK we just break from
- * this string returning a VTF_NONE value. Actually VTF_BREAK can handle
- * multiple depth breaking.
- */
- VALUE *
- execstr(STRPTR string, VALUE *result, BOOL args, LONG argc, VALUE *argv)
- {
- if(++CSDepth < MAX_CS_RECURSE)
- {
- LSYM *thissym, *nextsym;
- CS *cs = &CSList[CSDepth];
- cs->cs_Args = args;
- cs->cs_Argc = argc;
- cs->cs_Argv = argv;
- NewList(&cs->cs_Locals);
- result->val_Type = VTF_NONE;
- while(*string)
- {
- releasevalue(result);
- if(!resolveclause(&string, result))
- {
- if(result->val_Type == VTF_BREAK)
- {
- if(!(--result->val_Value.Number))
- result->val_Type = VTF_NONE;
- else
- result = FALSE;
- }
- else if(!args)
- result = FALSE;
- break;
- }
- }
- for(thissym = (LSYM *)cs->cs_Locals.lh_Head; thissym->ls_Node.ln_Succ; thissym = nextsym)
- {
- nextsym = (LSYM *)thissym->ls_Node.ln_Succ;
- freestring(thissym->ls_Node.ln_Name);
- releasevalue(&thissym->ls_Sym.sym_Value);
- FreeVec(thissym);
- }
- }
- else
- {
- settitle("error: command string recursion too deep");
- result->val_Type = VTF_NONE;
- }
- CSDepth--;
- return(result);
- }
-
- LSYM *
- findlsym(STRPTR name)
- {
- WORD i;
- for(i = CSDepth; i; i--)
- {
- LSYM *this;
- for(this = (LSYM *)CSList[i].cs_Locals.lh_Head; this->ls_Node.ln_Succ; this = (LSYM *)this->ls_Node.ln_Succ)
- {
- if(!strcmp(name, this->ls_Node.ln_Name))
- return(this);
- }
- }
- return(FALSE);
- }
-
- /*
- * find the arguments given to the innermost macro
- */
- BOOL
- findsargs(LONG *argc_p, VALUE **argv_p)
- {
- WORD i;
- for(i = CSDepth; i; i--)
- {
- if(CSList[i].cs_Args)
- {
- *argc_p = CSList[i].cs_Argc;
- *argv_p = CSList[i].cs_Argv;
- return(TRUE);
- }
- }
- return(FALSE);
- }
-
- VOID
- rxexecstring(STRPTR string, APTR rexxMsg)
- {
- VALUE result;
- cursor(OFF);
- if(execstr(string, &result, FALSE, 0, NULL))
- {
- if(result.val_Type == VTF_STRING)
- replyRexxCmd(rexxMsg, 0, 0, result.val_Value.String);
- else if(result.val_Type == VTF_NUMBER)
- replyRexxCmd(rexxMsg, result.val_Value.Number, 0, NULL);
- else
- replyRexxCmd(rexxMsg, 10, 0, NULL);
- }
- else
- replyRexxCmd(rexxMsg, 10, 0, NULL);
- releasevalue(&result);
- cursor(ON);
- }
-
- /*
- * Used by _main() to execute startup script
- */
- BOOL
- scriptfile(STRPTR fileName)
- {
- STRPTR filetext;
- if(filetext = squirrelfile(fileName))
- {
- VALUE result;
- settitlefmt("executing %s...", (LONG)fileName);
- cursor(OFF);
- execstr(filetext, &result, FALSE, 0, NULL);
- releasevalue(&result);
- cursor(ON);
- freestring(filetext);
- return(TRUE);
- }
- return(FALSE);
- }
-
- /*
- * Steps over white space, if a character COMMENT_CHAR (';') is found
- * the rest of the line is skipped.
- *
- * IMPORTANT:
- * If a command string is given to a command by enclosing it in quotes
- * it may contain comments (which won't be stripped until the command is
- * executed) but they (the comments) must NOT contain un-escaped quotes.
- */
- Local STRPTR
- nextclause(STRPTR str)
- {
- STRPTR str2 = str;
- for(;;)
- {
- UBYTE c;
- while(isspace(c = *str2++))
- ;
-
- if(c == COMMENT_CHAR)
- {
- while((c = *str2++) && (c != '\n'))
- ;
- if(!c)
- str2--;
- }
- else
- return(str2 - 1);
- }
- }
-
- /*
- * (symboldump `file' `type')
- *
- * type =
- * globals
- * locals
- * all
- */
- VALUE *
- cmd_symboldump(LONG argc, VALUE *argv)
- {
- if(TPLATE2(VTF_STRING, VTF_STRING))
- {
- BPTR fh = Open(ARG1.val_Value.String, MODE_NEWFILE);
- if(fh)
- {
- BOOL globs = FALSE;
- BOOL locs = FALSE;
- FPuts(fh, "symbol dump\n");
- if(!stricmp("globals", ARG2.val_Value.String))
- globs = TRUE;
- else if(!stricmp("locals", ARG2.val_Value.String))
- locs = TRUE;
- else if(!stricmp("all", ARG2.val_Value.String))
- {
- globs = TRUE;
- locs = TRUE;
- }
- if(globs)
- {
- WORD i;
- FPuts(fh, "\nglobal symboltable\n");
- for(i = 0; i < GSYMTABSIZE; i++)
- {
- GSYM *thissym = SymbolTab[i];
- while(thissym)
- {
- FPrintf(fh, "\t%s", (LONG)thissym->gs_Node.h_Name);
- dumponesym(&thissym->gs_Sym, fh);
- thissym = thissym->gs_Node.h_Next;
- }
- }
- }
- if(locs)
- {
- WORD i;
- FPuts(fh, "\nlocal symbols\n");
- for(i = 1; i <= CSDepth; i++)
- {
- LSYM *thissym = (LSYM *)CSList[i].cs_Locals.lh_Head;
- FPrintf(fh, "\tdepth %ld\n", i);
- while(thissym->ls_Node.ln_Succ)
- {
- FPrintf(fh, "\t\t%s", (LONG)thissym->ls_Node.ln_Name);
- dumponesym(&thissym->ls_Sym, fh);
- thissym = thissym->ls_Node.ln_Succ;
- }
- }
- }
- Close(fh);
- setnumres(TRUE);
- }
- else
- setnumres(FALSE);
- }
- return(&RES);
- }
-
- Local VOID
- dumponesym(SYM *sym, BPTR fh)
- {
- if(sym->sym_Type == STF_COMMAND)
- FPuts(fh, " (command)");
- else if(sym->sym_Type == STF_VARIABLE)
- FPuts(fh, " (variable)");
- else
- FPuts(fh, " (unknown symbol type)");
-
- if(sym->sym_Value.val_Type == VTF_NONE)
- FPuts(fh, " = no value\n");
- else if(sym->sym_Value.val_Type == VTF_STRING)
- FPrintf(fh, " = {%s}\n", sym->sym_Value.val_Value.Number);
- else if(sym->sym_Value.val_Type == VTF_NUMBER)
- FPrintf(fh, " = 0x%lx\n", sym->sym_Value.val_Value.Number);
- else if(sym->sym_Value.val_Type == VTF_FUNC)
- FPuts(fh, " = primitive function\n");
- else
- FPuts(fh, " unknown value type\n");
- }
-