FreeWRL / FreeX3D 4.3.0
CParseLexer.c
1/*
2
3
4???
5
6*/
7
8/****************************************************************************
9 This file is part of the FreeWRL/FreeX3D Distribution.
10
11 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12
13 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14 it under the terms of the GNU Lesser Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25****************************************************************************/
26
27
28
29#include <config.h>
30#include <system.h>
31#include <display.h>
32#include <internal.h>
33
34#include <libFreeWRL.h>
35#include <list.h>
36#include <io_files.h>
37
38
39#include "../vrml_parser/Structs.h"
40#include "../main/headers.h"
41#include "CParseGeneral.h"
42#include "../scenegraph/Vector.h"
43#include "../vrml_parser/CFieldDecls.h"
44#include "../world_script/fieldSet.h"
45#include "../input/InputFunctions.h"
46#include "../input/EAIHelpers.h" /* for newASCIIString() */
47#include "CParseParser.h"
48#include "CParseLexer.h"
49#include "CParse.h"
50
51void lexer_handle_EXTERNPROTO(struct VRMLLexer *me);
52//char *externProtoPointer = NULL; //not used
53/* Pre- and suffix for exposed events. */
54const char* EXPOSED_EVENT_IN_PRE="set_";
55const char* EXPOSED_EVENT_OUT_SUF="_changed";
56
57/* Tables of user-defined IDs */
58#define USER_IDS_INIT_SIZE 16
59
60/* Maximum id length (input buffer size) a bad EOF in .wrl or no \n on ROUTE before EOF can cause an over-run */
61#define MAX_IDLEN 155 //127
62/* Start buffer length for strings */
63#define INITIAL_STRINGLEN 256
64
65/* Input data */
66static int setLexerNextIn(struct VRMLLexer *);
67
68#define LEXER_GETINPUT(c) \
69 { \
70 ASSERT(!me->curID); \
71 if(!*me->nextIn) c=setLexerNextIn(me); \
72 else { \
73 unsigned char ccc; \
74 ccc = *(me->nextIn++);\
75 /*c=(unsigned int)*(me->nextIn++);*/ \
76 c = ccc; \
77 } \
78 }
79#define LEXER_UNGETINPUT(c) \
80 if(c!=EOF) \
81 { \
82 --(me->nextIn); \
83 }
84
85/* Check for eof */
86#define CHECK_EOF(var) \
87 if((var)==EOF) \
88 { \
89 me->isEof=TRUE; \
90 return FALSE; \
91 }
92
93/* Constructor and destructor */
94
95struct VRMLLexer* newLexer()
96{
97 int i;
98
99 struct VRMLLexer* ret=MALLOC(struct VRMLLexer *, sizeof(struct VRMLLexer));
100
101 ret->nextIn=NULL;
102
103 for (i=0; i<LEXER_INPUT_STACK_MAX; i++) ret->startOfStringPtr[i] = NULL;
104
105
106 ret->curID=NULL;
107 ret->isEof=TRUE;
108 ret->lexerInputLevel = -1;
109
110 /* Init id tables */
111 ret->userNodeNames=newStack(struct Vector*);
112 ret->userNodeTypesStack=newStack(int);
113 stack_push(int, ret->userNodeTypesStack, 0);
114 ret->userNodeTypesVec=newVector(char*, USER_IDS_INIT_SIZE);
115 ret->user_initializeOnly=newVector(char*, USER_IDS_INIT_SIZE);
116 ret->user_inputOutput=newVector(char*, USER_IDS_INIT_SIZE);
117 ret->user_inputOnly=newVector(char*, USER_IDS_INIT_SIZE);
118 ret->user_outputOnly=newVector(char*, USER_IDS_INIT_SIZE);
119 lexer_scopeIn(ret);
120
121#ifdef CPARSERVERBOSE
122 printf("new lexer created, userNodeTypesVec is %p, user_initializeOnly is %p, user_inputOutput is %p, user_inputOnly is %p, user_outputOnly is %p\n", ret->userNodeTypesVec, ret->user_initializeOnly, ret->user_inputOutput, ret->user_inputOnly, ret->user_outputOnly);
123#endif
124
125 return ret;
126}
127
128void deleteLexer(struct VRMLLexer* me)
129{
130 #ifdef CPARSERVERBOSE
131 printf ("deleteLexer called; deleting lexer %x %u\n",me,me);
132 #endif
133 FREE_IF_NZ (me->curID);
134 FREE_IF_NZ (me);
135 //FREE_IF_NZ (p->externProtoPointer);
136}
137
138
139/* end of file on this "stack level" for lexer input */
140static int setLexerNextIn(struct VRMLLexer *me) {
141 int retval = EOF;
142
143 #ifdef CPARSERVERBOSE
144 printf ("set lexerNextIn called \n");
145 #endif
146
147 if (me->lexerInputLevel > 0) {
148 #ifdef CPARSERVERBOSE
149 printf ("setlexerNextIn, decrementing; deleting %x, setting nextIn to %x\n", me->startOfStringPtr[me->lexerInputLevel], me->oldNextIn[me->lexerInputLevel]);
150 #endif
151
152 //FREE_IF_NZ (me->startOfStringPtr[me->lexerInputLevel]);
153 if(me->startOfStringPtr[me->lexerInputLevel]){
154 if(strlen(me->startOfStringPtr[me->lexerInputLevel])){
155 FREE_IF_NZ(me->startOfStringPtr[me->lexerInputLevel]);
156 }else{
157 me->startOfStringPtr[me->lexerInputLevel] = NULL;
158 }
159 }
160 me->nextIn = me->oldNextIn[me->lexerInputLevel];
161 me->lexerInputLevel--;
162 /* printf ("setlexerNextIn, level now is %d, and nextIn is :%s:\n",me->lexerInputLevel,me->nextIn); */
163 retval = (int)*(me->nextIn++);
164 }
165 #ifdef CPARSERVERBOSE
166 printf ("setLexerNextIn returning :%d:\n",retval);
167 #endif
168
169 return retval;
170}
171
172
173/* set the lexer to parse from the string. Pushes the current string onto a lexer stack */
174void lexer_fromString (struct VRMLLexer *me, char *str) {
175 if (str!= NULL) me->isEof=(str[0]=='\0');
176 else (me)->isEof=TRUE;
177
178 me->lexerInputLevel ++;
179 me->startOfStringPtr[me->lexerInputLevel]=str;
180 me->oldNextIn[me->lexerInputLevel] = me->nextIn; /* save the old "nextIn" for popping back */
181 me->nextIn=str;
182 #ifdef CPARSERVERBOSE
183 printf ("lexer_fromString, me %x %u\n",me,me);
184 printf ("lexer_fromString, working on level %d\n",me->lexerInputLevel);
185 printf ("lexer_fromString, passedin char pointer is %x %u\n",str,str);
186 printf ("lexer_fromString, saving nextin as %x\n",me->oldNextIn[me->lexerInputLevel]);
187 printf ("lexer_fromString, input is :%s:\n",str);
188 #endif
189}
190
191
192void lexer_forceStringCleanup (struct VRMLLexer *me) {
193 int i;
194 for (i=1; i<me->lexerInputLevel; i++) {
195 FREE_IF_NZ(me->startOfStringPtr[i]);
196 me->startOfStringPtr[i] = NULL;
197 }
198 #ifdef CPARSERVERBOSE
199 printf ("lexer_forceStringCleanup, level was %d\n",me->lexerInputLevel);
200 #endif
201
202 me->lexerInputLevel = -1;
203 me->nextIn = NULL;
204}
205
206static void lexer_scopeOut_(Stack*);
207void lexer_destroyIdStack(Stack* s)
208{
209 ASSERT(s);
210 while(!stack_empty(s))
211 lexer_scopeOut_(s);
212 deleteStack(struct Vector*, s);
213 s = NULL; /* JAS */
214}
215
216
217void lexer_destroyData(struct VRMLLexer* me)
218{
219 #define DESTROY_IDVEC(v) \
220 if(v) { int i; for(i=0; i<vectorSize(v); i++) {FREE_IF_NZ (vector_get(char*, v, i));} deleteVector(char*,v);} \
221 /* lexer_destroyIdVector(v); */ \
222 v=NULL /* might be redundant */ ;
223
224 /* User node names */
225 if(me->userNodeNames)
226 lexer_destroyIdStack(me->userNodeNames);
227 me->userNodeNames=NULL;
228
229 /* User node types */
230 DESTROY_IDVEC(me->userNodeTypesVec)
231 if(me->userNodeTypesStack) {
232 deleteStack(int, me->userNodeTypesStack);
233 me->userNodeTypesStack = NULL; /* JAS */
234 }
235
236 /* User fields */
237 DESTROY_IDVEC(me->user_initializeOnly)
238 DESTROY_IDVEC(me->user_inputOutput)
239 DESTROY_IDVEC(me->user_inputOnly)
240 DESTROY_IDVEC(me->user_outputOnly)
241}
242
243/* Scope in and scope out for IDs */
244
245static void lexer_scopeIn_(Stack** s)
246{
247 if(!*s)
248 *s=newStack(struct Vector*);
249 stack_push(struct Vector*, *s, newVector(char*, USER_IDS_INIT_SIZE));
250}
251
252static void lexer_scopeOut_(Stack* s)
253{
254 int i;
255 ASSERT(!stack_empty(s));
256
257 for(i=0; i!=vectorSize(stack_top(struct Vector*, s)); ++i)
258 FREE_IF_NZ (vector_get(char*, stack_top(struct Vector*, s), i));
259 deleteVector(char*, stack_top(struct Vector*, s));
260 stack_pop(struct Vector*, s);
261}
262
263/* Scope in PROTOs and DEFed nodes */
264void lexer_scopeIn(struct VRMLLexer* me)
265{
266/* printf ("lexer_scopeIn, not doing push anymore \n"); */
267 lexer_scopeIn_(&me->userNodeNames);
268 /* printf("lexer_scopeIn: push value %d onto userNodeTypesStack\n", vectorSize(me->userNodeTypesVec)); */
269 /* Remember the number of PROTOs that were defined when we first entered this scope. This is the
270 number of PROTOs that must be defined when we leave this scope. Keep this number on the userNodeTypesStack */
271 stack_push(int, me->userNodeTypesStack, vectorSize(me->userNodeTypesVec));
272 /* Fields aren't scoped because they need to be accessible in two levels */
273}
274
275/* Scope out PROTOs and DEFed nodes */
276void lexer_scopeOut(struct VRMLLexer* me)
277{
278/* printf ("lexer_scopeOut, not doing push anymore \n"); */
279 lexer_scopeOut_(me->userNodeNames);
280 /* lexer_scopeOut_PROTO(); */
281 /* Fields aren't scoped because they need to be accessible in two levels */
282}
283
284/* stack_top(int, me->userNodeTypesStack) returns the number of PROTOs that were defined before
285 we reached the local scope. To scope out any added names, we take off names added to the vector
286 userNodeTypesVec since the local scope started. i.e. we keep removing the newest PROTO name
287 from userNodeTypesVec until the size of this vector is the same as the number popped off of the top of
288 the userNodeTypesStack. Afterwards, pop off the top value of the userNodeTypesStack, to complete
289 the scopeOut */
290void lexer_scopeOut_PROTO(struct VRMLLexer* me)
291{
292 /* printf("lexer_scopeOut_PROTO: userNodeTypesVec has %d PROTO IDs top of userNodeTypesStack is %d\n", vectorSize(me->userNodeTypesVec), stack_top(int, userNodeTypesStack)); */
293 while(vectorSize(me->userNodeTypesVec)>stack_top(int, me->userNodeTypesStack))
294 {
295 /* Free the last element added to the vector */
296 FREE_IF_NZ (vector_back(char*, me->userNodeTypesVec));
297 /* Decrement the number of items in the vector */
298 /* printf(" popping item off of userNodeTypesVec\n"); */
299 vector_popBack(char*, me->userNodeTypesVec);
300 }
301 /* Take off the top value of userNodeTypesStack */
302 /* printf(" popped items off of userNodeTypesVec, now take top item off of userNodeTypesStack\n"); */
303 stack_pop(int, me->userNodeTypesStack);
304}
305
306/* Sets curID of lexer */
307BOOL lexer_setCurID(struct VRMLLexer* me)
308{
309 int c;
310 char buf[MAX_IDLEN+1];
311 char* cur=buf;
312
313 /* If it is already set, simply return. */
314 if(me->curID)
315 return TRUE;
316 lexer_skip(me);
317
318 /* Is it really an ID? */
319 LEXER_GETINPUT(c)
320 CHECK_EOF(c)
321 if(!IS_ID_FIRST(c))
322 {
323 LEXER_UNGETINPUT(c)
324 return FALSE;
325 }
326
327 /* Main loop. */
328 while(cur!=buf+MAX_IDLEN)
329 {
330 ASSERT(cur<buf+MAX_IDLEN);
331 *cur=c;
332 ++cur;
333
334 LEXER_GETINPUT(c)
335 if(!IS_ID_REST(c))
336 goto breakIdLoop;
337 }
338 parseError("ID buffer length hit! File must end with \n");
339breakIdLoop:
340 LEXER_UNGETINPUT(c)
341 ASSERT(cur<=buf+MAX_IDLEN);
342 *cur=0;
343
344 ASSERT(strlen(buf)==(cur-buf));
345 ASSERT(!me->curID);
346 me->curID=MALLOC(char *, sizeof(char)*(cur-buf+1));
347
348 strcpy(me->curID, buf);
349
350 #ifdef CPARSERVERBOSE
351 printf ("lexer_setCurID, got %s\n",me->curID);
352 #endif
353
354 return TRUE;
355}
356
357/* Lexes a keyword */
358BOOL lexer_keyword(struct VRMLLexer* me, int kw) {
359 if(!lexer_setCurID(me))
360 return FALSE;
361 ASSERT(me->curID);
362
363 if(!strcmp(me->curID, KEYWORDS[kw])) {
364 FREE_IF_NZ (me->curID);
365 return TRUE;
366 }
367 return FALSE;
368}
369
370/* Finds the index of a given string */
371int lexer_string2id(const char* str, const struct Vector* v)
372{
373
374/* printf ("lexer_string2id looking for %s vector %u\n",str,v); */
375 int i;
376 for(i=0; i!=vectorSize(v); ++i) {
377 /* printf ("lexer_string2id, comparing %s to %s\n",str,vector_get(const char*, v, i)); */
378 if(!strcmp(str, vector_get(const char*, v, i)))
379 return i;
380}
381 return ID_UNDEFINED;
382}
383
384/* Lexes an ID (node type, field name...) depending on args. */
385/* Basically, just calls lexer_specialID_string with the same args plus the current token */
386/* Checks for an ID (the next lexer token) in the builtin array of IDs passed in builtin and/or in the array of user defined
387 IDs passed in user. Returns the index to the ID in retB (if found in the built in list) or retU (if found in the
388 user defined list) if it is found. */
389
390BOOL lexer_specialID(struct VRMLLexer* me, int* retB, int* retU,
391 const char** builtIn, const int builtInCount, struct Vector* user)
392{
393 /* Get the next token */
394 if(!lexer_setCurID(me))
395 return FALSE;
396 ASSERT(me->curID);
397
398 #ifdef CPARSERVERBOSE
399 printf("lexer_specialID looking for %s\n", me->curID);
400 #endif
401
402 if(lexer_specialID_string(me, retB, retU, builtIn, builtInCount, user, me->curID)) {
403 FREE_IF_NZ (me->curID);
404 return TRUE;
405 }
406
407 return FALSE;
408}
409
410/* Checks for the ID passed in str in the builtin array of IDs passed in builtin and/or in the array of user defined
411 IDs passed in user. Returns the index to the ID in retB (if found in the built in list) or retU (if found in the
412 user defined list) if it is found. */
413BOOL lexer_specialID_string(struct VRMLLexer* me, int* retB, int* retU,
414 const char** builtIn, const int builtInCount,
415 struct Vector* user, const char* str)
416{
417 int i;
418 BOOL found=FALSE;
419 int ind;
420
421 #ifdef CPARSERVERBOSE
422 printf ("lexer_specialID_string, builtInCount %d, builtIn %u\n",builtInCount, builtIn);
423 #endif
424
425 /* Have to be looking in either the builtin and/or the user defined lists */
426 if(!retB && !retU)
427 return FALSE;
428
429 if(retB) *retB=ID_UNDEFINED;
430 if(retU) *retU=ID_UNDEFINED;
431
432 /* Try as built-in */
433 /* Look for the ID in the passed built in array. If it is found, return the index to the ID in retB */
434 for(i=0; i!=builtInCount; ++i) {
435 /* printf ("lexer_specialID_string, comparing :%s: and :%s:\n",str,builtIn[i]); */
436 if(!strcmp(str, builtIn[i])) {
437#ifdef CPARSERVERBOSE
438 printf("found ID %s matches %s, return retB %d\n", str, builtIn[i], i);
439#endif
440 /* is this a PROTOKEYWORD? If so, change any possible depreciated tags to new ones */
441 if (builtIn == PROTOKEYWORDS) {
442 switch (i) {
443 case PKW_eventIn: i = PKW_inputOnly; break;
444 case PKW_eventOut: i= PKW_outputOnly; break;
445 case PKW_exposedField: i= PKW_inputOutput; break;
446 case PKW_field: i= PKW_initializeOnly; break;
447 default : { /* do nothing - already in new format */ }
448 }
449 #ifdef CPARSERVERBOSE
450 printf("CONVERTED - found ID %s matches %s, return retB %d\n", str, builtIn[i], i);
451 #endif
452 }
453
454 if(retB) {
455 *retB=i;
456 found=TRUE;
457 }
458 break;
459 }
460}
461
462 /* Return if no user list is requested or it is empty */
463 if(!user)
464 return found;
465
466/*
467 for(i=0; i!=vectorSize(user); ++i) {
468 printf ("special_ID_string, user %d is %s\n",
469 i, vector_get(char*, user, i));
470}
471*/
472
473
474 /* Already defined user id? */
475 /* Look for the ID in the passed user array. If it is found, return the index to the ID in retU */
476 /* JAS - COUNT DOWN from last entered to first; this makes duplicates use the latest entry. */
477 /* use an index to see when we go from 0 to -1; int can not do this, as it is unsigned */
478 /* was : for(i=0; i!=vectorSize(user); ++i) { */
479
480
481for (ind= (int)vectorSize(user)-1; ind>=0; ind--) {
482
483 /* convert an int into an int */
484 i = (int) ind;
485
486 /* printf ("lexer sp, ele %d\n",i);
487 printf ("lexer_specialID_string, part II, comparing :%s: and :%s: lengths %d and %d\n",
488 str, vector_get(char*, user, i),
489 strlen(str), strlen(vector_get(char*, user, i))); */
490
491 if(!strcmp(str, vector_get(char*, user, i))) {
492 #ifdef CPARSERVERBOSE
493 printf("found ID %s matches %s, return retU %d\n", str, vector_get(char*, user, i), i);
494 #endif
495
496 if(retU) {
497 *retU=i;
498 found=TRUE;
499 }
500 break;
501 }
502 }
503
504 return found;
505}
506
507
508/* Lexes and defines an ID */
509/* Adds the ID to the passed vector of IDs (unless it is already present) */
510/* Note that we only check for duplicate IDs if multi is TRUE */
511BOOL lexer_defineID(struct VRMLLexer* me, int* ret, struct Vector* vec, BOOL multi) {
512
513 /* Get the next token */
514 if(!lexer_setCurID(me))
515 return FALSE;
516 ASSERT(me->curID);
517
518 #ifdef CPARSERVERBOSE
519 printf ("lexer_defineID, VRMLLexer %u Vector %u\n",me,vec);
520 if (multi) printf ("Multi SET\n"); else printf ("no Mlti set\n");
521 #endif
522
523 /* User list should be created */
524 ASSERT(vec);
525
526
527 /* If multiple definition possible? Look if the ID's already there */
528 if(multi) {
529 int i;
530 for(i=0; i!=vectorSize(vec); ++i) {
531
532 #ifdef CPARSERVERBOSE
533 printf ("lexer_defineID, comparing %s to %s\n",me->curID, vector_get(const char*, vec, i));
534 #endif
535
536 if(!strcmp(me->curID, vector_get(const char*, vec, i))) {
537 FREE_IF_NZ (me->curID);
538 *ret=i;
539 return TRUE;
540 }
541 }
542 } else {
543 /* is this already defined? */
544 if (gglobal()->internalc.global_strictParsing) {
545 int i;
546 for(i=0; i!=vectorSize(vec); ++i) {
547 if(!strcmp(me->curID, vector_get(const char*, vec, i))) {
548 ConsoleMessage ("warning, duplicate ID (%s at %u), using last DEF",me->curID,i);
549 }
550 }
551 }
552
553 }
554
555 /* Define the id */
556 /* Add this ID to the passed vector of IDs */
557 *ret=vectorSize(vec);
558 #ifdef CPARSERVERBOSE
559 printf("lexer_defineID: adding %s to vector %p\n", me->curID, vec);
560 #endif
561 /* save the curID on the stack... */
562 vector_pushBack(char*, vec, me->curID);
563
564 /* set curID to NULL to indicate that we have used this id */
565 me->curID=NULL;
566
567 return TRUE;
568}
569
570
571/* A eventIn/eventOut terminal symbol */
572/* Looks for the current token in builtin and/or user defined name arrays depending on the
573 requested return values and the eventtype (in or out)
574 If looking through EVENT_IN, EVENT_OUT, or EXPOSED_FIELD, checks to see if the current token
575 is valid with either set_ or _changed stripped from it
576 If rBO is non-null, then search through EVENT_IN or EVENT_OUT and return the index of the event (if found) in rBO
577 If rBE is non-null, then search through EXPOSED_FIELD and return the index of the event (if found) in rBE
578 If rUO is non-null, then search through user_inputOnly or user_outputOnly and return the index of the event (if found) in rUO
579 if rUE is non-null, then search through user_inputOutput and return the index of the event (if found) in rUE */
580
581BOOL lexer_event(struct VRMLLexer* me,
582 struct X3D_Node* routedNode,
583 int* rBO, int* rBE, int* rUO, int* rUE,
584 int routedToFrom)
585{
586 BOOL found=FALSE;
587
588 struct Vector* uarr;
589 const char** arr;
590 int arrCnt;
591 const char** userArr;
592 int userCnt;
593
594 if(routedToFrom==ROUTED_FIELD_EVENT_IN)
595 {
596 /* If we are looking for an eventIn we need to look through the EVENT_IN array and the user_inputOnly vector */
597 uarr=me->user_inputOnly;
598 arr=EVENT_IN;
599 arrCnt=EVENT_IN_COUNT;
600 } else
601 {
602 /* If we are looking for an eventOut we need to look through the EVENT_OUT array and the user_outputOnly vector */
603 uarr=me->user_outputOnly;
604 arr=EVENT_OUT;
605 arrCnt=EVENT_OUT_COUNT;
606 }
607
608 /* Get the next token - if this is a PROTO expansion, this will be non-NULL */
609 if (me->curID == NULL)
610 if(!lexer_setCurID(me)) {
611 return FALSE;
612 }
613
614 ASSERT(me->curID);
615
616#ifdef CPARSERVERBOSE
617 printf("lexer_event: looking for %s\n", me->curID);
618#endif
619
620 /* Get a pointer to the data in the vector of user defined event names */
621 userArr=&vector_get(const char*, uarr, 0);
622 userCnt=vectorSize(uarr);
623
624 /* Strip off set_ or _changed from current token. Then look through the EVENT_IN/EVENT_OUT array for the eventname (current token).
625 If it is found, return the index of the eventname. Also looks through fields of the routedNode to check if fieldname is valid for that node
626 (but doesn't seem to do anything if not valid ... ) */
627 if(rBO)
628 *rBO=findRoutedFieldInARR(routedNode, me->curID, routedToFrom, arr, arrCnt,
629 FALSE);
630
631 /* Strip off set_ or _changed from current token. Then look through the user_inputOnly/user_outputOnly array for the eventname (current token).
632 If it is found, return the index of the eventname. */
633 if(rUO)
634 *rUO=findRoutedFieldInARR(routedNode, me->curID, routedToFrom,
635 userArr, userCnt, TRUE);
636
637 /* Set the found flag to TRUE if the eventname was found in either the EVENT_IN/EVENT_OUT or user_inputOnly/user_outputOnly arrays */
638 if(!found)
639 found=((rBO && *rBO!=ID_UNDEFINED) || (rUO && *rUO!=ID_UNDEFINED));
640
641#ifdef CPARSERVERBOSE
642 if (rBO && *rBO != ID_UNDEFINED)
643 printf("lexer_event: found in EVENT_IN/EVENT_OUT\n");
644
645 if (rUO && *rUO != ID_UNDEFINED)
646 printf("lexer_event: found in user_inputOnly/user_outputOnly\n");
647#endif
648
649 /* Get a pointer to the event names in the vector of user defined exposed fields */
650 userArr=&vector_get(const char*, me->user_inputOutput, 0);
651 userCnt=vectorSize(me->user_inputOutput);
652
653 /* findRoutedFieldInEXPOSED_FIELD calls findRoutedFieldInARR(node, field, fromTo, EXPOSED_FIELD, EXPOSED_FIELD_COUNT, 0) */
654 /* Strip off set_ or _changed from current token. Then look through the EXPOSED_FIELD array for the eventname (current token).
655 If it is found, return the index of the eventname. Also looks through fields of the routedNode to check if fieldname is valid for that node
656 (but doesn't seem to do anything if not valid ... ) */
657 if(rBE)
658 *rBE=findRoutedFieldInEXPOSED_FIELD(routedNode, me->curID, routedToFrom);
659
660 /* Strip off set_ or _changed from current token. Then look through the user_inputOutput array for the eventname (current token).
661 If it is found, return the index of the eventname. */
662 if(rUE)
663 *rUE=findRoutedFieldInARR(routedNode, me->curID, routedToFrom,
664 userArr, userCnt, TRUE);
665
666 /* Set the found flag to TRUE if the eventname was found in either the EXPOSED_FIELD or user_inputOutput arrays */
667 if(!found)
668 found=((rBE && *rBE!=ID_UNDEFINED) || (rUE && *rUE!=ID_UNDEFINED));
669
670#ifdef CPARSERVERBOSE
671 if (rBE && *rBE != ID_UNDEFINED)
672 printf("lexer_event: found in EXPOSED_FIELD\n");
673
674 if (rUE && *rUE != ID_UNDEFINED)
675 printf("lexer_event: found in user_inputOutput\n");
676#endif
677
678 if(found) {
679 FREE_IF_NZ(me->curID);
680 }
681
682 return found;
683}
684
685/* Lexes a fieldId terminal symbol */
686/* If retBO isn't null, checks for the field in the FIELDNAMES array */
687/* If retBE isn't null, checks for the field in the EXPOSED_FIELD array */
688/* if retUO isn't null, checks for the field in the user_initializeOnly vector */
689/* if retUE isn't null, checks for the field in the user_inputOutput vector */
690/* returns the index of the field in the corresponding ret value if found */
691BOOL lexer_field(struct VRMLLexer* me,
692 int* retBO, int* retBE, int* retUO, int* retUE)
693{
694 const char** userArr;
695 int userCnt;
696
697 BOOL found=FALSE;
698
699 /* Get next token */
700 if(!lexer_setCurID(me))
701 return FALSE;
702 ASSERT(me->curID);
703
704 /* Get a pointer to the entries in the user_initializeOnly vector */
705 userArr=&vector_get(const char*, me->user_initializeOnly, 0);
706 userCnt=vectorSize(me->user_initializeOnly);
707
708#ifdef CPARSERVERBOSE
709 printf("lexer_field: looking for %s\n", me->curID);
710#endif
711 /* findFieldInFIELD is #defined to findFieldInARR(field, FIELDNAMES, FIELDNAMES_COUNT) */
712 /* look through the FIELDNAMES array for the fieldname (current token). If it is found, return the index of the fieldname */
713 if(retBO)
714 *retBO=findFieldInFIELD(me->curID);
715
716 /* look through the fieldnames from the user_initializeOnly names vector for the fieldname (current token). If it is found, return the index
717 of the fieldname */
718 if(retUO)
719 *retUO=findFieldInARR(me->curID, userArr, userCnt);
720
721 /* Set the found flag to TRUE if the fieldname was found in either FIELDNAMES or user_initializeOnly */
722 if(!found)
723 found=((retBO && *retBO!=ID_UNDEFINED) || (retUO && *retUO!=ID_UNDEFINED));
724
725 /* Get a pointer to the entries in the user_inputOutput vector */
726 userArr=&vector_get(const char*, me->user_inputOutput, 0);
727 userCnt=vectorSize(me->user_inputOutput);
728
729 /* findFieldInEXPOSED_FIELD #defined to findFieldInARR(field, EXPOSED_FIELD, EXPOSED_FIELD_COUNT) */
730 /* look through the EXPOSED_FIELD array for the fieldname (current token). If it is found, return the index of the fieldname. */
731 if(retBE)
732 *retBE=findFieldInEXPOSED_FIELD(me->curID);
733
734 /* look through the fieldnames from the user_inputOutput names vector for the fieldname (current token). If it is found, return the
735 index of the fieldname */
736 if(retUE)
737 *retUE=findFieldInARR(me->curID, userArr, userCnt);
738
739 /* Set the found flag to TRUE if the fieldname was found in either EXPOSED_FIELD or user_inputOutput */
740 if(!found)
741 found=((retBE && *retBE!=ID_UNDEFINED) || (retUE && *retUE!=ID_UNDEFINED));
742
743#ifdef CPARSERVERBOSE
744 if (retBO && *retBO != ID_UNDEFINED)
745 printf("lexer_field: found field in FIELDNAMES\n");
746 if (retUO && *retUO != ID_UNDEFINED)
747 printf("lexer_field: found field in me->user_initializeOnly\n");
748 if (retBE && *retBE != ID_UNDEFINED)
749 printf("lexer_field: found field in EXPOSED_FIELD\n");
750 if (retUE && *retUE != ID_UNDEFINED)
751 printf("lexer_field: found field in me->user_inputOutput\n");
752#endif
753
754 if(found)
755 {
756 FREE_IF_NZ (me->curID);
757 }
758
759 return found;
760}
761
762
763
764/* Conversion of user field name to char* */
765const char* lexer_stringUser_fieldName(struct VRMLLexer* me, int name, int mode)
766{
767 #define OOB_RETURN_VAL "__UNDEFINED__"
768
769 switch(mode)
770 {
771 case PKW_initializeOnly:
772 if (name>vectorSize(me->user_initializeOnly)) return OOB_RETURN_VAL;
773 return lexer_stringUser_initializeOnly(me, name);
774 case PKW_inputOutput:
775 if (name>vectorSize(me->user_inputOutput)) return OOB_RETURN_VAL;
776 return lexer_stringUser_inputOutput(me, name);
777 case PKW_inputOnly:
778 if (name>vectorSize(me->user_inputOnly)) return OOB_RETURN_VAL;
779 return lexer_stringUser_inputOnly(me, name);
780 case PKW_outputOnly:
781 if (name>vectorSize(me->user_outputOnly)) return OOB_RETURN_VAL;
782 return lexer_stringUser_outputOnly(me, name);
783 }
784 ASSERT(FALSE);
785 return OOB_RETURN_VAL; /* gets rid of compile time warnings */
786}
787
788/* Skip whitespace and comments. */
789void lexer_skip(struct VRMLLexer* me)
790{
791 int c;
792
793 if(me->curID) return;
794 while(TRUE)
795 {
796 LEXER_GETINPUT(c)
797 switch(c)
798 {
799
800 /* Whitespace: Simply ignore. */
801 case ' ':
802 case '\n':
803 case '\r':
804 case '\t':
805 case ',':
806 break;
807
808 /* Comment: Ignore until end of line. */
809 case '#':
810 do {
811 LEXER_GETINPUT(c)
812 /* printf ("lexer, found comment, current char %d:%c:\n",c,c); */
813 /* for those files created by ith VRML97 plugin for LightWave3D v6 from NewTek, Inc
814 we have added the \r check. JAS */
815 } while(c!='\n' && c!= '\r' && c!=EOF);
816
817 break;
818
819 /* Everything else: Unget and return. */
820 default:
821 LEXER_UNGETINPUT(c)
822 return;
823
824 }
825 }
826}
827
828/* Input the basic literals */
829/* ************************ */
830
831/* Processes sign for int32 and float */
832/* FIXME: Eats up "sign" for some wrong input (like -x) */
833#define NUMBER_PROCESS_SIGN_GENERAL(addCheck) \
834 { \
835 neg=(c=='-'); \
836 if(c=='-' || c=='+') \
837 { \
838 LEXER_GETINPUT(c) \
839 if(!(c>='0' && c<='9') addCheck) \
840 { \
841 LEXER_UNGETINPUT(c) \
842 return FALSE; \
843 } \
844 } \
845 }
846/* win 32 complains not enough parameters for _general but what should go for int? && true / && 1*/
847#ifdef _MSC_VER
848#define NUMBER_PROCESS_SIGN_INT \
849 NUMBER_PROCESS_SIGN_GENERAL(&& TRUE)
850#else
851#define NUMBER_PROCESS_SIGN_INT \
852 NUMBER_PROCESS_SIGN_GENERAL()
853#endif
854#define NUMBER_PROCESS_SIGN_FLOAT \
855 NUMBER_PROCESS_SIGN_GENERAL(&& c!='.')
856
857/* Changes sign of return value if neg is set and returns. */
858#define RETURN_NUMBER_WITH_SIGN \
859 { \
860 if(neg) \
861 *ret=-*ret; \
862 return TRUE; \
863 }
864
865BOOL lexer_int32(struct VRMLLexer* me, vrmlInt32T* ret)
866{
867 int c;
868 BOOL neg;
869
870 if(me->curID) return FALSE;
871 lexer_skip(me);
872
873 /* Check if it is really a number */
874 LEXER_GETINPUT(c)
875 CHECK_EOF(c)
876 if(c!='-' && c!='+' && !(c>='0' && c<='9'))
877 {
878 LEXER_UNGETINPUT(c)
879 return FALSE;
880 }
881
882 /* Process sign. */
883 NUMBER_PROCESS_SIGN_INT
884
885 /* Initialize return value. */
886 *ret=0;
887
888 /* Hex constant? Otherwise simply skip the useless 0 */
889 if(c=='0')
890 {
891 LEXER_GETINPUT(c)
892 if(c=='x')
893 {
894 while(TRUE)
895 {
896 LEXER_GETINPUT(c)
897 *ret*=0x10;
898 if(c>='0' && c<='9')
899 *ret+=c-'0';
900 else if(c>='A' && c<='F')
901 *ret+=10+(c-'A');
902 else if(c>='a' && c<='f')
903 *ret+=10+(c-'a');
904 else
905 break;
906 }
907 LEXER_UNGETINPUT(c)
908 ASSERT(!(*ret%0x10));
909 *ret/=0x10;
910
911 RETURN_NUMBER_WITH_SIGN
912 }
913 }
914
915 /* Main processing loop. */
916 while(TRUE)
917 {
918 if(!(c>='0' && c<='9'))
919 break;
920 *ret*=10;
921 *ret+=c-'0';
922
923 LEXER_GETINPUT(c)
924 }
925 LEXER_UNGETINPUT(c)
926
927 RETURN_NUMBER_WITH_SIGN
928}
929
930BOOL lexer_float(struct VRMLLexer* me, vrmlFloatT* ret)
931{
932 int c;
933
934 BOOL neg;
935 BOOL afterPoint; /* Already after decimal point? */
936 float decimalFact; /* Factor next decimal digit is multiplied with */
937
938 if(me->curID) return FALSE;
939 lexer_skip(me);
940
941 /* Really a float? */
942 LEXER_GETINPUT(c)
943 CHECK_EOF(c)
944 if(c!='-' && c!='+' && c!='.' && !(c>='0' && c<='9'))
945 {
946 LEXER_UNGETINPUT(c)
947 return FALSE;
948 }
949
950 /* Process sign. */
951 NUMBER_PROCESS_SIGN_FLOAT
952
953 /* Main processing loop. */
954 *ret=0;
955 afterPoint=FALSE;
956 decimalFact=(float) 0.1;
957 while(TRUE)
958 {
959 if(c=='.' && !afterPoint)
960 afterPoint=TRUE;
961 else if(c>='0' && c<='9')
962 if(afterPoint)
963 {
964 *ret+=decimalFact*(c-'0');
965 decimalFact/=10;
966 } else
967 {
968 *ret*=10;
969 *ret+=c-'0';
970 }
971 /* JAS - I hate doing this, but Lightwave exporter SOMETIMES seems to put double dots
972 in a VRML file. This catches them... see
973 http://neptune.gsfc.nasa.gov/osb/aquarius/animations/vrml.php */
974 else if (c=='.') {
975 /*printf ("double dots\n");*/
976 }
977 else
978 break;
979
980 LEXER_GETINPUT(c)
981 }
982 /* No unget, because c is needed later. */
983
984 /* Exponential factor? */
985 if(c=='e' || c=='E')
986 {
987 BOOL negExp;
988 int exp;
989
990 LEXER_GETINPUT(c)
991 negExp=(c=='-');
992 /* FIXME: Wrong for things like 1e-. */
993 if(c=='-' || c=='+')
994 LEXER_GETINPUT(c)
995
996 exp=0;
997 while(TRUE)
998 {
999 if(c>='0' && c<='9')
1000 {
1001 exp*=10;
1002 exp+=c-'0';
1003 } else
1004 break;
1005
1006 LEXER_GETINPUT(c)
1007 }
1008
1009 if(negExp)
1010 exp=-exp;
1011 *ret*=(float)(pow(10, exp));
1012 }
1013 LEXER_UNGETINPUT(c)
1014
1015 RETURN_NUMBER_WITH_SIGN
1016}
1017
1018
1019BOOL lexer_double(struct VRMLLexer* me, vrmlDoubleT* ret)
1020{
1021 int c;
1022
1023 BOOL neg;
1024 BOOL afterPoint; /* Already after decimal point? */
1025 double decimalFact; /* Factor next decimal digit is multiplied with */
1026
1027 if(me->curID) return FALSE;
1028 lexer_skip(me);
1029
1030 /* Really a double? */
1031 LEXER_GETINPUT(c)
1032 CHECK_EOF(c)
1033 if(c!='-' && c!='+' && c!='.' && !(c>='0' && c<='9'))
1034 {
1035 LEXER_UNGETINPUT(c)
1036 return FALSE;
1037 }
1038
1039 /* Process sign. */
1040 NUMBER_PROCESS_SIGN_FLOAT
1041
1042 /* Main processing loop. */
1043 *ret=0;
1044 afterPoint=FALSE;
1045 decimalFact=.1;
1046 while(TRUE)
1047 {
1048 if(c=='.' && !afterPoint)
1049 afterPoint=TRUE;
1050 else if(c>='0' && c<='9')
1051 if(afterPoint)
1052 {
1053 *ret+=decimalFact*(c-'0');
1054 decimalFact/=10;
1055 } else
1056 {
1057 *ret*=10;
1058 *ret+=c-'0';
1059 }
1060 /* JAS - I hate doing this, but Lightwave exporter SOMETIMES seems to put double dots
1061 in a VRML file. This catches them... see
1062 http://neptune.gsfc.nasa.gov/osb/aquarius/animations/vrml.php */
1063 else if (c=='.') {
1064 /*printf ("double dots\n");*/
1065 }
1066 else
1067 break;
1068
1069 LEXER_GETINPUT(c)
1070 }
1071 /* No unget, because c is needed later. */
1072
1073 /* Exponential factor? */
1074 if(c=='e' || c=='E')
1075 {
1076 BOOL negExp;
1077 int exp;
1078
1079 LEXER_GETINPUT(c)
1080 negExp=(c=='-');
1081 /* FIXME: Wrong for things like 1e-. */
1082 if(c=='-' || c=='+')
1083 LEXER_GETINPUT(c)
1084
1085 exp=0;
1086 while(TRUE)
1087 {
1088 if(c>='0' && c<='9')
1089 {
1090 exp*=10;
1091 exp+=c-'0';
1092 } else
1093 break;
1094
1095 LEXER_GETINPUT(c)
1096 }
1097
1098 if(negExp)
1099 exp=-exp;
1100 *ret*=(pow(10, exp));
1101 }
1102 LEXER_UNGETINPUT(c)
1103
1104 RETURN_NUMBER_WITH_SIGN
1105}
1106
1107BOOL lexer_string(struct VRMLLexer* me, vrmlStringT* ret)
1108{
1109 int c;
1110 char* buf;
1111 int bufLen=INITIAL_STRINGLEN;
1112 int cur=0;
1113
1114 if(me->curID) return FALSE;
1115 lexer_skip(me);
1116
1117 /* Really a string? */
1118 LEXER_GETINPUT(c)
1119 CHECK_EOF(c)
1120 if(c!='\"')
1121 {
1122 LEXER_UNGETINPUT(c)
1123 return FALSE;
1124 }
1125
1126 /* Set up buffer */
1127 buf=MALLOC(char *, sizeof(*buf)*bufLen);
1128 ASSERT(buf);
1129
1130 /* Main processing loop */
1131 while(TRUE)
1132 {
1133 /* Buffer resize needed? Extra space for closing 0. */
1134 if(cur+1==bufLen)
1135 {
1136 bufLen*=2;
1137 buf=REALLOC(buf, sizeof(*buf)*bufLen);
1138 }
1139 ASSERT(cur+1<bufLen);
1140
1141 LEXER_GETINPUT(c)
1142 switch(c)
1143 {
1144
1145 /* End of string */
1146 case EOF:
1147 parseError("String literal not closed at all!");
1148 case '\"':
1149 goto breakStringLoop;
1150
1151 /* Copy character */
1152 case '\\':
1153 LEXER_GETINPUT(c)
1154 if(c==EOF)
1155 {
1156 parseError("String literal not closed at all!");
1157 goto breakStringLoop;
1158 }
1159 default:
1160 buf[cur]=(char)c;
1161 ++cur;
1162
1163 }
1164 }
1165breakStringLoop:
1166 /* No unget, because c is closing quote */
1167 ASSERT(cur<bufLen);
1168 buf[cur]=0;
1169
1170 *ret=newASCIIString(buf);
1171 FREE_IF_NZ (buf);
1172 return TRUE;
1173}
1174
1175/* Operator check */
1176/* ************** */
1177
1178BOOL lexer_operator(struct VRMLLexer* me, char op)
1179{
1180 int c;
1181
1182if (me->curID) {
1183 ConsoleMessage ("lexer_operator: did not expect to find a text string - it is \"%s\" - as I am looking for a \'%c\'\n",me->curID,op);
1184 FREE_IF_NZ(me->curID);
1185 /* printf ("NEXTIN is :%s:\n",me->nextIn); */
1186 }
1187
1188 lexer_skip(me);
1189
1190 LEXER_GETINPUT(c);
1191 CHECK_EOF(c);
1192 /* printf ("lxer_opr, got %d\n",c); */
1193
1194 if(c!=op)
1195 {
1196 LEXER_UNGETINPUT(c);
1197 return FALSE;
1198 }
1199
1200 return TRUE;
1201}
1202
1203/* EXTERNPROTO HANDLING */
1204/************************/
1205#define PARSE_ERROR(msg) \
1206 { \
1207 parseError(msg); \
1208 return; \
1209 }
1210
1211#define FIND_PROTO_IN_proto_BUFFER \
1212 do { \
1213 proto = strstr (proto,"PROTO"); \
1214 if (proto == NULL) \
1215 PARSE_ERROR ("EXTERNPROTO does not contain a PROTO!"); \
1216 if (*(proto-1) != 'N') { \
1217 break; \
1218 } \
1219 } while (1==1);
1220
1221/* the following is cribbed from CParseParser for MFStrings, but we pass a VRMLLexer, not a VRMLParser */
1222int lexer_EXTERNPROTO_mfstringValue(struct VRMLLexer* me, struct Multi_String* ret) {
1223 struct Vector* vec=NULL;
1224 char fw_outline[2000];
1225
1226 /* Just a single value? */
1227 if(!lexer_openSquare(me)) {
1228 ret->p=MALLOC(vrmlStringT *, sizeof(vrmlStringT));
1229 if(!lexer_sfstringValue(me, (void*)ret->p))
1230 return FALSE;
1231 ret->n=1;
1232 return TRUE;
1233 }
1234
1235 /* Otherwise, a real vector */
1236 vec=newVector(vrmlStringT, 128);
1237 while(!lexer_closeSquare(me)) {
1238 vrmlStringT val;
1239 if(!lexer_sfstringValue (me, &val)) {
1240 /* parseError("Expected ] before end of MF-Value!"); */
1241 strcpy (fw_outline,"ERROR:Expected \"]\" before end of EXTERNPROTO URL value, found \"");
1242 if (me->curID != ((void *)0))
1243 strcat (fw_outline, me->curID);
1244 else
1245 strcat (fw_outline, "(EOF)");
1246 strcat (fw_outline,"\" ");
1247 ConsoleMessage(fw_outline);
1248 fprintf (stderr,"%s\n",fw_outline);
1249 break;
1250 }
1251
1252 vector_pushBack(vrmlStringT, vec, val);
1253 }
1254
1255 ret->n=vectorSize(vec);
1256 ret->p=vector_releaseData(vrmlStringT, vec);
1257
1258 deleteVector(vrmlStringT, vec);
1259 return TRUE;
1260}
1261
1262/* isolate the PROTO that we want from the just read in EXTERNPROTO string */
1263void embedEXTERNPROTO(struct VRMLLexer *me, const char *myName, char *buffer, char *pound) {
1264 char *cp;
1265 char *externProtoPointer;
1266 char *proto;
1267 int curlscount;
1268 int foundBracket;
1269
1270 /* step 1. Remove comments, so that we do not locate the requested PROTO in comments. */
1271 cp = buffer;
1272
1273 while (*cp != '\0') {
1274 if (*cp == '#') {
1275 do {
1276 *cp = ' ';
1277 cp++;
1278 /* printf ("lexer, found comment, current char %d:%c:\n",cp,cp); */
1279 /* for those files created by ith VRML97 plugin for LightWave3D v6 from NewTek, Inc
1280 we have added the \r check. JAS */
1281 } while((*cp!='\n') && (*cp!= '\r') && (*cp!='\0'));
1282 } else {
1283
1284 cp++;
1285 }
1286 }
1287
1288 /* find the requested name, or find the first PROTO here */
1289 if (pound != NULL) {
1290 pound++;
1291 /* printf ("looking for ID %s\n",pound); */
1292 proto=buffer;
1293
1294 do {
1295 FIND_PROTO_IN_proto_BUFFER
1296
1297 /* is this the PROTO we are looking for? */
1298 proto += sizeof ("PROTO");
1299 while ((*proto <= ' ') && (*proto != '\0')) proto++;
1300 /* printf ("found PROTO at %s\n",proto); */
1301 } while (strncmp(pound,proto,strlen(pound)) != 0);
1302 } else {
1303 /* no name requested; find the first PROTO that is not an EXTERNPROTO */
1304 proto = buffer;
1305 FIND_PROTO_IN_proto_BUFFER
1306 /* printf ("found PROTO at %s\n",proto); */
1307 }
1308
1309 /* go to the first '[' of the proto */
1310 cp = strchr(proto,'[');
1311 if (cp != NULL) proto = cp;
1312
1313 /* now, isolate this PROTO from the rest ... count the curly braces */
1314 cp = proto;
1315 curlscount = 0;
1316 foundBracket = FALSE;
1317 do {
1318 if (*cp == '{') {curlscount++; foundBracket = TRUE;}
1319 if (*cp == '}') curlscount--;
1320 cp++;
1321 if (*cp == '\0')
1322 PARSE_ERROR ("brackets missing in EXTERNPROTO");
1323
1324 } while (!foundBracket || (curlscount > 0));
1325 *cp = '\0';
1326
1327 /* now, insert this PROTO text INTO the stream */
1328
1329
1330 externProtoPointer = MALLOC (char *, sizeof (char) * (strlen (proto)+strlen(myName) +40));
1331 externProtoPointer[0]='\0';
1332 strcat (externProtoPointer, "PROTO ");
1333 strcat (externProtoPointer,myName);
1334 strcat (externProtoPointer," ");
1335 strcat (externProtoPointer,proto);
1336
1337/* printf ("pushing protoexp :%s:\n",externProtoPointer); */
1338
1339 /* push it on to the lexer input string stack */
1340 lexer_fromString(me,externProtoPointer);
1341}
1342
1343/* the curID is EXTERNPROTO. Replace the EXTERNPROTO with the actual PROTO string read in from
1344 an external file */
1345
1346void lexer_handle_EXTERNPROTO(struct VRMLLexer *me) {
1347#ifdef HAD_RESOURCE_LOAD
1348 char *myName = NULL;
1349#endif
1350 int mode;
1351 int type;
1352 struct Multi_String url;
1353
1354 resource_item_t *res;
1355
1356 /* expect the EXTERNPROTO proto name */
1357 if (lexer_setCurID(me)) {
1358 /* printf ("next token is %s\n",me->curID); */
1359#ifdef HAD_RESOURCE_LOAD
1360 myName = STRDUP(me->curID);
1361#endif
1362 FREE_IF_NZ(me->curID);
1363 } else {
1364 PARSE_ERROR ("EXTERNPROTO - expected a PROTO name\n");
1365 }
1366
1367 /* go through and save the parameters and types. */
1368
1369 if (!lexer_openSquare(me))
1370 PARSE_ERROR ("EXTERNPROTO - expected a '['");
1371
1372
1373 /* XXX - we should save these mode/type/name pairs, and compare them to the
1374 ones in the EXTERNPROTO definition. But, for now, we don't */
1375
1376 /* get the Name/Type value pairs and save them */
1377 while (lexer_protoFieldMode(me, &mode)) {
1378 /* printf ("mode is %d\n",mode); */
1379
1380 if(!lexer_fieldType(me, &type))
1381 PARSE_ERROR("Expected fieldType after proto-field keyword!")
1382
1383 /* printf ("type is %d\n",type); */
1384
1385
1386 if (lexer_setCurID(me)) {
1387 /* printf ("param name is %s\n",me->curID); */
1388 FREE_IF_NZ(me->curID);
1389 } else {
1390 PARSE_ERROR ("EXTERNPROTO - expected a PROTO name\n");
1391 }
1392 }
1393
1394 /* now, check for closed square */
1395 if (!lexer_closeSquare(me))
1396 PARSE_ERROR ("EXTERNPROTO - expected a ']'");
1397
1398 /* get the URL string */
1399 if (!lexer_EXTERNPROTO_mfstringValue(me,&url)) {
1400 PARSE_ERROR ("EXTERNPROTO - problem reading URL string");
1401 }
1402
1403 res = resource_create_multi(&url);
1404
1405 FREE_IF_NZ(url.p);
1406 url.p = NULL;
1407 url.n = 0;
1408 resource_identify((resource_item_t*)gglobal()->resources.root_res, res);
1409
1410 if (res->type != rest_invalid) {
1411#ifdef HAD_RESOURCE_LOAD
1412 if (resource_fetch(res)) {
1413 unsigned char *buffer;
1414 char *pound;
1415 pound = strchr(res->URLrequest, '#');
1416 if (resource_load(res)) {
1417 s_list_t *l;
1418 openned_file_t *of;
1419 l = res->openned_files;
1420 of = ml_elem(l);
1421 buffer = of->fileData;
1422 embedEXTERNPROTO(me, myName, (char *)buffer, pound);
1423 }
1424 }
1425#else
1426 res->status = ress_failed;
1427 printf("externProto not currently supported\n");
1428#endif
1429 }
1430
1431 if (res->status == ress_loaded) {
1432 /* ok - we are replacing EXTERNPROTO with PROTO */
1433 res->status = ress_parsed;
1434 res->complete = TRUE;
1435 } else {
1436 /* failure, FIXME: remove res from root_res... */
1437 /* resource_destroy(res); */
1438 }
1439
1440 /* so, lets continue. Maybe this EXTERNPROTO is never referenced?? */
1441 lexer_setCurID(me);
1442 /* printf ("so, curID is :%s: and rest is :%s:\n",me->curID, me->nextIn); */
1443 return;
1444}
1445
1446
1447/* recursively skip to the closing curly bracket - ignoring all that comes between. */
1448void skipToEndOfOpenCurly(struct VRMLLexer *me, int level) {
1449 int curlyCount = 1;
1450 vrmlStringT tmpstring;
1451
1452 #ifdef CPARSELEXERVERBOSE
1453 if (level == 0) printf ("start of skipToEndOfOpenCurly, have :%s:\n",me->nextIn);
1454 #endif
1455
1456 while ((curlyCount > 0) && (*me->nextIn != '\0')) {
1457 lexer_skip(me);
1458 #ifdef CPARSELEXERVERBOSE
1459 printf ("cc %d, looking at :%c:\n",curlyCount,*me->nextIn);
1460 #endif
1461
1462 if (*me->nextIn == '{') curlyCount++;
1463 else if (*me->nextIn == '}') curlyCount--;
1464 if (lexer_string(me,&tmpstring)) {
1465 #ifdef CPARSELEXERVERBOSE
1466 printf ("after string, :%s:\n",me->nextIn);
1467 printf ("and string :%s:\n",tmpstring->strptr);
1468 #endif
1469
1470 FREE_IF_NZ(tmpstring->strptr); /* throw it away */
1471 } else {
1472 me->nextIn++;
1473 }
1474 }
1475
1476 #ifdef CPARSELEXERVERBOSE
1477 if (level == 0) printf ("returning from skipToEndOfOpenCurly nextIn :%s:\n",me->nextIn);
1478 #endif
1479}
1480
1481/* concat 2 strings, and tell the lexer to scan from this new string */
1482void concatAndGiveToLexer(struct VRMLLexer *me, const char *str_a, const char *str_b) {
1483 char *newstring;
1484 int len_a=0;
1485 int len_b=0;
1486 if (str_a != NULL) len_a = (int) strlen(str_a);
1487 if (str_b != NULL) len_b = (int) strlen(str_b);
1488
1489 if ((len_a == 0) & (len_b == 0)) {
1490 printf ("concatAndGiveToLexer, no input!\n");
1491 return;
1492 }
1493
1494 newstring = MALLOC(char *, sizeof (char) * (len_a + len_b +10));
1495 newstring[0] = '\0';
1496 if (len_a != 0) strcat (newstring,str_a);
1497 if (len_b != 0) strcat (newstring,str_b);
1498
1499 /* printf ("concatAndGiveToLexer, sending in :%s:\n",newstring); */
1500 lexer_fromString(me,newstring);
1501}