FreeWRL/FreeX3D  3.0.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 
51 void lexer_handle_EXTERNPROTO(struct VRMLLexer *me);
52 //char *externProtoPointer = NULL; //not used
53 /* Pre- and suffix for exposed events. */
54 const char* EXPOSED_EVENT_IN_PRE="set_";
55 const 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 */
66 static 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 
95 struct 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 
128 void 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 */
140 static 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 */
174 void 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 
192 void 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 
206 static void lexer_scopeOut_(Stack*);
207 void 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 
217 void 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 
245 static 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 
252 static 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 */
264 void 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 */
276 void 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 */
290 void 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 */
307 BOOL lexer_setCurID(struct VRMLLexer* me)
308 {
309  unsigned 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 
317  lexer_skip(me);
318 
319  /* Is it really an ID? */
320  LEXER_GETINPUT(c)
321  CHECK_EOF(c)
322  if(!IS_ID_FIRST(c))
323  {
324  LEXER_UNGETINPUT(c)
325  return FALSE;
326  }
327 
328  /* Main loop. */
329  while(cur!=buf+MAX_IDLEN)
330  {
331  ASSERT(cur<buf+MAX_IDLEN);
332  *cur=c;
333  ++cur;
334 
335  LEXER_GETINPUT(c)
336  if(!IS_ID_REST(c))
337  goto breakIdLoop;
338  }
339  parseError("ID buffer length hit! File must end with \n");
340 breakIdLoop:
341  LEXER_UNGETINPUT(c)
342  ASSERT(cur<=buf+MAX_IDLEN);
343  *cur=0;
344 
345  ASSERT(strlen(buf)==(cur-buf));
346  ASSERT(!me->curID);
347  me->curID=MALLOC(char *, sizeof(char)*(cur-buf+1));
348 
349  strcpy(me->curID, buf);
350 
351  #ifdef CPARSERVERBOSE
352  printf ("lexer_setCurID, got %s\n",me->curID);
353  #endif
354 
355  return TRUE;
356 }
357 
358 /* Lexes a keyword */
359 BOOL lexer_keyword(struct VRMLLexer* me, int kw) {
360  if(!lexer_setCurID(me)) 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 */
371 int 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 
390 BOOL 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. */
413 BOOL 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 
481 for (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 */
511 BOOL 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 
581 BOOL 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 */
691 BOOL 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* */
765 const 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. */
789 void 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 
865 BOOL 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 
930 BOOL 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 
1019 BOOL 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 
1107 BOOL 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  }
1165 breakStringLoop:
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 
1178 BOOL lexer_operator(struct VRMLLexer* me, char op)
1179 {
1180  int c;
1181 
1182 if (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 */
1222 int 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 */
1263 void 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 
1346 void 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. */
1448 void 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 */
1482 void 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 }
Definition: list.h:37
Definition: Vector.h:36