diff options
Diffstat (limited to 'c/src/libnetworking/rtems_webserver/ejparse.c')
-rw-r--r-- | c/src/libnetworking/rtems_webserver/ejparse.c | 1804 |
1 files changed, 0 insertions, 1804 deletions
diff --git a/c/src/libnetworking/rtems_webserver/ejparse.c b/c/src/libnetworking/rtems_webserver/ejparse.c deleted file mode 100644 index fdbb9c1d8a..0000000000 --- a/c/src/libnetworking/rtems_webserver/ejparse.c +++ /dev/null @@ -1,1804 +0,0 @@ -/* - * ejparse.c -- Ejscript(TM) Parser - * - * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. - * - * See the file "license.txt" for usage and redistribution license requirements - * - * $Id$ - */ - -/******************************** Description *********************************/ - -/* - * Ejscript parser. This implementes a subset of the JavaScript language. - * Multiple Ejscript parsers can be opened at a time. - */ - -/********************************** Includes **********************************/ - -#include "ejIntrn.h" - -#ifdef CE - #include "CE/wincompat.h" -#endif - -/********************************** Local Data ********************************/ - -ej_t **ejHandles; /* List of ej handles */ -int ejMax = -1; /* Maximum size of */ - -/****************************** Forward Declarations **************************/ - -#ifndef B_STATS -#define setString(a,b,c) setstring(b,c) -#endif - -static ej_t *ejPtr(int eid); -static void clearString(char_t **ptr); -static void setString(B_ARGS_DEC, char_t **ptr, char_t *s); -static void appendString(char_t **ptr, char_t *s); -static int parse(ej_t *ep, int state, int flags); -static int parseStmt(ej_t *ep, int state, int flags); -static int parseDeclaration(ej_t *ep, int state, int flags); -static int parseArgs(ej_t *ep, int state, int flags); -static int parseCond(ej_t *ep, int state, int flags); -static int parseExpr(ej_t *ep, int state, int flags); -static int evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs); -static int evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs); -static int evalFunction(ej_t *ep); -static void freeFunc(ejfunc_t *func); -static void ejRemoveNewlines(ej_t *ep, int state); - -/************************************* Code ***********************************/ -/* - * Initialize a Ejscript engine - */ - -int ejOpenEngine(sym_fd_t variables, sym_fd_t functions) -{ - ej_t *ep; - int eid, vid; - - if ((eid = hAllocEntry((void*) &ejHandles, &ejMax, sizeof(ej_t))) < 0) { - return -1; - } - ep = ejHandles[eid]; - ep->eid = eid; - -/* - * Create a top level symbol table if one is not provided for variables and - * functions. Variables may create other symbol tables for block level - * declarations so we use hAlloc to manage a list of variable tables. - */ - if ((vid = hAlloc((void***) &ep->variables)) < 0) { - ejMax = hFree((void*) &ejHandles, ep->eid); - return -1; - } - if (vid >= ep->variableMax) { - ep->variableMax = vid + 1; - } - - if (variables == -1) { - ep->variables[vid] = symOpen(64) + EJ_OFFSET; - ep->flags |= FLAGS_VARIABLES; - } else { - ep->variables[vid] = variables + EJ_OFFSET; - } - - if (functions == -1) { - ep->functions = symOpen(64); - ep->flags |= FLAGS_FUNCTIONS; - } else { - ep->functions = functions; - } - - ejLexOpen(ep); - -/* - * Define standard constants - */ - ejSetGlobalVar(ep->eid, T("null"), NULL); - -#ifdef EMF - ejEmfOpen(ep->eid); -#endif - return ep->eid; -} - -/******************************************************************************/ -/* - * Close - */ - -void ejCloseEngine(int eid) -{ - ej_t *ep; - int i; - - if ((ep = ejPtr(eid)) == NULL) { - return; - } - -#ifdef EMF - ejEmfClose(eid); -#endif - - bfreeSafe(B_L, ep->error); - ep->error = NULL; - bfreeSafe(B_L, ep->result); - ep->result = NULL; - - ejLexClose(ep); - - for (i = ep->variableMax - 1; i >= 0; i--) { - if (ep->flags & FLAGS_VARIABLES) { - symClose(ep->variables[i] - EJ_OFFSET); - } - ep->variableMax = hFree((void***) &ep->variables, i); - } - - if (ep->flags & FLAGS_FUNCTIONS) { - symClose(ep->functions); - } - - ejMax = hFree((void*) &ejHandles, ep->eid); - bfree(B_L, ep); -} - -#ifndef __NO_EJ_FILE -/******************************************************************************/ -/* - * Evaluate a Ejscript file - */ - -char_t *ejEvalFile(int eid, char_t *path, char_t **emsg) -{ - gstat_t sbuf; - ej_t *ep; - char_t *script, *rs; - char *fileBuf; - int fd; - - a_assert(path && *path); - - if (emsg) { - *emsg = NULL; - } - - if ((ep = ejPtr(eid)) == NULL) { - return NULL; - } - - if ((fd = gopen(path, O_RDONLY | O_BINARY, 0666)) < 0) { - ejError(ep, T("Bad handle %d"), eid); - return NULL; - } - - if (gstat(path, &sbuf) < 0) { - gclose(fd); - ejError(ep, T("Cant stat %s"), path); - return NULL; - } - - if ((fileBuf = balloc(B_L, sbuf.st_size + 1)) == NULL) { - gclose(fd); - ejError(ep, T("Cant malloc %d"), sbuf.st_size); - return NULL; - } - - if (gread(fd, fileBuf, sbuf.st_size) != (int)sbuf.st_size) { - gclose(fd); - bfree(B_L, fileBuf); - ejError(ep, T("Error reading %s"), path); - return NULL; - } - - fileBuf[sbuf.st_size] = '\0'; - gclose(fd); - - if ((script = ballocAscToUni(fileBuf, sbuf.st_size)) == NULL) { - bfree(B_L, fileBuf); - ejError(ep, T("Cant malloc %d"), sbuf.st_size + 1); - return NULL; - } - bfree(B_L, fileBuf); - - rs = ejEvalBlock(eid, script, emsg); - - bfree(B_L, script); - return rs; -} -#endif /* __NO_EJ_FILE */ - -/******************************************************************************/ -/* - * Create a new variable scope block so that consecutive ejEval calls may - * be made with the same varible scope. This space MUST be closed with - * ejCloseBlock when the evaluations are complete. - */ - -int ejOpenBlock(int eid) -{ - ej_t *ep; - int vid; - - if((ep = ejPtr(eid)) == NULL) { - return -1; - } - - if ((vid = hAlloc((void***) &ep->variables)) < 0) { - return -1; - } - - if (vid >= ep->variableMax) { - ep->variableMax = vid + 1; - } - ep->variables[vid] = symOpen(64) + EJ_OFFSET; - return vid; - -} - -/******************************************************************************/ -/* - * Close a variable scope block. The vid parameter is the return value from - * the call to ejOpenBlock - */ - -int ejCloseBlock(int eid, int vid) -{ - ej_t *ep; - - if((ep = ejPtr(eid)) == NULL) { - return -1; - } - symClose(ep->variables[vid] - EJ_OFFSET); - ep->variableMax = hFree((void***) &ep->variables, vid); - return 0; - -} - -/******************************************************************************/ -/* - * Create a new variable scope block and evaluate a script. All variables - * created during this context will be automatically deleted when complete. - */ - -char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg) -{ - char_t* returnVal; - int vid; - - a_assert(script); - - vid = ejOpenBlock(eid); - returnVal = ejEval(eid, script, emsg); - ejCloseBlock(eid, vid); - - return returnVal; -} - -/******************************************************************************/ -/* - * Parse and evaluate a Ejscript. The caller may provide a symbol table to - * use for variables and function definitions. Return char_t pointer on - * success otherwise NULL pointer is returned. - */ - -char_t *ejEval(int eid, char_t *script, char_t **emsg) -{ - ej_t *ep; - ejinput_t *oldBlock; - int state; - void *endlessLoopTest; - int loopCounter; - - - a_assert(script); - - if (emsg) { - *emsg = NULL; - } - - if ((ep = ejPtr(eid)) == NULL) { - return NULL; - } - - setString(B_L, &ep->result, T("")); - -/* - * Allocate a new evaluation block, and save the old one - */ - oldBlock = ep->input; - ejLexOpenScript(ep, script); - -/* - * Do the actual parsing and evaluation - */ - loopCounter = 0; - endlessLoopTest = NULL; - - do { - state = parse(ep, STATE_BEGIN, FLAGS_EXE); - - if (state == STATE_RET) { - state = STATE_EOF; - } -/* - * prevent parser from going into infinite loop. If parsing the same - * line 10 times then fail and report Syntax error. Most normal error - * are caught in the parser itself. - */ - if (endlessLoopTest == ep->input->script.servp) { - if (loopCounter++ > 10) { - state = STATE_ERR; - ejError(ep, T("Syntax error")); - } - } else { - endlessLoopTest = ep->input->script.servp; - loopCounter = 0; - } - } while (state != STATE_EOF && state != STATE_ERR); - - ejLexCloseScript(ep); - -/* - * Return any error string to the user - */ - if (state == STATE_ERR && emsg) { - *emsg = bstrdup(B_L, ep->error); - } - -/* - * Restore the old evaluation block - */ - ep->input = oldBlock; - - if (state == STATE_EOF) { - return ep->result; - } - - if (state == STATE_ERR) { - return NULL; - } - - return ep->result; -} - -/******************************************************************************/ -/* - * Recursive descent parser for Ejscript - */ - -static int parse(ej_t *ep, int state, int flags) -{ - a_assert(ep); - - switch (state) { -/* - * Any statement, function arguments or conditional expressions - */ - case STATE_STMT: - if ((state = parseStmt(ep, state, flags)) != STATE_STMT_DONE && - state != STATE_EOF && state != STATE_STMT_BLOCK_DONE && - state != STATE_RET) { - state = STATE_ERR; - } - break; - - case STATE_DEC: - if ((state = parseStmt(ep, state, flags)) != STATE_DEC_DONE && - state != STATE_EOF) { - state = STATE_ERR; - } - break; - - case STATE_EXPR: - if ((state = parseStmt(ep, state, flags)) != STATE_EXPR_DONE && - state != STATE_EOF) { - state = STATE_ERR; - } - break; - -/* - * Variable declaration list - */ - case STATE_DEC_LIST: - state = parseDeclaration(ep, state, flags); - break; - -/* - * Function argument string - */ - case STATE_ARG_LIST: - state = parseArgs(ep, state, flags); - break; - -/* - * Logical condition list (relational operations separated by &&, ||) - */ - case STATE_COND: - state = parseCond(ep, state, flags); - break; - -/* - * Expression list - */ - case STATE_RELEXP: - state = parseExpr(ep, state, flags); - break; - } - - if (state == STATE_ERR && ep->error == NULL) { - ejError(ep, T("Syntax error")); - } - return state; -} - -/******************************************************************************/ -/* - * Parse any statement including functions and simple relational operations - */ - -static int parseStmt(ej_t *ep, int state, int flags) -{ - ejfunc_t func; - ejfunc_t *saveFunc; - ejinput_t condScript, endScript, bodyScript, incrScript; - char_t *value, *identifier; - int done, expectSemi, thenFlags, elseFlags, tid, cond, forFlags; - int ejVarType; - - a_assert(ep); - -/* - * Set these to NULL, else we try to free them if an error occurs. - */ - endScript.putBackToken = NULL; - bodyScript.putBackToken = NULL; - incrScript.putBackToken = NULL; - condScript.putBackToken = NULL; - - expectSemi = 0; - saveFunc = NULL; - - for (done = 0; !done; ) { - tid = ejLexGetToken(ep, state); - - switch (tid) { - default: - ejLexPutbackToken(ep, TOK_EXPR, ep->token); - done++; - break; - - case TOK_ERR: - state = STATE_ERR; - done++; - break; - - case TOK_EOF: - state = STATE_EOF; - done++; - break; - - case TOK_NEWLINE: - break; - - case TOK_SEMI: -/* - * This case is when we discover no statement and just a lone ';' - */ - if (state != STATE_STMT) { - ejLexPutbackToken(ep, tid, ep->token); - } - done++; - break; - - case TOK_ID: -/* - * This could either be a reference to a variable or an assignment - */ - identifier = NULL; - setString(B_L, &identifier, ep->token); -/* - * Peek ahead to see if this is an assignment - */ - tid = ejLexGetToken(ep, state); - if (tid == TOK_ASSIGNMENT) { - if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) { - clearString(&identifier); - goto error; - } - if (flags & FLAGS_EXE) { - if ( state == STATE_DEC ) { - ejSetLocalVar(ep->eid, identifier, ep->result); - } else { - ejVarType = ejGetVar(ep->eid, identifier, &value); - if (ejVarType > 0) { - ejSetLocalVar(ep->eid, identifier, ep->result); - } else { - ejSetGlobalVar(ep->eid, identifier, ep->result); - } - } - } - - } else if (tid == TOK_INC_DEC ) { - value = NULL; - if (flags & FLAGS_EXE) { - ejVarType = ejGetVar(ep->eid, identifier, &value); - if (ejVarType < 0) { - ejError(ep, T("Undefined variable %s\n"), identifier); - goto error; - } - setString(B_L, &ep->result, value); - if (evalExpr(ep, value, (int) *ep->token, T("1")) < 0) { - state = STATE_ERR; - break; - } - - if (ejVarType > 0) { - ejSetLocalVar(ep->eid, identifier, ep->result); - } else { - ejSetGlobalVar(ep->eid, identifier, ep->result); - } - } - - } else { -/* - * If we are processing a declaration, allow undefined vars - */ - value = NULL; - if (state == STATE_DEC) { - if (ejGetVar(ep->eid, identifier, &value) > 0) { - ejError(ep, T("Variable already declared"), - identifier); - clearString(&identifier); - goto error; - } - ejSetLocalVar(ep->eid, identifier, NULL); - } else { - if ( flags & FLAGS_EXE ) { - if (ejGetVar(ep->eid, identifier, &value) < 0) { - ejError(ep, T("Undefined variable %s\n"), - identifier); - clearString(&identifier); - goto error; - } - } - } - setString(B_L, &ep->result, value); - ejLexPutbackToken(ep, tid, ep->token); - } - clearString(&identifier); - - if (state == STATE_STMT) { - expectSemi++; - } - done++; - break; - - case TOK_LITERAL: -/* - * Set the result to the literal (number or string constant) - */ - setString(B_L, &ep->result, ep->token); - if (state == STATE_STMT) { - expectSemi++; - } - done++; - break; - - case TOK_FUNCTION: -/* - * We must save any current ep->func value for the current stack frame - */ - if (ep->func) { - saveFunc = ep->func; - } - memset(&func, 0, sizeof(ejfunc_t)); - setString(B_L, &func.fname, ep->token); - ep->func = &func; - - setString(B_L, &ep->result, T("")); - if (ejLexGetToken(ep, state) != TOK_LPAREN) { - freeFunc(&func); - goto error; - } - - if (parse(ep, STATE_ARG_LIST, flags) != STATE_ARG_LIST_DONE) { - freeFunc(&func); - ep->func = saveFunc; - goto error; - } -/* - * Evaluate the function if required - */ - if (flags & FLAGS_EXE && evalFunction(ep) < 0) { - freeFunc(&func); - ep->func = saveFunc; - goto error; - } - - freeFunc(&func); - ep->func = saveFunc; - - if (ejLexGetToken(ep, state) != TOK_RPAREN) { - goto error; - } - if (state == STATE_STMT) { - expectSemi++; - } - done++; - break; - - case TOK_IF: - if (state != STATE_STMT) { - goto error; - } - if (ejLexGetToken(ep, state) != TOK_LPAREN) { - goto error; - } -/* - * Evaluate the entire condition list "(condition)" - */ - if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) { - goto error; - } - if (ejLexGetToken(ep, state) != TOK_RPAREN) { - goto error; - } -/* - * This is the "then" case. We need to always parse both cases and - * execute only the relevant case. - */ - if (*ep->result == '1') { - thenFlags = flags; - elseFlags = flags & ~FLAGS_EXE; - } else { - thenFlags = flags & ~FLAGS_EXE; - elseFlags = flags; - } -/* - * Process the "then" case. Allow for RETURN statement - */ - switch (parse(ep, STATE_STMT, thenFlags)) { - case STATE_RET: - return STATE_RET; - case STATE_STMT_DONE: - break; - default: - goto error; - } -/* - * check to see if there is an "else" case - */ - ejRemoveNewlines(ep, state); - tid = ejLexGetToken(ep, state); - if (tid != TOK_ELSE) { - ejLexPutbackToken(ep, tid, ep->token); - done++; - break; - } -/* - * Process the "else" case. Allow for return. - */ - switch (parse(ep, STATE_STMT, elseFlags)) { - case STATE_RET: - return STATE_RET; - case STATE_STMT_DONE: - break; - default: - goto error; - } - done++; - break; - - case TOK_FOR: -/* - * Format for the expression is: - * - * for (initial; condition; incr) { - * body; - * } - */ - if (state != STATE_STMT) { - goto error; - } - if (ejLexGetToken(ep, state) != TOK_LPAREN) { - goto error; - } - -/* - * Evaluate the for loop initialization statement - */ - if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) { - goto error; - } - if (ejLexGetToken(ep, state) != TOK_SEMI) { - goto error; - } - -/* - * The first time through, we save the current input context just - * to each step: prior to the conditional, the loop increment and the - * loop body. - */ - ejLexSaveInputState(ep, &condScript); - if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) { - goto error; - } - cond = (*ep->result != '0'); - - if (ejLexGetToken(ep, state) != TOK_SEMI) { - goto error; - } - -/* - * Don't execute the loop increment statement or the body first time - */ - forFlags = flags & ~FLAGS_EXE; - ejLexSaveInputState(ep, &incrScript); - if (parse(ep, STATE_EXPR, forFlags) != STATE_EXPR_DONE) { - goto error; - } - if (ejLexGetToken(ep, state) != TOK_RPAREN) { - goto error; - } - -/* - * Parse the body and remember the end of the body script - */ - ejLexSaveInputState(ep, &bodyScript); - if (parse(ep, STATE_STMT, forFlags) != STATE_STMT_DONE) { - goto error; - } - ejLexSaveInputState(ep, &endScript); - -/* - * Now actually do the for loop. Note loop has been rotated - */ - while (cond && (flags & FLAGS_EXE) ) { -/* - * Evaluate the body - */ - ejLexRestoreInputState(ep, &bodyScript); - - switch (parse(ep, STATE_STMT, flags)) { - case STATE_RET: - return STATE_RET; - case STATE_STMT_DONE: - break; - default: - goto error; - } -/* - * Evaluate the increment script - */ - ejLexRestoreInputState(ep, &incrScript); - if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) { - goto error; - } -/* - * Evaluate the condition - */ - ejLexRestoreInputState(ep, &condScript); - if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) { - goto error; - } - cond = (*ep->result != '0'); - } - ejLexRestoreInputState(ep, &endScript); - done++; - break; - - case TOK_VAR: - if (parse(ep, STATE_DEC_LIST, flags) != STATE_DEC_LIST_DONE) { - goto error; - } - done++; - break; - - case TOK_COMMA: - ejLexPutbackToken(ep, TOK_EXPR, ep->token); - done++; - break; - - case TOK_LPAREN: - if (state == STATE_EXPR) { - if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) { - goto error; - } - if (ejLexGetToken(ep, state) != TOK_RPAREN) { - goto error; - } - return STATE_EXPR_DONE; - } - done++; - break; - - case TOK_RPAREN: - ejLexPutbackToken(ep, tid, ep->token); - return STATE_EXPR_DONE; - - case TOK_LBRACE: -/* - * This handles any code in braces except "if () {} else {}" - */ - if (state != STATE_STMT) { - goto error; - } - -/* - * Parse will return STATE_STMT_BLOCK_DONE when the RBRACE is seen - */ - do { - state = parse(ep, STATE_STMT, flags); - } while (state == STATE_STMT_DONE); - -/* - * Allow return statement. - */ - if (state == STATE_RET) { - return state; - } - - if (ejLexGetToken(ep, state) != TOK_RBRACE) { - goto error; - } - return STATE_STMT_DONE; - - case TOK_RBRACE: - if (state == STATE_STMT) { - ejLexPutbackToken(ep, tid, ep->token); - return STATE_STMT_BLOCK_DONE; - } - goto error; - - case TOK_RETURN: - if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) { - goto error; - } - if (flags & FLAGS_EXE) { - while ( ejLexGetToken(ep, state) != TOK_EOF ); - done++; - return STATE_RET; - } - break; - } - } - - if (expectSemi) { - tid = ejLexGetToken(ep, state); - if (tid != TOK_SEMI && tid != TOK_NEWLINE) { - goto error; - } - -/* - * Skip newline after semi-colon - */ - ejRemoveNewlines(ep, state); - } - -/* - * Free resources and return the correct status - */ -doneParse: - if (tid == TOK_FOR) { - ejLexFreeInputState(ep, &condScript); - ejLexFreeInputState(ep, &incrScript); - ejLexFreeInputState(ep, &endScript); - ejLexFreeInputState(ep, &bodyScript); - } - - if (state == STATE_STMT) { - return STATE_STMT_DONE; - } else if (state == STATE_DEC) { - return STATE_DEC_DONE; - } else if (state == STATE_EXPR) { - return STATE_EXPR_DONE; - } else if (state == STATE_EOF) { - return state; - } else { - return STATE_ERR; - } - -/* - * Common error exit - */ -error: - state = STATE_ERR; - goto doneParse; -} - -/******************************************************************************/ -/* - * Parse variable declaration list - */ - -static int parseDeclaration(ej_t *ep, int state, int flags) -{ - int tid; - - a_assert(ep); - -/* - * Declarations can be of the following forms: - * var x; - * var x, y, z; - * var x = 1 + 2 / 3, y = 2 + 4; - * - * We set the variable to NULL if there is no associated assignment. - */ - - do { - if ((tid = ejLexGetToken(ep, state)) != TOK_ID) { - return STATE_ERR; - } - ejLexPutbackToken(ep, tid, ep->token); - -/* - * Parse the entire assignment or simple identifier declaration - */ - if (parse(ep, STATE_DEC, flags) != STATE_DEC_DONE) { - return STATE_ERR; - } - -/* - * Peek at the next token, continue if comma seen - */ - tid = ejLexGetToken(ep, state); - if (tid == TOK_SEMI) { - return STATE_DEC_LIST_DONE; - } else if (tid != TOK_COMMA) { - return STATE_ERR; - } - } while (tid == TOK_COMMA); - - if (tid != TOK_SEMI) { - return STATE_ERR; - } - return STATE_DEC_LIST_DONE; -} - -/******************************************************************************/ -/* - * Parse function arguments - */ - -static int parseArgs(ej_t *ep, int state, int flags) -{ - int tid, aid; - - a_assert(ep); - - do { - state = parse(ep, STATE_RELEXP, flags); - if (state == STATE_EOF || state == STATE_ERR) { - return state; - } - if (state == STATE_RELEXP_DONE) { - aid = hAlloc((void***) &ep->func->args); - ep->func->args[aid] = bstrdup(B_L, ep->result); - ep->func->nArgs++; - } -/* - * Peek at the next token, continue if more args (ie. comma seen) - */ - tid = ejLexGetToken(ep, state); - if (tid != TOK_COMMA) { - ejLexPutbackToken(ep, tid, ep->token); - } - } while (tid == TOK_COMMA); - - if (tid != TOK_RPAREN && state != STATE_RELEXP_DONE) { - return STATE_ERR; - } - return STATE_ARG_LIST_DONE; -} - -/******************************************************************************/ -/* - * Parse conditional expression (relational ops separated by ||, &&) - */ - -static int parseCond(ej_t *ep, int state, int flags) -{ - char_t *lhs, *rhs; - int tid, operator; - - a_assert(ep); - - setString(B_L, &ep->result, T("")); - rhs = lhs = NULL; - operator = 0; - - do { -/* - * Recurse to handle one side of a conditional. Accumulate the - * left hand side and the final result in ep->result. - */ - state = parse(ep, STATE_RELEXP, flags); - if (state != STATE_RELEXP_DONE) { - state = STATE_ERR; - break; - } - - if (operator > 0) { - setString(B_L, &rhs, ep->result); - if (evalCond(ep, lhs, operator, rhs) < 0) { - state = STATE_ERR; - break; - } - } - setString(B_L, &lhs, ep->result); - - tid = ejLexGetToken(ep, state); - if (tid == TOK_LOGICAL) { - operator = (int) *ep->token; - - } else if (tid == TOK_RPAREN || tid == TOK_SEMI) { - ejLexPutbackToken(ep, tid, ep->token); - state = STATE_COND_DONE; - break; - - } else { - ejLexPutbackToken(ep, tid, ep->token); - } - - } while (state == STATE_RELEXP_DONE); - - if (lhs) { - bfree(B_L, lhs); - } - - if (rhs) { - bfree(B_L, rhs); - } - return state; -} - -/******************************************************************************/ -/* - * Parse expression (leftHandSide operator rightHandSide) - */ - -static int parseExpr(ej_t *ep, int state, int flags) -{ - char_t *lhs, *rhs; - int rel, tid; - - a_assert(ep); - - setString(B_L, &ep->result, T("")); - rhs = lhs = NULL; - rel = 0; - tid = 0; - - do { -/* - * This loop will handle an entire expression list. We call parse - * to evalutate each term which returns the result in ep->result. - */ - if (tid == TOK_LOGICAL) { - if ((state = parse(ep, STATE_RELEXP, flags)) != STATE_RELEXP_DONE) { - state = STATE_ERR; - break; - } - } else { - if ((state = parse(ep, STATE_EXPR, flags)) != STATE_EXPR_DONE) { - state = STATE_ERR; - break; - } - } - - if (rel > 0) { - setString(B_L, &rhs, ep->result); - if (tid == TOK_LOGICAL) { - if (evalCond(ep, lhs, rel, rhs) < 0) { - state = STATE_ERR; - break; - } - } else { - if (evalExpr(ep, lhs, rel, rhs) < 0) { - state = STATE_ERR; - break; - } - } - } - setString(B_L, &lhs, ep->result); - - if ((tid = ejLexGetToken(ep, state)) == TOK_EXPR || - tid == TOK_INC_DEC || tid == TOK_LOGICAL) { - rel = (int) *ep->token; - - } else { - ejLexPutbackToken(ep, tid, ep->token); - state = STATE_RELEXP_DONE; - } - - } while (state == STATE_EXPR_DONE); - - if (rhs) { - bfree(B_L, rhs); - } - - if (lhs) { - bfree(B_L, lhs); - } - - return state; -} - -/******************************************************************************/ -/* - * Evaluate a condition. Implements &&, ||, ! - */ - -static int evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs) -{ - char_t buf[16]; - int l, r, lval; - - a_assert(lhs); - a_assert(rhs); - a_assert(rel > 0); - - lval = 0; - if (gisdigit((int)*lhs) && gisdigit((int)*rhs)) { - l = gatoi(lhs); - r = gatoi(rhs); - switch (rel) { - case COND_AND: - lval = l && r; - break; - case COND_OR: - lval = l || r; - break; - default: - ejError(ep, T("Bad operator %d"), rel); - return -1; - } - } else { - if (!gisdigit((int)*lhs)) { - ejError(ep, T("Conditional must be numeric"), lhs); - } else { - ejError(ep, T("Conditional must be numeric"), rhs); - } - } - - stritoa(lval, buf, sizeof(buf)); - setString(B_L, &ep->result, buf); - return 0; -} - -/******************************************************************************/ -/* - * Evaluate an operation - */ - -static int evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs) -{ - char_t *cp, buf[16]; - int numeric, l, r, lval; - - a_assert(lhs); - a_assert(rhs); - a_assert(rel > 0); - -/* - * All of the characters in the lhs and rhs must be numeric - */ - numeric = 1; - for (cp = lhs; *cp; cp++) { - if (!gisdigit((int)*cp)) { - numeric = 0; - break; - } - } - - if (numeric) { - for (cp = rhs; *cp; cp++) { - if (!gisdigit((int)*cp)) { - numeric = 0; - break; - } - } - } - - if (numeric) { - l = gatoi(lhs); - r = gatoi(rhs); - switch (rel) { - case EXPR_PLUS: - lval = l + r; - break; - case EXPR_INC: - lval = l + 1; - break; - case EXPR_MINUS: - lval = l - r; - break; - case EXPR_DEC: - lval = l - 1; - break; - case EXPR_MUL: - lval = l * r; - break; - case EXPR_DIV: - if (r != 0) { - lval = l / r; - } else { - lval = 0; - } - break; - case EXPR_MOD: - if (r != 0) { - lval = l % r; - } else { - lval = 0; - } - break; - case EXPR_LSHIFT: - lval = l << r; - break; - case EXPR_RSHIFT: - lval = l >> r; - break; - case EXPR_EQ: - lval = l == r; - break; - case EXPR_NOTEQ: - lval = l != r; - break; - case EXPR_LESS: - lval = (l < r) ? 1 : 0; - break; - case EXPR_LESSEQ: - lval = (l <= r) ? 1 : 0; - break; - case EXPR_GREATER: - lval = (l > r) ? 1 : 0; - break; - case EXPR_GREATEREQ: - lval = (l >= r) ? 1 : 0; - break; - case EXPR_BOOL_COMP: - lval = (r == 0) ? 1 : 0; - break; - default: - ejError(ep, T("Bad operator %d"), rel); - return -1; - } - - } else { - switch (rel) { - case EXPR_PLUS: - clearString(&ep->result); - appendString(&ep->result, lhs); - appendString(&ep->result, rhs); - return 0; - case EXPR_LESS: - lval = gstrcmp(lhs, rhs) < 0; - break; - case EXPR_LESSEQ: - lval = gstrcmp(lhs, rhs) <= 0; - break; - case EXPR_GREATER: - lval = gstrcmp(lhs, rhs) > 0; - break; - case EXPR_GREATEREQ: - lval = gstrcmp(lhs, rhs) >= 0; - break; - case EXPR_EQ: - lval = gstrcmp(lhs, rhs) == 0; - break; - case EXPR_NOTEQ: - lval = gstrcmp(lhs, rhs) != 0; - break; - case EXPR_INC: - case EXPR_DEC: - case EXPR_MINUS: - case EXPR_DIV: - case EXPR_MOD: - case EXPR_LSHIFT: - case EXPR_RSHIFT: - default: - ejError(ep, T("Bad operator")); - return -1; - } - } - - stritoa(lval, buf, sizeof(buf)); - setString(B_L, &ep->result, buf); - return 0; -} - -/******************************************************************************/ -/* - * Evaluate a function - */ - -static int evalFunction(ej_t *ep) -{ - sym_t *sp; - int (*fn)(int eid, void *handle, int argc, char_t **argv); - - if ((sp = symLookup(ep->functions, ep->func->fname)) == NULL) { - ejError(ep, T("Undefined procedure %s"), ep->func->fname); - return -1; - } - - fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer; - if (fn == NULL) { - ejError(ep, T("Undefined procedure %s"), ep->func->fname); - return -1; - } - - return (*fn)(ep->eid, (void*) ep->userHandle, ep->func->nArgs, - ep->func->args); -} - -/******************************************************************************/ -/* - * Output a parse ej_error message - */ - -void ejError(ej_t* ep, char_t* fmt, ...) -{ - va_list args; - ejinput_t *ip; - char_t *errbuf, *msgbuf; - - a_assert(ep); - a_assert(fmt); - ip = ep->input; - - va_start(args, fmt); - msgbuf = NULL; - fmtValloc(&msgbuf, E_MAX_ERROR, fmt, args); - va_end(args); - - if (ep && ip) { - fmtAlloc(&errbuf, E_MAX_ERROR, T("%s\n At line %d, line => \n\n%s\n"), - msgbuf, ip->lineNumber, ip->line); - bfreeSafe(B_L, ep->error); - ep->error = errbuf; - } - bfreeSafe(B_L, msgbuf); -} - -/******************************************************************************/ -/* - * Clear a string value - */ - -static void clearString(char_t **ptr) -{ - a_assert(ptr); - - if (*ptr) { - bfree(B_L, *ptr); - } - *ptr = NULL; -} - -/******************************************************************************/ -/* - * Set a string value - */ - -static void setString(B_ARGS_DEC, char_t **ptr, char_t *s) -{ - a_assert(ptr); - - if (*ptr) { - bfree(B_ARGS, *ptr); - } - *ptr = bstrdup(B_ARGS, s); -} - -/******************************************************************************/ -/* - * Append to the pointer value - */ - -static void appendString(char_t **ptr, char_t *s) -{ - int len, oldlen; - - a_assert(ptr); - - if (*ptr) { - len = gstrlen(s); - oldlen = gstrlen(*ptr); - *ptr = brealloc(B_L, *ptr, (len + oldlen + 1) * sizeof(char_t)); - gstrcpy(&(*ptr)[oldlen], s); - } else { - *ptr = bstrdup(B_L, s); - } -} - -/******************************************************************************/ -/* - * Define a function - */ - -int ejSetGlobalFunction(int eid, char_t *name, - int (*fn)(int eid, void *handle, int argc, char_t **argv)) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return -1; - } - return ejSetGlobalFunctionDirect(ep->functions, name, fn); -} - -/******************************************************************************/ -/* - * Define a function directly into the function symbol table. - */ - -int ejSetGlobalFunctionDirect(sym_fd_t functions, char_t *name, - int (*fn)(int eid, void *handle, int argc, char_t **argv)) -{ - if (symEnter(functions, name, valueInteger((long) fn), 0) == NULL) { - return -1; - } - return 0; -} - -/******************************************************************************/ -/* - * Remove ("undefine") a function - */ - -int ejRemoveGlobalFunction(int eid, char_t *name) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return -1; - } - return symDelete(ep->functions, name); -} - -/******************************************************************************/ -/* - * Get a function definition - */ - -void *ejGetGlobalFunction(int eid, char_t *name) -{ - ej_t *ep; - sym_t *sp; - int (*fn)(int eid, void *handle, int argc, char_t **argv); - - if ((ep = ejPtr(eid)) == NULL) { - return NULL; - } - - if ((sp = symLookup(ep->functions, name)) != NULL) { - fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer; - return (void*) fn; - } - return NULL; -} - -/******************************************************************************/ -/* - * Utility routine to crack Ejscript arguments. Return the number of args - * seen. This routine only supports %s and %d type args. - * - * Typical usage: - * - * if (ejArgs(argc, argv, "%s %d", &name, &age) < 2) { - * error("Insufficient args\n"); - * return -1; - * } - */ - -int ejArgs(int argc, char_t **argv, char_t *fmt, ...) -{ - va_list vargs; - char_t *cp, **sp; - int *ip; - int argn; - - va_start(vargs, fmt); - - if (argv == NULL) { - return 0; - } - - for (argn = 0, cp = fmt; cp && *cp && argv[argn]; ) { - if (*cp++ != '%') { - continue; - } - - switch (*cp) { - case 'd': - ip = va_arg(vargs, int*); - *ip = gatoi(argv[argn]); - break; - - case 's': - sp = va_arg(vargs, char_t**); - *sp = argv[argn]; - break; - - default: -/* - * Unsupported - */ - a_assert(0); - } - argn++; - } - - va_end(vargs); - return argn; -} - -/******************************************************************************/ -/* - * Define the user handle - */ - -void ejSetUserHandle(int eid, int handle) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return; - } - ep->userHandle = handle; -} - -/******************************************************************************/ -/* - * Get the user handle - */ - -int ejGetUserHandle(int eid) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return -1; - } - return ep->userHandle; -} - -/******************************************************************************/ -/* - * Get the current line number - */ - -int ejGetLineNumber(int eid) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return -1; - } - return ep->input->lineNumber; -} - -/******************************************************************************/ -/* - * Set the result - */ - -void ejSetResult(int eid, char_t *s) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return; - } - setString(B_L, &ep->result, s); -} - -/******************************************************************************/ -/* - * Get the result - */ - -char_t *ejGetResult(int eid) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return NULL; - } - return ep->result; -} - -/******************************************************************************/ -/* - * Set a variable. Note: a variable with a value of NULL means declared but - * undefined. The value is defined in the top-most variable frame. - */ - -void ejSetVar(int eid, char_t *var, char_t *value) -{ - ej_t *ep; - value_t v; - - a_assert(var && *var); - - if ((ep = ejPtr(eid)) == NULL) { - return; - } - - if (value == NULL) { - v = valueString(value, 0); - } else { - v = valueString(value, VALUE_ALLOCATE); - } - symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0); -} - -/******************************************************************************/ -/* - * Set a local variable. Note: a variable with a value of NULL means - * declared but undefined. The value is defined in the top-most variable frame. - */ - -void ejSetLocalVar(int eid, char_t *var, char_t *value) -{ - ej_t *ep; - value_t v; - - a_assert(var && *var); - - if ((ep = ejPtr(eid)) == NULL) { - return; - } - - if (value == NULL) { - v = valueString(value, 0); - } else { - v = valueString(value, VALUE_ALLOCATE); - } - symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0); -} - -/******************************************************************************/ -/* - * Set a global variable. Note: a variable with a value of NULL means - * declared but undefined. The value is defined in the global variable frame. - */ - -void ejSetGlobalVar(int eid, char_t *var, char_t *value) -{ - ej_t *ep; - value_t v; - - a_assert(var && *var); - - if ((ep = ejPtr(eid)) == NULL) { - return; - } - - if (value == NULL) { - v = valueString(value, 0); - } else { - v = valueString(value, VALUE_ALLOCATE); - } - symEnter(ep->variables[0] - EJ_OFFSET, var, v, 0); -} - -/******************************************************************************/ -/* - * Get a variable - */ - -int ejGetVar(int eid, char_t *var, char_t **value) -{ - ej_t *ep; - sym_t *sp; - int i; - - a_assert(var && *var); - a_assert(value); - - if ((ep = ejPtr(eid)) == NULL) { - return -1; - } - - i = ep->variableMax - 1; - if ((sp = symLookup(ep->variables[i] - EJ_OFFSET, var)) == NULL) { - i = 0; - if ((sp = symLookup(ep->variables[0] - EJ_OFFSET, var)) == NULL) { - return -1; - } - } - a_assert(sp->content.type == string); - *value = sp->content.value.string; - return i; -} - -/******************************************************************************/ -/* - * Get the variable symbol table - */ - -sym_fd_t ejGetVariableTable(int eid) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return -1; - } - return *ep->variables; -} - -/******************************************************************************/ -/* - * Get the functions symbol table - */ - -sym_fd_t ejGetFunctionTable(int eid) -{ - ej_t *ep; - - if ((ep = ejPtr(eid)) == NULL) { - return -1; - } - return ep->functions; -} - -/******************************************************************************/ -/* - * Free an argument list - */ - -static void freeFunc(ejfunc_t *func) -{ - int i; - - for (i = func->nArgs - 1; i >= 0; i--) { - bfree(B_L, func->args[i]); - func->nArgs = hFree((void***) &func->args, i); - } - - if (func->fname) { - bfree(B_L, func->fname); - func->fname = NULL; - } -} - -/******************************************************************************/ -/* - * Get Ejscript pointer - */ - -static ej_t *ejPtr(int eid) -{ - a_assert(0 <= eid && eid < ejMax); - - if (eid < 0 || eid >= ejMax || ejHandles[eid] == NULL) { - ejError(NULL, T("Bad handle %d"), eid); - return NULL; - } - return ejHandles[eid]; -} - -/******************************************************************************/ -/* - * This function removes any new lines. Used for else cases, etc. - */ -static void ejRemoveNewlines(ej_t *ep, int state) -{ - int tid; - - do { - tid = ejLexGetToken(ep, state); - } while (tid == TOK_NEWLINE); - - ejLexPutbackToken(ep, tid, ep->token); -} - -/******************************************************************************/ |