source: rtems/cpukit/httpd/ejparse.c @ dc2a1750

4.104.114.84.95
Last change on this file since dc2a1750 was bfb4c547, checked in by Joel Sherrill <joel.sherrill@…>, on 03/05/04 at 18:14:27

2004-03-05 Joel Sherrill <joel@…>

  • libnetworking/rtems_webserver/ejparse.c, libnetworking/rtems_webserver/emfdb.c, libnetworking/rtems_webserver/sock.c, libnetworking/rtems_webserver/socket.c, libnetworking/rtems_webserver/sym.c, libnetworking/rtems_webserver/webs.c, libnetworking/rtems_webserver/websuemf.c: Remove warnings.
  • Property mode set to 100644
File size: 35.6 KB
Line 
1/*
2 * ejparse.c -- Ejscript(TM) Parser
3 *
4 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
5 *
6 * See the file "license.txt" for usage and redistribution license requirements
7 *
8 * $Id$
9 */
10
11/******************************** Description *********************************/
12
13/*
14 *      Ejscript parser. This implementes a subset of the JavaScript language.
15 *      Multiple Ejscript parsers can be opened at a time.
16 */
17
18/********************************** Includes **********************************/
19
20#include        "ejIntrn.h"
21
22#ifdef CE
23        #include        "CE/wincompat.h"
24#endif
25
26/********************************** Local Data ********************************/
27
28ej_t                    **ejHandles;                                                    /* List of ej handles */
29int                             ejMax = -1;                                                             /* Maximum size of      */
30
31/****************************** Forward Declarations **************************/
32
33#ifndef B_STATS
34#define setString(a,b,c)         setstring(b,c)
35#endif
36
37static ej_t             *ejPtr(int eid);
38static void             clearString(char_t **ptr);
39static void             setString(B_ARGS_DEC, char_t **ptr, char_t *s);
40static void             appendString(char_t **ptr, char_t *s);
41static int              parse(ej_t *ep, int state, int flags);
42static int              parseStmt(ej_t *ep, int state, int flags);
43static int              parseDeclaration(ej_t *ep, int state, int flags);
44static int              parseArgs(ej_t *ep, int state, int flags);
45static int              parseCond(ej_t *ep, int state, int flags);
46static int              parseExpr(ej_t *ep, int state, int flags);
47static int              evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs);
48static int              evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs);
49static int              evalFunction(ej_t *ep);
50static void             freeFunc(ejfunc_t *func);
51static void             ejRemoveNewlines(ej_t *ep, int state);
52
53/************************************* Code ***********************************/
54/*
55 *      Initialize a Ejscript engine
56 */
57
58int ejOpenEngine(sym_fd_t variables, sym_fd_t functions)
59{
60        ej_t    *ep;
61        int             eid, vid;
62
63        if ((eid = hAllocEntry((void*) &ejHandles, &ejMax, sizeof(ej_t))) < 0) {
64                return -1;
65        }
66        ep = ejHandles[eid];
67        ep->eid = eid;
68
69/*
70 *      Create a top level symbol table if one is not provided for variables and
71 *      functions. Variables may create other symbol tables for block level
72 *      declarations so we use hAlloc to manage a list of variable tables.
73 */
74        if ((vid = hAlloc((void***) &ep->variables)) < 0) {
75                ejMax = hFree((void*) &ejHandles, ep->eid);
76                return -1;
77        }
78        if (vid >= ep->variableMax) {
79                ep->variableMax = vid + 1;
80        }
81
82        if (variables == -1) {
83                ep->variables[vid] = symOpen(64) + EJ_OFFSET;
84                ep->flags |= FLAGS_VARIABLES;
85        } else {
86                ep->variables[vid] = variables + EJ_OFFSET;
87        }
88
89        if (functions == -1) {
90                ep->functions = symOpen(64);
91                ep->flags |= FLAGS_FUNCTIONS;
92        } else {
93                ep->functions = functions;
94        }
95
96        ejLexOpen(ep);
97
98/*
99 *      Define standard constants
100 */
101        ejSetGlobalVar(ep->eid, T("null"), NULL);
102
103#ifdef EMF
104        ejEmfOpen(ep->eid);
105#endif
106        return ep->eid;
107}
108
109/******************************************************************************/
110/*
111 *      Close
112 */
113
114void ejCloseEngine(int eid)
115{
116        ej_t    *ep;
117        int             i;
118
119        if ((ep = ejPtr(eid)) == NULL) {
120                return;
121        }
122
123#ifdef EMF
124        ejEmfClose(eid);
125#endif
126
127        bfreeSafe(B_L, ep->error);
128        ep->error = NULL;
129        bfreeSafe(B_L, ep->result);
130        ep->result = NULL;
131
132        ejLexClose(ep);
133
134        for (i = ep->variableMax - 1; i >= 0; i--) {
135                if (ep->flags & FLAGS_VARIABLES) {
136                        symClose(ep->variables[i] - EJ_OFFSET);
137                }
138                ep->variableMax = hFree((void***) &ep->variables, i);
139        }
140
141        if (ep->flags & FLAGS_FUNCTIONS) {
142                symClose(ep->functions);
143        }
144
145        ejMax = hFree((void*) &ejHandles, ep->eid);
146        bfree(B_L, ep);
147}
148
149#ifndef __NO_EJ_FILE
150/******************************************************************************/
151/*
152 *      Evaluate a Ejscript file
153 */
154
155char_t *ejEvalFile(int eid, char_t *path, char_t **emsg)
156{
157        gstat_t sbuf;
158        ej_t    *ep;
159        char_t  *script, *rs;
160        char    *fileBuf;
161        int             fd;
162
163        a_assert(path && *path);
164
165        if (emsg) {
166                *emsg = NULL;
167        }
168
169        if ((ep = ejPtr(eid)) == NULL) {
170                return NULL;
171        }
172
173        if ((fd = gopen(path, O_RDONLY | O_BINARY, 0666)) < 0) {
174                ejError(ep, T("Bad handle %d"), eid);
175                return NULL;
176        }
177       
178        if (gstat(path, &sbuf) < 0) {
179                gclose(fd);
180                ejError(ep, T("Cant stat %s"), path);
181                return NULL;
182        }
183       
184        if ((fileBuf = balloc(B_L, sbuf.st_size + 1)) == NULL) {
185                gclose(fd);
186                ejError(ep, T("Cant malloc %d"), sbuf.st_size);
187                return NULL;
188        }
189       
190        if (gread(fd, fileBuf, sbuf.st_size) != (int)sbuf.st_size) {
191                gclose(fd);
192                bfree(B_L, fileBuf);
193                ejError(ep, T("Error reading %s"), path);
194                return NULL;
195        }
196       
197        fileBuf[sbuf.st_size] = '\0';
198        gclose(fd);
199
200        if ((script = ballocAscToUni(fileBuf, sbuf.st_size)) == NULL) {
201                bfree(B_L, fileBuf);
202                ejError(ep, T("Cant malloc %d"), sbuf.st_size + 1);
203                return NULL;
204        }
205        bfree(B_L, fileBuf);
206
207        rs = ejEvalBlock(eid, script, emsg);
208
209        bfree(B_L, script);
210        return rs;
211}
212#endif /* __NO_EJ_FILE */
213
214/******************************************************************************/
215/*
216 *      Create a new variable scope block so that consecutive ejEval calls may
217 *      be made with the same varible scope. This space MUST be closed with
218 *      ejCloseBlock when the evaluations are complete.
219 */
220
221int ejOpenBlock(int eid)
222{
223        ej_t    *ep;
224        int             vid;
225
226        if((ep = ejPtr(eid)) == NULL) {
227                return -1;
228        }
229
230        if ((vid = hAlloc((void***) &ep->variables)) < 0) {
231                return -1;
232        }
233
234        if (vid >= ep->variableMax) {
235                ep->variableMax = vid + 1;
236        }
237        ep->variables[vid] = symOpen(64) + EJ_OFFSET;
238        return vid;
239
240}
241
242/******************************************************************************/
243/*
244 *      Close a variable scope block. The vid parameter is the return value from
245 *      the call to ejOpenBlock
246 */
247
248int ejCloseBlock(int eid, int vid)
249{
250        ej_t    *ep;
251
252        if((ep = ejPtr(eid)) == NULL) {
253                return -1;
254        }
255        symClose(ep->variables[vid] - EJ_OFFSET);
256        ep->variableMax = hFree((void***) &ep->variables, vid);
257        return 0;
258
259}
260
261/******************************************************************************/
262/*
263 *      Create a new variable scope block and evaluate a script. All variables
264 *      created during this context will be automatically deleted when complete.
265 */
266
267char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg)
268{
269        char_t* returnVal;
270        int             vid;
271
272        a_assert(script);
273
274        vid = ejOpenBlock(eid);
275        returnVal = ejEval(eid, script, emsg);
276        ejCloseBlock(eid, vid);
277
278        return returnVal;
279}
280
281/******************************************************************************/
282/*
283 *      Parse and evaluate a Ejscript. The caller may provide a symbol table to
284 *      use for variables and function definitions. Return char_t pointer on
285 *      success otherwise NULL pointer is returned.
286 */
287
288char_t *ejEval(int eid, char_t *script, char_t **emsg)
289{
290        ej_t    *ep;
291        ejinput_t       *oldBlock;
292        int             state;
293        void    *endlessLoopTest;
294        int             loopCounter;
295       
296       
297        a_assert(script);
298
299        if (emsg) {
300                *emsg = NULL;
301        }
302
303        if ((ep = ejPtr(eid)) == NULL) {
304                return NULL;
305        }
306
307        setString(B_L, &ep->result, T(""));
308
309/*
310 *      Allocate a new evaluation block, and save the old one
311 */
312        oldBlock = ep->input;
313        ejLexOpenScript(ep, script);
314
315/*
316 *      Do the actual parsing and evaluation
317 */
318        loopCounter = 0;
319        endlessLoopTest = NULL;
320
321        do {
322                state = parse(ep, STATE_BEGIN, FLAGS_EXE);
323
324                if (state == STATE_RET) {
325                        state = STATE_EOF;
326                }
327/*
328 *              prevent parser from going into infinite loop.  If parsing the same
329 *              line 10 times then fail and report Syntax error.  Most normal error
330 *              are caught in the parser itself.
331 */
332                if (endlessLoopTest == ep->input->script.servp) {
333                        if (loopCounter++ > 10) {
334                                state = STATE_ERR;
335                                ejError(ep, T("Syntax error"));
336                        }
337                } else {
338                        endlessLoopTest = ep->input->script.servp;
339                        loopCounter = 0;
340                }
341        } while (state != STATE_EOF && state != STATE_ERR);
342
343        ejLexCloseScript(ep);
344
345/*
346 *      Return any error string to the user
347 */
348        if (state == STATE_ERR && emsg) {
349                *emsg = bstrdup(B_L, ep->error);
350        }
351
352/*
353 *      Restore the old evaluation block
354 */
355        ep->input = oldBlock;
356
357        if (state == STATE_EOF) {
358                return ep->result;
359        }
360
361        if (state == STATE_ERR) {
362                return NULL;
363        }
364
365        return ep->result;
366}
367
368/******************************************************************************/
369/*
370 *      Recursive descent parser for Ejscript
371 */
372
373static int parse(ej_t *ep, int state, int flags)
374{
375        a_assert(ep);
376
377        switch (state) {
378/*
379 *      Any statement, function arguments or conditional expressions
380 */
381        case STATE_STMT:
382                if ((state = parseStmt(ep, state, flags)) != STATE_STMT_DONE &&
383                        state != STATE_EOF && state != STATE_STMT_BLOCK_DONE &&
384                        state != STATE_RET) {
385                        state = STATE_ERR;
386                }
387                break;
388
389        case STATE_DEC:
390                if ((state = parseStmt(ep, state, flags)) != STATE_DEC_DONE &&
391                        state != STATE_EOF) {
392                        state = STATE_ERR;
393                }
394                break;
395
396        case STATE_EXPR:
397                if ((state = parseStmt(ep, state, flags)) != STATE_EXPR_DONE &&
398                        state != STATE_EOF) {
399                        state = STATE_ERR;
400                }
401                break;
402
403/*
404 *      Variable declaration list
405 */
406        case STATE_DEC_LIST:
407                state = parseDeclaration(ep, state, flags);
408                break;
409
410/*
411 *      Function argument string
412 */
413        case STATE_ARG_LIST:
414                state = parseArgs(ep, state, flags);
415                break;
416
417/*
418 *      Logical condition list (relational operations separated by &&, ||)
419 */
420        case STATE_COND:
421                state = parseCond(ep, state, flags);
422                break;
423
424/*
425 *      Expression list
426 */
427        case STATE_RELEXP:
428                state = parseExpr(ep, state, flags);
429                break;
430        }
431
432        if (state == STATE_ERR && ep->error == NULL) {
433                ejError(ep, T("Syntax error"));
434        }
435        return state;
436}
437
438/******************************************************************************/
439/*
440 *      Parse any statement including functions and simple relational operations
441 */
442
443static int parseStmt(ej_t *ep, int state, int flags)
444{
445        ejfunc_t        func;
446        ejfunc_t        *saveFunc;
447        ejinput_t       condScript, endScript, bodyScript, incrScript;
448        char_t          *value, *identifier;
449        int                     done, expectSemi, thenFlags, elseFlags, tid, cond, forFlags;
450        int                     ejVarType;
451
452        a_assert(ep);
453
454/*
455 *      Set these to NULL, else we try to free them if an error occurs.
456 */
457        endScript.putBackToken = NULL;
458        bodyScript.putBackToken = NULL;
459        incrScript.putBackToken = NULL;
460        condScript.putBackToken = NULL;
461
462        expectSemi = 0;
463        saveFunc = NULL;
464
465        for (done = 0; !done; ) {
466                tid = ejLexGetToken(ep, state);
467
468                switch (tid) {
469                default:
470                        ejLexPutbackToken(ep, TOK_EXPR, ep->token);
471                        done++;
472                        break;
473
474                case TOK_ERR:
475                        state = STATE_ERR;
476                        done++;
477                        break;
478
479                case TOK_EOF:
480                        state = STATE_EOF;
481                        done++;
482                        break;
483
484                case TOK_NEWLINE:
485                        break;
486
487                case TOK_SEMI:
488/*
489 *                      This case is when we discover no statement and just a lone ';'
490 */
491                        if (state != STATE_STMT) {
492                                ejLexPutbackToken(ep, tid, ep->token);
493                        }
494                        done++;
495                        break;
496
497                case TOK_ID:
498/*
499 *                      This could either be a reference to a variable or an assignment
500 */
501                        identifier = NULL;
502                        setString(B_L, &identifier, ep->token);
503/*
504 *                      Peek ahead to see if this is an assignment
505 */
506                        tid = ejLexGetToken(ep, state);
507                        if (tid == TOK_ASSIGNMENT) {
508                                if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
509                                        clearString(&identifier);
510                                        goto error;
511                                }
512                                if (flags & FLAGS_EXE) {
513                                        if ( state == STATE_DEC ) {
514                                                ejSetLocalVar(ep->eid, identifier, ep->result);
515                                        } else {
516                                                ejVarType = ejGetVar(ep->eid, identifier, &value);
517                                                if (ejVarType > 0) {
518                                                        ejSetLocalVar(ep->eid, identifier, ep->result);
519                                                } else {
520                                                        ejSetGlobalVar(ep->eid, identifier, ep->result);
521                                                }
522                                        }
523                                }
524
525                        } else if (tid == TOK_INC_DEC ) {
526                                value = NULL;
527                                if (flags & FLAGS_EXE) {
528                                        ejVarType = ejGetVar(ep->eid, identifier, &value);
529                                        if (ejVarType < 0) {
530                                                ejError(ep, T("Undefined variable %s\n"), identifier);
531                                                goto error;
532                                        }
533                                        setString(B_L, &ep->result, value);
534                                        if (evalExpr(ep, value, (int) *ep->token, T("1")) < 0) {
535                                                state = STATE_ERR;
536                                                break;
537                                        }
538
539                                        if (ejVarType > 0) {
540                                                ejSetLocalVar(ep->eid, identifier, ep->result);
541                                        } else {
542                                                ejSetGlobalVar(ep->eid, identifier, ep->result);
543                                        }
544                                }
545
546                        } else {
547/*
548 *                              If we are processing a declaration, allow undefined vars
549 */
550                                value = NULL;
551                                if (state == STATE_DEC) {
552                                        if (ejGetVar(ep->eid, identifier, &value) > 0) {
553                                                ejError(ep, T("Variable already declared"),
554                                                        identifier);
555                                                clearString(&identifier);
556                                                goto error;
557                                        }
558                                        ejSetLocalVar(ep->eid, identifier, NULL);
559                                } else {
560                                        if ( flags & FLAGS_EXE ) {
561                                                if (ejGetVar(ep->eid, identifier, &value) < 0) {
562                                                        ejError(ep, T("Undefined variable %s\n"),
563                                                                identifier);
564                                                        clearString(&identifier);
565                                                        goto error;
566                                                }
567                                        }
568                                }
569                                setString(B_L, &ep->result, value);
570                                ejLexPutbackToken(ep, tid, ep->token);
571                        }
572                        clearString(&identifier);
573
574                        if (state == STATE_STMT) {
575                                expectSemi++;
576                        }
577                        done++;
578                        break;
579
580                case TOK_LITERAL:
581/*
582 *                      Set the result to the literal (number or string constant)
583 */
584                        setString(B_L, &ep->result, ep->token);
585                        if (state == STATE_STMT) {
586                                expectSemi++;
587                        }
588                        done++;
589                        break;
590
591                case TOK_FUNCTION:
592/*
593 *                      We must save any current ep->func value for the current stack frame
594 */
595                        if (ep->func) {
596                                saveFunc = ep->func;
597                        }
598                        memset(&func, 0, sizeof(ejfunc_t));
599                        setString(B_L, &func.fname, ep->token);
600                        ep->func = &func;
601
602                        setString(B_L, &ep->result, T(""));
603                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
604                                freeFunc(&func);
605                                goto error;
606                        }
607
608                        if (parse(ep, STATE_ARG_LIST, flags) != STATE_ARG_LIST_DONE) {
609                                freeFunc(&func);
610                                ep->func = saveFunc;
611                                goto error;
612                        }
613/*
614 *                      Evaluate the function if required
615 */
616                        if (flags & FLAGS_EXE && evalFunction(ep) < 0) {
617                                freeFunc(&func);
618                                ep->func = saveFunc;
619                                goto error;
620                        }
621
622                        freeFunc(&func);
623                        ep->func = saveFunc;
624
625                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
626                                goto error;
627                        }
628                        if (state == STATE_STMT) {
629                                expectSemi++;
630                        }
631                        done++;
632                        break;
633
634                case TOK_IF:
635                        if (state != STATE_STMT) {
636                                goto error;
637                        }
638                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
639                                goto error;
640                        }
641/*
642 *                      Evaluate the entire condition list "(condition)"
643 */
644                        if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
645                                goto error;
646                        }
647                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
648                                goto error;
649                        }
650/*
651 *                      This is the "then" case. We need to always parse both cases and
652 *                      execute only the relevant case.
653 */
654                        if (*ep->result == '1') {
655                                thenFlags = flags;
656                                elseFlags = flags & ~FLAGS_EXE;
657                        } else {
658                                thenFlags = flags & ~FLAGS_EXE;
659                                elseFlags = flags;
660                        }
661/*
662 *                      Process the "then" case.  Allow for RETURN statement
663 */
664                        switch (parse(ep, STATE_STMT, thenFlags)) {
665                        case STATE_RET:
666                                return STATE_RET;
667                        case STATE_STMT_DONE:
668                                break;
669                        default:
670                                goto error;
671                        }
672/*
673 *                      check to see if there is an "else" case
674 */
675                        ejRemoveNewlines(ep, state);
676                        tid = ejLexGetToken(ep, state);
677                        if (tid != TOK_ELSE) {
678                                ejLexPutbackToken(ep, tid, ep->token);
679                                done++;
680                                break;
681                        }
682/*
683 *                      Process the "else" case.  Allow for return.
684 */
685                        switch (parse(ep, STATE_STMT, elseFlags)) {
686                        case STATE_RET:
687                                return STATE_RET;
688                        case STATE_STMT_DONE:
689                                break;
690                        default:
691                                goto error;
692                        }
693                        done++;
694                        break;
695
696                case TOK_FOR:
697/*
698 *                      Format for the expression is:
699 *
700 *                              for (initial; condition; incr) {
701 *                                      body;
702 *                              }
703 */
704                        if (state != STATE_STMT) {
705                                goto error;
706                        }
707                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
708                                goto error;
709                        }
710
711/*
712 *                      Evaluate the for loop initialization statement
713 */
714                        if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
715                                goto error;
716                        }
717                        if (ejLexGetToken(ep, state) != TOK_SEMI) {
718                                goto error;
719                        }
720
721/*
722 *                      The first time through, we save the current input context just
723 *                      to each step: prior to the conditional, the loop increment and the
724 *                      loop body.
725 */
726                        ejLexSaveInputState(ep, &condScript);
727                        if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
728                                goto error;
729                        }
730                        cond = (*ep->result != '0');
731
732                        if (ejLexGetToken(ep, state) != TOK_SEMI) {
733                                goto error;
734                        }
735
736/*
737 *                      Don't execute the loop increment statement or the body first time
738 */
739                        forFlags = flags & ~FLAGS_EXE;
740                        ejLexSaveInputState(ep, &incrScript);
741                        if (parse(ep, STATE_EXPR, forFlags) != STATE_EXPR_DONE) {
742                                goto error;
743                        }
744                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
745                                goto error;
746                        }
747
748/*
749 *                      Parse the body and remember the end of the body script
750 */
751                        ejLexSaveInputState(ep, &bodyScript);
752                        if (parse(ep, STATE_STMT, forFlags) != STATE_STMT_DONE) {
753                                goto error;
754                        }
755                        ejLexSaveInputState(ep, &endScript);
756
757/*
758 *                      Now actually do the for loop. Note loop has been rotated
759 */
760                        while (cond && (flags & FLAGS_EXE) ) {
761/*
762 *                              Evaluate the body
763 */
764                                ejLexRestoreInputState(ep, &bodyScript);
765
766                                switch (parse(ep, STATE_STMT, flags)) {
767                                case STATE_RET:
768                                        return STATE_RET;
769                                case STATE_STMT_DONE:
770                                        break;
771                                default:
772                                        goto error;
773                                }
774/*
775 *                              Evaluate the increment script
776 */
777                                ejLexRestoreInputState(ep, &incrScript);
778                                if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
779                                        goto error;
780                                }
781/*
782 *                              Evaluate the condition
783 */
784                                ejLexRestoreInputState(ep, &condScript);
785                                if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
786                                        goto error;
787                                }
788                                cond = (*ep->result != '0');
789                        }
790                        ejLexRestoreInputState(ep, &endScript);
791                        done++;
792                        break;
793
794                case TOK_VAR:
795                        if (parse(ep, STATE_DEC_LIST, flags) != STATE_DEC_LIST_DONE) {
796                                goto error;
797                        }
798                        done++;
799                        break;
800
801                case TOK_COMMA:
802                        ejLexPutbackToken(ep, TOK_EXPR, ep->token);
803                        done++;
804                        break;
805
806                case TOK_LPAREN:
807                        if (state == STATE_EXPR) {
808                                if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
809                                        goto error;
810                                }
811                                if (ejLexGetToken(ep, state) != TOK_RPAREN) {
812                                        goto error;
813                                }
814                                return STATE_EXPR_DONE;
815                        }
816                        done++;
817                        break;
818
819                case TOK_RPAREN:
820                        ejLexPutbackToken(ep, tid, ep->token);
821                        return STATE_EXPR_DONE;
822
823                case TOK_LBRACE:
824/*
825 *                      This handles any code in braces except "if () {} else {}"
826 */
827                        if (state != STATE_STMT) {
828                                goto error;
829                        }
830
831/*
832 *                      Parse will return STATE_STMT_BLOCK_DONE when the RBRACE is seen
833 */
834                        do {
835                                state = parse(ep, STATE_STMT, flags);
836                        } while (state == STATE_STMT_DONE);
837
838/*
839 *                      Allow return statement.
840 */
841                        if (state == STATE_RET) {
842                                return state;
843                        }
844
845                        if (ejLexGetToken(ep, state) != TOK_RBRACE) {
846                                goto error;
847                        }
848                        return STATE_STMT_DONE;
849
850                case TOK_RBRACE:
851                        if (state == STATE_STMT) {
852                                ejLexPutbackToken(ep, tid, ep->token);
853                                return STATE_STMT_BLOCK_DONE;
854                        }
855                        goto error;
856
857                case TOK_RETURN:
858                        if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
859                                goto error;
860                        }
861                        if (flags & FLAGS_EXE) {
862                                while ( ejLexGetToken(ep, state) != TOK_EOF );
863                                done++;
864                                return STATE_RET;
865                        }
866                        break;
867                }
868        }
869
870        if (expectSemi) {
871                tid = ejLexGetToken(ep, state);
872                if (tid != TOK_SEMI && tid != TOK_NEWLINE) {
873                        goto error;
874                }
875
876/*
877 *              Skip newline after semi-colon
878 */
879                ejRemoveNewlines(ep, state);
880        }
881
882/*
883 *      Free resources and return the correct status
884 */
885doneParse:
886        if (tid == TOK_FOR) {
887                ejLexFreeInputState(ep, &condScript);
888                ejLexFreeInputState(ep, &incrScript);
889                ejLexFreeInputState(ep, &endScript);
890                ejLexFreeInputState(ep, &bodyScript);
891        }
892
893        if (state == STATE_STMT) {
894                return STATE_STMT_DONE;
895        } else if (state == STATE_DEC) {
896                return STATE_DEC_DONE;
897        } else if (state == STATE_EXPR) {
898                return STATE_EXPR_DONE;
899        } else if (state == STATE_EOF) {
900                return state;
901        } else {
902                return STATE_ERR;
903        }
904
905/*
906 *      Common error exit
907 */
908error:
909        state = STATE_ERR;
910        goto doneParse;
911}
912
913/******************************************************************************/
914/*
915 *      Parse variable declaration list
916 */
917
918static int parseDeclaration(ej_t *ep, int state, int flags)
919{
920        int             tid;
921
922        a_assert(ep);
923
924/*
925 *      Declarations can be of the following forms:
926 *                      var x;
927 *                      var x, y, z;
928 *                      var x = 1 + 2 / 3, y = 2 + 4;
929 *
930 *      We set the variable to NULL if there is no associated assignment.
931 */
932
933        do {
934                if ((tid = ejLexGetToken(ep, state)) != TOK_ID) {
935                        return STATE_ERR;
936                }
937                ejLexPutbackToken(ep, tid, ep->token);
938
939/*
940 *              Parse the entire assignment or simple identifier declaration
941 */
942                if (parse(ep, STATE_DEC, flags) != STATE_DEC_DONE) {
943                        return STATE_ERR;
944                }
945
946/*
947 *              Peek at the next token, continue if comma seen
948 */
949                tid = ejLexGetToken(ep, state);
950                if (tid == TOK_SEMI) {
951                        return STATE_DEC_LIST_DONE;
952                } else if (tid != TOK_COMMA) {
953                        return STATE_ERR;
954                }
955        } while (tid == TOK_COMMA);
956
957        if (tid != TOK_SEMI) {
958                return STATE_ERR;
959        }
960        return STATE_DEC_LIST_DONE;
961}
962
963/******************************************************************************/
964/*
965 *      Parse function arguments
966 */
967
968static int parseArgs(ej_t *ep, int state, int flags)
969{
970        int             tid, aid;
971
972        a_assert(ep);
973
974        do {
975                state = parse(ep, STATE_RELEXP, flags);
976                if (state == STATE_EOF || state == STATE_ERR) {
977                        return state;
978                }
979                if (state == STATE_RELEXP_DONE) {
980                        aid = hAlloc((void***) &ep->func->args);
981                        ep->func->args[aid] = bstrdup(B_L, ep->result);
982                        ep->func->nArgs++;
983                }
984/*
985 *              Peek at the next token, continue if more args (ie. comma seen)
986 */
987                tid = ejLexGetToken(ep, state);
988                if (tid != TOK_COMMA) {
989                        ejLexPutbackToken(ep, tid, ep->token);
990                }
991        } while (tid == TOK_COMMA);
992
993        if (tid != TOK_RPAREN && state != STATE_RELEXP_DONE) {
994                return STATE_ERR;
995        }
996        return STATE_ARG_LIST_DONE;
997}
998
999/******************************************************************************/
1000/*
1001 *      Parse conditional expression (relational ops separated by ||, &&)
1002 */
1003
1004static int parseCond(ej_t *ep, int state, int flags)
1005{
1006        char_t  *lhs, *rhs;
1007        int             tid, operator;
1008
1009        a_assert(ep);
1010
1011        setString(B_L, &ep->result, T(""));
1012        rhs = lhs = NULL;
1013        operator = 0;
1014
1015        do {
1016/*
1017 *      Recurse to handle one side of a conditional. Accumulate the
1018 *      left hand side and the final result in ep->result.
1019 */
1020                state = parse(ep, STATE_RELEXP, flags);
1021                if (state != STATE_RELEXP_DONE) {
1022                        state = STATE_ERR;
1023                        break;
1024                }
1025
1026                if (operator > 0) {
1027                        setString(B_L, &rhs, ep->result);
1028                        if (evalCond(ep, lhs, operator, rhs) < 0) {
1029                                state = STATE_ERR;
1030                                break;
1031                        }
1032                }
1033                setString(B_L, &lhs, ep->result);
1034
1035                tid = ejLexGetToken(ep, state);
1036                if (tid == TOK_LOGICAL) {
1037                        operator = (int) *ep->token;
1038
1039                } else if (tid == TOK_RPAREN || tid == TOK_SEMI) {
1040                        ejLexPutbackToken(ep, tid, ep->token);
1041                        state = STATE_COND_DONE;
1042                        break;
1043
1044                } else {
1045                        ejLexPutbackToken(ep, tid, ep->token);
1046                }
1047
1048        } while (state == STATE_RELEXP_DONE);
1049
1050        if (lhs) {
1051                bfree(B_L, lhs);
1052        }
1053
1054        if (rhs) {
1055                bfree(B_L, rhs);
1056        }
1057        return state;
1058}
1059
1060/******************************************************************************/
1061/*
1062 *      Parse expression (leftHandSide operator rightHandSide)
1063 */
1064
1065static int parseExpr(ej_t *ep, int state, int flags)
1066{
1067        char_t  *lhs, *rhs;
1068        int             rel, tid;
1069
1070        a_assert(ep);
1071
1072        setString(B_L, &ep->result, T(""));
1073        rhs = lhs = NULL;
1074        rel = 0;
1075        tid = 0;
1076
1077        do {
1078/*
1079 *      This loop will handle an entire expression list. We call parse
1080 *      to evalutate each term which returns the result in ep->result.
1081 */
1082                if (tid == TOK_LOGICAL) {
1083                        if ((state = parse(ep, STATE_RELEXP, flags)) != STATE_RELEXP_DONE) {
1084                                state = STATE_ERR;
1085                                break;
1086                        }
1087                } else {
1088                        if ((state = parse(ep, STATE_EXPR, flags)) != STATE_EXPR_DONE) {
1089                                state = STATE_ERR;
1090                                break;
1091                        }
1092                }
1093
1094                if (rel > 0) {
1095                        setString(B_L, &rhs, ep->result);
1096                        if (tid == TOK_LOGICAL) {
1097                                if (evalCond(ep, lhs, rel, rhs) < 0) {
1098                                        state = STATE_ERR;
1099                                        break;
1100                                }
1101                        } else {
1102                                if (evalExpr(ep, lhs, rel, rhs) < 0) {
1103                                        state = STATE_ERR;
1104                                        break;
1105                                }
1106                        }
1107                }
1108                setString(B_L, &lhs, ep->result);
1109
1110                if ((tid = ejLexGetToken(ep, state)) == TOK_EXPR ||
1111                         tid == TOK_INC_DEC || tid == TOK_LOGICAL) {
1112                        rel = (int) *ep->token;
1113
1114                } else {
1115                        ejLexPutbackToken(ep, tid, ep->token);
1116                        state = STATE_RELEXP_DONE;
1117                }
1118
1119        } while (state == STATE_EXPR_DONE);
1120
1121        if (rhs) {
1122                bfree(B_L, rhs);
1123        }
1124
1125        if (lhs) {
1126                bfree(B_L, lhs);
1127        }
1128
1129        return state;
1130}
1131
1132/******************************************************************************/
1133/*
1134 *      Evaluate a condition. Implements &&, ||, !
1135 */
1136
1137static int evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
1138{
1139        char_t  buf[16];
1140        int             l, r, lval;
1141
1142        a_assert(lhs);
1143        a_assert(rhs);
1144        a_assert(rel > 0);
1145
1146        lval = 0;
1147        if (gisdigit((int)*lhs) && gisdigit((int)*rhs)) {
1148                l = gatoi(lhs);
1149                r = gatoi(rhs);
1150                switch (rel) {
1151                case COND_AND:
1152                        lval = l && r;
1153                        break;
1154                case COND_OR:
1155                        lval = l || r;
1156                        break;
1157                default:
1158                        ejError(ep, T("Bad operator %d"), rel);
1159                        return -1;
1160                }
1161        } else {
1162                if (!gisdigit((int)*lhs)) {
1163                        ejError(ep, T("Conditional must be numeric"), lhs);
1164                } else {
1165                        ejError(ep, T("Conditional must be numeric"), rhs);
1166                }
1167        }
1168
1169        stritoa(lval, buf, sizeof(buf));
1170        setString(B_L, &ep->result, buf);
1171        return 0;
1172}
1173
1174/******************************************************************************/
1175/*
1176 *      Evaluate an operation
1177 */
1178
1179static int evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
1180{
1181        char_t  *cp, buf[16];
1182        int             numeric, l, r, lval;
1183
1184        a_assert(lhs);
1185        a_assert(rhs);
1186        a_assert(rel > 0);
1187
1188/*
1189 *      All of the characters in the lhs and rhs must be numeric
1190 */
1191        numeric = 1;
1192        for (cp = lhs; *cp; cp++) {
1193                if (!gisdigit((int)*cp)) {
1194                        numeric = 0;
1195                        break;
1196                }
1197        }
1198
1199        if (numeric) {
1200                for (cp = rhs; *cp; cp++) {
1201                        if (!gisdigit((int)*cp)) {
1202                                numeric = 0;
1203                                break;
1204                        }
1205                }
1206        }
1207
1208        if (numeric) {
1209                l = gatoi(lhs);
1210                r = gatoi(rhs);
1211                switch (rel) {
1212                case EXPR_PLUS:
1213                        lval = l + r;
1214                        break;
1215                case EXPR_INC:
1216                        lval = l + 1;
1217                        break;
1218                case EXPR_MINUS:
1219                        lval = l - r;
1220                        break;
1221                case EXPR_DEC:
1222                        lval = l - 1;
1223                        break;
1224                case EXPR_MUL:
1225                        lval = l * r;
1226                        break;
1227                case EXPR_DIV:
1228                        if (r != 0) {
1229                                lval = l / r;
1230                        } else {
1231                                lval = 0;
1232                        }
1233                        break;
1234                case EXPR_MOD:
1235                        if (r != 0) {
1236                                lval = l % r;
1237                        } else {
1238                                lval = 0;
1239                        }
1240                        break;
1241                case EXPR_LSHIFT:
1242                        lval = l << r;
1243                        break;
1244                case EXPR_RSHIFT:
1245                        lval = l >> r;
1246                        break;
1247                case EXPR_EQ:
1248                        lval = l == r;
1249                        break;
1250                case EXPR_NOTEQ:
1251                        lval = l != r;
1252                        break;
1253                case EXPR_LESS:
1254                        lval = (l < r) ? 1 : 0;
1255                        break;
1256                case EXPR_LESSEQ:
1257                        lval = (l <= r) ? 1 : 0;
1258                        break;
1259                case EXPR_GREATER:
1260                        lval = (l > r) ? 1 : 0;
1261                        break;
1262                case EXPR_GREATEREQ:
1263                        lval = (l >= r) ? 1 : 0;
1264                        break;
1265                case EXPR_BOOL_COMP:
1266                        lval = (r == 0) ? 1 : 0;
1267                        break;
1268                default:
1269                        ejError(ep, T("Bad operator %d"), rel);
1270                        return -1;
1271                }
1272
1273        } else {
1274                switch (rel) {
1275                case EXPR_PLUS:
1276                        clearString(&ep->result);
1277                        appendString(&ep->result, lhs);
1278                        appendString(&ep->result, rhs);
1279                        return 0;
1280                case EXPR_LESS:
1281                        lval = gstrcmp(lhs, rhs) < 0;
1282                        break;
1283                case EXPR_LESSEQ:
1284                        lval = gstrcmp(lhs, rhs) <= 0;
1285                        break;
1286                case EXPR_GREATER:
1287                        lval = gstrcmp(lhs, rhs) > 0;
1288                        break;
1289                case EXPR_GREATEREQ:
1290                        lval = gstrcmp(lhs, rhs) >= 0;
1291                        break;
1292                case EXPR_EQ:
1293                        lval = gstrcmp(lhs, rhs) == 0;
1294                        break;
1295                case EXPR_NOTEQ:
1296                        lval = gstrcmp(lhs, rhs) != 0;
1297                        break;
1298                case EXPR_INC:
1299                case EXPR_DEC:
1300                case EXPR_MINUS:
1301                case EXPR_DIV:
1302                case EXPR_MOD:
1303                case EXPR_LSHIFT:
1304                case EXPR_RSHIFT:
1305                default:
1306                        ejError(ep, T("Bad operator"));
1307                        return -1;
1308                }
1309        }
1310
1311        stritoa(lval, buf, sizeof(buf));
1312        setString(B_L, &ep->result, buf);
1313        return 0;
1314}
1315
1316/******************************************************************************/
1317/*
1318 *      Evaluate a function
1319 */
1320
1321static int evalFunction(ej_t *ep)
1322{
1323        sym_t   *sp;
1324        int             (*fn)(int eid, void *handle, int argc, char_t **argv);
1325
1326        if ((sp = symLookup(ep->functions, ep->func->fname)) == NULL) {
1327                ejError(ep, T("Undefined procedure %s"), ep->func->fname);
1328                return -1;
1329        }
1330
1331        fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer;
1332        if (fn == NULL) {
1333                ejError(ep, T("Undefined procedure %s"), ep->func->fname);
1334                return -1;
1335        }
1336
1337        return (*fn)(ep->eid, (void*) ep->userHandle, ep->func->nArgs,
1338                ep->func->args);
1339}
1340
1341/******************************************************************************/
1342/*
1343 *      Output a parse ej_error message
1344 */
1345
1346void ejError(ej_t* ep, char_t* fmt, ...)
1347{
1348        va_list         args;
1349        ejinput_t       *ip;
1350        char_t          *errbuf, *msgbuf;
1351
1352        a_assert(ep);
1353        a_assert(fmt);
1354        ip = ep->input;
1355
1356        va_start(args, fmt);
1357        msgbuf = NULL;
1358        fmtValloc(&msgbuf, E_MAX_ERROR, fmt, args);
1359        va_end(args);
1360
1361        if (ep && ip) {
1362                fmtAlloc(&errbuf, E_MAX_ERROR, T("%s\n At line %d, line => \n\n%s\n"),
1363                        msgbuf, ip->lineNumber, ip->line);
1364                bfreeSafe(B_L, ep->error);
1365                ep->error = errbuf;
1366        }
1367        bfreeSafe(B_L, msgbuf);
1368}
1369
1370/******************************************************************************/
1371/*
1372 *      Clear a string value
1373 */
1374
1375static void clearString(char_t **ptr)
1376{
1377        a_assert(ptr);
1378
1379        if (*ptr) {
1380                bfree(B_L, *ptr);
1381        }
1382        *ptr = NULL;
1383}
1384
1385/******************************************************************************/
1386/*
1387 *      Set a string value
1388 */
1389
1390static void setString(B_ARGS_DEC, char_t **ptr, char_t *s)
1391{
1392        a_assert(ptr);
1393
1394        if (*ptr) {
1395                bfree(B_ARGS, *ptr);
1396        }
1397        *ptr = bstrdup(B_ARGS, s);
1398}
1399
1400/******************************************************************************/
1401/*
1402 *      Append to the pointer value
1403 */
1404
1405static void appendString(char_t **ptr, char_t *s)
1406{
1407        int     len, oldlen;
1408
1409        a_assert(ptr);
1410
1411        if (*ptr) {
1412                len = gstrlen(s);
1413                oldlen = gstrlen(*ptr);
1414                *ptr = brealloc(B_L, *ptr, (len + oldlen + 1) * sizeof(char_t));
1415                gstrcpy(&(*ptr)[oldlen], s);
1416        } else {
1417                *ptr = bstrdup(B_L, s);
1418        }
1419}
1420
1421/******************************************************************************/
1422/*
1423 *      Define a function
1424 */
1425
1426int ejSetGlobalFunction(int eid, char_t *name,
1427        int (*fn)(int eid, void *handle, int argc, char_t **argv))
1428{
1429        ej_t    *ep;
1430
1431        if ((ep = ejPtr(eid)) == NULL) {
1432                return -1;
1433        }
1434        return ejSetGlobalFunctionDirect(ep->functions, name, fn);
1435}
1436
1437/******************************************************************************/
1438/*
1439 *      Define a function directly into the function symbol table.
1440 */
1441
1442int ejSetGlobalFunctionDirect(sym_fd_t functions, char_t *name,
1443        int (*fn)(int eid, void *handle, int argc, char_t **argv))
1444{
1445        if (symEnter(functions, name, valueInteger((long) fn), 0) == NULL) {
1446                return -1;
1447        }
1448        return 0;
1449}
1450
1451/******************************************************************************/
1452/*
1453 *      Remove ("undefine") a function
1454 */
1455
1456int ejRemoveGlobalFunction(int eid, char_t *name)
1457{
1458        ej_t    *ep;
1459
1460        if ((ep = ejPtr(eid)) == NULL) {
1461                return -1;
1462        }
1463        return symDelete(ep->functions, name);
1464}
1465
1466/******************************************************************************/
1467/*
1468 *      Get a function definition
1469 */
1470
1471void *ejGetGlobalFunction(int eid, char_t *name)
1472{
1473        ej_t    *ep;
1474        sym_t   *sp;
1475        int             (*fn)(int eid, void *handle, int argc, char_t **argv);
1476
1477        if ((ep = ejPtr(eid)) == NULL) {
1478                return NULL;
1479        }
1480
1481        if ((sp = symLookup(ep->functions, name)) != NULL) {
1482                fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer;
1483                return (void*) fn;
1484        }
1485        return NULL;
1486}
1487
1488/******************************************************************************/
1489/*
1490 *      Utility routine to crack Ejscript arguments. Return the number of args
1491 *      seen. This routine only supports %s and %d type args.
1492 *
1493 *      Typical usage:
1494 *
1495 *              if (ejArgs(argc, argv, "%s %d", &name, &age) < 2) {
1496 *                      error("Insufficient args\n");
1497 *                      return -1;
1498 *              }
1499 */
1500
1501int ejArgs(int argc, char_t **argv, char_t *fmt, ...)
1502{
1503        va_list vargs;
1504        char_t  *cp, **sp;
1505        int             *ip;
1506        int             argn;
1507
1508        va_start(vargs, fmt);
1509
1510        if (argv == NULL) {
1511                return 0;
1512        }
1513
1514        for (argn = 0, cp = fmt; cp && *cp && argv[argn]; ) {
1515                if (*cp++ != '%') {
1516                        continue;
1517                }
1518
1519                switch (*cp) {
1520                case 'd':
1521                        ip = va_arg(vargs, int*);
1522                        *ip = gatoi(argv[argn]);
1523                        break;
1524
1525                case 's':
1526                        sp = va_arg(vargs, char_t**);
1527                        *sp = argv[argn];
1528                        break;
1529
1530                default:
1531/*
1532 *                      Unsupported
1533 */
1534                        a_assert(0);
1535                }
1536                argn++;
1537        }
1538
1539        va_end(vargs);
1540        return argn;
1541}
1542
1543/******************************************************************************/
1544/*
1545 *      Define the user handle
1546 */
1547
1548void ejSetUserHandle(int eid, int handle)
1549{
1550        ej_t    *ep;
1551
1552        if ((ep = ejPtr(eid)) == NULL) {
1553                return;
1554        }
1555        ep->userHandle = handle;
1556}
1557
1558/******************************************************************************/
1559/*
1560 *      Get the user handle
1561 */
1562
1563int ejGetUserHandle(int eid)
1564{
1565        ej_t    *ep;
1566
1567        if ((ep = ejPtr(eid)) == NULL) {
1568                return -1;
1569        }
1570        return ep->userHandle;
1571}
1572
1573/******************************************************************************/
1574/*
1575 *      Get the current line number
1576 */
1577
1578int ejGetLineNumber(int eid)
1579{
1580        ej_t    *ep;
1581
1582        if ((ep = ejPtr(eid)) == NULL) {
1583                return -1;
1584        }
1585        return ep->input->lineNumber;
1586}
1587
1588/******************************************************************************/
1589/*
1590 *      Set the result
1591 */
1592
1593void ejSetResult(int eid, char_t *s)
1594{
1595        ej_t    *ep;
1596
1597        if ((ep = ejPtr(eid)) == NULL) {
1598                return;
1599        }
1600        setString(B_L, &ep->result, s);
1601}
1602
1603/******************************************************************************/
1604/*
1605 *      Get the result
1606 */
1607
1608char_t *ejGetResult(int eid)
1609{
1610        ej_t    *ep;
1611
1612        if ((ep = ejPtr(eid)) == NULL) {
1613                return NULL;
1614        }
1615        return ep->result;
1616}
1617
1618/******************************************************************************/
1619/*
1620 *      Set a variable. Note: a variable with a value of NULL means declared but
1621 *      undefined. The value is defined in the top-most variable frame.
1622 */
1623
1624void ejSetVar(int eid, char_t *var, char_t *value)
1625{
1626        ej_t    *ep;
1627        value_t v;
1628
1629        a_assert(var && *var);
1630
1631        if ((ep = ejPtr(eid)) == NULL) {
1632                return;
1633        }
1634
1635        if (value == NULL) {
1636                v = valueString(value, 0);
1637        } else {
1638                v = valueString(value, VALUE_ALLOCATE);
1639        }
1640        symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0);
1641}
1642
1643/******************************************************************************/
1644/*
1645 *      Set a local variable. Note: a variable with a value of NULL means
1646 *      declared but undefined. The value is defined in the top-most variable frame.
1647 */
1648
1649void ejSetLocalVar(int eid, char_t *var, char_t *value)
1650{
1651        ej_t    *ep;
1652        value_t v;
1653
1654        a_assert(var && *var);
1655
1656        if ((ep = ejPtr(eid)) == NULL) {
1657                return;
1658        }
1659
1660        if (value == NULL) {
1661                v = valueString(value, 0);
1662        } else {
1663                v = valueString(value, VALUE_ALLOCATE);
1664        }
1665        symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0);
1666}
1667
1668/******************************************************************************/
1669/*
1670 *      Set a global variable. Note: a variable with a value of NULL means
1671 *      declared but undefined. The value is defined in the global variable frame.
1672 */
1673
1674void ejSetGlobalVar(int eid, char_t *var, char_t *value)
1675{
1676        ej_t    *ep;
1677        value_t v;
1678
1679        a_assert(var && *var);
1680
1681        if ((ep = ejPtr(eid)) == NULL) {
1682                return;
1683        }
1684
1685        if (value == NULL) {
1686                v = valueString(value, 0);
1687        } else {
1688                v = valueString(value, VALUE_ALLOCATE);
1689        }
1690        symEnter(ep->variables[0] - EJ_OFFSET, var, v, 0);
1691}
1692
1693/******************************************************************************/
1694/*
1695 *      Get a variable
1696 */
1697
1698int ejGetVar(int eid, char_t *var, char_t **value)
1699{
1700        ej_t    *ep;
1701        sym_t   *sp;
1702        int             i;
1703
1704        a_assert(var && *var);
1705        a_assert(value);
1706
1707        if ((ep = ejPtr(eid)) == NULL) {
1708                return -1;
1709        }
1710
1711        i = ep->variableMax - 1;
1712        if ((sp = symLookup(ep->variables[i] - EJ_OFFSET, var)) == NULL) {
1713                i = 0;
1714                if ((sp = symLookup(ep->variables[0] - EJ_OFFSET, var)) == NULL) {
1715                        return -1;
1716                }
1717        }
1718        a_assert(sp->content.type == string);
1719        *value = sp->content.value.string;
1720        return i;
1721}
1722
1723/******************************************************************************/
1724/*
1725 *      Get the variable symbol table
1726 */
1727
1728sym_fd_t ejGetVariableTable(int eid)
1729{
1730        ej_t    *ep;
1731
1732        if ((ep = ejPtr(eid)) == NULL) {
1733                return -1;
1734        }
1735        return *ep->variables;
1736}
1737
1738/******************************************************************************/
1739/*
1740 *      Get the functions symbol table
1741 */
1742
1743sym_fd_t ejGetFunctionTable(int eid)
1744{
1745        ej_t    *ep;
1746
1747        if ((ep = ejPtr(eid)) == NULL) {
1748                return -1;
1749        }
1750        return ep->functions;
1751}
1752
1753/******************************************************************************/
1754/*
1755 *      Free an argument list
1756 */
1757
1758static void freeFunc(ejfunc_t *func)
1759{
1760        int     i;
1761
1762        for (i = func->nArgs - 1; i >= 0; i--) {
1763                bfree(B_L, func->args[i]);
1764                func->nArgs = hFree((void***) &func->args, i);
1765        }
1766
1767        if (func->fname) {
1768                bfree(B_L, func->fname);
1769                func->fname = NULL;
1770        }
1771}
1772
1773/******************************************************************************/
1774/*
1775 *      Get Ejscript pointer
1776 */
1777
1778static ej_t *ejPtr(int eid)
1779{
1780        a_assert(0 <= eid && eid < ejMax);
1781
1782        if (eid < 0 || eid >= ejMax || ejHandles[eid] == NULL) {
1783                ejError(NULL, T("Bad handle %d"), eid);
1784                return NULL;
1785        }
1786        return ejHandles[eid];
1787}
1788
1789/******************************************************************************/
1790/*
1791 *      This function removes any new lines.  Used for else     cases, etc.
1792 */
1793static void ejRemoveNewlines(ej_t *ep, int state)
1794{
1795        int tid;
1796
1797        do {
1798                tid = ejLexGetToken(ep, state);
1799        } while (tid == TOK_NEWLINE);
1800
1801        ejLexPutbackToken(ep, tid, ep->token);
1802}
1803
1804/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.