FreeWRL/FreeX3D  3.0.0
CParseParser.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 
36 
37 #include "../vrml_parser/Structs.h"
38 #include "../main/headers.h"
39 #include "CParseGeneral.h"
40 #include "../scenegraph/Vector.h"
41 #include "../vrml_parser/CFieldDecls.h"
42 #include "../world_script/JScript.h"
43 #include "../world_script/CScripts.h"
44 #include "../world_script/fieldSet.h"
45 #include "../input/EAIHeaders.h" /* resolving implicit declarations */
46 #include "../input/EAIHelpers.h" /* resolving implicit declarations */
47 #include "CParseParser.h"
48 #include "CParseLexer.h"
49 #include "CParse.h"
50 #include "CRoutes.h" /* for upper_power_of_two */
51 #include "../opengl/OpenGL_Utils.h"
52 
53 #define PARSE_ERROR(msg) \
54  { \
55  CPARSE_ERROR_CURID(msg); \
56  FREE_IF_NZ(me->lexer->curID); \
57  PARSER_FINALLY; \
58  }
59 #define PARSER_FINALLY
60 
61 #define DEFMEM_INIT_SIZE 16
62 
63 #define DJ_KEEP_COMPILER_WARNING 0
64 
65 typedef struct pCParseParser{
66  char fw_outline[2000];
67  int foundInputErrors;// = 0;
68  int latest_protoDefNumber;
70 void *CParseParser_constructor(){
71  void *v = MALLOCV(sizeof(struct pCParseParser));
72  memset(v,0,sizeof(struct pCParseParser));
73  return v;
74 }
75 void CParseParser_init(struct tCParseParser *t){
76  //public
77  //private
78  t->prv = CParseParser_constructor();
79  {
80  ppCParseParser p = (ppCParseParser)t->prv;
81  p->foundInputErrors = 0;
82  p->latest_protoDefNumber = 1;
83  }
84 }
85  //ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
86 
87 //static int foundInputErrors = 0;
88 void resetParseSuccessfullyFlag(void) {
89  ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
90  p->foundInputErrors = 0;
91 }
92 int parsedSuccessfully(void) {
93  ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
94  return p->foundInputErrors == 0;
95 }
96 
97 /* Parsing a specific type */
98 /* NOTE! We have to keep the order of these function calls the same
99  as the FIELDTYPE names, created from the @VRML::Fields = qw/ in
100  VRMLFields.pm (which writes the FIELDTYPE* defines in
101  CFuncs/Structs.h. Currently (September, 2008) this is the list:
102  SFFloat
103  MFFloat
104  SFRotation
105  MFRotation
106  SFVec3f
107  MFVec3f
108  SFBool
109  MFBool
110  SFInt32
111  MFInt32
112  SFNode
113  MFNode
114  SFColor
115  MFColor
116  SFColorRGBA
117  MFColorRGBA
118  SFTime
119  MFTime
120  SFString
121  MFString
122  SFVec2f
123  MFVec2f
124  SFImage
125  FreeWRLPTR
126  SFVec3d
127  MFVec3d
128  SFDouble
129  MFDouble
130  SFMatrix3f
131  MFMatrix3f
132  SFMatrix3d
133  MFMatrix3d
134  SFMatrix4f
135  MFMatrix4f
136  SFMatrix4d
137  MFMatrix4d
138  SFVec2d
139  MFVec2d
140  SFVec4f
141  MFVec4f
142  SFVec4d
143  MFVec4d
144 */
145 
146 /* Parses nodes, fields and other statements. */
147 static BOOL parser_routeStatement(struct VRMLParser*);
148 static BOOL parser_componentStatement(struct VRMLParser*);
149 static BOOL parser_exportStatement(struct VRMLParser*);
150 static BOOL parser_importStatement(struct VRMLParser*);
151 static BOOL parser_metaStatement(struct VRMLParser*);
152 static BOOL parser_unitStatement(struct VRMLParser*);
153 static BOOL parser_profileStatement(struct VRMLParser*);
154 
155 //static BOOL parser_protoStatement(struct VRMLParser*);
156 static BOOL parser_nodeStatement(struct VRMLParser*, vrmlNodeT*);
157 static BOOL parser_node(struct VRMLParser*, vrmlNodeT*, int);
158 static BOOL parser_field(struct VRMLParser*, struct X3D_Node*);
159 
160 
161 
162 static BOOL parser_sffloatValue_ (struct VRMLParser *, void *);
163 static BOOL parser_sfint32Value_ (struct VRMLParser *, void *);
164 static BOOL parser_sftimeValue (struct VRMLParser *, void *);
165 static BOOL parser_sfboolValue (struct VRMLParser *, void *);
166 static BOOL parser_sfnodeValue (struct VRMLParser *, void *);
167 static BOOL parser_sfrotationValue (struct VRMLParser *, void *);
168 static BOOL parser_sfcolorValue (struct VRMLParser *, void *);
169 static BOOL parser_sfcolorrgbaValue (struct VRMLParser *, void *);
170 static BOOL parser_sfmatrix3fValue (struct VRMLParser *, void *);
171 static BOOL parser_sfmatrix4fValue (struct VRMLParser *, void *);
172 static BOOL parser_sfvec2fValue (struct VRMLParser *, void *);
173 static BOOL parser_sfvec4fValue (struct VRMLParser *, void *);
174 static BOOL parser_sfvec2dValue (struct VRMLParser *, void *);
175 static BOOL parser_sfvec3dValue (struct VRMLParser *, void *);
176 static BOOL parser_sfvec4dValue (struct VRMLParser *, void *);
177 static BOOL parser_sfmatrix3dValue (struct VRMLParser *, void *);
178 static BOOL parser_sfmatrix4dValue (struct VRMLParser *, void *);
179 static BOOL parser_mfboolValue(struct VRMLParser*, void*);
180 static BOOL parser_mfcolorValue(struct VRMLParser*, void*);
181 static BOOL parser_mfcolorrgbaValue(struct VRMLParser*, void*);
182 static BOOL parser_mffloatValue(struct VRMLParser*, void*);
183 static BOOL parser_mfint32Value(struct VRMLParser*, void*);
184 static BOOL parser_mfnodeValue(struct VRMLParser*, void*);
185 static BOOL parser_mfrotationValue(struct VRMLParser*, void*);
186 static BOOL parser_mfstringValue(struct VRMLParser*, void*);
187 static BOOL parser_mftimeValue(struct VRMLParser*, void*);
188 static BOOL parser_mfvec2fValue(struct VRMLParser*, void*);
189 static BOOL parser_mfvec3fValue(struct VRMLParser*, void*);
190 static BOOL parser_mfvec3dValue(struct VRMLParser*, void*);
191 static BOOL parser_sfstringValue_(struct VRMLParser*, void*);
192 static BOOL parser_sfimageValue(struct VRMLParser*, void*);
193 static BOOL parser_mfvec2dValue(struct VRMLParser*, void*);
194 static BOOL parser_mfvec4fValue(struct VRMLParser*, void*);
195 static BOOL parser_mfvec4dValue(struct VRMLParser*, void*);
196 
197 
198 
199 
200 #define parser_sfvec3fValue(me, ret) \
201  parser_sfcolorValue(me, ret)
202 
203 
204 /* for those types not parsed yet, call this to print an error message */
205 static BOOL parser_fieldTypeNotParsedYet(struct VRMLParser* me, void* ret);
206 
207 /*PARSE_TYPE[] entries must be sychnronized with the FIELDTYPES values in Structs.h */
208 BOOL (*PARSE_TYPE[])(struct VRMLParser*, void*)={
209  &parser_sffloatValue_, &parser_mffloatValue, // 0,1 float
210  &parser_sfrotationValue, &parser_mfrotationValue, // 2,3 rotation
211  &parser_sfcolorValue, &parser_mfvec3fValue, // 4,5 Vec3f
212  &parser_sfboolValue, &parser_mfboolValue, // 6,7 Bool
213  &parser_sfint32Value_, &parser_mfint32Value, // 8,9 Int32
214  &parser_sfnodeValue, &parser_mfnodeValue, // 10,11 Node
215  &parser_sfcolorValue, &parser_mfcolorValue, // 12,13 Color
216  &parser_sfcolorrgbaValue, &parser_mfcolorrgbaValue, // 14,15 ColorRGBA
217  &parser_sftimeValue, &parser_mftimeValue, // 16,17 Time
218  &parser_sfstringValue_, &parser_mfstringValue, // 18,19 String
219  &parser_sfvec2fValue, &parser_mfvec2fValue, // 20,21 Vec2f
220  &parser_fieldTypeNotParsedYet, /* FreeWRLPTR 23 */ // 22, FREEWRL_PTR
221  &parser_sfimageValue, /* SFImage */ // 23 SFImage
222  &parser_sfvec3dValue, &parser_mfvec3dValue, // 24,25 Vec3d
223  &parser_sftimeValue, &parser_mftimeValue, // 26,27 Double
224  &parser_sfmatrix3fValue, &parser_fieldTypeNotParsedYet, // 28,29 Matrix3f
225  &parser_sfmatrix3dValue, &parser_fieldTypeNotParsedYet, // 30,31 Matrix3d
226  &parser_sfmatrix4fValue, &parser_fieldTypeNotParsedYet, // 32,33 Matrix4f
227  &parser_sfmatrix4dValue, &parser_fieldTypeNotParsedYet, // 34,35 Matrix4d
228  &parser_sfvec2dValue, &parser_mfvec2dValue, // 36,37 Vec2d //&parser_fieldTypeNotParsedYet,
229  &parser_sfvec4fValue, &parser_mfvec4fValue, // 38,39 Vec4f //&parser_fieldTypeNotParsedYet,
230  &parser_sfvec4dValue, &parser_mfvec4dValue, // 40,41 Vec4d //&parser_fieldTypeNotParsedYet,
231  &parser_fieldTypeNotParsedYet, // 42 FreeWRLThread
232 };
233 
234 
235 /************************************************************************************************/
236 /* parse an SF/MF; return the parsed value in the defaultVal field */
237 BOOL parseType(struct VRMLParser* me, int type, union anyVrml *defaultVal) {
238  ASSERT(PARSE_TYPE[type]);
239 
240  //ConsoleMessage ("parseType, type %d, dfv %p",type,defaultVal);
241  if (type == ID_UNDEFINED) return false;
242 
243  return PARSE_TYPE[type](me, (void*)defaultVal);
244 }
245 
246 /* ************************************************************************** */
247 /* ******************************* ProtoFieldDecl *************************** */
248 /* ************************************************************************** */
249 
250 /* Constructor and destructor */
251 /* ************************** */
252 
253 /* Without default value (event) */
254 struct ProtoFieldDecl* newProtoFieldDecl(indexT mode, indexT type, indexT name)
255 {
256  struct ProtoFieldDecl* ret=MALLOC(struct ProtoFieldDecl*, sizeof(struct ProtoFieldDecl));
257  bzero(ret,sizeof(struct ProtoFieldDecl));
258  /* printf("creating ProtoFieldDecl %p\n", ret); */
259  ret->mode=mode;
260  ret->type=type;
261  ret->name=name;
262  ret->alreadySet=FALSE;
263  ret->fieldString = NULL;
264  ret->cname = NULL;
265  ret->scriptDests = NULL;
266  ret->defaultVal.mfnode.p = NULL;
267  ret->defaultVal.mfnode.n = 0;
268  return ret;
269 }
270 struct ProtoFieldDecl* copy_ProtoFieldDecl(struct ProtoFieldDecl *sdecl) {
271  struct ProtoFieldDecl *ddecl;
272  ddecl = newProtoFieldDecl(sdecl->mode,sdecl->type,sdecl->name);
273  if(sdecl->cname)
274  ddecl->cname = STRDUP(sdecl->cname);
275  //if(sdecl->mode == PKW_inputOnly || sdecl->mode == PKW_inputOutput){
276  //I seem to need unconditional otherwise something bombs when cleaning up / freeing
277  shallow_copy_field(sdecl->type,&(sdecl->defaultVal),&(ddecl->defaultVal));
278  //}
279  return ddecl;
280 }
281 void clearASCIIString(struct Uni_String *us);
282 void freeASCIIString(struct Uni_String *us);
283 void clearMFString(struct Multi_String *ms);
284 void freeMFString(struct Multi_String **ms);
285 void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr)
286 {
287  //deletes just the malloced part, assuming another replacement value will be deep copied in its place
288  if(fieldPtr) {
289  int isMF;
290  isMF =type % 2;
291  if(type == FIELDTYPE_FreeWRLPTR){
292  if(0) FREE_IF_NZ(fieldPtr->sfstring);
293  } else if(type == FIELDTYPE_SFString){
294  struct Uni_String *us;
295  //union anyVrml holds a struct Uni_String * (a pointer to Uni_String)
296  us = fieldPtr->sfstring;
297  clearASCIIString(us); //fieldPtr);
298  FREE_IF_NZ(fieldPtr->sfstring);
299  //fieldPtr->sfstring = NULL;
300  }else if(type == FIELDTYPE_MFString){
301  clearMFString(&fieldPtr->mfstring);
302  fieldPtr->mfstring.n = 0;
303  } else if(isMF) {
304  //if(type == FIELDTYPE_SFImage){
305  FREE_IF_NZ(fieldPtr->mfnode.p);
306  fieldPtr->mfnode.n = 0;
307  }
308  }
309 }
310 
311 void deleteProtoFieldDecl(struct ProtoFieldDecl* me)
312 {
313  int type;
314  union anyVrml *fieldPtr;
315  FREE_IF_NZ(me->cname);
316  FREE_IF_NZ(me->fieldString);
317  fieldPtr = &(me->defaultVal);
318  type = me->type;
319  deleteMallocedFieldValue(type,fieldPtr);
320  FREE_IF_NZ(me);
321 }
322 
323 
324 /* ************************************************************************** */
325 /* ******************************** ProtoDefinition ************************* */
326 /* ************************************************************************** */
327 
328 struct ProtoDefinition* newProtoDefinition()
329 {
330  /* Attention! protoDefinition_copy also sets up data from raw MALLOC! Don't
331  * forget to mimic any changes to this method there, too!
332  */
333 
334  struct ProtoDefinition* ret;
335  ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
336 
337  ret=MALLOC(struct ProtoDefinition*, sizeof(struct ProtoDefinition));
338  ASSERT(ret);
339 
340  /* printf("creating new ProtoDefinition %u\n", ret); */
341 
342  ret->iface=newVector(struct ProtoFieldDecl*, 4);
343  ASSERT(ret->iface);
344 
345  /* proto bodies are tokenized to help IS and routing to/from PROTOS */
346 /*
347  ret->deconstructedProtoBody=newVector(struct ProtoElementPointer*, 128);
348  ASSERT(ret->deconstructedProtoBody);
349 */
350  ret->deconstructedProtoBody = NULL;
351 
352 
353 
354  ret->protoDefNumber = p->latest_protoDefNumber++;
355  ret->estimatedBodyLen = 0;
356  ret->protoName = NULL;
357  ret->isCopy = FALSE;
358  ret->isExtern = FALSE;
359 
360  return ret;
361 }
362 void deleteProtoDefinition(struct ProtoDefinition *ret) {
363  if(ret){
364  if(ret->iface){
365  int i;
366  for(i=0;i<vectorSize(ret->iface);i++) {
367  struct ProtoFieldDecl* iface = vector_get(struct ProtoFieldDecl*,ret->iface,i);
368  if(iface){
369  deleteProtoFieldDecl(iface);
370  }
371  }
372  }
373  deleteVector(struct ProtoFieldDecl*,ret->iface);
374  FREE_IF_NZ(ret->protoName);
375  }
376  //FREE_IF_NZ(ret);
377 }
378 /* Other members */
379 /* ************* */
380 
381 /* Retrieve a field by its "name" */
382 struct ProtoFieldDecl* protoDefinition_getField(struct ProtoDefinition* me,
383  indexT ind, indexT mode)
384 {
385  /* TODO: O(log(n)) by sorting */
386  size_t i;
387  /* printf ("protoDefinition_getField; sizeof iface %d\n",vectorSize(me->iface)); */
388  if (!me) return NULL; /* error here, can not go through fields */
389  for(i=0; i!=vectorSize(me->iface); ++i)
390  {
391  struct ProtoFieldDecl* f=vector_get(struct ProtoFieldDecl*, me->iface, i);
392  if(f->name==ind && f->mode==mode) {
393  /* printf ("protoDefinition_getField, comparing %d %d and %d %d\n", f->name, ind, f->mode, mode); */
394  return f;
395  }
396  }
397 
398  return NULL;
399 }
400 
401 
402 struct ProtoDefinition *getVRMLbrotoDefinition (struct X3D_Proto *me) {
403  return (struct ProtoDefinition *)me->__protoDef;
404 }
405 
406 BOOL isProto(struct X3D_Node *node)
407 {
408  BOOL retval = FALSE;
409  if(node)
410  if(node->_nodeType == NODE_Proto){
411  //as of sept 2014, the broto2 scene is sharing the x3dproto struct, it has a bit flag set: __protoFlags & 1
412  //we don't want to treat the scene like a protoinstance, because we want to render all a scenes children. Not so for protoinstance.
413  retval = TRUE;
414  }
415  return retval;
416 }
417 
418 
419 /* ************************************************************************** */
420 /* Constructor and destructor */
421 
422 struct VRMLParser* newParser(void *ectx, void* ptr, unsigned ofs, int parsingX3DfromXML) {
423  struct VRMLParser* ret=MALLOC(struct VRMLParser *, sizeof(struct VRMLParser));
424  ret->lexer=newLexer();
425  ASSERT(ret->lexer);
426  ret->ectx=ectx;
427  ret->ptr=ptr;
428  ret->ofs=ofs;
429  ret->curPROTO=NULL;
430  ret->DEFedNodes = NULL;
431  ret->PROTOs = NULL;
432  ret->parsingX3DfromXML = parsingX3DfromXML;
433  ret->brotoDEFedNodes = NULL;
434  return ret;
435 }
436 
437 struct VRMLParser* reuseParser(void *ectx, void* ptr, unsigned ofs) {
438  struct VRMLParser* ret;
439  struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
440 
441  /* keep the defined nodes around, etc */
442  ret = globalParser;
443 
444  /* keep the old lexer around, so that the ASSERTs do not get confused with sizes of stacks, etc
445  if (ret->lexer != NULL) deleteLexer(ret->lexer);
446  ret->lexer=newLexer();
447  */
448  ASSERT(ret->lexer);
449  ret->ectx=ectx;
450  ret->ptr=ptr;
451  ret->ofs=ofs;
452 /* We now need to keep the PROTOS and DEFS around
453  ret->curPROTO=NULL;
454  ret->DEFedNodes = NULL;
455  ret->PROTOs = NULL;
456 */
457 
458  return ret;
459 }
460 
461 void deleteParser(struct VRMLParser* me)
462 {
463  ASSERT(me->lexer);
464  deleteLexer(me->lexer);
465 
466  FREE_IF_NZ (me);
467 }
468 
469 static void parser_scopeOut_DEFUSE();
470 static void parser_scopeOut_PROTO();
471 void parser_destroyData(struct VRMLParser* me)
472 {
473 
474  /* printf ("\nCParser: parser_destroyData, destroyCParserData: , destroying data, me->DEFedNodes %u\n",me->DEFedNodes); */
475 
476  /* DEFed Nodes. */
477  if(me->DEFedNodes)
478  {
479  while(!stack_empty(me->DEFedNodes))
480  parser_scopeOut_DEFUSE(me);
481  deleteStack(struct Vector*, me->DEFedNodes);
482  me->DEFedNodes=NULL;
483  }
484  ASSERT(!me->DEFedNodes);
485 
486  /* PROTOs */
487  /* FIXME: PROTOs must not be stacked here!!! */
488  if(me->PROTOs)
489  {
490  while(!stack_empty(me->PROTOs))
491  parser_scopeOut_PROTO(me);
492  deleteStack(struct Vector*, me->PROTOs);
493  me->PROTOs=NULL;
494  }
495  ASSERT(!me->PROTOs);
496  if(me->lexer)
497  lexer_destroyData(me->lexer);
498  //FREE_IF_NZ(me->lexer);
499 
500  /* zero script count */
501  zeroScriptHandles ();
502 }
503 
504 /* Scoping */
505 
506 static void parser_scopeIn_DEFUSE(struct VRMLParser* me)
507 {
508  if(!me->DEFedNodes)
509  me->DEFedNodes=newStack(struct Vector*);
510 
511  ASSERT(me->DEFedNodes);
512  stack_push(struct Vector*, me->DEFedNodes,
513  newVector(struct X3D_Node*, DEFMEM_INIT_SIZE));
514  ASSERT(!stack_empty(me->DEFedNodes));
515 }
516 
517 /* PROTOs are scope by the parser in the PROTOs vector, and by the lexer in the userNodeTypesVec vector.
518  This is accomplished by keeping track of the number of PROTOs defined so far in a the userNodeTypesStack.
519  When a new scope is entered, the number of PROTOs defined up to this point is pushed onto the stack. When
520  we leave the scope the number of PROTOs now defined is compared to the top value of the stack, and the newest
521  PROTOs are removed until the number of PROTOs defined equals the top value of the stack.
522 
523  Management of the userNodeTypesStack is accomplished by the lexer. Therefore, scoping in PROTOs for the parser
524  does nothing except to make sure that the PROTOs vector has been initialized. */
525 static void parser_scopeIn_PROTO(struct VRMLParser* me)
526 {
527  if(!me->PROTOs) {
528  me->PROTOs=newVector(struct ProtoDefinition*, DEFMEM_INIT_SIZE);
529  }
530 }
531 
532 static void parser_scopeOut_DEFUSE(struct VRMLParser* me)
533 {
534  ASSERT(!stack_empty(me->DEFedNodes));
535  /* FIXME: Can't delete individual nodes, as they might be referenced! */
536  deleteVector(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes));
537  stack_pop(struct Vector*, me->DEFedNodes);
538 }
539 
540 /* Scoping out of PROTOs. Check the difference between the number of PROTO definitions currently
541  available and the number of PROTO definitions available when we first entered this scope (this is
542  the top value on the userNodeTypesVec stack). Remove all PROTO definitions from the PROTOs list that have
543  been added since we first entered this scope. */
544 static void parser_scopeOut_PROTO(struct VRMLParser* me)
545 {
546  /* Do not delete the ProtoDefinitions, as they are referenced in the scene
547  * graph! TODO: How to delete them properly? */
548 
549  vector_popBackN(struct ProtoDefinition*, me->PROTOs, lexer_getProtoPopCnt(me->lexer));
550  lexer_scopeOut_PROTO(me->lexer);
551 }
552 
553 void parser_scopeIn(struct VRMLParser* me)
554 {
555  lexer_scopeIn(me->lexer);
556  parser_scopeIn_DEFUSE(me);
557  parser_scopeIn_PROTO(me);
558 }
559 void parser_scopeOut(struct VRMLParser* me)
560 {
561  parser_scopeOut_DEFUSE(me);
562  parser_scopeOut_PROTO(me);
563  lexer_scopeOut(me->lexer);
564 }
565 /* save your spot in the lexer stream so if you're in the wrong handler
566  you can backup and let something else try to handle it*/
567 #define STRDUP_IF_NZ(_ptr) ((_ptr) ? STRDUP(_ptr) : NULL)
568 #define DECLAREUP char *saveNextIn, *saveCurID = NULL;
569 #define SAVEUP { FREE_IF_NZ(saveCurID); \
570  saveCurID = STRDUP_IF_NZ(me->lexer->curID); \
571  saveNextIn = me->lexer->nextIn;}
572 #define BACKUP {FREE_IF_NZ(me->lexer->curID); \
573  me->lexer->curID = saveCurID; \
574  me->lexer->nextIn = saveNextIn; }
575 #define FREEUP {FREE_IF_NZ(saveCurID);}
576 
577 static BOOL parser_brotoStatement(struct VRMLParser* me);
578 
579 void parse_proto_body(struct VRMLParser* me)
580 {
581  DECLAREUP
582 
583  /* As long as there are nodes, routes, or protos to be parsed keep doing so */
584  while(TRUE)
585  {
586  /* Try nodeStatement */
587  SAVEUP
588  {
589  vrmlNodeT node;
590  /* This will parse a builtin node, including all nested ROUTES and PROTOs, and return
591  a pointer to the node that was parsed.
592  If the node is a user-defined node (PROTO expansion) this will expand the PROTO (propagate
593  all field values, and add all routes to the CRoute table), and returns a pointer to the
594  root node of the scene graph for this PROTO */
595 #ifdef CPARSERVERBOSE
596  printf("parser_vrmlScene: Try node\n");
597 #endif
598  if(parser_nodeStatement(me, &node))
599  {
600  /* Add the node just parsed to the ROOT node for this scene */
601  if (node != NULL)
602  AddRemoveChildren(me->ptr, offsetPointer_deref(void *,me->ptr,me->ofs), &node, 1, 1,__FILE__,__LINE__);
603 #ifdef CPARSERVERBOSE
604  printf("parser_vrmlScene: node parsed\n");
605 #endif
606  //printf("pp.children.n=%d\n",pp->children.n);
607  continue;
608  }
609  }
610  BACKUP
611  /* Try routeStatement */
612  /* Checks that the ROUTE statement is valid (i.e. that the referenced node and field combinations
613  exist, and that they are compatible) and then adds the route to the CRoutes table of routes. */
614 
615 #ifdef CPARSERVERBOSE
616  printf("parser_vrmlScene: Try route\n");
617 #endif
618 
619 
620  /* try ROUTE, COMPONENT, EXPORT, IMPORT, META, PROFILE statements here */
621  BLOCK_STATEMENT(parser_vrmlScene)
622  BACKUP
623  /* Try protoStatement */
624  /* Add the PROTO name to the userNodeTypesVec list of names. Create and fill in a new protoDefinition structure and add it to the PROTOs list.
625  Goes through the interface declarations for the PROTO and adds each user-defined field name to the appropriate list of user-defined names (user_initializeOnly,
626  user_inputOnly, Out, or user_inputOutput), creates a new protoFieldDecl for the field and adds it to the iface vector of the ProtoDefinition,
627  and, in the case of fields and inputOutputs, gets the default value of the field and stores it in the protoFieldDecl.
628  Parses the body of the PROTO. Nodes are added to the scene graph for this PROTO. Routes are parsed and a new ProtoRoute structure
629  is created for each one and added to the routes vector of the ProtoDefinition. PROTOs are recursively parsed!
630  */
631 #ifdef CPARSERVERBOSE
632  printf("parser_vrmlScene: Try proto\n");
633 #endif
634 // if(parser_protoStatement(me)) {
635 //#ifdef CPARSERVERBOSE
636 // printf("parser_vrmlScene: PROTO parsed\n");
637 //#endif
638 // continue;
639 // }
640  BACKUP
641  if(parser_brotoStatement(me)) {
642 #ifdef CPARSERVERBOSE
643  printf("parser_vrmlScene: BROTO parsed\n");
644 #endif
645  continue;
646  }
647 
648  break;
649  }
650 }
651 
652 void broto_store_DEF(struct X3D_Proto* proto,struct X3D_Node* node, const char *name);
653 static BOOL parser_node_B(struct VRMLParser* me, vrmlNodeT* ret, int ind);
654 
655 static BOOL parser_node(struct VRMLParser* me, vrmlNodeT* node, int ival)
656 {
657  return parser_node_B(me,node,ival);
658 }
659 
660 /* ************************************************************************** */
661 /* The start symbol */
662 
663 /* ************************************************************************** */
664 /* The start symbol */
665 
666 BOOL parser_vrmlScene_B(struct VRMLParser* me)
667 {
668  parse_proto_body(me);
669 
670  /* We were unable to keep parsing Nodes, ROUTEs, or PROTOs. Check that this is indeed the end of the file. If it isn't,
671  there is an error, so we return FALSE. */
672 
673  return lexer_eof(me->lexer);
674 }
675 BOOL parser_vrmlScene(struct VRMLParser* me)
676 {
677  //ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
678  //if((X3D_NODE(me->ectx)->_nodeType == NODE_Proto) || (X3D_NODE(me->ectx)->_nodeType == NODE_Inline)) {
679  /* (sorry for documenting instead of refactoring)
680  broto era: me->ptr is both the executionContext node (scene, proto, inline)
681  and the where node of the (where,offset) place to put the parsed nodes.
682  for brotos (binary proto parsing) the context has a set of arrays where data is put during parsing:
683  ROUTES, EXPORTS, IMPORTS, DEFnames, protoDeclares, externProtoDeclares
684  and (as of sept 2014) these arrays are used later for instancing declared user prototype nodes
685  but (as of sept 2014) not used for rendering scenes - that's still in old arrays scattered around freewrl.
686  me->ptr could be split in the future, so me->ptr is just the where node
687  and a separate me->ctx would hold the context (scene, proto, inline)
688  -ctx either the node ie ctxnode, or if context is separated into a struct, just the struct ie ctxStruct
689  if ctxnode, then when parsing protobody, besides me->ptr = proto, do me->ctx = proto
690  its just this top level where the ctxnode and (where,) might be separated, ie js createVrmlFromString()
691  parses nodes into an MFNode that's not a Proto, or Inline (but the script should know what executionContext its in).
692  Sept 2014 Proto and Inline have the same structure, so one can be cast to the other. But in theory, if you
693  separate context out, so its a struct on its own, then Proto and Inline could be different, and both hold
694  a context struct as a private field.
695  */
696  return parser_vrmlScene_B(me);
697  //}else{
698  // // older vrml tradition:
699  // // me->ptr is the where node for (where,offset) to put parsed nodes
700  // return parser_vrmlScene_A(me);
701  //}
702 }
703 /* ************************************************************************** */
704 /* Nodes and fields */
705 
706 /* Parses an interface declaration and adds it to the PROTO or Script definition */
707 /* Adds the user-defined name to the appropriate user-defined name list (user_initializeOnly, user_inputOutput, user_inputOnly, or Out)
708  Creates a protoFieldDecl or scriptFieldDecl structure to hold field data.
709  Parses and stores the default value of fields and inputOutputs.
710  Adds the protoFieldDecl or scriptFieldDecl to the list of fields in the ProtoDefinition or Script structure. */
711 static BOOL parser_interfaceDeclaration(struct VRMLParser* me, struct ProtoDefinition* proto, struct Shader_Script* script) {
712  int mode;
713  int type;
714  int name = 0;
715  int externproto;
716  union anyVrml defaultVal;
717  DECLAREUP
718  struct ProtoFieldDecl* pdecl=NULL;
719  struct ProtoFieldDecl* pField=NULL;
720  struct ScriptFieldDecl* sdecl=NULL;
721  char *startOfField = NULL;
722  int startOfFieldLexerLevel = INT_ID_UNDEFINED;
723 
724 
725 #ifdef CPARSERVERBOSE
726  printf ("start of parser_interfaceDeclaration\n");
727 #endif
728 
729  bzero (&defaultVal, sizeof (union anyVrml));
730 
731  /* Either PROTO or Script interface! */
732  ASSERT((proto || script) && !(proto && script));
733 
734  /* lexer_protoFieldMode is #defined as
735  lexer_specialID(me, r, NULL, PROTOKEYWORDS, PROTOKEYWORDS_COUNT, NULL) */
736  /* Looks for the next token in the array PROTOKEYWORDS (inputOnly, outputOnly, inputOutput, field)
737  and returns the appropriate index in mode */
738  SAVEUP
739  if(!lexer_protoFieldMode(me->lexer, &mode)) {
740 #ifdef CPARSERVERBOSE
741  printf ("parser_interfaceDeclaration, not lexer_protoFieldMode, returning\n");
742 #endif
743  BACKUP
744  return FALSE;
745  }
746 
747  /* Script can not take inputOutputs */
748  if(0) //if(version == VRML2 OR LESS)
749  if (script != NULL) {
750  if(script->ShaderScriptNode->_nodeType==NODE_Script && mode==PKW_inputOutput)
751  {
752  PARSE_ERROR("Scripts must not have inputOutputs!")
753  //printf("dug9: maybe scripts can have inputOutputs\n");
754  }
755  }
756 
757  /* lexer_fieldType is #defined as lexer_specialID(me, r, NULL, FIELDTYPES, FIELDTYPES_COUNT, NULL) */
758  /* Looks for the next token in the array FIELDTYPES and returns the index in type */
759  if(!lexer_fieldType(me->lexer, &type))
760  PARSE_ERROR("Expected fieldType after proto-field keyword!")
761 
762 #ifdef CPARSERVERBOSE
763  printf ("parser_interfaceDeclaration, switching on mode %s\n",PROTOKEYWORDS[mode]);
764 #endif
765 
766 
767  switch(mode)
768  {
769 #define LEX_DEFINE_FIELDID(suff) \
770  case PKW_##suff: \
771  if(!lexer_define_##suff(me->lexer, &name)) \
772  PARSE_ERROR("Expected fieldNameId after field type!") \
773  break;
774 
775  LEX_DEFINE_FIELDID(initializeOnly)
776  LEX_DEFINE_FIELDID(inputOnly)
777  LEX_DEFINE_FIELDID(outputOnly)
778  LEX_DEFINE_FIELDID(inputOutput)
779 
780 
781 
782 #ifndef NDEBUG
783  default:
784  ASSERT(FALSE);
785 #endif
786  }
787 
788  /* If we are parsing a PROTO, create a new protoFieldDecl.
789  If we are parsing a Script, create a new scriptFieldDecl. */
790  externproto = FALSE;
791  if(proto) {
792 #ifdef CPARSERVERBOSE
793  printf ("parser_interfaceDeclaration, calling newProtoFieldDecl\n");
794 #endif
795 
796  pdecl=newProtoFieldDecl(mode, type, name);
797  pdecl->cname = STRDUP(protoFieldDecl_getStringName(me->lexer, pdecl));
798  //pdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
799  externproto = proto->isExtern;
800 #ifdef CPARSERVERBOSE
801  printf ("parser_interfaceDeclaration, finished calling newProtoFieldDecl\n");
802 #endif
803  } else {
804 #ifdef CPARSERVERBOSE
805  printf ("parser_interfaceDeclaration, calling newScriptFieldDecl\n");
806 #endif
807  //lexer_stringUser_fieldName(me,name,mod)
808  sdecl=newScriptFieldDecl(me->lexer, mode, type, name);
809  //sdecl=newScriptFieldDecl(lexer_stringUser_fieldName(me->lexer,name,mod), mode, type, name);
810  //sdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
811 
812  }
813 
814 
815  /* If this is a field or an exposed field */
816  if((mode==PKW_initializeOnly || mode==PKW_inputOutput) ) {
817 #ifdef CPARSERVERBOSE
818  printf ("parser_interfaceDeclaration, mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
819 #endif
820  if(!externproto){
821 
822  /* Get the next token(s) from the lexer and store them in defaultVal as the appropriate type.
823  This is the default value for this field. */
824  if (script && lexer_keyword(me->lexer, KW_IS)) {
825  int fieldE;
826  int fieldO;
827  struct ScriptFieldInstanceInfo* sfield;
828 
829  /* Find the proto field that this field is mapped to */
830  if(!lexer_field(me->lexer, NULL, NULL, &fieldO, &fieldE))
831  PARSE_ERROR("Expected fieldId after IS!")
832 
833  if(fieldO!=ID_UNDEFINED)
834  {
835  /* Get the protoFieldDeclaration for the field at index fieldO */
836  pField=protoDefinition_getField(me->curPROTO, fieldO, PKW_initializeOnly);
837  if(!pField)
838  PARSE_ERROR("IS source is no field of current PROTO!")
839  ASSERT(pField->mode==PKW_initializeOnly);
840  } else {
841  /* If the field was found in user_inputOutputs */
842  ASSERT(fieldE!=ID_UNDEFINED);
843  /* Get the protoFieldDeclaration for the inputOutput at index fieldO */
844  pField=protoDefinition_getField(me->curPROTO, fieldE, PKW_inputOutput);
845  if(!pField)
846  PARSE_ERROR("IS source is no field of current PROTO!")
847  ASSERT(pField->mode==PKW_inputOutput);
848  }
849 
850  if (pField) {
851  /* Add this scriptfielddecl to the list of script fields mapped to this proto field */
852  sfield = newScriptFieldInstanceInfo(sdecl, script);
853  vector_pushBack(struct ScriptFieldInstanceInfo*, pField->scriptDests, sfield);
854  defaultVal = pField->defaultVal;
855  }
856 
857  } else {
858  /* else proto or script but not KW_IS */
859  startOfField = (char *)me->lexer->nextIn;
860  startOfFieldLexerLevel = me->lexer->lexerInputLevel;
861 
862  /* set the defaultVal to something - we might have a problem if the parser expects this to be
863  a MF*, and there is "garbage" in there, as it will expect to free it. */
864  bzero (&defaultVal, sizeof (union anyVrml));
865 
866  if (!parseType(me, type, &defaultVal)) {
867  /* Invalid default value parsed. Delete the proto or script declaration. */
868  CPARSE_ERROR_CURID("Expected default value for field!");
869  if(pdecl) deleteProtoFieldDecl(pdecl);
870  if(sdecl) deleteScriptFieldDecl(sdecl);
871  FREEUP
872  return FALSE;
873  }
874  }
875  }
876  /* Store the default field value in the protoFieldDeclaration or scriptFieldDecl structure */
877  if(proto) {
878  pdecl->defaultVal=defaultVal;
879  }
880  else
881  {
882  ASSERT(script);
883  scriptFieldDecl_setFieldValue(sdecl, defaultVal);
884  }
885  } else {
886 #ifdef CPARSERVERBOSE
887  printf ("parser_interfaceDeclaration, NOT mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
888 #endif
889 
890  /* If this is a Script inputOnly/outputOnly IS statement */
891  if (script && lexer_keyword(me->lexer, KW_IS)) {
892  int evE, evO;
893  struct ScriptFieldInstanceInfo* sfield;
894  BOOL isIn = FALSE, isOut = FALSE;
895 
896 #ifdef CPARSERVERBOSE
897  printf ("parser_interfaceDeclaration, got IS\n");
898 #endif
899 
900  /* Get the inputOnly or outputOnly that this field IS */
901  if (mode == PKW_inputOnly) {
902  if (lexer_inputOnly(me->lexer, NULL, NULL, NULL, &evO, &evE)) {
903  isIn = TRUE;
904  isOut = (evE != ID_UNDEFINED);
905  }
906  } else {
907  if (lexer_outputOnly(me->lexer, NULL, NULL, NULL, &evO, &evE)) {
908  isOut = TRUE;
909  }
910  }
911 
912  /* Check that the event was found somewhere ... */
913  if (!isIn && !isOut) {
914 #ifdef CPARSERVERBOSE
915  printf ("parser_interfaceDeclaration, NOT isIn Nor isOut\n");
916 #endif
917  FREEUP
918  return FALSE;
919  }
920 
921 
922  /* Get the Proto field definition for the field that this IS */
923  pField = protoDefinition_getField(me->curPROTO, evO, isIn ? PKW_inputOnly: PKW_outputOnly); /* can handle inputOnly, outputOnly */
924 
925  ASSERT(pField);
926 
927  /* Add this script as a destination for this proto field */
928  sfield = newScriptFieldInstanceInfo(sdecl, script);
929  if (pField) vector_pushBack(struct ScriptFieldInstanceInfo*, pField->scriptDests, sfield);
930  }
931  }
932 
933  /* Add the new field declaration to the list of fields in the Proto or Script definition.
934  For a PROTO, this means adding it to the iface vector of the ProtoDefinition.
935  For a Script, this means adding it to the fields vector of the ScriptDefinition. */
936  if(proto) {
937  /* protoDefinition_addIfaceField is #defined as vector_pushBack(struct ProtoFieldDecl*, (me)->iface, field) */
938  /* Add the protoFieldDecl structure to the iface vector of the protoDefinition structure */
939 
940  /* copy the ASCII text over and save it as part of the field */
941  if (startOfField != NULL) {
942  if (startOfFieldLexerLevel == me->lexer->lexerInputLevel) {
943 
944  size_t sz = (size_t) ((me->lexer->nextIn)-startOfField);
945  /* printf ("non-recursive PROTO interface copy, string size is %d\n", sz); */
946 
947  FREE_IF_NZ(pdecl->fieldString);
948  pdecl->fieldString = MALLOC (char *, sz + 2);
949  if (NULL != pdecl->fieldString)
950  {
951  strncpy(pdecl->fieldString,startOfField,sz);
952  pdecl->fieldString[sz]='\0';
953  }
954  } else {
955  int i;
956  size_t sz;
957  char *curStrPtr;
958 
959  /* we had a PROTO field come in here; this gets difficult as we have to get different
960  lexer levels, not do simple "from here to here" string math */
961 
962  /* this is what happens:
963  me->lexerInputLevel ++;
964  me->startOfStringPtr[me->lexerInputLevel]=str;
965  me->oldNextIn[me->lexerInputLevel] = me->nextIn;
966  me->nextIn=str;
967  */
968 
969  /* the "original" level contains a PROTO call; we skip this one, but the
970  following code will show how to get it if you wish
971  sz = (size_t) (me->lexer->oldNextIn[startOfFieldLexerLevel+1] - startOfField);
972  printf ("complex recursive copy of PROTO invocation fields\n");
973  printf ("for level %d, size is %d\n",startOfFieldLexerLevel, sz);
974  */
975 
976  /* we start off with a string of zero length */
977  sz = 0;
978 
979  /* we go through any intermediate layers */
980  for (i=startOfFieldLexerLevel+1; i<me->lexer->lexerInputLevel; i++) {
981  printf ("CAUTION: unverified code in recursive PROTO invocations in classic VRML parser\n");
982  printf ("level %d\n",i);
983  printf ("size of this level, %d\n",(int) (me->lexer->oldNextIn[i+1] - me->lexer->startOfStringPtr[i]));
984  sz += (size_t) (me->lexer->oldNextIn[i+1] - me->lexer->startOfStringPtr[i]);
985 
986  }
987  /* printf ("final level, size %d\n",(int)(me->lexer->nextIn - me->lexer->startOfStringPtr[me->lexer->lexerInputLevel])); */
988  sz += (size_t)(me->lexer->nextIn - me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]);
989 
990  /* for good luck, and for the trailing null... */
991  sz += 2;
992 
993  /* now, copy over the "stuff" */
994 
995  FREE_IF_NZ(pdecl->fieldString);
996  pdecl->fieldString = MALLOC(char *, sz);
997  curStrPtr = pdecl->fieldString;
998 
999  /* now, copy the actual strings... */
1000  /* first layer */
1001  /* if we copy this, we will get the PROTO invocation, so we skip this one
1002  sz = (size_t) (me->lexer->oldNextIn[startOfFieldLexerLevel+1] - startOfField);
1003  strncpy(curStrPtr, startOfField, sz);
1004  curStrPtr += sz;
1005  curStrPtr[1] = '\0';
1006  printf ("first layer, we have %d len in copied string\n",strlen(pdecl->fieldString));
1007  printf ("and, it results in :%s:\n",pdecl->fieldString);
1008  */
1009 
1010  /* and, the intermediate layers... */
1011  for (i=startOfFieldLexerLevel+1; i<me->lexer->lexerInputLevel; i++) {
1012  sz = (size_t) (me->lexer->oldNextIn[i+1] - me->lexer->startOfStringPtr[i]);
1013  strncpy(curStrPtr,me->lexer->startOfStringPtr[i],sz);
1014  curStrPtr += sz;
1015  }
1016 
1017  /* and the final level */
1018  sz = (size_t)(me->lexer->nextIn - me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]);
1019  strncpy(curStrPtr,me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],sz);
1020  curStrPtr += sz;
1021 
1022  /* trailing null */
1023  //curStrPtr ++; dug9 dec6,2012 I found this was letting 1 char of junk into the string
1024  *curStrPtr = '\0';
1025  }
1026  }
1027  #ifdef CPARSERVERBOSE
1028  printf ("pdecl->fieldString is :%s:\n",pdecl->fieldString);
1029  #endif
1030 
1031  protoDefinition_addIfaceField(proto, pdecl);
1032  } else {
1033  /* Add the scriptFieldDecl structure to the fields vector of the Script structure */
1034  ASSERT(script);
1035  script_addField(script, sdecl);
1036  }
1037 
1038  #ifdef CPARSERVERBOSE
1039  printf ("end of parser_interfaceDeclaration\n");
1040  #endif
1041  FREEUP
1042  return TRUE;
1043 }
1044 
1045 //#include "broto2.h"
1046 
1047 
1048 /* Parses a protoStatement */
1049 /* Adds the PROTO name to the userNodeTypesVec list of names.
1050  Creates a new protoDefinition structure and adds it to the PROTOs list.
1051  Goes through the interface declarations for the PROTO and adds each user-defined field name to the appropriate list of user-defined names (user_initializeOnly,
1052  user_inputOnly, user_outputOnly, or user_inputOutput), creates a new protoFieldDecl for the field and adds it to the iface vector of the ProtoDefinition,
1053  and, in the case of fields and inputOutputs, gets the default value of the field and stores it in the protoFieldDecl.
1054  Parses the body of the PROTO. Nodes are added to the scene graph for this PROTO. Routes are parsed and a new ProtoRoute structure
1055  is created for each one and added to the routes vector of the ProtoDefinition. PROTOs are recursively parsed!
1056 */
1057 
1058 static BOOL parser_componentStatement(struct VRMLParser* me) {
1059  char *cname, *clevel;
1060  char cfullname[200];
1061  int myComponent = INT_ID_UNDEFINED;
1062  int myLevel = INT_ID_UNDEFINED;
1063 
1064 #if DJ_KEEP_COMPILER_WARNING
1065 #define COMPSTRINGSIZE 20
1066 #endif
1067 
1068  ASSERT(me->lexer);
1069  lexer_skip(me->lexer);
1070 
1071  /* Is this a COMPONENT statement? */
1072  if(!lexer_keyword(me->lexer, KW_COMPONENT)) return FALSE;
1073 
1074 #ifdef CPARSERVERBOSE
1075  printf ("parser_componentStatement...\n");
1076 #endif
1077 
1078  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS a COMPONENT statement */
1079  ASSERT(me->lexer->curID);
1080 
1081  //Feb 2016 Core:2 will be all one string now, thanks to allowing : in identifiers Sept 2015
1082  {
1083  //new way to handle 'Core:2' chunk
1084  int i;
1085  strcpy(cfullname,me->lexer->curID);
1086  /* now, we are finished with this COMPONENT */
1087  FREE_IF_NZ(me->lexer->curID);
1088 
1089  cname = cfullname;
1090  clevel = NULL;
1091  for(i=0;i<strlen(cfullname);i++)
1092  if(cfullname[i] == ':'){
1093  cfullname[i] = '\0';
1094  clevel = &cfullname[i+1];
1095  break;
1096  }
1097  myComponent = findFieldInCOMPONENTS(cname);
1098  myLevel = 0;
1099  if(clevel) myLevel = atoi(clevel);
1100  }
1101  handleComponent(myComponent,myLevel);
1102 
1103  return TRUE;
1104 }
1105 
1106 
1107 struct X3D_Proto *hasContext(struct X3D_Node* node){
1108  //returns non-null if this node type has a web3d executionContext
1109  //for us that's one of 2 (equivalent) types in our system:
1110  // X3D_Proto -used by ProtoInstance, ExternProtoInstance, Scene, libraryScene, ProtoDeclare, ExternProtoDeclare
1111  // X3D_Inline
1112  struct X3D_Proto * context = NULL;
1113  if(node)
1114  switch(node->_nodeType){
1115  case NODE_Proto:
1116  context = (struct X3D_Proto*)node; //offsetPointer_deref(void*, node, offsetof(struct X3D_Proto,__context));
1117  break;
1118  case NODE_Inline:
1119  context = (struct X3D_Proto*)node; // offsetPointer_deref(void*, node, offsetof(struct X3D_Inline,__context));
1120  break;
1121  }
1122  return context;
1123 }
1124 struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name);
1125 
1126 void handleExport_B (void *ctxnodeptr, char *nodename, char *as) {
1127  /* handle export statements. as will be either a string pointer, or NULL */
1128  struct X3D_Proto *context = hasContext(ctxnodeptr);
1129  if(context){
1130  struct X3D_Node *node = NULL;
1131  struct IMEXPORT *mxport = MALLOCV(sizeof(struct IMEXPORT));
1132  if(!context->__EXPORTS) context->__EXPORTS = newVector(struct IMEXPORT *,4);
1133  mxport->mxname = STRDUP(nodename);
1134  mxport->as = mxport->mxname;
1135  if(as)
1136  mxport->as = STRDUP(as);
1137  node = broto_search_DEFname(context,mxport->mxname);
1138  mxport->nodeptr = node;
1139  vector_pushBack(struct IMEXPORT*,context->__EXPORTS,mxport);
1140  }
1141  #ifdef CAPABILITIESVERBOSE
1142  printf ("handleExport: node :%s: ",node);
1143  if (as != NULL) printf (" AS :%s: ",node);
1144  printf ("\n");
1145  #endif
1146 }
1147 
1148 
1149 void handleImport_B (struct X3D_Node *nodeptr, char *nodeName,char *nodeImport, char *as) {
1150  /* handle Import statements. as will be either a string pointer, or NULL
1151  nodename - name of Inline node
1152  nodeImport - name of inline's node we expect Inline to export to us
1153  as - our execution context/scene's DEF name / alias - can be null in which case use nodeImport
1154  */
1155  struct X3D_Proto *context = hasContext(nodeptr);
1156  if(context){
1157  struct IMEXPORT *mxport = MALLOCV(sizeof(struct IMEXPORT));
1158  if(!context->__IMPORTS) context->__IMPORTS = newVector(struct IMEXPORT *,4);
1159  mxport->mxname = STRDUP(nodeImport);
1160  mxport->inlinename = STRDUP(nodeName);
1161  mxport->as = mxport->mxname;
1162  if(as)
1163  mxport->as = STRDUP(as);
1164  mxport->nodeptr = NULL; //IMPORT doesn't use this. Import is a char* mapping only.
1165  vector_pushBack(struct IMEXPORT*,context->__IMPORTS,mxport);
1166  }
1167 
1168  #ifdef CAPABILITIESVERBOSE
1169  printf ("handleImport: inlineNodeName :%s: nodeToImport :%s:",nodeName, nodeImport);
1170  if (as != NULL) printf (" AS :%s: ",as);
1171  printf ("\n");
1172  #endif
1173 }
1174 
1175 static BOOL parser_exportStatement(struct VRMLParser* me) {
1176  char *nodeToExport = NULL;
1177  char *alias = NULL;
1178 
1179  ASSERT(me->lexer);
1180  lexer_skip(me->lexer);
1181 
1182  /* Is this a EXPORT statement? */
1183  if(!lexer_keyword(me->lexer, KW_EXPORT)) return FALSE;
1184 
1185 #ifdef CPARSERVERBOSE
1186  printf ("parser_exportStatement...\n");
1187 #endif
1188 
1189  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an EXPORT statement... */
1190  ASSERT(me->lexer->curID);
1191 
1192  /* save this, and find the next token... */
1193  nodeToExport = me->lexer->curID;
1194  me->lexer->curID = NULL;
1195 
1196  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an EXPORT statement...*/
1197  ASSERT(me->lexer->curID);
1198 
1199  /* do we have an "AS" statement? */
1200  if (strcmp("AS",me->lexer->curID) == 0) {
1201  FREE_IF_NZ(me->lexer->curID);
1202  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an EXPORT statement...*/
1203  ASSERT(me->lexer->curID);
1204  alias = me->lexer->curID;
1205  }
1206 
1207  /* do the EXPORT */
1208  handleExport_B(me->ectx,nodeToExport, alias);
1209 
1210  /* free things up, only as required */
1211  FREE_IF_NZ(nodeToExport);
1212  if (alias != NULL) {FREE_IF_NZ(me->lexer->curID);}
1213  return TRUE;
1214 }
1215 
1216 static BOOL parser_importStatement(struct VRMLParser* me) {
1217  char *inlineNodeName = NULL;
1218  char *alias = NULL;
1219  char *nodeToImport = NULL;
1220 
1221  ASSERT(me->lexer);
1222  lexer_skip(me->lexer);
1223 
1224  /* Is this a IMPORT statement? */
1225  if(!lexer_keyword(me->lexer, KW_IMPORT)) return FALSE;
1226 
1227 #ifdef CPARSERVERBOSE
1228  printf ("parser_importStatement...\n");
1229 #endif
1230 
1231  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an IMPORT statement... */
1232  ASSERT(me->lexer->curID);
1233 
1234  /* save this, and find the next token... */
1235  inlineNodeName = STRDUP(me->lexer->curID);
1236  FREE_IF_NZ(me->lexer->curID);
1237 
1238  /* we should have a "." then an integer supportLevel */
1239  if (!lexer_point(me->lexer)) {
1240  CPARSE_ERROR_CURID("expected period in IMPORT statement")
1241  return TRUE;
1242  }
1243 
1244  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an IMPORT statement... */
1245  ASSERT(me->lexer->curID);
1246 
1247  /* ok, now, we should have the nodeToImport name... */
1248  nodeToImport = STRDUP(me->lexer->curID);
1249  FREE_IF_NZ(me->lexer->curID);
1250 
1251  /* get the next token */
1252  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an IMPORT statement...*/
1253  ASSERT(me->lexer->curID);
1254 
1255  /* do we have an "AS" statement? */
1256  if (strcmp("AS",me->lexer->curID) == 0) {
1257  FREE_IF_NZ(me->lexer->curID);
1258  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is an IMPORT statement...*/
1259  ASSERT(me->lexer->curID);
1260  alias = STRDUP(me->lexer->curID);
1261  FREE_IF_NZ(me->lexer->curID);
1262  }
1263 
1264  /* do the IMPORT */
1265  handleImport_B(me->ectx,inlineNodeName, nodeToImport, alias);
1266 
1267  FREE_IF_NZ (inlineNodeName);
1268  FREE_IF_NZ (nodeToImport);
1269  FREE_IF_NZ (alias);
1270  return TRUE;
1271 }
1272 static BOOL parser_metaStatement(struct VRMLParser* me) {
1273  vrmlStringT val1, val2;
1274 
1275  ASSERT(me->lexer);
1276  lexer_skip(me->lexer);
1277 
1278  /* Is this a META statement? */
1279  if(!lexer_keyword(me->lexer, KW_META)) return FALSE;
1280 
1281 #ifdef CPARSERVERBOSE
1282  printf ("parser_metaStatement...\n");
1283 #endif
1284 
1285  /* META lines have 2 strings */
1286 
1287  /* Otherwise, a real vector */
1288  val1=NULL; val2 = NULL;
1289 
1290  if(!parser_sfstringValue (me, &val1)) {
1291  CPARSE_ERROR_CURID("Expected a string after a META keyword")
1292  }
1293 
1294  if(!parser_sfstringValue (me, &val2)) {
1295  CPARSE_ERROR_CURID("Expected a string after a META keyword")
1296  }
1297 
1298  if ((val1 != NULL) && (val2 != NULL)) { handleMetaDataStringString(val1,val2); }
1299 
1300  /* cleanup */
1301  if (val1 != NULL) {FREE_IF_NZ(val1->strptr); FREE_IF_NZ(val1);}
1302  if (val2 != NULL) {FREE_IF_NZ(val2->strptr); FREE_IF_NZ(val2);}
1303  return TRUE;
1304 }
1305 static BOOL parser_unitStatement(struct VRMLParser* me) {
1306  // vrmlStringT val1, val2; //, val3;
1307  double conversionfactor;
1308  char *categoryname = NULL;
1309  char *unitname = NULL;
1310 
1311 
1312  ASSERT(me->lexer);
1313  lexer_skip(me->lexer);
1314 
1315  /* Is this a UNIT statement? */
1316  if(!lexer_keyword(me->lexer, KW_UNIT)) return FALSE;
1317 
1318 #ifdef CPARSERVERBOSE
1319  printf ("parser_unitStatement...\n");
1320 #endif
1321 
1322  /* UNIT lines have 2 IDs and a double */
1323 
1324  /* Otherwise, a real vector */
1325  categoryname=NULL; unitname = NULL; conversionfactor = 0.0; //val3 = NULL;
1326 
1327  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is a UNIT statement...*/
1328  ASSERT(me->lexer->curID);
1329 
1330  categoryname = STRDUP(me->lexer->curID);
1331  FREE_IF_NZ(me->lexer->curID);
1332 
1333  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this Is a UNIT statement...*/
1334  ASSERT(me->lexer->curID);
1335 
1336  unitname = STRDUP(me->lexer->curID);
1337  FREE_IF_NZ(me->lexer->curID);
1338 
1339  if(!parser_sftimeValue(me,&conversionfactor)) {
1340  CPARSE_ERROR_CURID("Expected a numeric string after a UNIT keyword")
1341  }
1342 
1343  if ((categoryname != NULL) && (unitname != NULL) && (conversionfactor != 0.0)) {
1344  handleUnitDataStringString(categoryname,unitname,conversionfactor);
1345  }
1346 
1347  /* cleanup */
1348  if (categoryname != NULL) FREE_IF_NZ(categoryname);
1349  if (unitname != NULL) FREE_IF_NZ(unitname);
1350  return TRUE;
1351 }
1352 
1353 
1354 static BOOL parser_profileStatement(struct VRMLParser* me) {
1355  int myProfile = INT_ID_UNDEFINED;
1356 
1357  ASSERT(me->lexer);
1358  lexer_skip(me->lexer);
1359 
1360  /* Is this a PROFILE statement? */
1361  if(!lexer_keyword(me->lexer, KW_PROFILE)) return FALSE;
1362 
1363 #ifdef CPARSERVERBOSE
1364  printf ("parser_profileStatement...\n");
1365 #endif
1366 
1367  if(!lexer_setCurID(me->lexer)) return TRUE; /* true, because this IS an PROFILE statement... */
1368  ASSERT(me->lexer->curID);
1369 
1370  myProfile = findFieldInPROFILES(me->lexer->curID);
1371 
1372  if (myProfile != ID_UNDEFINED) {
1373  handleProfile(myProfile);
1374  } else {
1375  CPARSE_ERROR_CURID("Expected a profile after a PROFILE keyword")
1376  return TRUE;
1377  }
1378 
1379  /* XXX FIXME - do something with the Profile statement */
1380 #ifdef CPARSERVERBOSE
1381  printf ("my profile is %d\n",myProfile);
1382 #endif
1383  /* now, we are finished with this PROFILE */
1384  FREE_IF_NZ(me->lexer->curID);
1385  return TRUE;
1386 }
1387 //#include "broto4.h"
1388 
1389 
1390 
1391 
1392 //#include "broto5.h"
1393 static BOOL parser_routeStatement_B(struct VRMLParser* me);
1394 
1395 static BOOL parser_routeStatement(struct VRMLParser* me)
1396 {
1397  return parser_routeStatement_B(me);
1398 }
1399 
1400 /* Register a ROUTE here */
1401 /* If we are in a PROTO add a new ProtoRoute structure to the vector ProtoDefinition->routes */
1402 /* Otherwise, add the ROUTE to the routing table CRoutes */
1403 void parser_registerRoute(struct VRMLParser* me,
1404  struct X3D_Node* fromNode, int fromOfs,
1405  struct X3D_Node* toNode, int toOfs,
1406  int ft)
1407 {
1408  ASSERT(me);
1409  if ((fromOfs == ID_UNDEFINED) || (toOfs == ID_UNDEFINED)) {
1410  ConsoleMessage ("problem registering route - either fromField or toField invalid");
1411  } else {
1412  CRoutes_RegisterSimple(fromNode, fromOfs, toNode, toOfs, ft);
1413  }
1414 }
1415 //#include "broto6.h"
1416 
1417 /* parse a DEF statement. Return a pointer to a vrmlNodeT */
1418 static vrmlNodeT parse_KW_DEF(struct VRMLParser *me) {
1419  int ind = ID_UNDEFINED;
1420  vrmlNodeT node;
1421 
1422  /* lexer_defineNodeName is #defined as lexer_defineID(me, ret, stack_top(struct Vector*, userNodeNames), TRUE) */
1423  /* Checks if this node already exists in the userNodeNames vector. If it doesn't, adds it. */
1424  if(!lexer_defineNodeName(me->lexer, &ind))
1425  PARSE_ERROR("Expected nodeNameId after DEF!\n")
1426  ASSERT(ind!=ID_UNDEFINED);
1427 
1428 
1429  /* If the DEFedNodes stack has not already been created. If not, create new stack and add an X3D_Nodes vector to that stack */
1430  if(!me->DEFedNodes || stack_empty(me->DEFedNodes)) {
1431  /* printf ("parsing KW_DEF, creating new Vectors...\n"); */
1432  parser_scopeIn_DEFUSE(me);
1433  }
1434  ASSERT(me->DEFedNodes);
1435  ASSERT(!stack_empty(me->DEFedNodes));
1436 
1437  /* Did we just add the name to the userNodeNames vector? If so, then the node hasn't yet been
1438  added to the DEFedNodes vector, so add it */
1439  ASSERT(ind<=vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
1440  if(ind==vectorSize(stack_top(struct Vector*, me->DEFedNodes))) {
1441  vector_pushBack(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), NULL);
1442  }
1443  ASSERT(ind<vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
1444 
1445 
1446  /* Parse this node. Create an X3D_Node structure of the appropriate type for this node
1447  and fill in the values for the fields specified.
1448  Add any routes to the CRoutes table. Add any PROTOs to the PROTOs vector */
1449 #ifdef CPARSERVERBOSE
1450  printf("parser_KW_DEF: parsing DEFed node \n");
1451 #endif
1452  if(!parser_node(me, &node,ind)) {
1453  /* PARSE_ERROR("Expected node in DEF statement!\n") */
1454  /* try to make a better error message. */
1455  CPARSE_ERROR_CURID("ERROR:Expected an X3D node in a DEF statement, got \"");
1456  PARSER_FINALLY;
1457  return NULL;
1458  }
1459 #ifdef CPARSERVERBOSE
1460  printf("parser_KW_DEF: DEFed node successfully parsed\n");
1461 #endif
1462 
1463  /* Return a pointer to the node in the variable ret */
1464  return (vrmlNodeT) vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind);
1465 }
1466 
1467 
1468 
1469 /* parse a USE statement. Return a pointer to a vrmlNodeT */
1470 static vrmlNodeT parse_KW_USE(struct VRMLParser *me) {
1471  int ind;
1472 
1473  /* lexer_nodeName is #defined as
1474  lexer_specialID(me, NULL, ret, NULL, 0, stack_top(struct Vector*, userNodeNames)) */
1475  /* Look for the nodename in list of user-defined node names (userNodeNames) and return the index in ret */
1476  if(!lexer_nodeName(me->lexer, &ind)) {
1477  CPARSE_ERROR_CURID("ERROR:Expected valid DEF name after USE; found: ");
1478  FREE_IF_NZ(me->lexer->curID);
1479  return NULL;
1480  }
1481 #ifdef CPARSERVERBOSE
1482  printf("parser_KW_USE: parsing USE\n");
1483 #endif
1484 
1485  /* If we're USEing it, it has to already be defined. */
1486  ASSERT(ind!=ID_UNDEFINED);
1487 
1488  /* It also has to be in the DEFedNodes stack */
1489  ASSERT(me->DEFedNodes && !stack_empty(me->DEFedNodes) &&
1490  ind<vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
1491 
1492  #ifdef CPARSERVERBOSE
1493  printf ("parser_KW_USE, returning vector %u\n", vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind));
1494  #endif
1495 
1496  /* Get a pointer to the X3D_Node structure for this DEFed node and return it in ret */
1497  return (vrmlNodeT) vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind);
1498 }
1499 
1500 
1501 
1502 /* Parses a node (node non-terminal) */
1503 /* Looks up the node type on the builtin NODES list and the userNodeNames list.
1504  If this is a builtin node type, creates a new X3D_Node structure of the appropriate type for the node, and then parses the statements for that node.
1505  For each field statement, gets the value for that field and stores it in the X3D_Node structure.
1506  For each ROUTE statement, adds the route to the CRoutes table.
1507  For each PROTO statement, adds the PROTO definition to te PROTOs list.
1508  Return a pointer to the X3D_Node structure that holds the information for this node.
1509  If this is a user-defined node type (i.e. a PROTO expansion), complete the proto expansion.
1510  For each field in the ProtoDefinition either parse and propagate the specified value for this field, or
1511  propagate the default value of the field. (i.e. copy the appropriate value into every node/field combination in
1512  the dests list.)
1513  For each route in the routes list of the ProtoDefinition, add the route to the CRoutes table.
1514  Return a pointer to the X3D_Node structure that is the scenegraph for this PROTO.
1515 */
1516 /* Specific initialization of node fields */
1517 void push_binding_stack_set(struct X3D_Node* layersetnode);
1518 void push_next_layerId_from_binding_stack_set(struct X3D_Node *layer);
1519 void pop_binding_stack_set();
1520 
1521 static BOOL parser_nodeStatement(struct VRMLParser* me, vrmlNodeT* ret)
1522 {
1523  ASSERT(me->lexer);
1524 
1525  /* A DEF-statement? */
1526  if(lexer_keyword(me->lexer, KW_DEF)) {
1527  //vrmlNodeT * node = ret;
1528  //*node = parse_KW_DEF(me);
1529  *ret = parse_KW_DEF(me);
1530  return TRUE;
1531  }
1532 
1533  /* A USE-statement? */
1534  if(lexer_keyword(me->lexer, KW_USE)) {
1535  *ret= parse_KW_USE(me);
1536  return TRUE;
1537  }
1538 
1539  /* Otherwise, simply a node. */
1540  return parser_node(me, ret, ID_UNDEFINED);
1541 }
1542 //#include "broto7.h"
1543 
1544 
1545 
1546 /* add_parent for Multi_Node */
1547 void mfnode_add_parent(struct Multi_Node* node, struct X3D_Node* parent)
1548 {
1549  int i;
1550  for(i=0; i!=node->n; ++i) {
1551  ADD_PARENT(node->p[i], parent);
1552  }
1553 }
1554 
1555 
1556 /* Parses a field value (literally or IS) */
1557 /* Gets the actual value of a field and stores it in a node, or, for an IS statement, adds this node and field as a destination to the appropriate protoFieldDecl */
1558 /* Passed pointer to the parser, an offsetPointer structure pointing to the current node and an offset to the field being parsed, type of the event value (i.e. MFString) index in FIELDTYPES, */
1559 /* index of the field in the FIELDNAMES (or equivalent) array */
1560 /* Parses a field value of a certain type (literally or IS) */
1561 void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr);
1562 static BOOL parser_fieldValue(struct VRMLParser* me, struct X3D_Node *node, int offs,
1563  int type, int origFieldE, BOOL protoExpansion, struct ProtoDefinition* pdef, struct ProtoFieldDecl* origField)
1564 {
1565 #undef PARSER_FINALLY
1566 #define PARSER_FINALLY
1567 
1568 #ifdef CPARSERVERBOSE
1569  printf ("start of parser_fieldValue\n");
1570  printf ("me->curPROTO = %u\n",me->curPROTO);
1571 #endif
1572 
1573  {
1574 #ifdef CPARSERVERBOSE
1575  printf ("parser_fieldValue, not an IS\n");
1576 #endif
1577  /* Get a pointer to the actual field */
1578 #define myOffsetPointer_deref(t, me) \
1579  ((t)(((char*)(node))+offs))
1580 
1581  void* directRet=myOffsetPointer_deref(void*, ret);
1582  deleteMallocedFieldValue(type,directRet);
1583  /* we could print out a type, as shown below for the first element of a Multi_Color:
1584  { struct Multi_Color * mc;
1585  mc = (struct Multi_Color *) directRet;
1586  printf ("directret n is %d\n",mc->n);
1587 
1588  printf ("directret orig is %u, %f %f %f\n",
1589  mc->p,
1590  mc->p[0].c[0],
1591  mc->p[0].c[1],
1592  mc->p[0].c[2]);
1593  }
1594  */
1595 
1596  PARSER_FINALLY;
1597  #ifdef CPARSERVERBOSE
1598  printf ("parser_fieldValue, me %u, directRet %u\n",me,directRet);
1599  #endif
1600 
1601  /* Get the actual value from the file (next token from lexer) and store it as the appropriate type in the node */
1602  return PARSE_TYPE[type](me, directRet);
1603  }
1604 
1605 #undef PARSER_FINALLY
1606 #define PARSER_FINALLY
1607 }
1608 
1609 
1610 /* Specific initialization of node fields */
1611 void parser_specificInitNode_B(struct X3D_Node* n, struct VRMLParser* me)
1612 {
1613 #define NODE_SPECIFIC_INIT(type, code) \
1614  case NODE_##type: \
1615  { \
1616  struct X3D_##type* node=(struct X3D_##type*)n; \
1617  code \
1618  break; \
1619  }
1620 
1621  switch(n->_nodeType)
1622  {
1623  /* Scripts get a script object associated to them */
1624  NODE_SPECIFIC_INIT(Script, node->__scriptObj=new_Shader_ScriptB(X3D_NODE(node));)
1625  NODE_SPECIFIC_INIT(ShaderProgram, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1626  NODE_SPECIFIC_INIT(PackagedShader, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1627  NODE_SPECIFIC_INIT(ComposedShader, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1628  NODE_SPECIFIC_INIT(Effect, node->_shaderUserDefinedFields=X3D_NODE(new_Shader_ScriptB(X3D_NODE(node)));)
1629  }
1630 }
1631 
1632 /* ************************************************************************** */
1633 /* Built-in fields */
1634 /* Parses a built-in field and sets it in node */
1635 
1636 
1637 /* The init codes used. */
1638 #define INIT_CODE_sfnode(var) \
1639  ADD_PARENT(node2->var, X3D_NODE(node2));
1640 #define INIT_CODE_mfnode(var) \
1641  mfnode_add_parent(&node2->var, X3D_NODE(node2));
1642 #define INIT_CODE_sfbool(var)
1643 #define INIT_CODE_sfcolor(var)
1644 #define INIT_CODE_sfcolorrgba(var)
1645 #define INIT_CODE_sffloat(var)
1646 #define INIT_CODE_sfimage(var)
1647 #define INIT_CODE_sfint32(var)
1648 #define INIT_CODE_sfrotation(var)
1649 #define INIT_CODE_sfstring(var)
1650 #define INIT_CODE_sftime(var)
1651 #define INIT_CODE_sfvec2f(var)
1652 #define INIT_CODE_sfvec3f(var)
1653 #define INIT_CODE_sfvec3d(var)
1654 #define INIT_CODE_mfbool(var)
1655 #define INIT_CODE_mfcolor(var)
1656 #define INIT_CODE_mfcolorrgba(var)
1657 #define INIT_CODE_mffloat(var)
1658 #define INIT_CODE_mfint32(var)
1659 #define INIT_CODE_mfrotation(var)
1660 #define INIT_CODE_mfstring(var)
1661 #define INIT_CODE_mftime(var)
1662 #define INIT_CODE_mfvec2f(var)
1663 #define INIT_CODE_mfvec3f(var)
1664 #define INIT_CODE_mfvec3d(var)
1665 #define INIT_CODE_sfdouble(var)
1666 #define INIT_CODE_mfdouble(var)
1667 #define INIT_CODE_sfvec4d(var)
1668 #define INIT_CODE_mfmatrix3f(var)
1669 #define INIT_CODE_mfmatrix4f(var)
1670 
1671 #define INIT_CODE_mfmatrix3d(var)
1672 #define INIT_CODE_mfmatrix4d(var)
1673 #define INIT_CODE_mfvec2d(var)
1674 #define INIT_CODE_mfvec4d(var)
1675 #define INIT_CODE_mfvec4f(var)
1676 #define INIT_CODE_sfmatrix3d(var)
1677 #define INIT_CODE_sfmatrix3f(var)
1678 #define INIT_CODE_sfmatrix4d(var)
1679 #define INIT_CODE_sfmatrix4f(var)
1680 #define INIT_CODE_sfvec2d(var)
1681 #define INIT_CODE_sfvec4f(var)
1682 
1683 /* Parses a fieldvalue for a built-in field and sets it in node */
1684 static BOOL parser_field_B(struct VRMLParser* me, struct X3D_Node* node)
1685 {
1686  int fieldO;
1687  int fieldE;
1688  //BOOL retval;
1689  DECLAREUP
1690  ASSERT(me->lexer);
1691 
1692  /* printf ("start of parser_field, me->lexer->nextIn :%s:\n",me->lexer->nextIn); */
1693 
1694  /* Ask the lexer to find the field (next lexer token) in either the FIELDNAMES array or
1695  the EXPOSED_FIELD array. The index of the field in the array is returned in fieldO
1696  (if found in FIELDNAMES) or fieldE (if found in EXPOSED_FIELD).
1697  If the fieldname is found in neither array, lexer_field will return FALSE. */
1698  SAVEUP
1699 
1700  if(!lexer_field(me->lexer, &fieldO, &fieldE, NULL, NULL))
1701  {
1702  /* If lexer_field does return false, this is an inputOnly/outputOnly IS user_definedField statement.
1703  Add a Offset_Pointer structure to the dests list for the protoFieldDecl for
1704  the user defined field. The Offset_Pointer structure contains a pointer to the node currently
1705  being parsed along with an offset that references the field that is linked to the
1706  user defined field.
1707 
1708  i.e. for a statement "rotation IS myrot" the protoFieldDecl for myrot is retrieved,
1709  and an Offset_Pointer structure is added to the dests list which contains a pointer
1710  to the current node and the offset for the "rotation" field in that node.
1711 
1712  If we've done all this, then we've parsed the field statement completely, and we return. */
1713  BACKUP
1714  return FALSE;
1715  }
1716  FREEUP
1717  /* Ignore all events */
1718 #define EVENT_IN(n, f, t, v, realType)
1719 #define EVENT_OUT(n, f, t, v, realType)
1720 
1721  /* End of node is the same for fields and inputOutputs */
1722 #define END_NODE(type) \
1723  } \
1724  } \
1725  break;
1726 
1727 /* The field type indices */
1728 #define FTIND_sfnode FIELDTYPE_SFNode
1729 #define FTIND_sfbool FIELDTYPE_SFBool
1730 #define FTIND_sfcolor FIELDTYPE_SFColor
1731 #define FTIND_sfcolorrgba FIELDTYPE_SFColorRGBA
1732 #define FTIND_sffloat FIELDTYPE_SFFloat
1733 #define FTIND_sfimage FIELDTYPE_SFImage
1734 #define FTIND_sfint32 FIELDTYPE_SFInt32
1735 #define FTIND_sfrotation FIELDTYPE_SFRotation
1736 #define FTIND_sfstring FIELDTYPE_SFString
1737 #define FTIND_sftime FIELDTYPE_SFTime
1738 #define FTIND_sfdouble FIELDTYPE_SFDouble
1739 #define FTIND_sfvec2f FIELDTYPE_SFVec2f
1740 #define FTIND_sfvec2d FIELDTYPE_SFVec2d
1741 #define FTIND_sfvec3f FIELDTYPE_SFVec3f
1742 #define FTIND_sfvec3d FIELDTYPE_SFVec3d
1743 #define FTIND_sfvec4f FIELDTYPE_SFVec4f
1744 #define FTIND_sfvec4d FIELDTYPE_SFVec4d
1745 #define FTIND_sfmatrix3f FIELDTYPE_SFMatrix3f
1746 #define FTIND_sfmatrix4f FIELDTYPE_SFMatrix4f
1747 #define FTIND_sfmatrix3d FIELDTYPE_SFMatrix3d
1748 #define FTIND_sfmatrix4d FIELDTYPE_SFMatrix4d
1749 
1750 #define FTIND_mfnode FIELDTYPE_MFNode
1751 #define FTIND_mfbool FIELDTYPE_MFBool
1752 #define FTIND_mfcolor FIELDTYPE_MFColor
1753 #define FTIND_mfcolorrgba FIELDTYPE_MFColorRGBA
1754 #define FTIND_mffloat FIELDTYPE_MFFloat
1755 #define FTIND_mfint32 FIELDTYPE_MFInt32
1756 #define FTIND_mfrotation FIELDTYPE_MFRotation
1757 #define FTIND_mfstring FIELDTYPE_MFString
1758 #define FTIND_mftime FIELDTYPE_MFTime
1759 #define FTIND_mfvec2f FIELDTYPE_MFVec2f
1760 #define FTIND_mfvec2d FIELDTYPE_MFVec2d
1761 #define FTIND_mfvec3f FIELDTYPE_MFVec3f
1762 #define FTIND_mfvec3d FIELDTYPE_MFVec3d
1763 #define FTIND_mfvec4d FIELDTYPE_MFVec4d
1764 #define FTIND_mfvec4f FIELDTYPE_MFVec4f
1765 #define FTIND_mfdouble FIELDTYPE_MFDouble
1766 #define FTIND_mfmatrix3f FIELDTYPE_MFMatrix3f
1767 #define FTIND_mfmatrix4f FIELDTYPE_MFMatrix4f
1768 #define FTIND_mfmatrix3d FIELDTYPE_MFMatrix3d
1769 #define FTIND_mfmatrix4d FIELDTYPE_MFMatrix4d
1770 
1771 /* Process a field (either exposed or ordinary) generally */
1772 /* For a normal "field value" (i.e. position 1 0 1) statement gets the actual value of the field
1773  from the file (next token(s) to be processed) and stores it in the node
1774  For an IS statement, adds this node-field combo as a destination to the appropriate protoFieldDecl */
1775 #define PROCESS_FIELD_B(exposed, node, field, fieldType, var, fe) \
1776  case exposed##FIELD_##field: \
1777  if(!parser_fieldValue(me, \
1778  X3D_NODE(node2), (int) offsetof(struct X3D_##node, var), \
1779  FTIND_##fieldType, fe, FALSE, NULL, NULL)) {\
1780  PARSE_ERROR("Expected " #fieldType " Value for a fieldtype!") }\
1781  INIT_CODE_##fieldType(var) \
1782  return TRUE;
1783 
1784  //INIT_CODE_##fieldType(var) \ we're doing this add_parent during instancing as of feb 2013
1785  //return TRUE;
1786 
1787 /* Default action if node is not encountered in list of known nodes */
1788 #define NODE_DEFAULT_B \
1789  default: \
1790  PARSE_ERROR("Parser PROCESS_FIELD_B, Unsupported node!")
1791 
1792 /* printf ("at XXX, fieldE = %d, fieldO = %d nodeType %s\n",fieldE, fieldO,stringNodeType (node->_nodeType));
1793  if (fieldE!=ID_UNDEFINED) printf (".... field is %s\n",EXPOSED_FIELD[fieldE]);
1794  if (fieldO!=ID_UNDEFINED) printf (".... field is %s\n",FIELD[fieldO]); */
1795 
1796 /* Field was found in EXPOSED_FIELD list. Parse value or IS statement */
1797 if(fieldE!=ID_UNDEFINED)
1798  switch(node->_nodeType)
1799 {
1800 
1801 /* Processes exposed fields for node */
1802 #define BEGIN_NODE(type) \
1803  case NODE_##type: \
1804  { \
1805  struct X3D_##type* node2=(struct X3D_##type*)node; \
1806  /* printf ("at YYY, in case for node %s\n",stringNodeType(NODE_##type)); */ \
1807  UNUSED(node2); /* for compiler warning reductions */ \
1808  switch(fieldE) \
1809  {
1810 
1811 /* Process exposed fields */
1812 #define EXPOSED_FIELD(node, field, fieldType, var, realType) \
1813  PROCESS_FIELD_B(EXPOSED_, node, field, fieldType, var, fieldE)
1814 
1815 /* Ignore just fields */
1816 #define FIELD(n, f, t, v, realType)
1817 
1818 /* Process it */
1819 #include "NodeFields.h"
1820 
1821 /* Undef the field-specific macros */
1822 #undef BEGIN_NODE
1823 #undef FIELD
1824 #undef EXPOSED_FIELD
1825 
1826 NODE_DEFAULT_B
1827 
1828 }
1829 
1830 /* Field was found in FIELDS list. Parse value or IS statement */
1831 if(fieldO!=ID_UNDEFINED)
1832  switch(node->_nodeType)
1833 {
1834 
1835  /* Processes ordinary fields for node */
1836 #define BEGIN_NODE(type) \
1837  case NODE_##type: \
1838  { \
1839  struct X3D_##type* node2=(struct X3D_##type*)node; \
1840  UNUSED(node2); /* for compiler warning reductions */ \
1841  switch(fieldO) \
1842  {
1843 
1844  /* Process fields */
1845 #define FIELD(node, field, fieldType, var, realType) \
1846  PROCESS_FIELD_B(, node, field, fieldType, var, ID_UNDEFINED)
1847 
1848  /* Ignore exposed fields */
1849 #define EXPOSED_FIELD(n, f, t, v, realType)
1850 
1851  /* Process it */
1852 #include "NodeFields.h"
1853 
1854  /* Undef the field-specific macros */
1855 #undef BEGIN_NODE
1856 #undef FIELD
1857 #undef EXPOSED_FIELD
1858 
1859  NODE_DEFAULT_B
1860 
1861  }
1862 
1863 /* Clean up */
1864 #undef END_NODE
1865 #undef EVENT_IN
1866 #undef EVENT_OUT
1867 
1868 /* If field was found, return TRUE; would have happened! */
1869 PARSE_ERROR("Unsupported field for node!")
1870  return FALSE;
1871  }
1872 
1873 
1874 static BOOL parser_field(struct VRMLParser* me, struct X3D_Node* node)
1875 {
1876  return parser_field_B(me,node);
1877 }
1878 
1879 
1880 /* ************************************************************************** */
1881 /* MF* field values */
1882 
1883 /* take a USE field, and stuff it into a Multi*type field - see parser_mf routines below */
1884 
1885 static void stuffDEFUSE(struct Multi_Node *outMF, vrmlNodeT in, int type) {
1886  /* printf ("stuff_it_in, got vrmlT vector successfully - it is a type of %s\n",stringNodeType(in->_nodeType));
1887  printf ("stuff_it_in, ret is %d\n",out); */
1888 
1889  /* convert, say, a X3D_something to a struct Multi_Node { int n; int *p; }; */
1890  switch (type) {
1891  /* convert the node pointer into the "p" field of a Multi_MFNode */
1892  case FIELDTYPE_MFNode:
1893  /*struct Multi_Node { int n; void * *p; };*/
1894  outMF->n=1;
1895  outMF->p=MALLOC(void *, sizeof(struct X3D_Node*));
1896  outMF->p[0] = in;
1897  break;
1898 
1899  case FIELDTYPE_MFFloat:
1900  case FIELDTYPE_MFRotation:
1901  case FIELDTYPE_MFVec3f:
1902  case FIELDTYPE_MFBool:
1903  case FIELDTYPE_MFInt32:
1904  case FIELDTYPE_MFColor:
1905  case FIELDTYPE_MFColorRGBA:
1906  case FIELDTYPE_MFTime:
1907  case FIELDTYPE_MFDouble:
1908  case FIELDTYPE_MFString:
1909  case FIELDTYPE_MFVec2f:
1910  { size_t localSize;
1911  localSize = returnRoutingElementLength(convertToSFType(type)); /* converts MF to equiv SF type */
1912  /* struct Multi_Float { int n; float *p; }; */
1913  /* treat these all the same, as the data type is same size */
1914  outMF->n=1;
1915  outMF->p=MALLOC(void *, localSize);
1916  memcpy (&outMF->p[0], &in, localSize);
1917  break;
1918  }
1919  default: {
1920  ConsoleMessage("VRML Parser; stuffDEFUSE, unhandled type");
1921  }
1922  }
1923 }
1924 
1925 
1926 /* if we expect to find a MF field, but the user only puts a SF Field, we make up the MF field with
1927  1 entry, and copy the data over */
1928 static void stuffSFintoMF(struct Multi_Node *outMF, vrmlNodeT *inSF, int type) {
1929  int rsz;
1930  int elelen;
1931  int i;
1932 
1933  /* printf ("stuffSFintoMF, got vrmlT vector successfully - it is a type of %s\n",FIELDTYPES[type]); */
1934 
1935  rsz = returnElementRowSize(type);
1936  elelen = returnElementLength(type);
1937 
1938  /* printf ("stuffSFintoMF - rowsize %d length %d\n",rsz,elelen); */
1939 
1940  /* convert, say, a X3D_something to a struct Multi_Node { int n; int *p; }; */
1941  /* convert the node pointer into the "p" field of a Multi_MFNode */
1942 
1943  /* struct Multi_Float { int n; float *p; }; */
1944  /* struct Multi_Vec3f { int n; struct SFColor *p; }; */
1945  /* treat these all the same, as the data type is same size */
1946 
1947  /* is the "old" size something other than 1? */
1948  /* I am not sure when this would ever happen, but one never knows... */
1949 
1950  /* free up old memory here */
1951  for (i=0; i<outMF->n; i++) {
1952  if (type == FIELDTYPE_MFString) {
1953  struct Uni_String *m = (struct Uni_String *)outMF->p[i];
1954  /* printf ("freeing string :%s:\n",m->strptr); */
1955  FREE_IF_NZ(m->strptr);
1956  }
1957 
1958  }
1959 
1960  if (outMF->n != 1) {
1961  /* printf ("deleting pointer %p\n",outMF->p); */
1962  FREE_IF_NZ(outMF->p);
1963  outMF->n=1;
1964  outMF->p=MALLOC(void *, rsz * elelen);
1965  }
1966 
1967  /* { float *ptr; ptr = (float *) in; for (n=0; n<rsz; n++) { printf ("float %d is %f\n",n,*ptr); ptr++; } } */
1968 
1969  memcpy (outMF->p, inSF, rsz * elelen);
1970 }
1971 
1972 /* Parse a MF* field */
1973 #define PARSER_MFFIELD(name, type) \
1974  static BOOL parser_mf##name##Value(struct VRMLParser* me, void *ret) { \
1975  struct Vector* vec; \
1976  vrmlNodeT RCX; \
1977  struct Multi_##type *rv; \
1978  RCX = NULL; \
1979  vec = NULL; \
1980  \
1981  /* printf ("start of a mfield parse for type %s curID :%s: me %u lexer %u\n",FIELDTYPES[FIELDTYPE_MF##type], me->lexer->curID,me,me->lexer); */ \
1982  /* printf (" str :%s:\n",me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]); */ \
1983  /* if (me->lexer->curID != NULL) printf ("parser_MF, have %s\n",me->lexer->curID); else printf("parser_MF, NULL\n"); */ \
1984 \
1985  if (!(me->parsingX3DfromXML)) { \
1986  /* is this a USE statement? */ \
1987  if(lexer_keyword(me->lexer, KW_USE)) { \
1988  /* printf ("parser_MF, got a USE!\n"); */ \
1989  /* Get a pointer to the X3D_Node structure for this DEFed node and return it in ret */ \
1990  RCX=parse_KW_USE(me); \
1991  if (RCX == NULL) return FALSE; \
1992  /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
1993  stuffDEFUSE(ret, RCX, FIELDTYPE_MF##type); \
1994  return TRUE; \
1995  } \
1996  \
1997  else if (lexer_keyword(me->lexer, KW_DEF)) { \
1998  /* printf ("parser_MF, got the DEF!\n"); */ \
1999  /* Get a pointer to the X3D_Node structure for this DEFed node and return it in ret */ \
2000  RCX=parse_KW_DEF(me); \
2001  if (RCX == NULL) return FALSE; \
2002  \
2003  /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
2004  stuffDEFUSE(ret, RCX, FIELDTYPE_MF##type); \
2005  return TRUE; \
2006  } \
2007  }\
2008 \
2009 /* printf ("step 2... curID :%s:\n", me->lexer->curID); */ \
2010 /* possibly a SFNodeish type value?? */ \
2011 if (me->lexer->curID != NULL) { \
2012  /* printf ("parser_MF, curID was not null (it is %s) me %u lexer %u... lets just parse node\n",me->lexer->curID,me,me->lexer); */ \
2013  if (!parser_node(me, &RCX, ID_UNDEFINED)) { \
2014  return FALSE; \
2015  } \
2016  if (RCX == NULL) return FALSE; \
2017  /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
2018  stuffDEFUSE(ret, RCX, FIELDTYPE_MF##type); \
2019  return TRUE; \
2020  } \
2021 /* Just a single value? */ \
2022 /* NOTE: the XML parser will ALWAYS give this without the brackets */ \
2023 if((!lexer_openSquare(me->lexer)) && (!(me->parsingX3DfromXML))) { \
2024  vrml##type##T RCXRet; \
2025  /* printf ("parser_MF, not an opensquare, lets just parse node\n"); */ \
2026  if(!parser_sf##name##Value(me, &RCXRet)) { \
2027  return FALSE; \
2028  } \
2029  /* printf ("after sf parse rcx %u\n",RCXRet); */ \
2030  /* RCX is the return value, if this value IN THE VRML FILE IS ZERO, then this valid parse will fail... */ \
2031  /* so it is commented out if (RCX == NULL) return FALSE; */ \
2032  /* so, we have a Multi_XX return val. (see Structs.h), have to get the info into a vrmlNodeT */ \
2033  stuffSFintoMF(ret, (vrmlNodeT *)&RCXRet, FIELDTYPE_MF##type); \
2034  return TRUE; \
2035 } \
2036 \
2037  /* Otherwise, a real vector */ \
2038  /* printf ("parser_MF, this is a real vector:%s:\n",me->lexer->nextIn); */ \
2039  vec=newVector(vrml##type##T, 128); \
2040  if (!me->parsingX3DfromXML) { \
2041  while(!lexer_closeSquare(me->lexer)) { \
2042  vrml##type##T val; \
2043  if(!parser_sf##name##Value(me, &val)) { \
2044  CPARSE_ERROR_CURID("ERROR:Expected \"]\" before end of MF-Value") \
2045  break; \
2046  } \
2047  vector_pushBack(vrml##type##T, vec, val); \
2048  } \
2049  } else { \
2050  lexer_skip(me->lexer); \
2051  while(*me->lexer->nextIn != '\0') { \
2052  vrml##type##T val; \
2053  if(!parser_sf##name##Value(me, &val)) { \
2054  CPARSE_ERROR_CURID("ERROR:Expected \"]\" before end of MF-Value") \
2055  break; \
2056  } \
2057  vector_pushBack(vrml##type##T, vec, val); \
2058  lexer_skip(me->lexer); \
2059  } \
2060  }\
2061  rv = (struct Multi_##type*) ret; \
2062  rv->n=vectorSize(vec); \
2063  rv->p=vector_releaseData(vrml##type##T, vec); \
2064  \
2065  deleteVector(vrml##type##T, vec); \
2066  return TRUE; \
2067  }
2068 
2069  PARSER_MFFIELD(bool, Bool)
2070  PARSER_MFFIELD(color, Color)
2071  PARSER_MFFIELD(colorrgba, ColorRGBA)
2072  PARSER_MFFIELD(float, Float)
2073  PARSER_MFFIELD(int32, Int32)
2074  PARSER_MFFIELD(node, Node)
2075  PARSER_MFFIELD(rotation, Rotation)
2076  PARSER_MFFIELD(string, String)
2077  PARSER_MFFIELD(time, Time)
2078  PARSER_MFFIELD(vec2f, Vec2f)
2079  PARSER_MFFIELD(vec3f, Vec3f)
2080  PARSER_MFFIELD(vec3d, Vec3d)
2081  PARSER_MFFIELD(vec2d, Vec2d)
2082  PARSER_MFFIELD(vec4f, Vec4f)
2083  PARSER_MFFIELD(vec4d, Vec4d)
2084 
2085 /* ************************************************************************** */
2086 /* SF* field values */
2087 
2088 /* Parses a fixed-size vector-field of floats (SFColor, SFRotation, SFVecXf) */
2089 #define PARSER_FIXED_VEC(name, type, cnt) \
2090  BOOL parser_sf##name##Value(struct VRMLParser* me, void* ret) \
2091  { \
2092  int i; \
2093  vrml##type##T *rv; \
2094  ASSERT(me->lexer); \
2095  rv = (vrml##type##T *) ret; \
2096  for(i=0; i!=cnt; ++i) {\
2097  if(!parser_sffloatValue(me, rv->c+i)) \
2098  return FALSE; \
2099  }\
2100  return TRUE; \
2101  }
2102 
2103 /* Parses a fixed-size vector-field of floats (SFColor, SFRotation, SFVecXf) */
2104 #define PARSER_FIXED_DOUBLE_VEC(name, type, cnt) \
2105  BOOL parser_sf##name##Value(struct VRMLParser* me, void* ret) \
2106  { \
2107  int i; \
2108  vrml##type##T *rv; \
2109  ASSERT(me->lexer); \
2110  rv = (vrml##type##T *) ret; \
2111  for(i=0; i!=cnt; ++i) {\
2112  if(!parser_sfdoubleValue_(me, rv->c+i)) \
2113  return FALSE; \
2114  }\
2115  return TRUE; \
2116  }
2117 
2118  BOOL parser_sfdoubleValue_(struct VRMLParser* me, vrmlDoubleT* ret)
2119  {
2120  return lexer_double(me->lexer, ret);
2121  }
2122 static BOOL parser_sffloatValue_(struct VRMLParser* me, void* ret)
2123  {
2124  vrmlFloatT *rf;
2125  rf = (vrmlFloatT*)ret;
2126  return lexer_float(me->lexer, rf);
2127  }
2128 static BOOL parser_sfint32Value_(struct VRMLParser* me, void* ret)
2129  {
2130  vrmlInt32T* rf;
2131  rf = (vrmlInt32T*)ret;
2132  return lexer_int32(me->lexer, rf);
2133  }
2134 
2135 
2136 
2137 static BOOL set_X3Dstring(struct VRMLLexer* me, vrmlStringT* ret) {
2138  /* printf ("lexer_X3DString, setting string to be :%s:\n",me->startOfStringPtr[me->lexerInputLevel]); */
2139  *ret=newASCIIString((char *)me->startOfStringPtr[me->lexerInputLevel]);
2140  return TRUE;
2141 }
2142 
2143 static BOOL parser_sfstringValue_(struct VRMLParser* me, void* ret) {
2144  vrmlStringT* rv;
2145 
2146  rv = (vrmlStringT*)ret;
2147 
2148  /* are we parsing the "classic VRML" formatted string? Ie, one with
2149  starting and finishing quotes? */
2150  if (!me->parsingX3DfromXML) return lexer_string(me->lexer, rv);
2151 
2152  else return set_X3Dstring(me->lexer, rv);
2153 
2154  return TRUE;
2155 }
2156 
2157 static BOOL parser_sfboolValue(struct VRMLParser* me, void* ret) {
2158  vrmlBoolT *rv;
2159 
2160  rv = (vrmlBoolT*)ret;
2161 
2162  /* are we in the VRML (x3dv) parser? */
2163  if (!me->parsingX3DfromXML) {
2164  if(lexer_keyword(me->lexer, KW_TRUE)) {
2165  *rv=TRUE;
2166  return TRUE;
2167  }
2168  if(lexer_keyword(me->lexer, KW_FALSE)) {
2169  *rv=FALSE;
2170  return TRUE;
2171  }
2172  return FALSE;
2173  }
2174  /* possibly, this is from the XML Parser */
2175  if (!strcmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"true")) {
2176  *rv = TRUE;
2177  return TRUE;
2178  }
2179  if (!strcmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"false")) {
2180  *rv = FALSE;
2181  return TRUE;
2182  }
2183 
2184  /* possibly this is from the XML parser, but there is a case problem */
2185  if (!gglobal()->internalc.global_strictParsing && (!strcmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"TRUE"))) {
2186  CPARSE_ERROR_CURID("found upper case TRUE in XML file - should be lower case");
2187  *rv = TRUE;
2188  return TRUE;
2189  }
2190  if (!gglobal()->internalc.global_strictParsing && (!strcmp(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel],"FALSE"))) {
2191  CPARSE_ERROR_CURID ("found upper case FALSE in XML file - should be lower case");
2192  *rv = FALSE;
2193  return TRUE;
2194  }
2195 
2196 
2197 
2198  /* Noperooni - this was from X3D, but did not parse */
2199  *rv = FALSE;
2200  return FALSE;
2201 }
2202 
2203  PARSER_FIXED_VEC(color, Color, 3)
2204  PARSER_FIXED_VEC(colorrgba, ColorRGBA, 4)
2205  PARSER_FIXED_VEC(matrix3f, Matrix3f, 9)
2206  PARSER_FIXED_VEC(matrix4f, Matrix4f, 16)
2207  PARSER_FIXED_VEC(vec2f, Vec2f, 2)
2208  PARSER_FIXED_VEC(vec4f, Vec4f, 4)
2209  PARSER_FIXED_VEC(rotation, Rotation, 4)
2210  PARSER_FIXED_DOUBLE_VEC(vec2d, Vec2d, 2)
2211  PARSER_FIXED_DOUBLE_VEC(vec3d, Vec3d, 3)
2212  PARSER_FIXED_DOUBLE_VEC(vec4d, Vec4d, 4)
2213  PARSER_FIXED_DOUBLE_VEC(matrix3d, Matrix3d, 9)
2214  PARSER_FIXED_DOUBLE_VEC(matrix4d, Matrix4d, 16)
2215 
2216 /* JAS this code assumes that the ret points to a SFInt_32 type, and just
2217  fills in the values. */
2218 
2219  static BOOL parser_sfimageValue(struct VRMLParser* me, void* ret)
2220  {
2221  vrmlImageT *rv;
2222  vrmlInt32T width, height, depth;
2223  vrmlInt32T* ptr;
2224 
2225  rv = (vrmlImageT*) ret;
2226 
2227  if(!lexer_int32(me->lexer, &width))
2228  return FALSE;
2229  if(!lexer_int32(me->lexer, &height))
2230  return FALSE;
2231  if(!lexer_int32(me->lexer, &depth))
2232  return FALSE;
2233 
2234 
2235  rv->n=3+width*height;
2236  rv->p=MALLOC(int *, sizeof(int) * rv->n);
2237  rv->p[0]=width;
2238  rv->p[1]=height;
2239  rv->p[2]=depth;
2240 
2241  for(ptr=rv->p+3; ptr!=rv->p+rv->n; ++ptr)
2242  if(!lexer_int32(me->lexer, ptr))
2243  {
2244  FREE_IF_NZ(rv->p);
2245  rv->n=0;
2246  return FALSE;
2247  }
2248 
2249  return TRUE;
2250  }
2251 
2252 
2253 static BOOL parser_sfnodeValue(struct VRMLParser* me, void* ret) {
2254  intptr_t tmp;
2255  vrmlNodeT* rv;
2256 
2257  ASSERT(me->lexer);
2258  rv = (vrmlNodeT*)ret;
2259 
2260  if(lexer_keyword(me->lexer, KW_NULL)) {
2261  *rv=NULL;
2262  return TRUE;
2263  }
2264 
2265  /* are we parsing from a proto expansion? */
2266  if (!me->parsingX3DfromXML) {
2267  return parser_nodeStatement(me, rv);
2268  } else {
2269  /* expect something like a number (memory pointer) to be here */
2270  if (sscanf(me->lexer->startOfStringPtr[me->lexer->lexerInputLevel], "%lu", &tmp) != 1) {
2271  CPARSE_ERROR_FIELDSTRING ("error finding SFNode id on line :%s:",
2272  me->lexer->startOfStringPtr[me->lexer->lexerInputLevel]);
2273  *rv=NULL;
2274  return FALSE;
2275  }
2276  *rv = (vrmlNodeT)tmp;
2277  }
2278  return TRUE;
2279 }
2280 
2281 
2282 static BOOL parser_sftimeValue(struct VRMLParser* me, void* ret)
2283  {
2284  vrmlTimeT *rv;
2285  rv = (vrmlTimeT*)ret;
2286  return lexer_double(me->lexer, rv);
2287  }
2288 
2289 
2290 static BOOL parser_fieldTypeNotParsedYet(struct VRMLParser* me, void* ret) {
2291  CPARSE_ERROR_CURID ("received a request to parse a type not supported yet");
2292  return FALSE;
2293 }
2294 
2295 
2296 /* prettyprint this error */
2297  #define OUTLINELEN 800
2298  #define FROMSRC 140
2299 void cParseErrorCurID(struct VRMLParser *me, char *str) {
2300  char fw_outline[OUTLINELEN];
2301  ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
2302 
2303  if (strlen(str) > FROMSRC) { //str[FROMSRC] = '\0';
2304  strncpy(fw_outline,str,FROMSRC);
2305  fw_outline[FROMSRC-1] = '\0';
2306  }else{
2307  strcpy(fw_outline,str);
2308  }
2309  if (me->lexer->curID != ((void *)0)) {
2310  strcat (fw_outline, "; current token :");
2311  strcat (fw_outline, me->lexer->curID);
2312  strcat (fw_outline, ": ");
2313  }
2314  if (me->lexer->nextIn != NULL) {
2315  strcat (fw_outline," at: \"");
2316  strncat(fw_outline,me->lexer->nextIn,FROMSRC);
2317  if (strlen(me->lexer->nextIn) > FROMSRC)
2318  strcat (fw_outline,"...");
2319  strcat (fw_outline,"\"");
2320  }
2321 
2322  p->foundInputErrors++;
2323  ConsoleMessage(fw_outline);
2324 }
2325 
2326 void cParseErrorFieldString(struct VRMLParser *me, char *str, const char *str2) {
2327 
2328  char fw_outline[OUTLINELEN];
2329  int str2len = (int) strlen(str2);
2330  ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
2331 
2332  if (strlen(str) > FROMSRC) str[FROMSRC] = '\0';
2333  strcpy(fw_outline,str);
2334  strcat (fw_outline," (");
2335  strncat (fw_outline,str2,str2len);
2336  strcat (fw_outline, ") ");
2337  if (me->lexer->curID != ((void *)0)) strcat (fw_outline, me->lexer->curID);
2338  if (me->lexer->nextIn != NULL) {
2339  strcat (fw_outline," at: \"");
2340  strncat(fw_outline,me->lexer->nextIn,FROMSRC);
2341  if (strlen(me->lexer->nextIn) > FROMSRC)
2342  strcat (fw_outline,"...");
2343  strcat (fw_outline,"\"");
2344  }
2345 
2346  p->foundInputErrors++;
2347  ConsoleMessage(fw_outline);
2348 }
2349 
2350 //
2351 //
2352 // ******************** BROTO section *********************************************************
2353 //
2354 //
2355 
2356 /*
2357 Sept 2014
2358 X3D_Proto is now being used for non-node entities as well as ProtoInstance:
2359 a) protoInstance PI
2360 b) protoDeclare PD
2361 c) externProtoInstance EPI
2362 d) externProtoDeclare EPD
2363 e) sceneInstance SI (rootNodes parent, deep)
2364 f) protoLibrary PL (scene declare, shallow)
2365 
2366 WRL Parsing now uses the same code for both scene and protoBody, recursing as deep as needed,
2367 and uses a 'depth' flag for deciding whether to instance what its parsing (ie for scene) or not
2368 (protoDeclares, shallow).
2369 
2370 deep - instancing a live scene, so nodes are registered, routes are registered, scripts are registered, PIs are deep copied
2371 shallow - we are in a protoDeclare -perhaps in its body- so we just copy the interface of any contained PIs for routing,
2372  we do not register nodes, scripts, or do any binding
2373 
2374 executionContext EC: scene or protoBody (according to specs), basically a name context, and where routes are supposed to be
2375 
2376 X3D_Proto fields
2377  void * __DEFnames; //besides giving def names to the parser, it also saves them in a Vector per-EC
2378  void * __IS; //the IS keyword details are parsed to this, per EC, and a function generates browser ROUTES if deep
2379  void * __ROUTES; //ROUTES are saved here per EC, as well as registered with browser when deep
2380  void * __afterPound; //for EPD, if url is myfile.wrl#Geom then Geom is the afterPound, and is the name of the desired PD in the proto library
2381  void * __externProtoDeclares; //besides giving EPD type names back to parser, the EPDs are stored here per-EC
2382  void * __loadResource; //for network types, like EPD, this is the resource its monitoring that's downloading the PL
2383  int __loadstatus; //for network types like EPD, helps EPD advance step-wise on each visit, as the resource is loaded and parsed
2384  struct X3D_Node *__parentProto; //parent EC, when instancing
2385  void * __protoDeclares; //besides giving PD type name back to parser, the parsed PD is stored here per-EC
2386  void * __nodes; //flat table of malloced builtin and x3d_proto nodes (for future recursive startofloopnodeupdates and/or node-wise GC)
2387  void * __subcontexts; //flat table of any protoInstances/externProtoInstances and Inlines (for future recursive startofloopnodeupdates, routing, script running, sensor running)
2388  void * __GC; //Garbage collection table - vector of mallocs to free, from Vectors, vector elements, strdups etc
2389  void * __protoDef; //struct for holding user fields, as used for Script, Proto
2390  int __protoFlags; //char [4] 0) deep=1, shallow=0 1) 1 means useBrotos=0 old way 2) 0-declare 1-instance 2-scene 3) extern=1, else 0
2391  struct X3D_Node *__prototype; //for PI, EPI: will be PD, EPD, so when deep_copying it can get the body
2392  void * __scripts; //stores script nodes parsed here per EC as well as registering with browser when instancing
2393  void * __typename; //for PD,EPD (and PI, EPI): besides giving PD user-defined type name (vs builtin type) back to parser, its stored here
2394  struct Multi_String __url; //for network types like EPD - the parsed URL for downloading
2395  void * _parentResource; //for network types, like EPD, this is a resource_item_t * of the main scene, to get its absolute URL in resource_identify
2396 
2397  //familiar fields:
2398  struct Multi_Node _children; //same use as children[] field in Group/Transform, except hidden as _children for some scenes t85.wrl that name a user field as children
2399  struct Multi_Node _sortedChildren;
2400  struct Multi_Node addChildren;
2401  struct X3D_Node *metadata;
2402  struct Multi_Node removeChildren;
2403  struct SFVec3f bboxCenter;
2404  struct SFVec3f bboxSize;
2405 */
2406 
2407 
2408 
2409 /* Parses a node (node non-terminal) */
2410 /* Looks up the node type on the builtin NODES list and the userNodeNames list.
2411  If this is a builtin node type, creates a new X3D_Node structure of the appropriate type for the node,
2412  and then parses the statements for that node.
2413  For each field statement, gets the value for that field and stores it in the X3D_Node structure.
2414  For each ROUTE statement, adds the route to the CRoutes table.
2415  For each PROTO statement, adds the PROTO definition to the PROTOs list.
2416  Return a pointer to the X3D_Node structure that holds the information for this node.
2417  If this is a user-defined node type (i.e. a PROTO expansion/instance), complete the proto expansion/instance
2418  For each field in the ProtoDefinition either parse and propagate the specified value for this field, or
2419  propagate the default value of the field. (i.e. copy the appropriate value into every node/field combination in
2420  the dests list.)
2421  For each route in the routes list of the ProtoDefinition, add the route to the CRoutes table.
2422  Return a pointer to the X3D_Node structure that is the scenegraph for this PROTO.
2423 */
2424 struct X3D_Proto *brotoInstance(struct X3D_Proto* proto, BOOL ideep);
2425 static BOOL parser_field_user(struct VRMLParser* me, struct X3D_Node *node);
2426 static BOOL parser_interfaceDeclarationB(struct VRMLParser* me, struct ProtoDefinition* proto, struct Shader_Script* script);
2427 void deep_copy_broto_body2(struct X3D_Proto** proto, struct X3D_Proto** dest);
2428 void initialize_one_script(struct Shader_Script* ss, const struct Multi_String *url);
2429 void add_node_to_broto_context(struct X3D_Proto *currentContext,struct X3D_Node *node);
2430 
2431 static BOOL parser_externbrotoStatement(struct VRMLParser* me);
2432 static BOOL parser_node_B(struct VRMLParser* me, vrmlNodeT* ret, int ind) {
2433  int nodeTypeB, nodeTypeU, isBroto;
2434  struct X3D_Node* node=NULL;
2435  struct X3D_Proto *currentContext;
2436  char pflagdepth;
2437  struct Shader_Script* script=NULL;
2438  struct Shader_Script* shader=NULL;
2439  DECLAREUP
2440  //struct X3D_Node* what_am_I = X3D_NODE(me->ptr);
2441  currentContext = (struct X3D_Proto*)me->ectx;
2442  pflagdepth = ciflag_get(currentContext->__protoFlags,0); //((char *)(&currentContext->__protoFlags))[0];
2443 
2444 
2445  ASSERT(me->lexer);
2446  *ret=node; /* set this to NULL, for now... if this is a real node, it will return a node pointer */
2447 
2448  /* lexer_node( ... ) #defined to lexer_specialID(me, r1, r2, NODES, NODES_COUNT, userNodeTypesVec) where userNodeTypesVec is a list of PROTO defs */
2449  /* this will get the next token (which will be the node type) and search the NODES array for it. If it is found in the NODES array nodeTypeB will be set to
2450  the index of type in the NODES array. If it is not in NODES, the list of user-defined nodes will be searched for the type. If it is found in the user-defined
2451  list nodeTypeU will be set to the index of the type in userNodeTypesVec. A return value of FALSE indicates that the node type wasn't found in either list */
2452 
2453 #ifdef CPARSERVERBOSE
2454  printf ("parser_node START, curID :%s: nextIn :%s:\n",me->lexer->curID, me->lexer->nextIn);
2455 #endif
2456 
2457 
2458 //#define XBLOCK_STATEMENT_B(LOCATION)
2459  if(parser_routeStatement(me)) {
2460  return TRUE;
2461  }
2462 
2463  if (parser_componentStatement(me)) {
2464  return TRUE;
2465  }
2466 
2467  if (parser_exportStatement(me)) {
2468  return TRUE;
2469  }
2470 
2471  if (parser_importStatement(me)) {
2472  return TRUE;
2473  }
2474 
2475  if (parser_metaStatement(me)) {
2476  return TRUE;
2477  }
2478 
2479  if (parser_profileStatement(me)) {
2480  return TRUE;
2481  }
2482  if(parser_brotoStatement(me)) {
2483  return TRUE;
2484  }
2485  if(parser_externbrotoStatement(me)) {
2486  return TRUE;
2487  }
2488 
2489 
2490 
2491 
2492  if(!lexer_node(me->lexer, &nodeTypeB, &nodeTypeU)) {
2493 #ifdef CPARSERVERBOSE
2494  printf ("parser_node, not lexed - is this one of those special nodes?\n");
2495 #endif
2496  return FALSE;
2497  }
2498 
2499  /* printf ("after lexer_node, at this point, me->lexer->curID :%s:\n",me->lexer->curID); */
2500  /* could this be a proto expansion?? */
2501 
2502  /* Checks that the next non-whitespace non-comment character is '{' and skips it. */
2503  if(!lexer_openCurly(me->lexer))
2504  PARSE_ERROR("Expected { after node-type id!")
2505 
2506 #ifdef CPARSERVERBOSE
2507  printf ("parser_node: have nodeTypeB %d nodeTypeU %d\n",nodeTypeB, nodeTypeU);
2508 #endif
2509  isBroto = FALSE;
2510  if (nodeTypeU != ID_UNDEFINED) {
2511  /* The node name was located in userNodeTypesVec (list of defined PROTOs),
2512  therefore this is an attempt to instantiate a PROTO */
2513  /* expand this PROTO, put the code right in line, and let the parser
2514  go over it as if there was never a proto here... */
2515  struct X3D_Proto *proto; //, *currentContext;
2516  char *protoname = vector_get(char*, me->lexer->userNodeTypesVec, nodeTypeU);
2517  //currentContext = (struct X3D_Proto*)me->ptr;
2518  //BOOL isAvailableBroto(char *pname, struct X3D_Proto* currentContext, struct X3D_Proto **proto);
2519  //struct X3D_Proto *shallowBrotoInstance(X3D_Proto* proto);
2520  if( isAvailableBroto(protoname, currentContext , &proto))
2521  {
2522  /* its a binary proto, new in 2013 */
2523  int idepth = 0; //if its old brotos (2013) don't do depth until sceneInstance. If 2014 broto2, don't do depth here if we're in a protoDeclare or externProtoDeclare
2524  idepth = pflagdepth == 1; //2014 broto2: if we're parsing a scene (or Inline) then deepcopy proto to instance it, else shallow
2525  node=X3D_NODE(brotoInstance(proto,idepth));
2526  node->_executionContext = X3D_NODE(currentContext); //me->ptr;
2527  add_node_to_broto_context(currentContext,node);
2528  //moved below, for all nodes if(idepth) add_parent(node,X3D_NODE(currentContext),__FILE__,__LINE__); //helps propagate VF_Sensitive to parent of proto, if proto's 1st node is sensor
2529  isBroto = TRUE;
2530  ASSERT(node);
2531  if (ind != ID_UNDEFINED) {
2532  char *name;
2533  /* Set the top memmber of the DEFed nodes stack to this node */
2534  vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind)=node;
2535 #ifdef CPARSERVERBOSE
2536  printf("parser_node: adding DEFed node (pointer %p) to DEFedNodes vector\n", node);
2537 #endif
2538  name = vector_get(char*, stack_top(struct Vector*, me->lexer->userNodeNames), ind);
2539  broto_store_DEF((struct X3D_Proto*)(me->ectx),node, name);
2540  }
2541  }
2542  }
2543 
2544  /* Built-in node */
2545  /* Node was found in NODES array */
2546  if(nodeTypeB!=ID_UNDEFINED) {
2547 #ifdef CPARSERVERBOSE
2548  printf("parser_node: parsing builtin node\n");
2549 #endif
2550 
2551  /* Get malloced struct of appropriate X3D_Node type with default values filled in */
2552  if(pflagdepth){
2553  node=X3D_NODE(createNewX3DNode((int)nodeTypeB)); //registers node types like sensors, textures in tables for scene
2554  if(node->_nodeType == NODE_Inline){
2555  if(X3D_NODE(me->ectx)->_nodeType != NODE_Inline && X3D_NODE(me->ectx)->_nodeType != NODE_Proto)
2556  printf("ouch trying to caste a %d nodetype to inline or proto\n",X3D_NODE(me->ectx)->_nodeType);
2557  X3D_INLINE(node)->__parentProto = me->ectx;
2558  }
2559  }else{
2560  node=X3D_NODE(createNewX3DNode0((int)nodeTypeB)); //doesn't register node types in tables, for protoDeclare
2561  }
2562  node->_executionContext = X3D_NODE(currentContext); //me->ptr;
2563  add_node_to_broto_context(currentContext,node);
2564  ASSERT(node);
2565 
2566  /* if ind != ID_UNDEFINED, we have the first node of a DEF. Save this node pointer, in case
2567  some code uses it. eg: DEF xx Transform {children Script {field yy USE xx}} */
2568  if (ind != ID_UNDEFINED) {
2569  /* Set the top memmber of the DEFed nodes stack to this node */
2570  char *name;
2571  vector_get(struct X3D_Node*, stack_top(struct Vector*, me->DEFedNodes), ind)=node;
2572  name = vector_get(char*, stack_top(struct Vector*, me->lexer->userNodeNames), ind);
2573  broto_store_DEF((struct X3D_Proto*)(me->ectx),node, name);
2574 
2575 #ifdef CPARSERVERBOSE
2576  printf("parser_node: adding DEFed node (pointer %p) to DEFedNodes vector\n", node);
2577 #endif
2578  }
2579 
2580 
2581  /* Node specific initialization */
2582  /* From what I can tell, this only does something for Script nodes. It sets node->__scriptObj to new_Shader_Script() */
2583  parser_specificInitNode_B(node, me);
2584 
2585  /* Set flag for Shaders/Scripts - these ones can have any number of fields */
2586  switch (node->_nodeType) {
2587  case NODE_Script: script=X3D_SCRIPT(node)->__scriptObj; break;
2588  case NODE_ShaderProgram: shader=(struct Shader_Script *)(X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields); break;
2589  case NODE_PackagedShader: shader=(struct Shader_Script *)(X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields); break;
2590  case NODE_ComposedShader: shader=(struct Shader_Script *)(X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields); break;
2591  case NODE_Effect: shader=(struct Shader_Script *)(X3D_EFFECT(node)->_shaderUserDefinedFields); break;
2592  case NODE_LayerSet:
2593  push_binding_stack_set(node); break;
2594  case NODE_LayoutLayer:
2595  case NODE_Layer:
2596  push_next_layerId_from_binding_stack_set(node); break;
2597  default: {}
2598  }
2599  } /*endif nodetypeB*/
2600 
2601  /* As long as the lexer is returning field statements, ROUTE statements,
2602  or PROTO statements continue parsing node */
2603 
2604  /* to get IS handling in the main scene parsing code including for Script user fields
2605  I split up the script interface parser so it only creates the field, then
2606  BACKUPs the lexer and lets field_user and found_IS take a crack at it
2607  */
2608  if( (nodeTypeB!=ID_UNDEFINED) || isBroto)
2609  {
2610  #define SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING 1
2611  while(TRUE)
2612  {
2613  /* Try to parse the next statement as a field. For normal "field value" statements
2614  (i.e. position 1 0 1) this gets the value of the field from the lexer (next token(s)
2615  to be processed) and stores it as the appropriate type in the node.
2616  For IS statements (i.e. position IS mypos) this adds the node-field combo
2617  (as an offsetPointer) to the dests list for the protoFieldDecl associated with the user
2618  defined field (in the given case, this would be mypos). */
2619 #ifdef CPARSERVERBOSE
2620  printf("parser_node: try parsing field ... \n");
2621 #endif
2622  /* check for IS - can be any mode, and builtin or user field on builtin node or usernode/protoInstance */
2623  if( found_IS_field(me,node) ){
2624  continue;
2625  }
2626 
2627  if(SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING)
2628  if(parser_field_user(me,node)) {
2629  continue;
2630  }
2631 
2632  /*check for builtin field value on builtin node or usernode/protoInstance*/
2633  if(parser_field(me, node)) {
2634 #ifdef CPARSERVERBOSE
2635  printf("parser_node: field parsed\n");
2636 #endif
2637  continue;
2638  }
2639 
2640 
2641  /* Try to parse the next statement as a ROUTE (i.e. statement starts with ROUTE). This checks that the ROUTE statement is valid (i.e. that the referenced node and field combinations
2642  exist, and that they are compatible) and then adds the route to either the CRoutes table of routes, or adds a new ProtoRoute structure to the vector
2643  ProtoDefinition->routes if we are parsing a PROTO */
2644 #ifdef CPARSERVERBOSE
2645  printf("parser_node: try parsing ROUTE ... \n");
2646 #endif
2647 
2648  /* try ROUTE, COMPONENT, EXPORT, IMPORT, META, PROFILE statements here */
2649  SAVEUP
2650  BLOCK_STATEMENT(parser_node);
2651 
2652  /* Try to parse the next statement as a PROTO (i.e. statement starts with PROTO). */
2653  /* Add the PROTO name to the userNodeTypesVec list of names. Create and fill in a new protoDefinition structure and add it to the PROTOs list.
2654  Goes through the interface declarations for the PROTO and adds each user-defined field name to the appropriate list of user-defined names (user_initializeOnly,
2655  user_inputOnly, Out, or user_inputOutput), creates a new protoFieldDecl for the field and adds it to the iface vector of the ProtoDefinition,
2656  and, in the case of fields and inputOutputs, gets the default value of the field and stores it in the protoFieldDecl.
2657  Parses the body of the PROTO. Nodes are added to the scene graph for this PROTO. Routes are parsed and a new ProtoRoute structure
2658  is created for each one and added to the routes vector of the ProtoDefinition. PROTOs are recursively parsed!
2659  */
2660 #ifdef CPARSERVERBOSE
2661  printf("parser_node: try parsing PROTO ... \n");
2662 #endif
2663  BACKUP
2664 
2665 // if(parser_protoStatement(me)) {
2666 //#ifdef CPARSERVERBOSE
2667 // printf("parser_node: PROTO parsed\n");
2668 //#endif
2669 // continue;
2670 // }
2671 
2672  if(parser_brotoStatement(me)) {
2673 #ifdef CPARSERVERBOSE
2674  printf("parser_vrmlScene: BROTO parsed\n");
2675 #endif
2676  continue;
2677  }
2678 
2679 #ifdef CPARSERVERBOSE
2680  printf("parser_node: try parsing Script or Shader field\n");
2681 #endif
2682 
2683  /* check for user field declaration on builtin node of type script or shaderprogram
2684  'mode fieldtype fieldname <fieldvalue>'
2685  and create the field
2686  aside: protoDeclares and protoInstances handled elsewhere:
2687  - protoInstance 'fieldname fieldvalue' are handled like builtins in found_IS and parser_field
2688  - protoDeclare 'mode fieldtype fieldname <fieldvalue>' are handled in parser_protostatement
2689  */
2690  if(SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING) //this one just adds the field, and leave it to others to parse the 'fieldname fieldvalue'
2691  if(script && parser_interfaceDeclarationB(me, NULL, script)){
2692  continue;
2693  }
2694  if(!SPLIT_SCRIPTUSERFIELD_CREATION_FROM_VALUEPARSING)
2695  if(script && parser_interfaceDeclaration(me, NULL, script)) {
2696 #ifdef CPARSERVERBOSE
2697  printf("parser_node: SCRIPT field parsed\n");
2698 #endif
2699  continue;
2700  }
2701 
2702  if(shader && parser_interfaceDeclaration(me, NULL, shader)) {
2703 #ifdef CPARSERVERBOSE
2704  printf("parser_node: Shader field parsed\n");
2705 #endif
2706  continue;
2707  }
2708 
2709  break;
2710  }
2711 
2712  /* Init code for Scripts */
2713  if(script) {
2714 #ifdef CPARSERVERBOSE
2715  printf("parser_node: try parsing SCRIPT url\n");
2716 #endif
2717  if(pflagdepth) //broto1: do this later in sceneInstance broto2: do it during instancing here and brotoInstance
2718  //script_initCodeFromMFUri(script, &X3D_SCRIPT(node)->url);
2719  initialize_one_script(script,&X3D_SCRIPT(node)->url);
2720 #ifdef CPARSERVERBOSE
2721  printf("parser_node: SCRIPT url parsed\n");
2722 #endif
2723  } /* nodetypeB or brotoInstance */
2724 
2725  if(isBroto && pflagdepth){
2726  //copying the body _after_ the protoInstance field values have been parsed
2727  //allows ISd fields in body nodes to get the pkw_initializeOnly/inputOutput value
2728  //from the protoInstance interface
2729  //if(1){
2730  // deep_copy_broto_body2(&X3D_PROTO(X3D_PROTO(node)->__prototype),&X3D_PROTO(node));
2731  //}else{
2732  struct X3D_Proto *ptype, *pdest;
2733  ptype = X3D_PROTO(X3D_PROTO(node)->__prototype);
2734  pdest = X3D_PROTO(node);
2735  deep_copy_broto_body2(&ptype,&pdest);
2736  //}
2737  }
2738  // if(pflagdepth) add_parent(node,parent??,__FILE__,__LINE__); //helps propagate VF_Sensitive to parent of proto, if proto's 1st node is sensor. We do in macro PROCESS_FIELD_B
2739 
2740  /* We must have a node that we've parsed at this point. */
2741  ASSERT(node);
2742  }
2743 
2744  /* Check that the node is closed by a '}', and skip this token */
2745 #ifdef CPARSERVERBOSE
2746  printf ("calling lexer_closeCurly at B\n");
2747 #endif
2748 
2749  if(!lexer_closeCurly(me->lexer)) {
2750  CPARSE_ERROR_CURID("ERROR: Expected a closing brace after fields of a node;")
2751  PARSER_FINALLY;
2752  return FALSE;
2753  }
2754  if(node->_nodeType == NODE_LayerSet)
2755  pop_binding_stack_set();
2756 
2757  /* Return the parsed node */
2758 
2759  #ifdef CPARSERVERBOSE
2760  printf ("returning at end of parser_node, ret %u\n",node);
2761  if (node != NULL) printf ("and, node type is %s\n",stringNodeType(node->_nodeType));
2762  #endif
2763  *ret=node;
2764  return TRUE;
2765 }
2766 
2767 
2768 //#include "broto1.h"
2769 /* mode fieldtype fieldname <fieldValue>
2770  Goal: just create the field and let other functions parse fieldvalue
2771  read the first 3 tokens, Quality Assure them.
2772  create the field, iniitalize to bzero
2773  add the field to proto/script field list
2774  if mode is field (not event) backup lexer to fieldname
2775  exit
2776  (and other functions will parse and set fieldValue)
2777 */
2778 static BOOL parser_interfaceDeclarationB(struct VRMLParser* me, struct ProtoDefinition* proto, struct Shader_Script* script) {
2779  int mode;
2780  int type;
2781  int name;
2782  DECLAREUP
2783  union anyVrml defaultVal;
2784  struct ProtoFieldDecl* pdecl=NULL;
2785  //struct ProtoFieldDecl* pField=NULL;
2786  struct ScriptFieldDecl* sdecl=NULL;
2787  //char *startOfField = NULL;
2788  //int startOfFieldLexerLevel = INT_ID_UNDEFINED;
2789 
2790 
2791 #ifdef CPARSERVERBOSE
2792  printf ("start of parser_interfaceDeclaration\n");
2793 #endif
2794 
2795 
2796  /* Either PROTO or Script interface! */
2797  ASSERT((proto || script) && !(proto && script));
2798 
2799  /* lexer_protoFieldMode is #defined as
2800  lexer_specialID(me, r, NULL, PROTOKEYWORDS, PROTOKEYWORDS_COUNT, NULL) */
2801  /* Looks for the next token in the array PROTOKEYWORDS (inputOnly, outputOnly, inputOutput, field)
2802  and returns the appropriate index in mode */
2803  SAVEUP
2804  if(!lexer_protoFieldMode(me->lexer, &mode)) {
2805 #ifdef CPARSERVERBOSE
2806  printf ("parser_interfaceDeclaration, not lexer_protoFieldMode, returning\n");
2807 #endif
2808  BACKUP
2809  return FALSE;
2810  }
2811 
2812  /* Script can not take inputOutputs */
2813  if(0) // change in post-DUK era - we allow inputoutputs now
2814  if (script != NULL) {
2815  if(script->ShaderScriptNode->_nodeType==NODE_Script && mode==PKW_inputOutput)
2816  {
2817  PARSE_ERROR("Scripts must not have inputOutputs!")
2818  //printf("dug9: maybe scripts can have inputOutputs\n");
2819  }
2820  }
2821 
2822  /* lexer_fieldType is #defined as lexer_specialID(me, r, NULL, FIELDTYPES, FIELDTYPES_COUNT, NULL) */
2823  /* Looks for the next token in the array FIELDTYPES and returns the index in type */
2824  if(!lexer_fieldType(me->lexer, &type))
2825  PARSE_ERROR("Expected fieldType after proto-field keyword!")
2826 
2827 #ifdef CPARSERVERBOSE
2828  printf ("parser_interfaceDeclaration, switching on mode %s\n",PROTOKEYWORDS[mode]);
2829 #endif
2830 
2831  //save fieldname - if field (not event) we'll back up here when we exit
2832  //so something else can parse IS or fieldValue
2833  SAVEUP
2834 
2835  switch(mode)
2836  {
2837 #define LEX_DEFINE_FIELDID(suff) \
2838  case PKW_##suff: \
2839  if(!lexer_define_##suff(me->lexer, &name)) \
2840  PARSE_ERROR("Expected fieldNameId after field type!") \
2841  break;
2842 
2843  LEX_DEFINE_FIELDID(initializeOnly)
2844  LEX_DEFINE_FIELDID(inputOnly)
2845  LEX_DEFINE_FIELDID(outputOnly)
2846  LEX_DEFINE_FIELDID(inputOutput)
2847 
2848 
2849 
2850 #ifndef NDEBUG
2851  default:
2852  ASSERT(FALSE);
2853 #endif
2854  }
2855 
2856  /* If we are parsing a PROTO, create a new protoFieldDecl.
2857  If we are parsing a Script, create a new scriptFieldDecl. */
2858  if(proto) {
2859 #ifdef CPARSERVERBOSE
2860  printf ("parser_interfaceDeclaration, calling newProtoFieldDecl\n");
2861 #endif
2862 
2863  pdecl=newProtoFieldDecl(mode, type, name);
2864  //pdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
2865 
2866 #ifdef CPARSERVERBOSE
2867  printf ("parser_interfaceDeclaration, finished calling newProtoFieldDecl\n");
2868 #endif
2869  } else {
2870 #ifdef CPARSERVERBOSE
2871  printf ("parser_interfaceDeclaration, calling newScriptFieldDecl\n");
2872 #endif
2873  //lexer_stringUser_fieldName(me,name,mod)
2874  sdecl=newScriptFieldDecl(me->lexer, mode, type, name);
2875  //sdecl=newScriptFieldDecl(lexer_stringUser_fieldName(me->lexer,name,mod), mode, type, name);
2876  //sdecl->fieldString = STRDUP(lexer_stringUser_fieldName(me->lexer, name, mode));
2877 
2878  }
2879 
2880 
2881  /* If this is a field or an exposed field give it a bzero default value*/
2882  if(mode==PKW_initializeOnly || mode==PKW_inputOutput) {
2883 #ifdef CPARSERVERBOSE
2884  printf ("parser_interfaceDeclaration, mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
2885 #endif
2886  bzero (&defaultVal, sizeof (union anyVrml));
2887 
2888  /* Store the default field value in the protoFieldDeclaration or scriptFieldDecl structure */
2889  if(proto) {
2890  pdecl->defaultVal=defaultVal;
2891  }
2892  else
2893  {
2894  ASSERT(script);
2895  //defaultVal.sfcolor.c[1] = .333;
2896  scriptFieldDecl_setFieldValue(sdecl, defaultVal);
2897  }
2898  }
2899 
2900  /* Add the new field declaration to the list of fields in the Proto or Script definition.
2901  For a PROTO, this means adding it to the iface vector of the ProtoDefinition.
2902  For a Script, this means adding it to the fields vector of the ScriptDefinition. */
2903  if(proto) {
2904  /* protoDefinition_addIfaceField is #defined as vector_pushBack(struct ProtoFieldDecl*, (me)->iface, field) */
2905  /* Add the protoFieldDecl structure to the iface vector of the protoDefinition structure */
2906  protoDefinition_addIfaceField(proto, pdecl);
2907  } else {
2908  /* Add the scriptFieldDecl structure to the fields vector of the Script structure */
2909  ASSERT(script);
2910  vector_pushBack(struct ScriptFieldDecl*, script->fields, sdecl);
2911  //script_addField(script, sdecl); //this also registered the field. We'll do that during sceneInstance
2912  }
2913 
2914  #ifdef CPARSERVERBOSE
2915  printf ("end of parser_interfaceDeclaration\n");
2916  #endif
2917  //if(mode == PKW_initializeOnly || mode == PKW_inputOutput)
2918  BACKUP //backup so something else parses 'fieldname <fieldvalue>' or 'fieldname IS protofieldname'
2919  //if it's just fieldname -it's an event with no IS- parser_field_user will detect and just swallow the fieldname
2920  //else
2921  //{
2922  // FREE_IF_NZ(me->lexer->curID); //event - swallow fieldname
2923  //}
2924  return TRUE;
2925 }
2926 
2927 BOOL find_anyfield_by_name(struct VRMLLexer* lexer, struct X3D_Node* node, union anyVrml **anyptr, int *imode, int *itype, char* nodeFieldName, int *isource, void **fdecl, int *ifield);
2928 void scriptFieldDecl_jsFieldInit(struct ScriptFieldDecl* me, int num);
2929 
2930 // OLD_IPHONE_AQUA #ifdef AQUA
2931 // OLD_IPHONE_AQUA #include <malloc/malloc.h>
2932 // OLD_IPHONE_AQUA #else
2933 
2934 #include <malloc.h>
2935 
2936 // OLD_IPHONE_AQUA #endif
2937 
2938 static BOOL parser_field_user(struct VRMLParser* me, struct X3D_Node *node) {
2939  int mode;
2940  int type;
2941  //int user;
2942  int source;
2943  int ifield;
2944  char *nodeFieldName;
2945  //int len;
2946  DECLAREUP
2947  //struct ProtoDefinition* proto;
2948  //struct Shader_Script* shader;
2949  union anyVrml *targetVal;
2950  void *fdecl;
2951  //struct ProtoFieldDecl* pdecl=NULL;
2952  //struct ProtoFieldDecl* pField=NULL;
2953  //struct ScriptFieldDecl* sdecl=NULL;
2954 
2955 
2956 #ifdef CPARSERVERBOSE
2957  printf ("start of parser_field_user\n");
2958 #endif
2959 
2960 
2961  /* Either PROTO or Script interface! */
2962  //ASSERT((proto || script) && !(proto && script));
2963 
2964  //get the fieldname
2965  SAVEUP //save the lexer spot so if it's not a 'fieldname <fieldValue>' we can backup
2966  /* get nodeFieldName */
2967  if(!lexer_setCurID(me->lexer)) return FALSE;
2968  ASSERT(me->lexer->curID);
2969  //len = strlen(me->lexer->curID);
2970  //nodeFieldName = alloca(len+1); //this also works but hard to verify cleanup
2971  //nodeFieldName = MALLOCV(len+1); //also works
2972  //strcpy(nodeFieldName,me->lexer->curID);
2973  nodeFieldName = STRDUP(me->lexer->curID);
2974  //nodeFieldName= me->lexer->curID;
2975  //if(!nodeFieldName){
2976  // nodeFieldName = "";
2977  //}
2978 
2979  //BACKUP;
2980  FREE_IF_NZ(me->lexer->curID);
2981 
2982  //retrieve field mode, type
2983  targetVal = NULL;
2984  if(!find_anyfield_by_name(me->lexer,node,&targetVal,&mode,&type,nodeFieldName,&source,&fdecl,&ifield)){
2985  //if(!find_anyfield_by_name(me->lexer,node,&targetVal,&mode,&type,me->lexer->curID,&source,&fdecl,&ifield)){
2986  BACKUP
2987  FREE_IF_NZ(nodeFieldName);
2988  return FALSE; //couldn't find field in user or builtin fields anywhere
2989  }
2990  if(source < 1){
2991  BACKUP
2992  FREE_IF_NZ(nodeFieldName);
2993  return FALSE; //we don't want builtins -handled elsewhere- just user fields
2994  }
2995 
2996  /* If this is a field or an exposed field */
2997  if(mode==PKW_initializeOnly || mode==PKW_inputOutput) {
2998 #ifdef CPARSERVERBOSE
2999  printf ("parser_field_user, mode==PKW_initializeOnly || mode==PKW_inputOutput\n");
3000 #endif
3001 
3002  /* set the defaultVal to something - we might have a problem if the parser expects this to be
3003  a MF*, and there is "garbage" in there, as it will expect to free it. */
3004  //bzero (&defaultVal, sizeof (union anyVrml)); //default val pulled from existing field default
3005  deleteMallocedFieldValue(type,targetVal);
3006  if (!parseType(me, type, targetVal)) {
3007  /* Invalid default value parsed. Delete the proto or script declaration. */
3008  CPARSE_ERROR_CURID("Expected default value for field!");
3009  //if(pdecl) deleteProtoFieldDecl(pdecl);
3010  //if(sdecl) deleteScriptFieldDecl(sdecl);
3011  FREE_IF_NZ(nodeFieldName);
3012  return FALSE;
3013  }
3014  if(source==3){
3015  //externProtoDeclares don't set an initial value, yet externProtoInstances copy the declare fields, even if junk or null
3016  // (versus regular protoDeclares which must set initial field values on inputOutput/initializeOnly)
3017  //so the alreadySet flag is to say that the EPI had a value set here, and when
3018  //filling out a late-ariving externprotodefinition EPD, only EPI fields that were initialzed are copied to the child PI
3019  //-see load_externProtoInstance()
3020  struct X3D_Proto *pnode = X3D_PROTO(node);
3021  //I could filter and just do extern proto, but lazy, so do any proto
3022  struct ProtoDefinition *pd = pnode->__protoDef;
3023  struct ProtoFieldDecl * pf = protoDefinition_getFieldByNum(pd, ifield);
3024  pf->alreadySet = 1;
3025  }
3026  if(source==1)
3027  {
3028  //((struct ScriptFieldDecl*) fdecl)->valueSet=TRUE;
3029  //((struct ScriptFieldDecl*) fdecl)->value = *targetVal;
3030  //X3D_SCRIPT(node)->__scriptObj
3031  //if(0) //don't do this during parsing, do it during scene instancing.
3032  //scriptFieldDecl_jsFieldInit(
3033  // (struct ScriptFieldDecl*) fdecl,
3034  // ((struct Shader_Script*)X3D_SCRIPT(node)->__scriptObj)->num);
3035  }
3036  //printf("n=%f\n",targetVal->sfcolor.c[0]);
3038  //if(proto) {
3039  // pdecl->defaultVal=defaultVal;
3040  //}
3041  //else
3042  //{
3043  // ASSERT(shader);
3044  // scriptFieldDecl_setFieldValue(sdecl, defaultVal);
3045  //}
3046  }
3047  #ifdef CPARSERVERBOSE
3048  printf ("end of parser_user_field\n");
3049  #endif
3050  FREEUP
3051  FREE_IF_NZ(nodeFieldName);
3052  return TRUE;
3053 }
3054 
3055 /* PROTO keyword handling.
3056  Like PROTO above: parses ProtoDeclare Interface
3057  Unlike PROTO above: parses the ProtoDeclare Body like a mini-scene,
3058  through re-entrant/recursive call to the same function that parses the main scene
3059  So a SceneDeclare is-a ProtoDeclare and vice versa.
3060 */
3061 static BOOL parser_brotoStatement(struct VRMLParser* me)
3062 {
3063  int name;
3064  struct ProtoDefinition* obj;
3065  //char *startOfBody;
3066  //char *endOfBody;
3067  //char *initCP;
3068  //uintptr_t bodyLen;
3069  struct X3D_Proto *proto, *parent;
3070  void *ptr;
3071  void *ectx;
3072  DECLAREUP
3073  unsigned int ofs;
3074 
3075 
3076  /* Really a PROTO? */
3077  SAVEUP
3078  if(!lexer_keyword(me->lexer, KW_PROTO)) //KW_BROTO))
3079  {
3080  BACKUP
3081  return FALSE;
3082  }
3083 
3084  /* Our name */
3085  /* lexer_defineNodeType is #defined as lexer_defineID(me, ret, userNodeTypesVec, FALSE) */
3086  /* Add the PROTO name to the userNodeTypesVec list of names return the index of the name in the list in name */
3087  if(!lexer_defineNodeType(me->lexer, &name))
3088  PARSE_ERROR("Expected nodeTypeId after PROTO!\n")
3089  ASSERT(name!=ID_UNDEFINED);
3090 
3091  /* Create a new blank ProtoDefinition structure to contain the data for this PROTO */
3092  obj=newProtoDefinition();
3093 
3094  /* save the name, if we can get it - it will be the last name on the list, because we will have JUST parsed it. */
3095  if (vectorSize(me->lexer->userNodeTypesVec) != ID_UNDEFINED) {
3096  obj->protoName = STRDUP(vector_get(const char*, me->lexer->userNodeTypesVec, vectorSize(me->lexer->userNodeTypesVec)-1));
3097  } else {
3098  printf ("warning - have proto but no name, so just copying a default string in\n");
3099  obj->protoName = STRDUP("noProtoNameDefined");
3100  }
3101 
3102  #ifdef CPARSERVERBOSE
3103  printf ("parser_protoStatement, working on proto :%s:\n",obj->protoName);
3104  #endif
3105 
3106  /* If the PROTOs stack has not yet been created, create it */
3107  if(!me->PROTOs) {
3108  parser_scopeIn_PROTO(me);
3109  }
3110 
3111  ASSERT(me->PROTOs);
3112  /* ASSERT(name==vectorSize(me->PROTOs)); */
3113 
3114  /* Add the empty ProtoDefinition structure we just created onto the PROTOs stack */
3115  vector_pushBack(struct ProtoDefinition*, me->PROTOs, obj);
3116 
3117  /* Now we want to fill in the information in the ProtoDefinition */
3118 
3119  /* Interface declarations */
3120 
3121  /* Make sure that the next token is a '['. Skip over it. */
3122  if(!lexer_openSquare(me->lexer))
3123  PARSE_ERROR("Expected [ to start interface declaration!")
3124 
3125  /* Read the next line and parse it as an interface declaration. */
3126  /* Add the user-defined field name to the appropriate list of user-defined names (user_initializeOnly, user_inputOnly, Out, or user_inputOutput).
3127  Create a new protoFieldDecl for this field and add it to the iface vector for the ProtoDefinition obj.
3128  For fields and inputOutputs, get the default value of the field and store it in the protoFieldDecl. */
3129  while(parser_interfaceDeclaration(me, obj, NULL));
3130 
3131  /* Make sure that the next token is a ']'. Skip over it. */
3132  if(!lexer_closeSquare(me->lexer))
3133  PARSE_ERROR("Expected ] after interface declaration!")
3134 
3135  //pseudocode:
3136  //proto = new Proto() //off scenegraph storage please
3137  //proto.__protoDef = obj
3138  //contextParent.declared_protos.add(proto);
3139  //parser_proto_body(proto)
3140  //return NULL; //no scenegraph node created, or more precisely: nothing to link in to parent's children
3141 
3142  //create a ProtoDeclare
3143  proto = createNewX3DNode0(NODE_Proto);
3144  //add it to the current context's list of declared protos
3145  if(X3D_NODE(me->ectx)->_nodeType != NODE_Proto && X3D_NODE(me->ectx)->_nodeType != NODE_Inline )
3146  printf("ouch trying to caste node type %d to proto\n",X3D_NODE(me->ectx)->_nodeType);
3147  parent = (struct X3D_Proto*)me->ectx;
3148  if(parent->__protoDeclares == NULL)
3149  parent->__protoDeclares = newVector(struct X3D_Proto*,4);
3150  vector_pushBack(struct X3D_Proto*,parent->__protoDeclares,proto);
3151 
3152 
3153  proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
3154  proto->__protoFlags = parent->__protoFlags;
3155  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
3157  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
3158  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,3); //((char*)(&proto->__protoFlags))[3] = 0; //not an externProtoDeclare
3159  //set ProtoDefinition *obj
3160  proto->__protoDef = obj;
3161  proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
3162  proto->__typename = STRDUP(obj->protoName);
3163 
3164  /* PROTO body */
3165  /* Make sure that the next oken is a '{'. Skip over it. */
3166  if(!lexer_openCurly(me->lexer))
3167  PARSE_ERROR("Expected { to start PROTO body!")
3168 
3169  /* record the start of this proto body - keep the text around */
3170  //startOfBody = (char *) me->lexer->nextIn;
3171  //initCP = (char *) me->lexer->startOfStringPtr[me->lexer->lexerInputLevel];
3172 
3173  /* Create a new vector of nodes and push it onto the DEFedNodes stack */
3174  /* This is the list of nodes defined for this scope */
3175  /* Also checks that the PROTOs vector exists, and creates it if it does not */
3176  parser_scopeIn(me);
3177 
3178  /* Parse body */
3179  {
3180 
3181 #ifdef CPARSERVERBOSE
3182  printf ("about to parse PROTO body; new proto def %p\n",obj);
3183 #endif
3184 
3185  //me->curPROTO=obj;
3186  ectx = me->ectx;
3187  ptr = me->ptr;
3188  ofs = me->ofs; //Q. does this change? Or are we always ofs of children in Proto? H: parseFromString different
3189  me->ectx = proto;
3190  me->ptr = proto;
3191  me->ofs = offsetof(struct X3D_Proto, __children);
3192  parse_proto_body(me);
3193  me->ectx = ectx;
3194  me->ptr = ptr;
3195  me->ofs = ofs;
3196 
3197  /* We are done parsing this proto. Set the curPROTO to the last proto we were parsing. */
3198  // me->curPROTO=oldCurPROTO;
3199  }
3200  if(!lexer_closeCurly(me->lexer))
3201  PARSE_ERROR("Expected } to end PROTO body!")
3202 
3203  /* Takes the top DEFedNodes vector off of the stack. The local scope now refers to the next vector in the DEFedNodes stack */
3204  parser_scopeOut(me);
3205 
3206  /* Make sure that the next token is a '}'. Skip over it. */
3207 #ifdef CPARSERVERBOSE
3208  printf ("calling lexer_closeCurly at A\n");
3209 printf ("parser_protoStatement, FINISHED proto :%s:\n",obj->protoName);
3210 #endif
3211  FREEUP
3212  return TRUE;
3213 }
3214 
3215 /* EXTERNPROTO keyword handling.
3216  Like PROTO above: parses ExternProtoDeclare Interface as a X3D_Proto
3217  - with __url and resource for fetching the definition
3218 */
3219 #define LOAD_INITIAL_STATE 0
3220 static BOOL parser_externbrotoStatement(struct VRMLParser* me)
3221 {
3222  int name;
3223  struct ProtoDefinition* obj;
3224  //char *startOfBody;
3225  //char *endOfBody;
3226  //char *initCP;
3227  //intptr_t bodyLen;
3228  struct X3D_Proto *proto, *parent;
3229  //void *ptr;
3230  DECLAREUP
3231  //unsigned int ofs;
3232 
3233 
3234  /* Really a EXTERNPROTO? */
3235  SAVEUP
3236  if(!lexer_keyword(me->lexer, KW_EXTERNPROTO))
3237  {
3238  BACKUP
3239  return FALSE;
3240  }
3241 
3242  /* Our name */
3243  /* lexer_defineNodeType is #defined as lexer_defineID(me, ret, userNodeTypesVec, FALSE) */
3244  /* Add the EXTERNPROTO name to the userNodeTypesVec list of names return the index of the name in the list in name */
3245  if(!lexer_defineNodeType(me->lexer, &name))
3246  PARSE_ERROR("Expected nodeTypeId after EXTERNPROTO!\n")
3247  ASSERT(name!=ID_UNDEFINED);
3248 
3249  /* Create a new blank ProtoDefinition structure to contain the data for this EXTERNPROTO */
3250  obj=newProtoDefinition();
3251  obj->isExtern = TRUE;
3252  /* save the name, if we can get it - it will be the last name on the list, because we will have JUST parsed it. */
3253  if (vectorSize(me->lexer->userNodeTypesVec) != ID_UNDEFINED) {
3254  obj->protoName = STRDUP(vector_get(const char*, me->lexer->userNodeTypesVec, vectorSize(me->lexer->userNodeTypesVec)-1));
3255  } else {
3256  printf ("warning - have proto but no name, so just copying a default string in\n");
3257  obj->protoName = STRDUP("noProtoNameDefined");
3258  }
3259 
3260  #ifdef CPARSERVERBOSE
3261  printf ("parser_protoStatement, working on proto :%s:\n",obj->protoName);
3262  #endif
3263 
3264  /* If the PROTOs stack has not yet been created, create it */
3265  if(!me->PROTOs) {
3266  parser_scopeIn_PROTO(me);
3267  }
3268 
3269  ASSERT(me->PROTOs);
3270  /* ASSERT(name==vectorSize(me->PROTOs)); */
3271 
3272  /* Add the empty ProtoDefinition structure we just created onto the PROTOs stack */
3273  vector_pushBack(struct ProtoDefinition*, me->PROTOs, obj);
3274 
3275  /* Now we want to fill in the information in the ProtoDefinition */
3276 
3277  /* Interface declarations */
3278 
3279  /* Make sure that the next token is a '['. Skip over it. */
3280  if(!lexer_openSquare(me->lexer))
3281  PARSE_ERROR("Expected [ to start interface declaration!")
3282 
3283  /* Read the next line and parse it as an interface declaration. */
3284  /* Add the user-defined field name to the appropriate list of user-defined names (user_initializeOnly, user_inputOnly, Out, or user_inputOutput).
3285  Create a new protoFieldDecl for this field and add it to the iface vector for the ProtoDefinition obj.
3286  For fields and inputOutputs, get the default value of the field and store it in the protoFieldDecl. */
3287  while(parser_interfaceDeclaration(me, obj, NULL));
3288 
3289  /* Make sure that the next token is a ']'. Skip over it. */
3290  if(!lexer_closeSquare(me->lexer))
3291  PARSE_ERROR("Expected ] after interface declaration!")
3292 
3293  //pseudocode:
3294  //proto = new Proto() //off scenegraph storage please
3295  //proto.__protoDef = obj
3296  //contextParent.declared_protos.add(proto);
3297  //parser_proto_body(proto)
3298  //return NULL; //no scenegraph node created, or more precisely: nothing to link in to parent's children
3299 
3300  //create a ProtoDeclare
3301  proto = createNewX3DNode0(NODE_Proto);
3302  //add it to the current context's list of declared protos
3303  parent = (struct X3D_Proto*)me->ectx;
3304  if(parent->__externProtoDeclares == NULL)
3305  parent->__externProtoDeclares = newVector(struct X3D_Proto*,4);
3306  vector_pushBack(struct X3D_Proto*,parent->__externProtoDeclares,proto);
3307 
3308 
3309  proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
3310  proto->__protoFlags = parent->__protoFlags;
3311  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
3313  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
3314  proto->__protoFlags = ciflag_set(proto->__protoFlags,1,3); //((char*)(&proto->__protoFlags))[3] = 1; //an externProtoDeclare
3315  //set ProtoDefinition *obj
3316  proto->__protoDef = obj;
3317  proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
3318  proto->__typename = (void *)STRDUP(obj->protoName);
3319 
3320  /* EXTERNPROTO url */
3321  {
3322  //struct Multi_String url;
3323  //unsigned char *buffer;
3324  //char *pound;
3325  //resource_item_t *res;
3326 
3327  /* get the URL string */
3328  if (!parser_mfstringValue(me,&proto->url)) {
3329  PARSE_ERROR ("EXTERNPROTO - problem reading URL string");
3330  }
3331  proto->__loadstatus = LOAD_INITIAL_STATE;
3332  /*the rest is done in load_externProto during rendering*/
3333  }
3334 
3335  FREEUP
3336  return TRUE;
3337 }
3338 
3339 /*Q. could/should brotoRoutes resolve to pointers early during parsing (as they are now)
3340  or late (by storing char* DEFNode, char* fieldname)?
3341  - late might help with Inline IMPORT/EXPORT, where routes are declared
3342  before the nodes appear.
3343 */
3344 //see CRoutes.h
3345 //struct brotoRoute
3346 //{
3347 // struct X3D_Node* fromNode;
3348 // int fromOfs;
3349 // struct X3D_Node* toNode;
3350 // int toOfs;
3351 // int ft;
3352 //};
3353 struct brotoRoute *createNewBrotoRoute();
3354 void broto_store_route(struct X3D_Proto* proto,
3355  struct X3D_Node* fromNode, int fromIndex,
3356  struct X3D_Node* toNode, int toIndex,
3357  int ft)
3358 {
3359  Stack* routes;
3360  struct brotoRoute* route;
3361  //struct X3D_Proto* protoDeclare = (struct X3D_Proto*)me->ptr;
3362  ASSERT(proto);
3363  if ((fromIndex == ID_UNDEFINED) || (toIndex == ID_UNDEFINED)) {
3364  ConsoleMessage ("problem registering route - either fromField or toField invalid");
3365  return;
3366  }
3367 
3368  route = createNewBrotoRoute();
3369  route->from.node = fromNode;
3370  route->from.ifield = fromIndex;
3371  route->to.node = toNode;
3372  route->to.ifield = toIndex;
3373  route->lastCommand = 1; //??
3374  route->ft = ft;
3375 
3376  routes = proto->__ROUTES;
3377  if( routes == NULL){
3378  routes = newStack(struct brotoRoute *);
3379  proto->__ROUTES = routes;
3380  }
3381  stack_push(struct brotoRoute *, routes, route);
3382  return;
3383 }
3384 //struct ImportRoute
3385 //{
3386 // char* fromNode;
3387 // char* fromField;
3388 // char* toNode;
3389 // char* toField;
3390 //};
3391 //void broto_store_ImportRoute_old(struct X3D_Proto* proto, char *fromNode, char *fromField, char *toNode, char* toField)
3392 //{
3393 // struct ImportRoute* improute;
3394 // if( proto->__IMPROUTES == NULL)
3395 // proto->__IMPROUTES= newStack(struct ImportRoute *);
3396 // improute = MALLOC(struct ImportRoute*,sizeof(struct ImportRoute));
3397 // improute->fromNode = strdup(fromNode);
3398 // improute->fromField = strdup(fromField);
3399 // improute->toNode = strdup(toNode);
3400 // improute->toField = strdup(toField);
3401 // stack_push(struct ImportRoute *, proto->__IMPROUTES, improute);
3402 //}
3403 void broto_store_ImportRoute_obsolete(struct X3D_Proto* proto, char *fromNode, char *fromField, char *toNode, char* toField)
3404 {
3405  //there could be combinations of known/strong/node* and weak char* route ends - in that case split up this function
3406  struct brotoRoute* route;
3407  if( proto->__ROUTES == NULL)
3408  proto->__ROUTES= newStack(struct brotoRoute *);
3409  route = createNewBrotoRoute();
3410  route->ft = -1;
3411  route->lastCommand = 0; //not added to CRoutes until inline loaded
3412  route->from.weak = 2; //weak references to publish/from,subscribe/to ends not loaded yet
3413  route->from.cnode = STRDUP(fromNode);
3414  route->from.cfield = STRDUP(fromField);
3415  route->from.ftype = -1; //unknown
3416  route->to.weak = 2;
3417  route->to.cnode = STRDUP(toNode);
3418  route->to.cfield = STRDUP(toField);
3419  route->to.ftype = -1; //unknown
3420  stack_push(struct brotoRoute *, proto->__ROUTES, route);
3421 }
3422 struct brotoRoute *createNewBrotoRoute(){
3423  struct brotoRoute* route;
3424  route = MALLOC(struct brotoRoute*,sizeof(struct brotoRoute));
3425  memset(route,0,sizeof(struct brotoRoute));
3426  return route;
3427 }
3428 void broto_store_broute(struct X3D_Proto* context,struct brotoRoute *route){
3429  if( context->__ROUTES == NULL)
3430  context->__ROUTES= newStack(struct brotoRoute *);
3431  stack_push(struct brotoRoute *, context->__ROUTES, route);
3432 }
3433 void free_brouteEnd(struct brouteEnd *bend){
3434  FREE_IF_NZ(bend->cnode);
3435  FREE_IF_NZ(bend->cfield);
3436 }
3437 void free_broute(struct brotoRoute *route){
3438  free_brouteEnd(&route->from);
3439  free_brouteEnd(&route->to);
3440 }
3441 //BOOL route_parse_nodefield(pre, eventType)
3442 //used by parser_routeStatement:
3443 
3444 BOOL route_parse_nodefield(struct VRMLParser* me, int *NodeIndex, struct X3D_Node** Node, int KW_eventType,
3445  int *Ofs, int *fieldType, struct ScriptFieldDecl** ScriptField)
3446 {
3447  int PKW_eventType = PKW_outputOnly;
3448  char *cerror1;
3449 
3450  int mode;
3451  int type;
3452  int source;
3453  int ifield; //, iprotofield;
3454  char *nodeFieldName;
3455  //DECLAREUP
3456  int foundField;
3457  union anyVrml *fieldPtr;
3458  void *fdecl = NULL;
3459 
3460  *Ofs = 0;
3461  //Node = NULL;
3462  *ScriptField=NULL;
3463  cerror1 = "";
3464 
3465  if(KW_eventType == KW_outputOnly){
3466  PKW_eventType = PKW_outputOnly;
3467  cerror1 = "Expected an event of type : outputOnly :";
3468  }else if(KW_eventType == KW_inputOnly) {
3469  PKW_eventType = PKW_inputOnly;
3470  cerror1 = "Expected an event of type : inputOnly :";
3471  }
3472 
3473  /* Target-node */
3474 
3475  /* Look for the current token in the userNodeNames vector (DEFed names) */
3476  if(!lexer_nodeName(me->lexer, NodeIndex)) {
3477  /* The current token is not a valid DEFed name. Error. */
3478  CPARSE_ERROR_CURID("ERROR:ROUTE: Expected a valid DEF name; found \"");
3479  PARSER_FINALLY;
3480  return FALSE;
3481  }
3482 
3483 
3484  /* Check that there are DEFedNodes in the DEFedNodes vector, and that the index given for this node is valid */
3485  ASSERT(me->DEFedNodes && !stack_empty(me->DEFedNodes) && *NodeIndex<vectorSize(stack_top(struct Vector*, me->DEFedNodes)));
3486  /* Get the X3D_Node structure for the DEFed node we just looked up in the userNodeNames list */
3487  *Node=vector_get(struct X3D_Node*,
3488  stack_top(struct Vector*, me->DEFedNodes),
3489  *NodeIndex);
3490  /* We were'nt able to get the X3D_Node structure for the DEFed node. Error. */
3491  if (*Node == NULL) {
3492  /* we had a bracket underflow, from what I can see. JAS */
3493  CPARSE_ERROR_CURID("ERROR:ROUTE: no DEF name found - check scoping and \"}\"s");
3494  PARSER_FINALLY;
3495  return FALSE;
3496  }
3497 
3498 
3499  /* The next character has to be a '.' - skip over it */
3500  if(!lexer_point(me->lexer)) {
3501  CPARSE_ERROR_CURID("ERROR:ROUTE: Expected \".\" after the NODE name")
3502  PARSER_FINALLY;
3503  return FALSE;
3504  }
3505  //SAVEUP //save the lexer spot so if it's not an IS we can back up
3506  /* get nodeFieldName */
3507  if(!lexer_setCurID(me->lexer)) return FALSE;
3508  ASSERT(me->lexer->curID);
3509  nodeFieldName = STRDUP(me->lexer->curID);
3510  //BACKUP;
3511  FREE_IF_NZ(me->lexer->curID);
3512 
3513  fieldPtr = NULL;
3514  foundField = find_anyfield_by_nameAndRouteDir( *Node, &fieldPtr, &mode, &type,
3515  nodeFieldName, &source, &fdecl, &ifield, PKW_eventType);
3516  if(foundField)
3517  {
3518  if(source == 0)
3519  *Ofs = NODE_OFFSETS[(*Node)->_nodeType][ifield*5 + 1];
3520  else
3521  *Ofs = ifield;
3522  *ScriptField = fdecl;
3523  *fieldType = type;
3524  return TRUE;
3525  }
3526  if((*Node)->_nodeType==NODE_Script && !fdecl) {
3527  PARSE_ERROR("Event-field invalid for this PROTO/Script!")
3528  } else {
3529  PARSE_ERROR(cerror1)
3530  }
3531  FREE_IF_NZ(nodeFieldName);
3532  PARSER_FINALLY;
3533  return FALSE;
3534 }
3535 struct IMEXPORT *broto_search_IMPORTname(struct X3D_Proto *context, char *name);
3536 BOOL route_parse_nodefield_B(struct VRMLParser* me, char **ssnode, char **ssfield)
3537 {
3538  /* parse a route node.field
3539  this _B version is designed to
3540  1. be a little less tragic if things don't go well - just don't register a bad route, warn the user
3541  2. look for DEF names in the proto context instead of global browser context, as per specs, if we aren't doing that already
3542  3. to accomodate routes to/from late-arriving inline IMPORT nodes
3543  */
3544  char *snode,*sfield;
3545  //struct X3D_Node* xnode;
3546  //int foundField;
3547 
3548  /* Get the next token */
3549  if(!lexer_setCurID(me->lexer))
3550  return FALSE;
3551  ASSERT(me->lexer->curID);
3552  snode = STRDUP(me->lexer->curID);
3553  FREE_IF_NZ(me->lexer->curID);
3554 
3555 
3556  /* The next character has to be a '.' - skip over it */
3557  if(!lexer_point(me->lexer)) {
3558  CPARSE_ERROR_CURID("ERROR:ROUTE: Expected \".\" after the NODE name")
3559  PARSER_FINALLY;
3560  return FALSE;
3561  }
3562 
3563  /* get fieldName */
3564  if(!lexer_setCurID(me->lexer))
3565  return FALSE;
3566  ASSERT(me->lexer->curID);
3567  sfield = STRDUP(me->lexer->curID);
3568  FREE_IF_NZ(me->lexer->curID);
3569 
3570  *ssnode = snode;
3571  *ssfield = sfield;
3572 
3573  PARSER_FINALLY;
3574  return TRUE;
3575 }
3576 
3577 
3578 void QAandRegister_parsedRoute_B(struct X3D_Proto *context, char* fnode, char* ffield, char* tnode, char* tfield);
3579 
3580 // modified by dug9 oct25, 2014
3581 // this one is designed not to crash if theres an IMPORT route
3582 static BOOL parser_routeStatement_B(struct VRMLParser* me)
3583 {
3584  char *sfnode, *sffield;
3585  char *stnode, *stfield;
3586  int foundfrom, foundto, gotTO;
3587 
3588  ppCParseParser p = (ppCParseParser)gglobal()->CParseParser.prv;
3589 
3590  ASSERT(me->lexer);
3591  lexer_skip(me->lexer);
3592 
3593  /* Is this a routeStatement? */
3594  if(!lexer_keyword(me->lexer, KW_ROUTE))
3595  return FALSE;
3596 
3597  /* Parse the elements. */
3598 
3599  /* Parse the first part of a routing statement: DEFEDNODE.event by locating the node DEFEDNODE in either the builtin or user-defined name arrays
3600  and locating the event in the builtin or user-defined event name arrays */
3601  //ROUTE_PARSE_NODEFIELD(from, outputOnly);
3602  foundfrom = route_parse_nodefield_B(me,&sfnode, &sffield);
3603 
3604  /* Next token has to be "TO" */
3605  gotTO = TRUE;
3606  if(!lexer_keyword(me->lexer, KW_TO)) {
3607  /* try to make a better error message. */
3608  char *buf = p->fw_outline;
3609  strcpy (buf,"ERROR:ROUTE: Expected \"TO\" found \"");
3610  if (me->lexer->curID != NULL) strcat (buf, me->lexer->curID); else strcat (buf, "(EOF)");
3611  CPARSE_ERROR_CURID(buf);
3612  PARSER_FINALLY;
3613  //return FALSE;
3614  gotTO = FALSE;
3615  }
3616 /* Parse the second part of a routing statement: DEFEDNODE.event by locating the node DEFEDNODE in either the builtin or user-defined name arrays
3617  and locating the event in the builtin or user-defined event name arrays */
3618  //ROUTE_PARSE_NODEFIELD(to, inputOnly);
3619  foundto = route_parse_nodefield_B(me,&stnode, &stfield);
3620 
3621  if(!(foundfrom && gotTO && foundto)){
3622  FREE_IF_NZ(sfnode);
3623  FREE_IF_NZ(sffield);
3624  FREE_IF_NZ(stnode);
3625  FREE_IF_NZ(stfield);
3626  PARSER_FINALLY;
3627  return FALSE;
3628  }
3629 
3630  QAandRegister_parsedRoute_B(X3D_PROTO(me->ectx), sfnode, sffield, stnode, stfield);
3631  FREE_IF_NZ(sfnode);
3632  FREE_IF_NZ(sffield);
3633  FREE_IF_NZ(stnode);
3634  FREE_IF_NZ(stfield);
3635 
3636  return TRUE;
3637 }
3638 
3639 /*
3640  Binary Protos aka Brotos - allows deeply nested protos, by using scene parsing code to parse protobodies
3641  recursively, as Flux2008 likely does
3642  History:
3643  Jan 2013, Broto1- did first version for .wrl parsing, but it unrolled the results into the main scene tables
3644  (Routes, scripts, etc) via function sceneInstance() - and didn't do .x3d parsing, nor externProtos
3645  Sept 2014 Broto2 - attempt to render directly from Broto-format scene, and fix externProtos
3646  Concepts:
3647  deep vs shallow: when instancing a prototype, you go deep if you copy the protoDeclare body
3648  to the body of the protoInstance, and recursively deepen any contained protoInstances.
3649  You go shallow if you just copy the interface (so you can route to it) leaving the body empty. Related to proto expansion.
3650  Scene as Proto - to allow the parser to use the same code to parse the scene and protobodies -recursing-
3651  the scene and protos need to have a common format. Once parsed, Broto1 converted the SceneProto to old tables and structs.
3652  Broto2 is rendering the SceneProto directly, saving awkward conversion, and requiring rendering
3653  algorithms that recurse
3654  ExternProtoDeclare/instance - design goal: have externProtoDeclare wrap/contain a protoDeclare,
3655  and instance the protodeclare as its first node once loaded, and have an algorithm that ISes
3656  between the externProtoDeclare interface and the contained protoInstance fields. This 'wrapper' design
3657  allows flexibility in ordering of fields, and can do minor PKW mode conversions, and allow the parser
3658  to continue parsing the scene while the externproto definition downloads and parses asynchronously
3659  p2p - pointer2pointer node* lookup table when copying a binary protoDeclare to a protoInstance:
3660  tables in the declare -such as routes and DEFs- are in terms of the Declare node*, and after new nodoes
3661  are created for the protoInstance, the protoDeclare-to-protoInstance node* lookup can be done during
3662  copying of the tables
3663  Broto2: 6 things share an X3D_Proto node structure:
3664  1. ProtoInstance - the only one of these 5 that's shown as a node type in web3d.org specs
3665  2. ProtoDeclare - we don't register the struct as a node when mallocing, and we don't expand (deepen) its contained protoInstances
3666  3. ExternProtoInstance - in the specs, this would be just another ProtoInstance.
3667  4. ExternProtoDeclare - will be like ProtoDeclare, with a URL and a way to watch for it's protodefinition being loaded, like Inline
3668  5. Scene - so that parsing can parse protoDeclares and Scene using the same code, we use the same struct.
3669  - Broto1 parsed the scene shallow, then in a second step sceneInstance() deepened the brotos while converting to old scene format
3670  - Broto2 parses deep for scenes and inlines, shallow for protodeclares and externProtodeclares
3671  6. Inline - declared as a separatey X3D_Inline type, but maintained as identical struct to X3D_Proto
3672  To keep these 5 distinguished,
3673  char *pflags = (char *)(int* &__protoFlags)
3674  pflag[0]: deep parsing instruction
3675  1= parse deep: deepen any protoInstances recursively, and register nodes when mallocing (for scene, inline)
3676  0= parse shallow: instance protos with no body, don't register nodes during mallocing (for protoDeclare, externProtoDeclare)
3677  pflag[1]: oldway parsing instruction
3678  1= oldway, for where to send routes etc
3679  0= broto1, broto2 way
3680  pflag[2]: declare, instance, or scene object
3681  0 = protoDeclare or externProtoDeclare //shouldn't be rendered
3682  1 = ProtoInstance or externProtoInstance //first child node is in the render transform stack
3683  2 = scene //all child nodes are rendered
3684  pflag[3]: extern or intern object
3685  0 = scene, protodeclare, protoInstance
3686  1 = externProtoInstance, externprotodeclare
3687 */
3688 
3689 //moved to header:
3690 //struct brotoDefpair{
3691 // struct X3D_Node* node;
3692 // char* name;
3693 //};
3694 void broto_store_DEF(struct X3D_Proto* proto,struct X3D_Node* node, const char *name)
3695 {
3696  Stack *defs;
3697  struct brotoDefpair def;
3698  def.node = node;
3699  def.name = STRDUP(name);
3700  defs = proto->__DEFnames;
3701  if( defs == NULL)
3702  {
3703  defs = newStack(struct brotoDefpair);
3704  proto->__DEFnames = defs;
3705  }
3706  stack_push(struct brotoDefpair, defs, def);
3707 }
3708 int broto_search_DEF_index_by_node(struct X3D_Proto* proto, struct X3D_Node *node){
3709  int index;
3710  Stack *defs = proto->__DEFnames;
3711  index = -1;
3712  if(defs){
3713  int i;
3714  for(i=0;i<vectorSize(defs);i++){
3715  struct brotoDefpair def = vector_get(struct brotoDefpair,defs,i);
3716  if(def.node == node){
3717  index = i;
3718  break;
3719  }
3720  }
3721  }
3722  return index;
3723 }
3724 
3725 void broto_clear_DEF_by_node(struct X3D_Proto* proto,struct X3D_Node* node)
3726 {
3727  int index;
3728  Stack *defs;
3729  struct brotoDefpair def;
3730  index = broto_search_DEF_index_by_node(proto,node);
3731  if(index > -1){
3732  defs = proto->__DEFnames;
3733  def = vector_get(struct brotoDefpair,defs,index);
3734  FREE_IF_NZ(def.name);
3735  vector_removeElement(sizeof(struct brotoDefpair),defs,index);
3736  }
3737 }
3738 struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name){
3739  int i, istart, iend;
3740  struct brotoDefpair def;
3741  //in theory we should search backward. test 9.wrl has 2 TRs. If you make the first one with no children,
3742  // and the second one around the viewpoint, and you send an animation via route to TR.translation
3743  // octaga, instant and viv route to the 2nd one / last TR before the ROUTE
3744  if(context->__DEFnames){
3745  istart = vectorSize(context->__DEFnames) -1;
3746  iend = 0;
3747  for(i=istart;i>=iend; i--) {
3748  def = vector_get(struct brotoDefpair, context->__DEFnames,i);
3749  if(!strcmp(def.name, name)) return def.node;
3750  }
3751  }
3752  return NULL;
3753 }
3754 struct IMEXPORT *broto_search_IMPORTname(struct X3D_Proto *context, char *name){
3755  int i;
3756  struct IMEXPORT *def;
3757  if(context->__IMPORTS)
3758  for(i=0;i<vectorSize(context->__IMPORTS);i++){
3759  def = vector_get(struct IMEXPORT *, context->__IMPORTS,i);
3760  if(!strcmp(def->as,name)) return def;
3761  }
3762  return NULL;
3763 }
3764 struct IMEXPORT *broto_search_EXPORTname(struct X3D_Proto *context, char *name){
3765  int i;
3766  struct IMEXPORT *def;
3767  if(context->__EXPORTS)
3768  for(i=0;i<vectorSize(context->__EXPORTS);i++){
3769  def = vector_get(struct IMEXPORT *, context->__EXPORTS,i);
3770  if(!strcmp(def->as,name)) return def;
3771  }
3772  return NULL;
3773 }
3774 
3775 
3776 BOOL isAvailableBroto(char *pname, struct X3D_Proto* currentContext, struct X3D_Proto **proto)
3777 {
3778  /* search list of already-defined binary protos in current context,
3779  and in ancestor proto contexts*/
3780  int i;
3781  struct ProtoDefinition* obj;
3782  struct X3D_Proto *p;
3783  struct X3D_Proto* context;
3784  //struct Multi_Node *plist;
3785  struct Vector *plist;
3786 
3787  *proto = NULL;
3788  /* besides current context list also search parent context list if there is one */
3789  context = currentContext;
3790  do {
3791  int j;
3792  //flux,vivaty search top-down, cortona,blaxxun,white_dune search bottom-up within context,
3793  // this only makes a difference if you have more than one protodefinition with the same protoName
3794  // in the same context
3795  BOOL bottomUp = TRUE;
3796  //plist = &context->__protoDeclares;
3797  plist = (struct Vector*) context->__protoDeclares;
3798  if(plist){
3799  int n = vectorSize(plist);
3800  for(i=0;i<n;i++)
3801  {
3802  j = i;
3803  if(bottomUp) j = n - 1 - i;
3804  //p = (struct X3D_Proto*)plist->p[j];
3805  p = vector_get(struct X3D_Proto*,plist,j);
3806  obj = p->__protoDef;
3807  if(!strcmp(obj->protoName,pname))
3808  {
3809  *proto = p;
3810  return TRUE;
3811  }
3812  }
3813  }
3814  plist = (struct Vector*) context->__externProtoDeclares;
3815  if(plist){
3816  int n = vectorSize(plist);
3817  for(i=0;i<n;i++)
3818  {
3819  j = i;
3820  if(bottomUp) j = n - 1 - i;
3821  //p = (struct X3D_Proto*)plist->p[j];
3822  p = vector_get(struct X3D_Proto*,plist,j);
3823  obj = p->__protoDef;
3824  if(!strcmp(obj->protoName,pname))
3825  {
3826  *proto = p;
3827  return TRUE;
3828  }
3829  }
3830  }
3831  context = (struct X3D_Proto*)context->__parentProto;
3832  }while(context);
3833  printf("ouch no broto definition found\n");
3834  return FALSE;
3835 }
3837  struct X3D_Node* pp; //old or protoDeclare pointer
3838  struct X3D_Node* pn; //new or protoInstance pointer
3839 };
3840 
3841 struct X3D_Node* inPointerTable(struct X3D_Node* source,struct Vector *p2p)
3842 {
3843  int i;
3844  struct X3D_Node *dest = NULL;
3845  struct pointer2pointer pair;
3846  for(i=0;i<p2p->n;i++)
3847  {
3848  pair = vector_get(struct pointer2pointer, p2p, i);
3849  if(pair.pp == source){
3850  dest = pair.pn;
3851  break;
3852  }
3853  }
3854  return dest;
3855 }
3856 struct X3D_Node *p2p_lookup(struct X3D_Node *pnode, struct Vector *p2p);
3857 void copy_routes2(Stack *routes, struct X3D_Proto* target, struct Vector *p2p)
3858 {
3859  //for 2014 broto2, deep copying of brotodeclare to brotoinstance
3860  int i;
3861  struct brotoRoute *route;
3862  struct X3D_Node *fromNode, *toNode;
3863  if(routes == NULL) return;
3864  for(i=0;i<routes->n;i++)
3865  {
3866  route = vector_get(struct brotoRoute*, routes, i);
3867  //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
3868  //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
3869  fromNode = p2p_lookup(route->from.node,p2p);
3870  toNode = p2p_lookup(route->to.node,p2p);
3871  CRoutes_RegisterSimpleB(fromNode, route->from.ifield, toNode, route->to.ifield, route->ft);
3872  //we'll also store in the deep broto instance, although they aren't used there (yet), and
3873  //if target is the main scene, they are abandoned. Maybe someday they'll be used.
3874  //if( target )
3875  broto_store_route(target,fromNode,route->from.ifield, toNode, route->to.ifield, route->ft);
3876  }
3877 }
3878 //copy broto defnames to single global scene defnames, for node* to defname lookup in parser_getNameFromNode
3879 //but can't go the other way (name to node) because there can be duplicate nodes with the same name in
3880 //different contexts
3881 //this version for 2014 broto2
3882 void copy_defnames2(Stack *defnames, struct X3D_Proto* target, struct Vector *p2p)
3883 {
3884  //Stack* defs;
3885  //struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
3886 
3887  //defs = globalParser->brotoDEFedNodes;
3888  //if( defs == NULL)
3889  //{
3890  // defs = newStack(struct brotoDefpair *);
3891  // globalParser->brotoDEFedNodes = defs;
3892  //}
3893  if(target->__DEFnames == NULL)
3894  target->__DEFnames = newStack(struct brotoDefpair);
3895  if(defnames)
3896  {
3897  int i,n;
3898  struct brotoDefpair def, def2;
3899  n = vectorSize(defnames);
3900  for(i=0;i<n;i++){
3901  def = vector_get(struct brotoDefpair,defnames,i);
3902  def2.name = STRDUP(def.name); //I wonder who owns this name
3903  def2.node = p2p_lookup(def.node, p2p);
3904  //stack_push(struct brotoDefpair*, defs, def2);
3905  stack_push(struct brotoDefpair, target->__DEFnames, def2); //added for broto2
3906  }
3907  }
3908 }
3909 void copy_IS(Stack *istable, struct X3D_Proto* target, struct Vector *p2p);
3910 void copy_IStable(Stack **sourceIS, Stack** destIS);
3911 void copy_field(int typeIndex, union anyVrml* source, union anyVrml* dest, struct Vector *p2p,
3912  Stack *instancedScripts, struct X3D_Proto *ctx, struct X3D_Node *parent);
3913 void initialize_scripts(Stack *instancedScripts);
3914 void deep_copy_broto_body2(struct X3D_Proto** proto, struct X3D_Proto** dest)
3915 {
3916  //for use with 2014 broto2 when parsing scene/inline and we want to deep-instance brotos as we parse
3917  //converts from binary proto/broto format to old scene format:
3918  // - ROUTES are registered in global ROUTE registry
3919  // - nodes are instanced and registered in memoryTable for startOfLoopNodesUpdate and killNode access
3920  // - sensors, viewpoints etc are registered
3921  //proto - broto instance with
3922  // - a pointer __prototype to its generic prototype
3923  //dest - protoinstance with user fields filled out for this instance already
3924  // - children/body not filled out yet - it's done here
3925  // - any field/exposedField values in interface IS copied to body node fields
3926  // - broto ROUTES registered in global route registry, with this instances' node* addresses
3927  // ? ( sensors, viewpoints will be directly registered in global/main scene structs)
3928  //what will appear different in the scene:
3929  // old: PROTO instances appear as Group nodes with metaSF nodes for interface routing, mangled DEFnames
3930  // new: PROTO instances will appear as X3DProto nodes with userfields for interface routing, local DEFnames
3931 
3932  //DEEP COPYING start here
3933  //we're instancing for the final scene, so go deep
3934  //0. setup pointer lookup table proto to instance
3935  //1. copy nodes, recursing on MFNode,SFnode fields
3936  // to copy, instance a new node of the same type and save (new pointer, old pointer) in lookup table
3937  // iterate over proto's node's fields, copying, and recursing on MFNode, SFNode
3938  // if node is a ProtoInstance, deepcopy it
3939  //2. copy ROUTE table, looking up new_pointers in pointer lookup table
3940  //3. copy IS table, looking up new_pointers in pointer lookup table
3941  //4. copy DEFname table, looking up new pointers in pointer lookup table
3942  //
3943 
3944  struct X3D_Proto *prototype, *p;
3945  struct X3D_Node *parent;
3946  Stack *instancedScripts;
3947  struct Vector *p2p = newVector(struct pointer2pointer,10);
3948 
3949  //2. copy body from source's _prototype.children to dest.children, ISing initialvalues as we go
3950  p=(*dest);
3951  p->__children.n = 0;
3952  p->__children.p = NULL;
3953  parent = (struct X3D_Node*) (*dest); //NULL;
3954  prototype = (struct X3D_Proto*)(*proto)->__prototype;
3955 
3956  p->__prototype = X3D_NODE(prototype);
3957  //p->__protoFlags = prototype->__protoFlags; //done in brotoInstance
3958  p->__protoFlags = ciflag_set(p->__protoFlags,1,2); //deep instancing of protoInstances inside a protoDeclare
3959 
3960  //prototype = (struct X3D_Proto*)p->__prototype;
3961  //2.c) copy IS
3962  //p->__IS = copy IStable from prototype, and the targetNode* pointer will be wrong until p2p
3963  //copy_IStable(&((Stack*)prototype->__IS), &((Stack*)p->__IS));
3964 
3965  copy_IStable((Stack **) &(prototype->__IS), (Stack **) &(p->__IS));
3966 
3967  instancedScripts = (*dest)->__scripts;
3968  if( instancedScripts == NULL)
3969  {
3970  instancedScripts = newStack(struct X3D_Node *);
3971  (*dest)->__scripts = instancedScripts;
3972  }
3973 
3974  //2.a) copy rootnodes
3975  copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(prototype->__children),(union anyVrml*)&(p->__children),
3976  p2p,instancedScripts,p,parent);
3977  //2.b) copy routes
3978  copy_routes2(prototype->__ROUTES, p, p2p);
3979  //2.d) copy defnames
3980  copy_defnames2(prototype->__DEFnames, p, p2p);
3981 
3983  copy_IS(p->__IS, p, p2p);
3984 
3985  initialize_scripts(instancedScripts);
3986 
3987  //*dest = p;
3988  deleteVector(struct pointer2pointer,p2p); //free p2p
3989  return;
3990 }
3991 struct X3D_Proto *brotoInstance(struct X3D_Proto* proto, BOOL ideep)
3992 {
3993  //shallow copy - just the user-fields, and point back to the *prototype for later
3994  // deep copy of body and IS-table (2014 broto2 when parsing a protoDeclare or externProtoDeclare)
3995  //deep copy - copy body and tables, and if an item in the body is a protoInstance, deep copy it (recursively)
3996  // (2014 broto2 when parsing a scene or inline)
3997 
3998  int i;
3999  //int iProtoDeclarationLevel;
4000  struct ProtoDefinition *pobj,*nobj;
4001  struct ProtoFieldDecl *pdecl,*ndecl;
4002  struct X3D_Proto *p;
4003  if(ideep){
4004  int pflags;
4005  p = createNewX3DNode(NODE_Proto);
4006  //memcpy(p,proto,sizeof(struct X3D_Proto)); //dangerous, make sure you re-instance all pointer variables
4007  p->__children.n = 0; //don't copy children in here - see below
4008  p->__children.p = NULL;
4009  pflags = 0;
4010  //char pflags[4];
4011  pflags = ciflag_set(pflags,1,0); //pflags[0] = 1; //deep
4012  //pflags[1] = 0; //new way/brotos
4013  pflags = ciflag_set(pflags,1,2); //pflags[2] = 1; //this is a protoInstance
4014  pflags = ciflag_set(pflags,0,3); //pflags[3] = 0; //not an extern
4015  if(ciflag_get(proto->__protoFlags,3)==1)
4016  pflags = ciflag_set(pflags,1,3); //its an externProtoInstance
4017  //memcpy(&p->__protoFlags,pflags,sizeof(int));
4018  p->__protoFlags = pflags;
4019  }else{
4020  //shallow
4021  p = createNewX3DNode0(NODE_Proto);
4022  //memcpy(p,proto,sizeof(struct X3D_Proto)); //dangerous, make sure you re-instance all pointer variables
4023  p->__children.n = 0; //don't copy children in here.
4024  p->__children.p = NULL;
4025  //char pflags[4];
4026  //pflags[0] = 0; //shallow
4027  //pflags[1] = 0; //new way/brotos
4028  //pflags[2] = 0; //this is a protoDeclare if shallow
4029  //pflags[3] = 0; //not an extern
4030  //memcpy(&p->__protoFlags,pflags,sizeof(int));
4031  p->__protoFlags = 0;
4032  //if(ciflag_get(proto->__protoFlags,3)==1) //+ Jan 2015
4033  // p->__protoFlags = ciflag_set(p->__protoFlags,1,3); //+ Jan 2015, its an externProtoInstance
4034  }
4035  //memcpy(p,proto,sizeof(struct X3D_Proto)); //dangerous, make sure you re-instance all pointer variables
4036  p->__prototype = proto->__prototype;
4037  p->_nodeType = proto->_nodeType;
4038  p->_defaultContainer = proto->_defaultContainer;
4039  p->_renderFlags = proto->_renderFlags;
4040  pobj = proto->__protoDef;
4041  if(pobj){ //Prodcon doesn't bother mallocing this for scene nRn
4042  nobj = MALLOC(struct ProtoDefinition*,sizeof(struct ProtoDefinition));
4043  memcpy(nobj,pobj,sizeof(struct ProtoDefinition));
4044  nobj->iface = newVector(struct ProtoFieldDecl *, pobj->iface->n);
4045  if(pobj->protoName)
4046  nobj->protoName = STRDUP(pobj->protoName);
4047  for(i=0;i<pobj->iface->n;i++)
4048  {
4049  pdecl = protoDefinition_getFieldByNum(pobj, i);
4050  if(0){
4051  ndecl=newProtoFieldDecl(pdecl->mode, pdecl->type, pdecl->name);
4052  //memcpy(ndecl,pdecl,sizeof(struct ProtoFieldDecl *)); //not just the pointer
4053  memcpy(ndecl,pdecl,sizeof(struct ProtoFieldDecl)); //.. the whole struct
4054  }else{
4055  ndecl = copy_ProtoFieldDecl(pdecl);
4056  }
4057  protoDefinition_addIfaceField(nobj, ndecl);
4058  }
4059  p->__protoDef = nobj;
4060  }
4061  //if(0) if(ideep) moved to after field parsing, so ISing of initial values on the ProtoInstance get into the body
4062  // deep_copy_broto_body2(&proto,&p);
4063  return p;
4064 }
4065 struct X3D_Node *p2p_lookup(struct X3D_Node *pnode, struct Vector *p2p)
4066 {
4067  int i;
4068  struct pointer2pointer pair;
4069  for(i=0;i<p2p->n;i++)
4070  {
4071  pair = vector_get(struct pointer2pointer, p2p, i);
4072  if(pnode == pair.pp) return pair.pn;
4073  }
4074  return NULL;
4075 }
4076 //copy broto routes to old-style global scene routes
4077 void copy_routes(Stack *routes, struct X3D_Proto* target, struct Vector *p2p)
4078 {
4079  int i;
4080  struct brotoRoute *route;
4081  struct X3D_Node *fromNode, *toNode;
4082  if(routes == NULL) return;
4083  for(i=0;i<routes->n;i++)
4084  {
4085  route = vector_get(struct brotoRoute*, routes, i);
4086  //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
4087  //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
4088  fromNode = p2p_lookup(route->from.node,p2p);
4089  toNode = p2p_lookup(route->to.node,p2p);
4090  CRoutes_RegisterSimpleB(fromNode, route->from.ifield, toNode, route->to.ifield, route->ft);
4091  //we'll also store in the deep broto instance, although they aren't used there (yet), and
4092  //if target is the main scene, they are abandoned. Maybe someday they'll be used.
4093  //if( target )
4094  // broto_store_route(target,fromNode,route->fromOfs, toNode, route->toOfs, route->ft);
4095  }
4096 }
4097 //struct ISrecord {
4098 // int protoFieldIndex;
4099 // int nodeFieldSource; //target node field source: builtin=0, script user field=1, broto user field =2
4100 // int nodeFieldIndexOrOffset; //int OFFSET for builtin fields, int field index for user fields in script, broto
4101 // struct X3D_Node* node; //target node
4102 //};
4103 struct brotoIS
4104 {
4105  struct X3D_Proto *proto;
4106  char *protofieldname;
4107  int pmode;
4108  int iprotofield;
4109  int type;
4110  struct X3D_Node *node;
4111  char* nodefieldname;
4112  int mode;
4113  int ifield;
4114  int source; //0= builtin field, 1=script, 2={ComposedShader,ShaderProgram,PackagedShader} 3=Proto
4115 };
4116 
4117 //copy broto IS to old-style global scene routes
4118 void copy_IS(Stack *istable, struct X3D_Proto* target, struct Vector *p2p)
4119 {
4120  int i;
4121  struct brotoIS *is;
4122  struct X3D_Node *node, *pnode;
4123  if(istable == NULL) return;
4124  for(i=0;i<istable->n;i++)
4125  {
4126  int ifield, iprotofield;
4127  is = vector_get(struct brotoIS*, istable, i);
4128  //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
4129  //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
4130  node = p2p_lookup(is->node,p2p);
4131  is->node = node; //replace protodeclare's body node - we need the new one for unregistering these routes
4132  pnode = X3D_NODE(target);
4133  ifield = is->ifield;
4134  //if(node->_nodeType != NODE_Script && node->_nodeType != NODE_Proto)
4135  // ifield = NODE_OFFSETS[node->_nodeType][ifield*5 +1];
4136  iprotofield = is->iprotofield;
4137  //if(pnode->_nodeType != NODE_Script && pnode->_nodeType != NODE_Proto)
4138  // iprotofield = NODE_OFFSETS[node->_nodeType][offset*5 +1];
4139  if(is->pmode == PKW_outputOnly){ //we should use pmode instead of mode, because pmode is more restrictive, so we don't route from pmode initializeOnly (which causes cycles in 10.wrl)
4140  //idir = 0;
4141  //if(node->_nodeType == NODE_Script) idir = FROM_SCRIPT;
4142  CRoutes_RegisterSimpleB(node, ifield, pnode, iprotofield, 0);
4143 
4144  }else if(is->pmode == PKW_inputOnly){
4145  CRoutes_RegisterSimpleB(pnode, iprotofield, node, ifield, 0);
4146  }else if(is->pmode == PKW_inputOutput){
4147  CRoutes_RegisterSimpleB(node, ifield, pnode, iprotofield, 0);
4148  CRoutes_RegisterSimpleB(pnode, iprotofield, node, ifield, 0);
4149  }else{
4150  //initialize Only - nothing to do routing wise
4151  }
4152  }
4153 }
4154 void unregister_IStableRoutes(Stack* istable, struct X3D_Proto* target){
4155  // goal reverse browser route registering we did in copy_IS,
4156  // for example if we unload an inline, and in the inline was protoInstance,
4157  // then 'construction' routes like these injected for ISing will be left dangling
4158  // in the route registry unless we unregister them here.
4159  int i;
4160  struct brotoIS *is;
4161  struct X3D_Node *node, *pnode;
4162  if(istable == NULL) return;
4163  for(i=0;i<istable->n;i++)
4164  {
4165  int ifield, iprotofield;
4166  is = vector_get(struct brotoIS*, istable, i);
4167  //parser_registerRoute(me, fromNode, fromOfs, toNode, toOfs, toType); //old way direct registration
4168  //broto_store_route(me,fromNode,fromOfs,toNode,toOfs,toType); //new way delay until sceneInstance()
4169  node = is->node;
4170  is->node = node; //replace protodeclare's body node - we need the new one for unregistering these routes
4171  pnode = X3D_NODE(target);
4172  ifield = is->ifield;
4173  //if(node->_nodeType != NODE_Script && node->_nodeType != NODE_Proto)
4174  // ifield = NODE_OFFSETS[node->_nodeType][ifield*5 +1];
4175  iprotofield = is->iprotofield;
4176  //if(pnode->_nodeType != NODE_Script && pnode->_nodeType != NODE_Proto)
4177  // iprotofield = NODE_OFFSETS[node->_nodeType][offset*5 +1];
4178  if(is->pmode == PKW_outputOnly){ //we should use pmode instead of mode, because pmode is more restrictive, so we don't route from pmode initializeOnly (which causes cycles in 10.wrl)
4179  //idir = 0;
4180  //if(node->_nodeType == NODE_Script) idir = FROM_SCRIPT;
4181  CRoutes_RemoveSimpleB(node, ifield, pnode, iprotofield, 0);
4182 
4183  }else if(is->pmode == PKW_inputOnly){
4184  CRoutes_RemoveSimpleB(pnode, iprotofield, node, ifield, 0);
4185  }else if(is->pmode == PKW_inputOutput){
4186  CRoutes_RemoveSimpleB(node, ifield, pnode, iprotofield, 0);
4187  CRoutes_RemoveSimpleB(pnode, iprotofield, node, ifield, 0);
4188  }else{
4189  //initialize Only - nothing to do routing wise
4190  }
4191  }
4192 
4193 }
4194 void copy_IStable(Stack **sourceIS, Stack** destIS)
4195 {
4196  int i;
4197  if(*sourceIS){
4198  struct brotoIS *iss, *isd;
4199  *destIS = newStack(struct brotoIS*);
4200 
4201  for(i=0;i<(*sourceIS)->n;i++)
4202  {
4203  isd = MALLOC(struct brotoIS*,sizeof(struct brotoIS));
4204  iss = vector_get(struct brotoIS*,*sourceIS,i);
4205  memcpy(isd,iss,sizeof(struct brotoIS));
4206  //(*isd) = (*iss); //deep copy struct brotoIS?
4207  stack_push(struct brotoIS*, *destIS, isd);
4208  }
4209  }
4210 }
4211 struct brotoIS * in_IStable(struct X3D_Node *target, int ifield, Stack *IS, int source)
4212 {
4213  int i;
4214  struct Vector* IStable = (struct Vector*)IS;
4215  if(IStable){
4216  for(i=0;i<IStable->n;i++)
4217  {
4218  struct brotoIS * record = vector_get(struct brotoIS*,IStable,i);
4219  if(target == record->node){
4220  if(ifield == record->ifield && source == record->source){
4221  //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
4222  return record;
4223  }
4224  }
4225  }
4226  }
4227  return NULL;
4228 }
4229 //copy broto defnames to single global scene defnames, for node* to defname lookup in parser_getNameFromNode
4230 //but can't go the other way (name to node) because there can be duplicate nodes with the same name in
4231 //different contexts
4232 void copy_defnames(Stack *defnames, struct X3D_Proto* target, struct Vector *p2p)
4233 {
4234  Stack* defs;
4235  struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
4236 
4237  defs = globalParser->brotoDEFedNodes;
4238  if( defs == NULL)
4239  {
4240  defs = newStack(struct brotoDefpair *);
4241  globalParser->brotoDEFedNodes = defs;
4242  }
4243  if(defnames)
4244  {
4245  int i,n;
4246  struct brotoDefpair* def, *def2;
4247  n = vectorSize(defnames);
4248  for(i=0;i<n;i++){
4249  def = vector_get(struct brotoDefpair*,defnames,i);
4250  def2 = MALLOC(struct brotoDefpair*,sizeof(struct brotoDefpair));
4251  def2->name = def->name; //I wonder who owns this name
4252  def2->node = p2p_lookup(def->node, p2p);
4253  stack_push(struct brotoDefpair*, defs, def2);
4254  }
4255  }
4256 }
4257 char *broto_getNameFromNode(struct X3D_Node* node)
4258 {
4259  char *ret;
4260  Stack* defs;
4261  struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
4262  ret = NULL;
4263  if(globalParser){
4264  defs = globalParser->brotoDEFedNodes;
4265  if(defs){
4266  int i,n;
4267  struct brotoDefpair* def;
4268  n = vectorSize(defs);
4269  for(i=0;i<n;i++){
4270  def = vector_get(struct brotoDefpair*,defs,i);
4271  if(def->node == node){
4272  ret = def->name;
4273  break;
4274  }
4275  }
4276  }
4277  }
4278  return ret;
4279 }
4280 void deep_copy_node(struct X3D_Node** source, struct X3D_Node** dest, struct Vector *p2p,
4281  Stack *instancedScripts, struct X3D_Proto *ctx);
4282 //void deep_copy_broto(struct X3D_Proto** proto, struct X3D_Proto** dest, Stack *instancedScripts);
4283 
4284 void copy_field(int typeIndex, union anyVrml* source, union anyVrml* dest, struct Vector *p2p,
4285  Stack *instancedScripts, struct X3D_Proto *ctx, struct X3D_Node *parent)
4286 {
4287  int i, isize;
4288  int sftype, isMF;
4289  struct Multi_Node *mfs,*mfd;
4290 
4291  isMF = typeIndex % 2; //this is wrong - you need a functional lookup or re-arrange the #defines
4292  sftype = typeIndex - isMF;
4293  //from EAI_C_CommonFunctions.c
4294  //isize = returnElementLength(sftype) * returnElementRowSize(sftype);
4295  isize = sizeofSForMF(sftype);
4296  if(isMF)
4297  {
4298  int nele;
4299  char *ps, *pd;
4300  mfs = (struct Multi_Node*)source;
4301  mfd = (struct Multi_Node*)dest;
4302  deleteMallocedFieldValue(typeIndex,dest);
4303  //we need to malloc and do more copying
4304  nele = mfs->n;
4305  if( sftype == FIELDTYPE_SFNode ) nele = (int) upper_power_of_two(nele);
4306  if(!nele){
4307  mfd->p = NULL;
4308  }else{
4309  mfd->p = MALLOC (struct X3D_Node **, isize*nele);
4310  bzero(mfd->p,isize*nele);
4311  //mfd->n = mfs->n;
4312  ps = (char *)mfs->p;
4313  pd = (char *)mfd->p;
4314  for(i=0;i<mfs->n;i++)
4315  {
4316  copy_field(sftype,(union anyVrml*)ps,(union anyVrml*)pd,p2p,instancedScripts,ctx,parent);
4317  ps += isize;
4318  pd += isize;
4319  }
4320  }
4321  mfd->n = mfs->n; //ATOMIC OP
4322  }else{
4323  //isSF
4324  switch(typeIndex)
4325  {
4326  case FIELDTYPE_SFNode:
4327  {
4328  if(source->sfnode){
4329  deep_copy_node(&source->sfnode,&dest->sfnode,p2p,instancedScripts,ctx);
4330  add_parent(dest->sfnode,parent,__FILE__,__LINE__);
4331  }else{
4332  dest->sfnode = NULL;
4333  }
4334  }
4335  break;
4336  case FIELDTYPE_SFString:
4337  {
4338  struct Uni_String **ss, *sd;
4339  deleteMallocedFieldValue(typeIndex,dest);
4340  ss = (struct Uni_String **)source;
4341  sd = (struct Uni_String *)MALLOC (struct Uni_String*, sizeof(struct Uni_String));
4342  memcpy(sd,*ss,sizeof(struct Uni_String));
4343  sd->strptr = STRDUP((*ss)->strptr);
4344  dest->sfstring = sd;
4345  }
4346  break;
4347  default:
4348  //memcpy(dest,source,sizeof(union anyVrml));
4349  memcpy(dest,source,isize);
4350  break;
4351  }
4352  }
4353 } //return copy_field
4354 
4355 //deep_copy_broto_body((struct X3D_Proto**)source,(struct X3D_Proto**)dest,p2p,instancedScripts);
4356 void deep_copy_broto_body(struct X3D_Proto** proto, struct X3D_Proto** dest, Stack *instancedScripts)
4357 {
4358  //converts from binary proto/broto format to old scene format:
4359  // - ROUTES are registered in global ROUTE registry
4360  // - nodes are instanced and registered in memoryTable for startOfLoopNodesUpdate and killNode access
4361  // - sensors, viewpoints etc are registered
4362  //proto - broto instance with
4363  // - a pointer __prototype to its generic prototype
4364  //dest - protoinstance with user fields filled out for this instance already
4365  // - children/body not filled out yet - it's done here
4366  // - any field/exposedField values in interface IS copied to body node fields
4367  // - broto ROUTES registered in global route registry, with this instances' node* addresses
4368  // ? ( sensors, viewpoints will be directly registered in global/main scene structs)
4369  //what will appear different in the scene:
4370  // old: PROTO instances appear as Group nodes with metaSF nodes for interface routing, mangled DEFnames
4371  // new: PROTO instances will appear as X3DProto nodes with userfields for interface routing, local DEFnames
4372 
4373  //DEEP COPYING start here
4374  //we're instancing for the final scene, so go deep
4375  //0. setup pointer lookup table proto to instance
4376  //1. copy nodes, recursing on MFNode,SFnode fields
4377  // to copy, instance a new node of the same type and save (new pointer, old pointer) in lookup table
4378  // iterate over proto's node's fields, copying, and recursing on MFNode, SFNode
4379  // if node is a ProtoInstance, deepcopy it
4380  //2. copy ROUTE table, looking up new_pointers in pointer lookup table
4381  //3. copy IS table, looking up new_pointers in pointer lookup table
4382  //4. copy DEFname table, looking up new pointers in pointer lookup table
4383  //
4384 
4385  struct X3D_Proto *prototype, *p;
4386  struct X3D_Node *parent;
4387  struct Vector *p2p = newVector(struct pointer2pointer,10);
4388 
4389  //2. copy body from source's _prototype.children to dest.children, ISing initialvalues as we go
4390  p=(*dest);
4391  p->__children.n = 0;
4392  p->__children.p = NULL;
4393  parent = (struct X3D_Node*) (*dest); //NULL;
4394  prototype = (struct X3D_Proto*)(*proto)->__prototype;
4395  //prototype = (struct X3D_Proto*)p->__prototype;
4396  //2.c) copy IS
4397  //p->__IS = copy IStable from prototype, and the targetNode* pointer will be wrong until p2p
4398  //copy_IStable(&((Stack*)prototype->__IS), &((Stack*)p->__IS));
4399 
4400  copy_IStable((Stack **) &(prototype->__IS), (Stack **) &(p->__IS));
4401 
4402  //2.a) copy rootnodes
4403  copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(prototype->__children),(union anyVrml*)&(p->__children),
4404  p2p,instancedScripts,p,parent);
4405  //2.b) copy routes
4406  copy_routes(prototype->__ROUTES, p, p2p);
4407  //2.d) copy defnames
4408  copy_defnames(prototype->__DEFnames, p, p2p);
4409 
4410  //3. convert IS events to backward routes
4411  copy_IS(p->__IS, p, p2p);
4412 
4413  //*dest = p;
4414  //free p2p
4415  return;
4416 }
4417 
4418 /* shallow_copy_field - a step beyond memcpy(anyvrml,anyvrml,len) by getting the MF elements
4419  malloced and copied to, except shallow in that SFNodes aren't deep copied - just the
4420  pointers are copied
4421 */
4422 void shallow_copy_field(int typeIndex, union anyVrml* source, union anyVrml* dest)
4423 {
4424  int i, isize;
4425  int sftype, isMF;
4426  struct Multi_Node *mfs,*mfd;
4427 
4428  isMF = typeIndex % 2;
4429  sftype = typeIndex - isMF;
4430  //from EAI_C_CommonFunctions.c
4431  //isize = returnElementLength(sftype) * returnElementRowSize(sftype);
4432  isize = sizeofSForMF(sftype);
4433  if(isMF)
4434  {
4435  int nele;
4436  char *ps, *pd;
4437  mfs = (struct Multi_Node*)source;
4438  mfd = (struct Multi_Node*)dest;
4439  //we need to malloc and do more copying
4440  deleteMallocedFieldValue(typeIndex,dest);
4441  nele = mfs->n;
4442  if( sftype == FIELDTYPE_SFNode ) nele = (int) upper_power_of_two(nele);
4443  if(!nele){
4444  mfd->p = NULL;
4445  mfd->n = 0;
4446  }else{
4447  mfd->p = MALLOC (struct X3D_Node **, isize*nele);
4448  bzero(mfd->p,isize*nele);
4449  mfd->n = mfs->n;
4450  ps = (char *)mfs->p;
4451  pd = (char *)mfd->p;
4452  for(i=0;i<mfs->n;i++)
4453  {
4454  shallow_copy_field(sftype,(union anyVrml*)ps,(union anyVrml*)pd);
4455  ps += isize;
4456  pd += isize;
4457  }
4458  }
4459  }else{
4460  //isSF
4461  switch(typeIndex)
4462  {
4463  case FIELDTYPE_SFString:
4464  {
4465  //go deep, same as copy_field
4466  struct Uni_String **ss, *sd;
4467  deleteMallocedFieldValue(typeIndex,dest);
4468  ss = (struct Uni_String **)source;
4469  if(*ss){
4470  sd = (struct Uni_String *)MALLOC (struct Uni_String*, sizeof(struct Uni_String));
4471  memcpy(sd,*ss,sizeof(struct Uni_String));
4472  sd->strptr = STRDUP((*ss)->strptr);
4473  dest->sfstring = sd;
4474  }
4475  }
4476  break;
4477  default:
4478  //memcpy(dest,source,sizeof(union anyVrml));
4479  memcpy(dest,source,isize);
4480 
4481  break;
4482  }
4483  }
4484 } //return copy_field
4485 int PKW_from_KW(int KW_index)
4486 {
4487  /* translates the KEYWORDS[KW_index] field mode found in the 4th column of the OFFSETS_
4488  into an index that works in the PROTOKEYWORDS[] array */
4489  int pkw = -1;
4490  switch(KW_index)
4491  {
4492  case KW_initializeOnly:
4493  pkw = PKW_initializeOnly; break;
4494  case KW_inputOnly:
4495  pkw = PKW_inputOnly; break;
4496  case KW_outputOnly:
4497  pkw = PKW_outputOnly; break;
4498  case KW_inputOutput:
4499  pkw = PKW_inputOutput; break;
4500  case KW_field:
4501  pkw = PKW_field; break;
4502  case KW_eventIn:
4503  pkw = PKW_eventIn; break;
4504  case KW_eventOut:
4505  pkw = PKW_eventOut; break;
4506  case KW_exposedField:
4507  pkw = PKW_exposedField; break;
4508  default:
4509  pkw = -1;
4510  }
4511  return pkw;
4512 }
4513 BOOL isManagedField(int mode, int type, BOOL isPublic);
4514 void registerParentIfManagedField(int type, int mode, BOOL isPublic, union anyVrml* any, struct X3D_Node* parent)
4515 {
4516  //puts what you say is the parent of the sfnode/mfnodes into the parentVector of each sfnode/mfnodes
4517  // if its a managed field.
4518  //isPublic - no leading _ on field name, or script/proto user field - you tell us, its easier that way
4519  //managed field: public && node field && value holding
4520  //int isManagedField;
4521  //isManagedField = isPublic && (type == FIELDTYPE_SFNode || type == FIELDTYPE_MFNode);
4522  //isManagedField = isManagedField && (mode == PKW_initializeOnly || mode == PKW_inputOutput);
4523  if(isManagedField(mode,type,isPublic))
4524  {
4525  int n,k,haveSomething;
4526  struct X3D_Node **plist, *sfn;
4527  haveSomething = (type==FIELDTYPE_SFNode && any->sfnode) || (type==FIELDTYPE_MFNode && any->mfnode.n);
4528  haveSomething = haveSomething && parent;
4529  if(haveSomething){
4530  if(type==FIELDTYPE_SFNode){
4531  plist = &any->sfnode;
4532  n = 1;
4533  }else{
4534  plist = any->mfnode.p;
4535  n = any->mfnode.n;
4536  }
4537  for(k=0;k<n;k++)
4538  {
4539  sfn = plist[k];
4540  if(sfn){
4541  if( !sfn->_parentVector)
4542  sfn->_parentVector = newVector(struct X3D_Node*,2);
4543  vector_pushBack(struct X3D_Node*, sfn->_parentVector, parent);
4544  }
4545  }
4546  }
4547  }
4548 }
4549 void freeMallocedNodeFields(struct X3D_Node* node);
4550 void deleteProtoDefinition(struct ProtoDefinition *ret);
4551 void freePublicBuiltinNodeFields(struct X3D_Node* node);
4552 void **shaderFields(struct X3D_Node* node);
4553 void deep_copy_node(struct X3D_Node** source, struct X3D_Node** dest, struct Vector *p2p, Stack *instancedScripts,
4554  struct X3D_Proto* ctx)
4555 {
4556  struct pointer2pointer pair;
4557  struct X3D_Node* parent;
4558  void **shaderfield = NULL;
4559  if(*source == NULL){
4560  *dest = NULL;
4561  return;
4562  }
4563  *dest = inPointerTable(*source,p2p);
4564  if(*dest)
4565  return; //already created and we're likely at what would be a USE in the original ProtoDeclare body
4566  //create new Node
4567  //problem with both brotoInstance and createNewX3DNode in deep_copy:
4568  // default field values are malloced, but we don't need or use them, -we copy below- so we need to gc them
4569  // solution - in copy_field or shallow_copy_field, call deleteMallocedFieldValue(type,unionAnyvrml)
4570  if((*source)->_nodeType == NODE_Proto){
4571  *dest = X3D_NODE(brotoInstance(X3D_PROTO(X3D_PROTO(*source)->__prototype),ciflag_get(ctx->__protoFlags,0)));
4572  }else{
4573  *dest=X3D_NODE(createNewX3DNode( (*source)->_nodeType)); //will register sensors and viewpionts
4574  }
4575  add_node_to_broto_context(ctx,(*dest));
4576 
4577  parent = *dest;
4578  if((*source)->_nodeType == NODE_Script)
4579  stack_push(struct X3D_Node*,instancedScripts,*dest);
4580  //register in pointer lookup table
4581  //pair = MALLOC(struct pointer2pointer*,sizeof(struct pointer2pointer));
4582  pair.pp = *source;
4583  pair.pn = *dest;
4584  vector_pushBack(struct pointer2pointer, p2p, pair);
4585  shaderfield = shaderFields(*source);
4586  //copy fields
4587  {
4588  typedef struct field_info{
4589  int nameIndex;
4590  int offset;
4591  int typeIndex;
4592  int ioType;
4593  int version;
4594  } *finfo;
4595  finfo offsets;
4596  finfo field;
4597  int ifield;
4598 
4599  offsets = (finfo)NODE_OFFSETS[(*source)->_nodeType];
4600  ifield = 0;
4601  field = &offsets[ifield];
4602  //printf("\n");
4603  while( field->nameIndex > -1)
4604  {
4605  int is_source;
4606  struct brotoIS * isrecord;
4607  //printf(" %s",FIELDNAMES[field->nameIndex]); //[0]]);
4608  //printf(" (%s)\n",FIELDTYPES[field->typeIndex]); //field[2]]);
4609  isrecord = NULL;
4610  is_source = 0; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
4611  isrecord = in_IStable(*source,ifield,(Stack *)ctx->__IS, is_source);
4612  if (isrecord != NULL)
4613  {
4614  //do something to change from:
4615  // copy *source to *dest, to
4616  // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
4617  union anyVrml *source_field, *dest_field;
4618  struct ProtoDefinition *sp;
4619  struct ProtoFieldDecl *sdecl;
4620  sp = ctx->__protoDef;
4621  sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
4622 
4623  //source_field = (union anyVrml*)&((char*)*source)[field->offset];
4624  source_field = (union anyVrml*)&(sdecl->defaultVal);
4625  dest_field = (union anyVrml*)&((char*)*dest )[field->offset];
4626  //copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx);
4627  shallow_copy_field(field->typeIndex, source_field, dest_field);
4628  registerParentIfManagedField(field->typeIndex,PKW_from_KW(field->ioType),1, dest_field, *dest);
4629 
4630  // similarly below when processing ISs on user fields in script and broto fields.
4631  // istable could include a hint on the type of field to be looking for:
4632  // ie builtin offset vs scriptfield/brotofield/userfield index
4633  // while remembering some node types could have either ie Script{ url IS protofield_URL SFString hemoglobin IS protofield_blood...
4634  }
4635  //in general we don't generically copy private fields starting with '_'
4636  //that's because usually its the compile_(nodetype)() function that populates those private fields,
4637  //and compile_ will get a shot at the node later, if/when its compiled.
4638  //except user field list pointers for proto, script etc we need to deep copy here
4639  else if((*source)->_nodeType == NODE_Proto && !strcmp(FIELDNAMES[field->nameIndex],"__protoDef") )
4640  {
4641  int k;
4642  //struct X3D_Proto *prototype, *p;
4643  struct ProtoDefinition *sp, *dp;
4644  struct ProtoFieldDecl *sdecl,*ddecl;
4645  struct X3D_Proto *s, *d;
4646 
4647  s = (struct X3D_Proto*)*source;
4648  d = (struct X3D_Proto*)*dest;
4649  sp = s->__protoDef;
4650  dp = d->__protoDef; //Jan 2015 = NULL; May 2015 not null, default broto field values
4651 
4652  if(sp){ //are there any Proto fields? Not for the Scene - this may not be malloced for the scene
4653  //dp = MALLOC(struct ProtoDefinition*,sizeof(struct ProtoDefinition));
4654  if(dp == NULL) //Jan 2015
4655  dp = newProtoDefinition();
4656  //memcpy(dp,sp,sizeof(struct ProtoDefinition));
4657  //usually brotoInstance or newProtoDefinition creates iface
4658  //however brotoInstance populates with default initializeOnly values
4659  //and here we are going to copy over the/any non-default brotoInstance over-ride values
4660  if(!dp->iface) //may 2015 should not be null
4661  dp->iface = newVector(struct ProtoFieldDecl *, sp->iface->n);
4662  //dp->protoName = STRDUP(sp->protoName);
4663  dp->isCopy = TRUE;
4664  for(k=0;k<sp->iface->n;k++)
4665  {
4666  sdecl = protoDefinition_getFieldByNum(sp, k);
4667  ddecl = protoDefinition_getFieldByNum(dp, k);
4668  //ddecl=newProtoFieldDecl(sdecl->mode, sdecl->type, sdecl->name);
4669  //memcpy(ndecl,pdecl,sizeof(struct ProtoFieldDecl *)); //not just the pointer
4670  //ddecl->cname = STRDUP(sdecl->cname);
4671  is_source = 3; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
4672 
4673 
4674  isrecord = in_IStable(*source,k,(Stack *)ctx->__IS, is_source);
4675  if (isrecord != NULL)
4676  {
4677  //do something to change from:
4678  // copy *source to *dest, to
4679  // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
4680  union anyVrml *source_field, *dest_field;
4681  struct ProtoDefinition *sp;
4682  struct ProtoFieldDecl *sdecl;
4683  sp = ctx->__protoDef;
4684  sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
4685 
4686  //source_field = (union anyVrml*)&((char*)*source)[field->offset];
4687  source_field = (union anyVrml*)&(sdecl->defaultVal);
4688  dest_field = (union anyVrml*)&(ddecl->defaultVal);
4689  //copy_field(sdecl->type,source_field,dest_field,p2p,instancedScripts,ctx);
4690  //shallow copy means if its an SFNode or MFNode field, don't
4691  //deep copy - just copy the pointers. That's because the SFNodes involved
4692  //are already instanced/memoryTable malloced for the live scene: they were
4693  //done for the current proto interface
4694  shallow_copy_field(sdecl->type, source_field, dest_field);
4695  registerParentIfManagedField(sdecl->type,sdecl->mode,1, dest_field, *dest);
4696  ddecl->alreadySet = sdecl->alreadySet;
4697  }else{
4698  if(0) //shallow copy for testing
4699  memcpy(ddecl,sdecl,sizeof(struct ProtoFieldDecl)); //.. the whole struct
4700  /* proper deep copy we must do to get value-holding SFNode fields
4701  (event fields will have uninitialized junk)*/
4702  if(sdecl->mode == PKW_initializeOnly || sdecl->mode == PKW_inputOutput){
4703  //if(1){
4704  union anyVrml *source_field, *dest_field;
4705  source_field = (union anyVrml*)&(sdecl->defaultVal);
4706  dest_field = (union anyVrml*)&(ddecl->defaultVal);
4707  copy_field(sdecl->type,source_field,dest_field,p2p,instancedScripts,ctx,parent);
4708  ddecl->alreadySet = sdecl->alreadySet;
4709  }
4710  }
4711  //protoDefinition_addIfaceField(dp, ddecl);
4712  }
4713  d->__protoDef = dp;
4714  }
4715  }
4716  else if((*source)->_nodeType == NODE_Script && !strcmp(FIELDNAMES[field->nameIndex],"__scriptObj") )
4717  {
4718  /*deep copy script user fields */
4719  int k;
4720  struct Vector *sfields;
4721  struct ScriptFieldDecl *sfield, *dfield;
4722  struct Shader_Script *sp, *dp;
4723  struct X3D_Script *s, *d;
4724 
4725  s = (struct X3D_Script*)*source;
4726  d = (struct X3D_Script*)*dest;
4727  sp = s->__scriptObj;
4728  dp = d->__scriptObj = new_Shader_ScriptB(*dest);
4729  dp->loaded = sp->loaded; //s.b. FALSE
4730  dp->num = sp->num; //s.b. -1
4731  sfields = sp->fields;
4732  for(k=0;k<sfields->n;k++)
4733  {
4734  BOOL isInitialize;
4735  dfield = MALLOC(struct ScriptFieldDecl*,sizeof(struct ScriptFieldDecl));
4736  bzero(dfield,sizeof(struct ScriptFieldDecl));
4737  dfield->fieldDecl = MALLOC(struct FieldDecl *,sizeof(struct FieldDecl));
4738  bzero(dfield->fieldDecl,sizeof(struct FieldDecl));
4739  is_source = 1; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
4740  sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
4741 
4742  isrecord = in_IStable(*source,k,(Stack *)ctx->__IS, is_source);
4743  isInitialize = isrecord && (isrecord->mode == PKW_initializeOnly || isrecord->mode == PKW_inputOutput);
4744  if( isInitialize )
4745  {
4746  //do something to change from:
4747  // copy *source to *dest, to
4748  // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
4749  union anyVrml *source_field, *dest_field;
4750  struct ProtoDefinition *sp;
4751  struct ProtoFieldDecl *sdecl;
4752 
4753  sp = ctx->__protoDef;
4754  sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
4755  if(sdecl->fieldString)
4756  dfield->ASCIIvalue = STRDUP(sdecl->fieldString);
4757  memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
4758  //ddecl = dfield->fieldDecl;
4759  //ddecl->fieldType = sdecl->type;
4760  //ddecl->JSparamNameIndex = sfield->fieldDecl->;
4761  //ddecl->lexerNameIndex = sdecl->name;
4762  //ddecl->PKWmode = sdecl->mode;
4763  //ddecl->shaderVariableID = 0;
4764  //source_field = (union anyVrml*)&((char*)*source)[field->offset];
4765  source_field = (union anyVrml*)&(sdecl->defaultVal);
4766  dest_field = (union anyVrml*)&(dfield->value);
4767  //copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx);
4768  shallow_copy_field(sdecl->type, source_field, dest_field);
4769  registerParentIfManagedField(sdecl->type, sdecl->mode, 1, dest_field, *dest);
4770 
4771  }else{
4772  if(sfield->ASCIIvalue)
4773  dfield->ASCIIvalue = STRDUP(sfield->ASCIIvalue);
4774  //*(output->fieldDecl) = *(sfield->fieldDecl);
4775  memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
4776  /* shallow copy for testing some scenarios*/
4777  if(0){
4778  dfield->value = sfield->value;
4779  }
4780  /* proper deep copy we must do to get value-holding SFNode fields
4781  (event fields will have uninitialized junk)*/
4782  if(sfield->fieldDecl->PKWmode == PKW_initializeOnly || sfield->fieldDecl->PKWmode == PKW_inputOutput){
4783  union anyVrml *source_field, *dest_field;
4784  source_field = (union anyVrml*)&(sfield->value);
4785  dest_field = (union anyVrml*)&(dfield->value);
4786  copy_field(dfield->fieldDecl->fieldType,source_field,dest_field,p2p,instancedScripts,ctx,parent);
4787  }
4788  dfield->valueSet = sfield->valueSet;
4789  }
4790  vector_pushBack(struct ScriptFieldDecl *, dp->fields, dfield);
4791  }
4792  }
4793  else if(shaderfield && !strcmp(FIELDNAMES[field->nameIndex],"_shaderUserDefinedFields") )
4794  {
4795  /*copied block above for Script, and hacked a few lines to abstract
4796  the __scriptObj vs _shaderUserDefinedFields
4797  Applies to:
4798  ComposedShader
4799  Effect
4800  ShaderProgram
4801  PackagedShader
4802  see function shaderFields in X3DParser.c
4803 
4804  */
4805  /*deep copy script user fields */
4806  int k;
4807  struct Vector *sfields;
4808  struct ScriptFieldDecl *sfield, *dfield;
4809  struct Shader_Script *sp, *dp;
4810  void **dshaderfield;
4811  //struct X3D_Script *s, *d;
4812 
4813  //s = (struct X3D_Script*)*source;
4814  //d = (struct X3D_Script*)*dest;
4815  dshaderfield = shaderFields(*dest);
4816  sp = *shaderfield; //s->__scriptObj;
4817  dp = new_Shader_ScriptB(*dest);
4818  (*dshaderfield) = (void*) dp;
4819  dp->loaded = sp->loaded; //s.b. FALSE
4820  dp->num = sp->num; //s.b. -1
4821  sfields = sp->fields;
4822  for(k=0;k<sfields->n;k++)
4823  {
4824  BOOL isInitialize;
4825  dfield = MALLOC(struct ScriptFieldDecl*,sizeof(struct ScriptFieldDecl));
4826  bzero(dfield,sizeof(struct ScriptFieldDecl));
4827  dfield->fieldDecl = MALLOC(struct FieldDecl *,sizeof(struct FieldDecl));
4828  bzero(dfield->fieldDecl,sizeof(struct FieldDecl));
4829  is_source = 2; //field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
4830  sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
4831 
4832  isrecord = in_IStable(*source,k,(Stack *)ctx->__IS, is_source);
4833  isInitialize = isrecord && (isrecord->mode == PKW_initializeOnly || isrecord->mode == PKW_inputOutput);
4834  if( isInitialize )
4835  {
4836  //do something to change from:
4837  // copy *source to *dest, to
4838  // copy ctx->interface[ctx->__IS[is_addr].interfacefieldIndex]].value to *dest.[ifield]
4839  union anyVrml *source_field, *dest_field;
4840  struct ProtoDefinition *sp;
4841  struct ProtoFieldDecl *sdecl;
4842 
4843  sp = ctx->__protoDef;
4844  sdecl = protoDefinition_getFieldByNum(sp, isrecord->iprotofield);
4845  if(sdecl->fieldString)
4846  dfield->ASCIIvalue = STRDUP(sdecl->fieldString);
4847  memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
4848  //ddecl = dfield->fieldDecl;
4849  //ddecl->fieldType = sdecl->type;
4850  //ddecl->JSparamNameIndex = sfield->fieldDecl->;
4851  //ddecl->lexerNameIndex = sdecl->name;
4852  //ddecl->PKWmode = sdecl->mode;
4853  //ddecl->shaderVariableID = 0;
4854  //source_field = (union anyVrml*)&((char*)*source)[field->offset];
4855  source_field = (union anyVrml*)&(sdecl->defaultVal);
4856  dest_field = (union anyVrml*)&(dfield->value);
4857  //copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx);
4858  shallow_copy_field(sdecl->type, source_field, dest_field);
4859  registerParentIfManagedField(sdecl->type, sdecl->mode, 1, dest_field, *dest);
4860 
4861  }else{
4862  if(sfield->ASCIIvalue)
4863  dfield->ASCIIvalue = STRDUP(sfield->ASCIIvalue);
4864  //*(output->fieldDecl) = *(sfield->fieldDecl);
4865  memcpy(dfield->fieldDecl,sfield->fieldDecl,sizeof(struct FieldDecl));
4866  /* shallow copy for testing some scenarios*/
4867  if(0){
4868  dfield->value = sfield->value;
4869  }
4870  /* proper deep copy we must do to get value-holding SFNode fields
4871  (event fields will have uninitialized junk)*/
4872  if(sfield->fieldDecl->PKWmode == PKW_initializeOnly || sfield->fieldDecl->PKWmode == PKW_inputOutput){
4873  union anyVrml *source_field, *dest_field;
4874  source_field = (union anyVrml*)&(sfield->value);
4875  dest_field = (union anyVrml*)&(dfield->value);
4876  copy_field(dfield->fieldDecl->fieldType,source_field,dest_field,p2p,instancedScripts,ctx,parent);
4877  }
4878  dfield->valueSet = sfield->valueSet;
4879  }
4880  vector_pushBack(struct ScriptFieldDecl *, dp->fields, dfield);
4881  }
4882  }
4883  else
4884  {
4885  if( FIELDNAMES[field->nameIndex][0] != '_'){ //Q. should we ignor private fields?
4886  union anyVrml *source_field, *dest_field;
4887  source_field = (union anyVrml*)&((char*)*source)[field->offset];
4888  dest_field = (union anyVrml*)&((char*)*dest )[field->offset];
4889  //if(!strcmp(FIELDNAMES[field->nameIndex],"appearance"))
4890  //{
4891  // struct X3D_Shape* shp1, *shp2;
4892  // shp1 = (struct X3D_Shape*)source;
4893  // shp2 = (struct X3D_Shape*)(*source);
4894  // printf("appearance shp1= %d shp2= %d\n",(int)shp1,(int)shp2);
4895  //}
4896  copy_field(field->typeIndex,source_field,dest_field,p2p,instancedScripts,ctx,parent);
4897  }
4898  }
4899  ifield++;
4900  field = &offsets[ifield];
4901  }
4902  }
4903  if((*source)->_nodeType == NODE_Proto)
4904  {
4905  /* deep copy the body/context/_prototype from the Proto:
4906  - defnames, ISes, Routes, body nodes from _prototype upgraded by ISes
4907  */
4908  struct X3D_Proto *pdest;
4909  unsigned char pdepthflag;
4910  pdest = X3D_PROTO(*dest);
4911  if(0){
4912  //Jan 2015 - depth is upgraded in brotoInstance above
4913  pdepthflag = ciflag_get(ctx->__protoFlags,0);
4914  pdest->__protoFlags = ciflag_set(pdest->__protoFlags,pdepthflag,0); //upgrade depth flag to that of containing context ie deep == 1 live scenery (vs 0 for still protodeclare)
4915  }
4916  deep_copy_broto_body2((struct X3D_Proto**)source,(struct X3D_Proto**)dest);
4917  }
4918 }
4919 int nextScriptHandle (void);
4920 
4921 void initialize_one_script(struct Shader_Script* ss, const struct Multi_String *url){
4922  struct ScriptFieldDecl* field;
4923  int j;
4924 
4925  //printf("script node %p \n",sn);
4926  ss->num = nextScriptHandle();
4927  //printf(" num=%d \n",ss->num);
4928  JSInit(ss); //ss->num);
4929  // 2)init each field
4930  for(j=0;j<ss->fields->n;j++)
4931  {
4932  //printf("initializing field %d of %d \n",j,ss->fields->n);
4933  field = vector_get(struct ScriptFieldDecl*,ss->fields,j);
4934  //script_addField(ss,field);
4935 
4936  //scriptFieldDecl_jsFieldInit(field, ss->num); //saves it for initializeOnly work
4937  field->script = ss;
4938  //printf("\t field index %d JSparamnameIndex %d name %s\n",
4939  // j,field->fieldDecl->JSparamNameIndex,JSparamnames[field->fieldDecl->JSparamNameIndex].name);
4940  //Q. do I need this: - it mallocs something. Or is this just for initializeOnly?
4941  //void SaveScriptField (int num, indexT kind, indexT type, const char* field, union anyVrml value) {
4942 
4943  }
4944  // 3)init from URI
4945  script_initCodeFromMFUri(ss, url);
4946 }
4947 
4948 void initialize_scripts(Stack *instancedScripts)
4949 {
4950  /*
4951  Old (pre-2013) Script special handling during Parsing:
4952  1. new script node? get a num for it
4953  ret->num=nextScriptHandle(); JSInit(ret->num);
4954  2. new script field? add it and initailize its value:
4955  script_addField > scriptFieldDecl_jsFieldInit(field, me->num);
4956  3. after all fields of a script node have been added, try initializing the URL field
4957  script_initCodeFromUri > script_initCode
4958 
4959  New (2013 BROTO era) Script Special handling:
4960  Parsing: don't do any of the above 3
4961  Instancing: in sceneInstance():
4962  - instance all nodes generically, including script nodes,
4963  except for each script node instanced put it in a special node* list
4964  - after all nodes have been instanced, call this initializeScripts() function:
4965  -- go through the special node* list of instanced scripts and for each (script) node*:
4966  1)get a script num 2)init each field 3)init from URI (like the above 3)
4967 
4968  */
4969  //int n, i,j;
4970  //struct X3D_Node* p;
4971  //struct X3D_Script* sn;
4972  //struct Shader_Script* ss; //)X3D_SCRIPT(node)->__scriptObj)->num
4973  //struct ScriptFieldDecl* field;
4974  //JSObject *eventInFunction;
4975 
4976 
4977  if(instancedScripts)
4978  {
4979  int n, i,j;
4980  struct X3D_Node* p;
4981  struct X3D_Script* sn;
4982  struct Shader_Script* ss; //)X3D_SCRIPT(node)->__scriptObj)->num
4983  struct ScriptFieldDecl* field;
4984 
4985 
4986  n = instancedScripts->n;
4987  for(i=0;i<n;i++)
4988  {
4989  p = vector_get(struct X3D_Node*,instancedScripts,i);
4990  sn = (struct X3D_Script*)p;
4991  // 1)get a script num
4992  ss = sn->__scriptObj;
4993  if(1){
4994  initialize_one_script(ss,&sn->url);
4995  }else{
4996 
4997  //printf("script node %p \n",sn);
4998  //printf("in initialize_scripts i=%d __scriptObj =%p ",i,ss);
4999  ss->num = nextScriptHandle();
5000  //printf(" num=%d \n",ss->num);
5001  JSInit(ss); //ss->num);
5002  // 2)init each field
5003  for(j=0;j<ss->fields->n;j++)
5004  {
5005  //printf("initializing field %d of %d \n",j,ss->fields->n);
5006  field = vector_get(struct ScriptFieldDecl*,ss->fields,j);
5007  //script_addField(ss,field);
5008 
5009  scriptFieldDecl_jsFieldInit(field, ss->num); //saves it for initializeOnly work
5010  //printf("\t field index %d JSparamnameIndex %d name %s\n",
5011  // j,field->fieldDecl->JSparamNameIndex,JSparamnames[field->fieldDecl->JSparamNameIndex].name);
5012  //Q. do I need this: - it mallocs something. Or is this just for initializeOnly?
5013  //void SaveScriptField (int num, indexT kind, indexT type, const char* field, union anyVrml value) {
5014 
5015  }
5016  // 3)init from URI
5017  script_initCodeFromMFUri(ss, &sn->url);
5018  }
5019  }
5020  }
5021 
5022 }
5023 void sceneInstance(struct X3D_Proto* sceneProto, struct X3D_Node *sceneInstance)
5024 {
5025  //deprecated Sept 2014 by dug9: we now instance as we parse a scene (or if we did parse a scene as a sceneDeclare
5026  // we could call brotoInstance() and deep_copy_broto_body2() to instance the scene)
5027 
5028  //sceneProto - cParse results in new X3D_Proto format
5029  //sceneInstance - pass in a Group node to accept scene rootNodes
5030  // - (ROUTES, sensors, viewpoints will be directly registered in global/main scene structs)
5031  //converts from binary proto/broto format to old scene format:
5032  // - ROUTES are registered in global ROUTE registry
5033  // - nodes are instanced and registered in memoryTable for startOfLoopNodesUpdate and killNode access
5034  // - sensors, viewpoints etc are registered
5035  //what will appear different in the scene:
5036  // old: PROTO instances appear as Group nodes with metaSF nodes for interface routing, mangled DEFnames
5037  // new: PROTO instances will appear as X3DProto nodes with userfields for interface routing, local DEFnames
5038 
5039  //DEEP COPYING start here
5040  //we're instancing for the final scene, so go deep
5041  //0. setup pointer lookup table proto to instance
5042  //1. copy nodes, recursing on MFNode,SFnode fields
5043  // to copy, instance a new node of the same type and save (new pointer, old pointer) in lookup table
5044  // iterate over proto's node's fields, copying, and recursing on MFNode, SFNode
5045  // if node is a ProtoInstance, deepcopy it
5046  //2. copy ROUTE table, looking up new_pointers in pointer lookup table
5047  //3. copy IS table, looking up new_pointers in pointer lookup table
5048  //4. copy DEFname table, looking up new pointers in pointer lookup table
5049  //
5050 
5051 
5052  struct X3D_Proto *scenePlaceholderProto;
5053  struct X3D_Node *parent;
5054  struct Multi_Node *children;
5055  struct Vector *p2p = newVector(struct pointer2pointer,10);
5056  Stack *instancedScripts = newStack(struct X3D_Node*);
5057  children = childrenField(sceneInstance);
5058  children->n = 0;
5059  children->p = NULL;
5060  parent = (struct X3D_Node*)sceneInstance;
5061  scenePlaceholderProto = createNewX3DNode0(NODE_Proto);
5062  //if(0){
5063  // prototype = (struct X3D_Proto*)sceneProto->__prototype;
5064  // //copy rootnodes
5065  // copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(prototype->children),(union anyVrml*)&(sceneInstance->children),p2p);
5066  //}else{
5067  //I think the sceneProto being passed in is already the prototype -with body- and not an interface/instance
5068  //copy rootnodes
5069  copy_field(FIELDTYPE_MFNode,(union anyVrml*)&(sceneProto->__children),(union anyVrml*)children,
5070  p2p,instancedScripts,scenePlaceholderProto,parent);
5071  //}
5072  //copy sceneProto routes (child protoInstance routes copied elsewhere)
5073  copy_routes(sceneProto->__ROUTES, NULL, p2p);
5074  //shouldn't be any IS-table in main scene (child protoInstance IS-tables copied elsewhere)
5075  copy_IS(sceneProto->__IS, NULL, p2p);
5076  //copy sceneProto defnames (child protoInstance defnames copied elsewhere - will duplicate)
5077  copy_defnames(sceneProto->__DEFnames, NULL, p2p);
5078 
5079  initialize_scripts(instancedScripts);
5080 
5081  return;
5082 }
5083 
5084 
5085 /* added Jan 15, 2013:
5086  parse an IS statement:
5087  - test if it's an IS, if not backup and return lexer's original position
5088  - register IS in ProtoDeclare's IS-table.
5089  - swallow the the nodeFieldName, IS and protoFieldName tokens.
5090  - set the value of the field in the node, if appropriate.
5091 
5092  Background:
5093  Goal: allow IS in the main scene, or more precisely,
5094  to parse ProtoDeclare Bodies with main scene parsing code for new style protos.
5095  That means we need IS handling in the main scene parsing code.
5096  This seems like a nice place to put the handler.
5097  I'm expecting everything else already handled except IS:
5098  ----------------------------
5099  WRL Parsing Fields on Nodes
5100  when parsing a node we expect to see
5101  A. For built-in fields and user fields on protoInstances where mode and fieldtype are known in advance:
5102  (optional DEF name) nodeType ({ list of fields } or USE name)
5103  And for each field mentioned, one of:
5104  fieldname <fieldvalue> where <fieldvalue> is one of:
5105 * IS protoFieldName #on any type & mode that jives^ with protoField type & mode
5106  1 2 3 #just for SF modes: field/initializeOnly, exposedField/inputOutput
5107  [1 2 3, 4 5 6] #just for MF modes: field/initializeOnly, exposedField/inputOutput
5108  USE nodename #just for SFNode modes: field/initializOnly, exposedField/inputOutput
5109  DEF nodename type{} #just for SFNode modes: field/initializOnly, exposedField/inputOutput
5110  type{} #just for SFNode modes: field/initializOnly, exposedField/inputOutput
5111  where type{} is any builtin or user node type
5112  B. for user fields on scripts and protoDeclares:
5113  mode fieldtype fieldname <fieldvalue>
5114  where:
5115  mode is one of field, eventIn, eventOut, exposedField
5116  fieldtype is one of SF*,MF* where * is one of Color,Vec3f,Node,...
5117  <fieldvalue> can be one of the above combinations as for builtin fields
5118 
5119  ^See the IS mode-jive table here:
5120  http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/concepts.html#PROTOdefinitionsemantics
5121  where:
5122  'Prototype Declaration' means the Interface of a ProtoDeclare/PROTO
5123  'Prototype Definition' means the Body of a ProtoDeclare/PROTO
5124  ---------------------------------
5125 
5126 */
5127 BOOL nodeTypeSupportsUserFields(struct X3D_Node *node)
5128 {
5129  BOOL user = FALSE;
5130  user = node->_nodeType == NODE_Proto || node->_nodeType == NODE_Script ||
5131  node->_nodeType == NODE_ComposedShader || node->_nodeType == NODE_ShaderProgram ||
5132  node->_nodeType == NODE_PackagedShader || node->_nodeType == NODE_Effect ? TRUE : FALSE;
5133  return user;
5134 }
5135 
5136 
5137 const char *rootFieldName(const char* fieldname, int* len, int *has_changed, int *has_set)
5138 {
5139  /*
5140  given a fieldname wholename "set_amazing_changed"
5141  it returns: s="amazing_changed", len = 7, has_changed 1, has_set 1
5142  you can use s and len in strncmp to test against the rootname
5143  */
5144  static char* str_changed = "_changed";
5145 
5146  static int len_changed = 8;
5147  static int len_set = 4;
5148 
5149  int ln;
5150  const char* s;
5151 
5152  ln = (int) strlen(fieldname);
5153 
5154  *has_changed = ln > len_changed ? !strncmp(&fieldname[ln-len_changed],str_changed,len_changed) : FALSE;
5155  *has_set = ln > len_set ? !strncmp(fieldname,"set_",len_set) : FALSE;
5156  s = *has_set ? &fieldname[len_set] : fieldname;
5157  *len = *has_changed? (int)(&fieldname[ln - len_changed] - s) : (int)(&fieldname[ln] - s);
5158  return s;
5159 }
5160 BOOL fieldSynonymCompare(const char *routeFieldName, const char* nodeFieldName) //, int nodeFieldMode)
5161 {
5162  // like strcmp, it returns false if there's no difference / a match
5163  // except it compares rootnames if there is a set_ or _changed on either
5164  // ie (set_amazing, amazing_changed) returns FALSE (a match of rootname).
5165  int lr,hsr,hcr,ln,hsn,hcn;
5166  const char *rf, *nf;
5167 
5168  if(!strcmp(routeFieldName,nodeFieldName) )return FALSE; //easy match of wholenames
5169 
5170  //get rootnames with set_ and _changed stripped off
5171  rf = rootFieldName(routeFieldName,&lr,&hsr,&hcr);
5172  nf = rootFieldName(nodeFieldName, &ln,&hsn,&hcn);
5173 
5174  if(lr != ln) return TRUE; //rootname lengths are different so no hope of match
5175  if(strncmp(rf,nf,lr)) return TRUE; //rootnames are different so no hope of match
5176  //the rootnames are equal
5177  //Q. are there some special conditions for matching, with nodeFieldMode or route/IS field mode
5178  //a) for routes you know a-priori/beforehand 'ROUTE from TO to' and on the
5179  // from node you want either eventOut/outputOnly (_changed) or exposedField/inputOutput (rootname)
5180  // to node you want either eventIn/inputOnly or (set_) or exposedField/inputOutput (rootname)
5181  //b) for IS there is a "mode-jive table" that says
5182  // - if your node is inputOutput the protofield can be any mode.
5183  // - otherwise the nodefield and protofield modes must match.
5184  // in both cases you would want to try to match wholenames first ie trust the scene author.
5185  return FALSE; //a match
5186 }
5187 
5188 
5189 //#define WRLMODE(val) (((val) % 4)+4) //jan 2013 codegen PROTOKEYWORDS[] was ordered with x3d synonyms first, wrl last
5190 
5191 //#define X3DMODE(val) ((val) % 4)
5192 //#define X3DMODE(##val) PKW_from_KW((##val)
5193 int X3DMODE(int val)
5194 {
5195  int iret = 0;
5196  switch(val){
5197  case PKW_field:
5198  case PKW_initializeOnly:
5199  iret = PKW_initializeOnly; break;
5200  case PKW_exposedField:
5201  case PKW_inputOutput:
5202  iret = PKW_inputOutput; break;
5203  case PKW_eventIn:
5204  case PKW_inputOnly:
5205  iret = PKW_inputOnly; break;
5206  case PKW_eventOut:
5207  case PKW_outputOnly:
5208  iret = PKW_outputOnly; break;
5209  default:
5210  printf("ouch from X3DMODE\n");
5211  }
5212  return iret;
5213 }
5214 
5215 #ifndef DISABLER
5216 BOOL walk_fields(struct X3D_Node* node, int (*callbackFunc)(), void* callbackData);
5217 #else
5218 BOOL walk_fields(struct X3D_Node* node, BOOL (*callbackFunc)(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,
5219  const char *fieldName, indexT mode, indexT type,int isource,BOOL publicfield), void* callbackData);
5220 #endif
5221 //=========== find any field by name via walk_fields
5222 typedef struct cbDataExactName {
5223  char *fname;
5224  union anyVrml* fieldValue;
5225  int mode;
5226  int type;
5227  int jfield;
5228  int source;
5229  BOOL publicfield;
5231 BOOL cbExactName(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
5232 {
5233  BOOL found;
5234  s_cbDataExactName *cbd = (s_cbDataExactName*)callbackData;
5235  found = !strcmp(fieldName,cbd->fname);
5236  if(found){
5237  cbd->fieldValue = fieldPtr;
5238  cbd->fname = fieldName;
5239  cbd->jfield = jfield;
5240  cbd->mode = mode;
5241  cbd->type = type;
5242  cbd->publicfield = publicfield;
5243  cbd->source = source;
5244  }
5245  return found; //returning true continues field walk, returning false breaks out.
5246 }
5247 BOOL find_anyfield_by_name(struct VRMLLexer* lexer, struct X3D_Node* node, union anyVrml **anyptr,
5248  int *imode, int *itype, char* nodeFieldName, int *isource, void** fdecl, int *ifield)
5249 {
5250  int found;
5251  s_cbDataExactName cbd;
5252  cbd.fname = nodeFieldName;
5253  found = walk_fields(node,cbExactName,&cbd);
5254  if(found){
5255  *anyptr = cbd.fieldValue;
5256  *imode = cbd.mode;
5257  *itype = cbd.type;
5258  *isource = cbd.source;
5259  *ifield = cbd.jfield;
5260  }
5261  return found;
5262 }
5263 //========== find any field by name and route direction via walk_fields
5265  char *fname;
5266  int PKW_eventType;
5267  union anyVrml* fieldValue;
5268  int mode;
5269  int type;
5270  int jfield;
5271  int source;
5272  BOOL publicfield;
5274 
5275 BOOL cbRootNameAndRouteDir(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
5276 {
5277 
5278  BOOL found;
5280  found = !fieldSynonymCompare(fieldName,cbd->fname) ? TRUE : FALSE;
5281  found = found && (mode == cbd->PKW_eventType || mode == PKW_inputOutput);
5282  if(found){
5283  cbd->fname = fieldName;
5284  cbd->jfield = jfield;
5285  cbd->mode = mode;
5286  cbd->type = type;
5287  cbd->publicfield = publicfield;
5288  cbd->source = source;
5289  }
5290  return found;
5291 }
5292 BOOL find_anyfield_by_nameAndRouteDir(struct X3D_Node* node, union anyVrml **anyptr,
5293  int *imode, int *itype, char* nodeFieldName, int *isource, void** fdecl, int *ifield, int PKW_eventType)
5294 {
5295  int found;
5297  cbd.fname = nodeFieldName;
5298  cbd.PKW_eventType = PKW_eventType;
5299  found = walk_fields(node,cbRootNameAndRouteDir,&cbd);
5300  if(found){
5301  *anyptr = cbd.fieldValue;
5302  *imode = cbd.mode;
5303  *itype = cbd.type;
5304  *isource = cbd.source;
5305  *ifield = cbd.jfield;
5306  }
5307  return found;
5308 }
5309 //========== count public fields via walk_fields, used by js fieldDefinitionArray
5310 
5311 BOOL cbCountFields(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
5312 {
5313  int found = FALSE;
5314  int *count = (int*)callbackData;
5315  (*count)++;
5316  return found;
5317 }
5318 int count_fields(struct X3D_Node* node)
5319 {
5320  //int found;
5321  int count = 0;
5322  //found =
5323  walk_fields(node,cbCountFields,&count);
5324  return count;
5325 }
5326 //========
5327 void **shaderFields(struct X3D_Node* node);
5328 //convenience wrappers to get details for built-in fields and -on script and protoInstance- dynamic fields
5329 int getFieldFromNodeAndName0(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value){
5330  void **shaderfield;
5331  *type = 0;
5332  *kind = 0;
5333  *iifield = -1;
5334  *value = NULL;
5335  shaderfield = shaderFields(node);
5336  //Q. what about shader script?
5337  if(node->_nodeType == NODE_Script)
5338  {
5339  int k;
5340  struct Vector *sfields;
5341  struct ScriptFieldDecl *sfield;
5342  struct FieldDecl *fdecl;
5343  struct Shader_Script *sp;
5344  struct CRjsnameStruct *JSparamnames = getJSparamnames();
5345  struct X3D_Script *snode;
5346 
5347  snode = (struct X3D_Script*)node;
5348  sp = (struct Shader_Script *)snode->__scriptObj;
5349  sfields = sp->fields;
5350  for(k=0;k<sfields->n;k++)
5351  {
5352  char *fieldName;
5353  sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
5354  //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
5355  fdecl = sfield->fieldDecl;
5356  fieldName = fieldDecl_getShaderScriptName(fdecl);
5357  if(!strcmp(fieldName,fieldname)){
5358  *type = fdecl->fieldType;
5359  *kind = fdecl->PKWmode;
5360  *value = &(sfield->value);
5361  *iifield = k;
5362  return 1;
5363  }
5364  }
5365  }
5366  else if(shaderfield)
5367  {
5368  int k;
5369  struct Vector *sfields;
5370  struct ScriptFieldDecl *sfield;
5371  struct FieldDecl *fdecl;
5372  struct Shader_Script *sp;
5373  struct CRjsnameStruct *JSparamnames = getJSparamnames();
5374 
5375  sp = (struct Shader_Script *)(*shaderfield);
5376  sfields = sp->fields;
5377  for(k=0;k<sfields->n;k++)
5378  {
5379  char *fieldName;
5380  sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
5381  //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
5382  fdecl = sfield->fieldDecl;
5383  fieldName = fieldDecl_getShaderScriptName(fdecl);
5384  if(!strcmp(fieldName,fieldname)){
5385  *type = fdecl->fieldType;
5386  *kind = fdecl->PKWmode;
5387  *value = &(sfield->value);
5388  *iifield = k;
5389  return 1;
5390  }
5391  }
5392  }else if(node->_nodeType == NODE_Proto) {
5393  int k; //, mode;
5394  struct ProtoFieldDecl* pfield;
5395  struct X3D_Proto* pnode = (struct X3D_Proto*)node;
5396  struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
5397  if(pstruct){
5398  if(pstruct->iface)
5399  for(k=0; k!=vectorSize(pstruct->iface); ++k)
5400  {
5401  const char *fieldName;
5402  pfield= vector_get(struct ProtoFieldDecl*, pstruct->iface, k);
5403  //mode = pfield->mode;
5404  fieldName = pfield->cname;
5405  if(!strcmp(fieldName,fieldname)){
5406  *type = pfield->type;
5407  *kind = pfield->mode;
5408  if(pfield->mode == PKW_initializeOnly || pfield->mode == PKW_inputOutput)
5409  *value = &(pfield->defaultVal);
5410  *iifield = k;
5411  return 1;
5412  }
5413  }
5414  }
5415  }
5416  //builtins on non-script, non-proto nodes (and also builtin fields like url on Script)
5417  {
5418  typedef struct field_info{
5419  int nameIndex;
5420  int offset;
5421  int typeIndex;
5422  int ioType;
5423  int version;
5424  } *finfo;
5425 
5426  finfo offsets;
5427  finfo field;
5428  int ifield;
5429  offsets = (finfo)NODE_OFFSETS[node->_nodeType];
5430  ifield = 0;
5431  field = &offsets[ifield];
5432  while( field->nameIndex > -1) //<< generalized for scripts and builtins?
5433  {
5434  if(!strcmp(FIELDNAMES[field->nameIndex],fieldname)){
5435  int kkind;
5436  *type = field->typeIndex;
5437  kkind = -1;
5438  switch(field->ioType){
5439  case KW_initializeOnly: kkind = PKW_initializeOnly; break;
5440  case KW_inputOnly: kkind = PKW_inputOnly; break;
5441  case KW_outputOnly: kkind = PKW_outputOnly; break;
5442  case KW_inputOutput: kkind = PKW_inputOutput; break;
5443  }
5444  *kind = kkind;
5445  *iifield = ifield;
5446  *value = (union anyVrml*)&((char*)node)[field->offset];
5447  return 1;
5448  }
5449  ifield++;
5450  field = &offsets[ifield];
5451  }
5452  }
5453  return 0;
5454 }
5455 int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value){
5456  int ifound = 0;
5457  ifound = getFieldFromNodeAndName0(node,fieldname,type,kind,iifield,value);
5458  if(!ifound){
5459  int ln, hsn, hcn;
5460  const char *nf;
5461  nf = rootFieldName(fieldname, &ln,&hcn,&hsn);
5462 
5463  if(hsn){
5464  //set_ prefix
5465  ifound = getFieldFromNodeAndName0(node,nf,type,kind,iifield,value);
5466  }
5467  ln++;
5468  if(hcn) {
5469  //_changed suffix
5470  char rootname[MAXJSVARIABLELENGTH];
5471  strncpy(rootname,fieldname,ln);
5472  rootname[ln] = '\0';
5473  ifound = getFieldFromNodeAndName0(node,rootname,type,kind,iifield,value);
5474  }
5475  }
5476  return ifound;
5477 }
5478 int getFieldFromNodeAndIndex(struct X3D_Node* node, int ifield, const char **fieldname, int *type, int *kind, union anyVrml **value){
5479  int iret = 0;
5480  *type = 0;
5481  *kind = 0;
5482  *fieldname = NULL;
5483  *value = NULL;
5484  if(node->_nodeType == NODE_Script )
5485  {
5486  int k;
5487  struct Vector *sfields;
5488  struct ScriptFieldDecl *sfield;
5489  struct FieldDecl *fdecl;
5490  struct Shader_Script *sp;
5491  struct CRjsnameStruct *JSparamnames = getJSparamnames();
5492  struct X3D_Script *snode;
5493 
5494  snode = (struct X3D_Script*)node;
5495 
5496  //sp = *(struct Shader_Script **)&((char*)node)[field->offset];
5497  sp = (struct Shader_Script *)snode->__scriptObj;
5498  sfields = sp->fields;
5499  //fprintf(fp,"sp->fields->n = %d\n",sp->fields->n);
5500  k = ifield;
5501  if(k > -1 && k < sfields->n)
5502  {
5503  sfield = vector_get(struct ScriptFieldDecl *,sfields,k);
5504  //if(sfield->ASCIIvalue) printf("Ascii value=%s\n",sfield->ASCIIvalue);
5505  fdecl = sfield->fieldDecl;
5506  *fieldname = fieldDecl_getShaderScriptName(fdecl);
5507  *type = fdecl->fieldType;
5508  *kind = fdecl->PKWmode;
5509  *value = &(sfield->value);
5510  iret = 1;
5511  }
5512  return iret;
5513  }else if(node->_nodeType == NODE_Proto ) {
5514  int k; //, mode;
5515  struct ProtoFieldDecl* pfield;
5516  struct X3D_Proto* pnode = (struct X3D_Proto*)node;
5517  struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
5518  if(pstruct){
5519  if(pstruct->iface){
5520  k = ifield;
5521  if(k > -1 && k < vectorSize(pstruct->iface))
5522  {
5523  pfield= vector_get(struct ProtoFieldDecl*, pstruct->iface, k);
5524  //mode = pfield->mode;
5525  *fieldname = pfield->cname;
5526  *type = pfield->type;
5527  *kind = pfield->mode;
5528  if(pfield->mode == PKW_initializeOnly || pfield->mode == PKW_inputOutput)
5529  *value = &(pfield->defaultVal);
5530  iret = 1;
5531  }
5532  }
5533  }
5534  return iret;
5535  }
5536  //builtins on non-script, non-proto nodes (and also builtin fields like url on Script)
5537  {
5538  typedef struct field_info{
5539  int nameIndex;
5540  int offset;
5541  int typeIndex;
5542  int ioType;
5543  int version;
5544  } *finfo;
5545 
5546  finfo offsets;
5547  int k, kkind;
5548  int kfield;
5549 
5550 
5551  offsets = (finfo)NODE_OFFSETS[node->_nodeType];
5552  kfield = ifield;
5553  //convert to index if in absolute offset
5554  if(kfield >= offsets[0].offset){
5555  int k = 0;
5556  while(offsets[k].nameIndex > -1){
5557  if(ifield == offsets[k].offset){
5558  kfield = k;
5559  break;
5560  }
5561  k++;
5562  }
5563  }
5564  for(k=0;k<=kfield;k++)
5565  if(offsets[k].nameIndex == -1) return 0;
5566  *fieldname = FIELDNAMES[offsets[kfield].nameIndex];
5567  *type = offsets[kfield].typeIndex;
5568  kkind = -1;
5569  switch(offsets[kfield].ioType){
5570  case KW_initializeOnly: kkind = PKW_initializeOnly; break;
5571  case KW_inputOnly: kkind = PKW_inputOnly; break;
5572  case KW_outputOnly: kkind = PKW_outputOnly; break;
5573  case KW_inputOutput: kkind = PKW_inputOutput; break;
5574  }
5575  *kind = kkind;
5576  *value = (union anyVrml*)&((char*)node)[offsets[kfield].offset];
5577  return 1;
5578  }
5579 }
5580 
5581 
5582 
5583 void broto_store_IS(struct X3D_Proto *proto,char *protofieldname,int pmode, int iprotofield, int type,
5584  struct X3D_Node *node, char* nodefieldname, int mode, int ifield, int source)
5585 {
5586  Stack* ISs;
5587  struct brotoIS* is;
5588 
5589  is = MALLOC(struct brotoIS*,sizeof(struct brotoIS));
5590  is->proto = proto;
5591  is->protofieldname = strdup(protofieldname);
5592  is->pmode = pmode;
5593  is->iprotofield = iprotofield;
5594  is->type = type;
5595  is->node = node;
5596  is->nodefieldname = strdup(nodefieldname);
5597  is->mode = mode;
5598  is->ifield = ifield;
5599  is->source = source;
5600 
5601  ISs = proto->__IS;
5602  if( ISs == NULL){
5603  ISs = newStack(struct brotoIS *);
5604  proto->__IS = ISs;
5605  }
5606  stack_push(struct brotoIS *, ISs, is);
5607  return;
5608 }
5609 
5610 BOOL found_IS_field(struct VRMLParser* me, struct X3D_Node *node)
5611 {
5612  /* if IS found, then
5613  if field/exposedfield/initializeOnly/inputOutput
5614  copy value
5615  register IS in IS-table
5616  */
5617  int i;
5618  int mode;
5619  int type;
5620  int source;
5621  int ifield, iprotofield;
5622  struct ProtoDefinition* pdef=NULL;
5623  struct X3D_Proto* proto;
5624  char *protoFieldName;
5625  char *nodeFieldName;
5626  DECLAREUP
5627  BOOL foundField;
5628  BOOL foundProtoField;
5629  struct ProtoFieldDecl* f;
5630  union anyVrml *fieldPtr;
5631  void *fdecl;
5632 
5633 
5634 
5635 
5636  SAVEUP //save the lexer spot so if it's not an IS we can back up
5637  /* get nodeFieldName */
5638  if(!lexer_setCurID(me->lexer)) return FALSE;
5639  ASSERT(me->lexer->curID);
5640  nodeFieldName = STRDUP(me->lexer->curID);
5641  //BACKUP;
5642  FREE_IF_NZ(me->lexer->curID);
5643 
5644  /*
5645  We want to know 5 things about the node:
5646  0. is it a user or builtin node
5647  1. does the field/event exist on the node
5648  if so then
5649  3. what's it's type - SF/MF,type - needed for compatibility check with proto field
5650  4. what's it's mode - [in][out][in/out] - ditto, IS-table routing direction and initialization
5651  5. what's its route field address: how does the is-table or route get to it:
5652  - integer Offset for builtin, integer field index for usernode
5653  - when deepcopying a protoDeclare during sceneInstance, the node address would be remapped,
5654  but these integers would stay the same
5655  */
5656  fieldPtr = NULL;
5657  foundField = find_anyfield_by_name(me->lexer, node, &fieldPtr, &mode, &type, nodeFieldName, &source, &fdecl, &ifield);
5658 
5659  if(!(foundField))
5660  {
5661  BACKUP
5662  FREE_IF_NZ(nodeFieldName);
5663  return FALSE; /* not a field or event */
5664  }
5665 
5666  /* got a node field or event */
5667  /* check if IS-statement? */
5668  if(!lexer_keyword(me->lexer, KW_IS)) {
5669  BACKUP
5670  FREE_IF_NZ(nodeFieldName);
5671  return FALSE; /* not an IS, maybe regular field or USE/DEF */
5672  }
5673 
5674  /* got an IS, so unconditionally swallow 3 tokens: nodeFieldName IS protoFieldName */
5675 
5676  /* get protoFieldName */
5677  if(!lexer_setCurID(me->lexer)) return FALSE;
5678  ASSERT(me->lexer->curID);
5679  protoFieldName = STRDUP(me->lexer->curID);
5680  FREE_IF_NZ(me->lexer->curID);
5681 
5682 
5683  /*Now we need to know the same things about the proto node and field:
5684  0. we know it's a user node - all X3D_Proto/Protos are, and they (should) have no public builtin fields
5685  (children should be removed)
5686  1. does the field/event exist on the proto
5687  if so then
5688  3. what's it's type - SF/MF,type - needed for compatibility check with node field
5689  4. what's it's mode - [in][out][in/out] - ditto, IS-table routing direction and initialization
5690  5. what's its route field address: how does the is-table or route get to it:
5691  - integer field index for usernode
5692  */
5693  proto = (struct X3D_Proto*)me->ectx;
5694  pdef = (struct ProtoDefinition*)proto->__protoDef; //__brotoObj;
5695  foundProtoField = FALSE;
5696  f = NULL;
5697  {
5698  const char* pname = NULL;
5699  iprotofield = -1;
5700  for(i=0; i!=vectorSize(pdef->iface); ++i)
5701  {
5702  f=vector_get(struct ProtoFieldDecl*, pdef->iface, i);
5703  pname = f->cname;
5704 
5705  foundProtoField = !strcmp(pname,protoFieldName) ? TRUE : FALSE;
5706  if(foundProtoField ) {
5707  /* printf ("protoDefinition_getField, comparing %d %d and %d %d\n", f->name, ind, f->mode, mode); */
5708  //return f;
5709  iprotofield = i;
5710  break;
5711  }
5712  }
5713  if( !foundProtoField ){
5714  ConsoleMessage("Parser error: no matching protoField for %s IS %s\n",
5715  nodeFieldName,protoFieldName);
5716  FREE_IF_NZ(me->lexer->curID);
5717  FREEUP
5718  FREE_IF_NZ(nodeFieldName);
5719  FREE_IF_NZ(protoFieldName);
5720  return TRUE;
5721  }
5722  //check its type
5723  if(f->type != type){
5724  if(!pname) pname = "";
5725  ConsoleMessage("Parser error: IS - we have a name match: %s IS %s found protofield %s\n",
5726  nodeFieldName,protoFieldName,pname);
5727  ConsoleMessage("...But the types don't match: nodefield %s protofield %s\n",
5728  FIELDTYPES[type],FIELDTYPES[f->type]);
5729  FREE_IF_NZ(me->lexer->curID);
5730  FREEUP
5731  FREE_IF_NZ(nodeFieldName);
5732  FREE_IF_NZ(protoFieldName);
5733  return TRUE;
5734  }
5735  //check its mode
5736  // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/concepts.html#t-RulesmappingPROTOTYPEdecl
5737  // there's what I call a mode-jive table
5738  // proto interface
5739  // inputOutput initializeOnly inputOnly outputOnly
5740  // node inputOutput jives jives jives jives
5741  // initializeOnly jives
5742  // inputOnly jives
5743  // outputOnly jives
5744  //
5745  // so if our nodefield's mode is inputOutput/exposedField then we are covered for all protoField modes
5746  // otherwise, the nodefield's mode must be the same as the protofield's mode
5747  if(X3DMODE(mode) != PKW_inputOutput && X3DMODE(mode) != X3DMODE(f->mode)){
5748  if(X3DMODE(f->mode) != PKW_inputOutput){
5749  ConsoleMessage("Parser Error: IS - we have a name match: %s IS %s found protofield %s\n",
5750  nodeFieldName,protoFieldName,f->fieldString);
5751  ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
5752  PROTOKEYWORDS[mode],PROTOKEYWORDS[f->mode]);
5753  FREE_IF_NZ(me->lexer->curID);
5754  FREEUP
5755  FREE_IF_NZ(nodeFieldName);
5756  FREE_IF_NZ(protoFieldName);
5757  return TRUE;
5758  }else{
5759  ConsoleMessage("Parser Warning: IS - we have a name match: %s IS %s found protofield %s\n",
5760  nodeFieldName,protoFieldName,f->fieldString);
5761  ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
5762  PROTOKEYWORDS[mode],PROTOKEYWORDS[f->mode]);
5763  ConsoleMessage("...will thunk\n");
5764  }
5765  }
5766  }
5767 
5768  //we have an IS that's compatible/jives
5769  //a) copy the value if it's an initializeOnly or inputOutput
5770  if(X3DMODE(f->mode) == PKW_initializeOnly || X3DMODE(f->mode) == PKW_inputOutput)
5771  {
5772 
5773  //Q. how do I do this? Just a memcpy on anyVrml or ???
5774  //printf("size of anyVrml=%d\n",sizeof(union anyVrml));
5775  //printf("f->mode=%d f->type=%d fieldptr mode=%d type=%d\n",f->mode,f->type,mode,type);
5776  //heapdump();
5777  //isMF = type % 2;
5778  //sftype = type - isMF;
5779  //from EAI_C_CommonFunctions.c
5780  //isize = returnElementLength(sftype) * returnElementRowSize(sftype);
5781  shallow_copy_field(type, &(f->defaultVal) , fieldPtr);
5782  //memcpy(fieldPtr,&(f->defaultVal),isize); //sizeof(union anyVrml));
5783  //heapdump();
5784  //if(0)//should probably only do this for the final deep_copy sceneInstance, not here during parsing
5785  //if(source==1)
5786  //{
5787  // scriptFieldDecl_jsFieldInit(
5788  // (struct ScriptFieldDecl*) fdecl,
5789  // ((struct Shader_Script*)X3D_SCRIPT(node)->__scriptObj)->num);
5790  //}
5791 
5792  }
5793  //b) register it in the IS-table for our context
5794  broto_store_IS(proto,protoFieldName,X3DMODE(f->mode),iprotofield,type,
5795  node,nodeFieldName,X3DMODE(mode),ifield,source);
5796  /* Add this scriptfielddecl to the list of script fields mapped to this proto field */
5797  //sfield = newScriptFieldInstanceInfo(sdecl, script);
5798  //vector_pushBack(struct ScriptFieldInstanceInfo*, pField->scriptDests, sfield);
5799  //we need an IS-table for builtin node targets - what did CProto do?
5800  //defaultVal = &(f->defaultVal);
5801 
5802  //
5803  FREEUP
5804  FREE_IF_NZ(nodeFieldName);
5805  FREE_IF_NZ(protoFieldName);
5806 
5807  return TRUE;
5808 
5809 }
5810 
5811 /* note that we get the resources in a couple of steps; this tries to keep the scenegraph running
5812  copied from load_Inline
5813 
5814 */
5815 
5816 resource_item_t * resLibraryAlreadyRequested(resource_item_t *res){
5817  /* for externProto libraries, check if there's already a resitem launched for the library
5818  and if so, return the associated resitem, else return null.
5819  - compare the absolutized (resource-identified) before-#
5820  - exampe for hddp://something.com/mylibrary.wrl#myProto1 we'll compare hddp://something.com/mylibrary.wrl
5821  */
5822  void3 *ulr;
5823  ulr = librarySearch(res->URLrequest);
5824  if(ulr) return ulr->three; //resource
5825  return NULL;
5826 }
5827 
5828 
5829 /* EXTERNPROTO library status */
5830 #define LOAD_INITIAL_STATE 0
5831 #define LOAD_REQUEST_RESOURCE 1
5832 #define LOAD_FETCHING_RESOURCE 2
5833 //#define LOAD_PARSING 3
5834 #define LOAD_STABLE 10
5835 /* dug9 Sept 2014 wrapper technique for externProto for useBrotos:
5836  PD - proto declare - a type declaration (shallow copies of contained protos; allocated nodes not registered)
5837  PI - proto insstance - a node for the scenegraph to render (deep copies of contained protos; nodes registered)
5838  EPD - extern PD
5839  EPI - extern PI
5840  Wrapper technique:
5841  EPD { url, resource, loadstatus, PD once loaded }
5842  EPI { *EPD, PI once loaded }
5843  1. during parsing, when an ExternProtoDeclare is encountered, an empty X3D_Proto is created
5844  to represent the ExternProtoDeclare EPD as a type, and fields as declared are added, along
5845  with the url. No body. A flag is set saying it's not loaded.
5846  2. parsing continues. When an instance of that type is encountered, a copy of the EPD is
5847  created as an externProtoInstance EPI -also empty, and with a pointer back to EPD. Parsing
5848  continues, including routing to the EPI
5849  3. during rendering when the EPI is visited (currently in startofloopnodeupdates()) it
5850  checks itself to see if its been instanced yet, and
5851  a) if not loaded:- checks to see if the EPD has been loaded yet,
5852  i) if not, gives a time slice to the EPD when visiting it, see #4
5853  ii) if yes, then instances itself, and generates routes between the wrapper EPI and contained PI
5854  b) if loaded, renders or whatever its supposed to be doing as a normal node
5855  4. EPD when visited
5856  a) checks to see if the resource has been created, if not creates it.
5857  It checks to see if another EPD has already requested the URL (in the case of a proto library)
5858  and if so, uses that EPD's resource, else submits a new resource for fetching
5859  b) if resource is loaded, then i) if its in a proto library, fetches the #name else ii) takes the first proto
5860  and sets it in its __protoDeclare list, and marks itself loaded
5861 */
5862 
5863 void load_externProtoDeclare (struct X3D_Proto *node) {
5864  resource_item_t *res, *res2;
5865  // printf ("load_externProto %u, loadStatus %d loadResource %u\n",node, node->__loadstatus, node->__loadResource);
5866 
5867  //printf ("load_externProto, node %p loadStatus %d\n",node,node->load);
5868  char flagInstance, flagExtern;
5869  flagInstance = ciflag_get(node->__protoFlags,2);
5870  flagExtern = ciflag_get(node->__protoFlags,3);
5871  if(flagInstance == 0 && flagExtern == 1) {
5872  /* printf ("loading externProtoDeclare\n"); */
5873 
5874  switch (node->__loadstatus) {
5875  case LOAD_INITIAL_STATE: /* nothing happened yet */
5876 
5877  if (node->url.n == 0) {
5878  node->__loadstatus = LOAD_STABLE; /* a "do-nothing" approach */
5879  break;
5880  } else {
5881  res = resource_create_multi(&(node->url));
5882  res->media_type = resm_unknown;
5883  node->__loadstatus = LOAD_REQUEST_RESOURCE;
5884  node->__loadResource = res;
5885  }
5886  break;
5887 
5888  case LOAD_REQUEST_RESOURCE:
5889  res = node->__loadResource;
5890  resource_identify(node->_parentResource, res);
5891  node->__afterPound = (void*)res->afterPoundCharacters;
5892  //check if this is a library request, and if so has it already been requested
5893  res2 = NULL;
5894  if(node->__afterPound)
5895  res2 = resLibraryAlreadyRequested(res);
5896  if(res2){
5897  node->__loadResource = res2;
5898  }else{
5899  struct X3D_Proto *libraryScene;
5900  /* printf ("load_Inline, we have type %s status %s\n",
5901  resourceTypeToString(res->type), resourceStatusToString(res->status)); */
5902  res->actions = resa_download | resa_load; //not resa_parse which we do below
5903  libraryScene = createNewX3DNode0(NODE_Proto);
5904  res->ectx = (void*)libraryScene;
5905  res->whereToPlaceData = X3D_NODE(libraryScene);
5906  res->offsetFromWhereToPlaceData = offsetof (struct X3D_Proto, __children);
5907  addLibrary(res->URLrequest,libraryScene,res);
5908  resitem_enqueue(ml_new(res));
5909  }
5910  node->__loadstatus = LOAD_FETCHING_RESOURCE;
5911  break;
5912 
5913  case LOAD_FETCHING_RESOURCE:
5914  res = node->__loadResource;
5915  /* printf ("load_Inline, we have type %s status %s\n",
5916  resourceTypeToString(res->type), resourceStatusToString(res->status)); */
5917  if(res->complete){
5918  if (res->status == ress_loaded) {
5919  res->actions = resa_process;
5920  res->complete = FALSE;
5921  resitem_enqueue(ml_new(res));
5922  } else if ((res->status == ress_failed) || (res->status == ress_invalid)) {
5923  //no hope left
5924  printf ("resource failed to load\n");
5925  node->__loadstatus = LOAD_STABLE; // a "do-nothing" approach
5926  } else if (res->status == ress_parsed) {
5927  //fetch the particular desired PROTO from the libraryScene, and place in _protoDeclares
5928  //or in _prototype
5929  struct X3D_Proto *libraryScene = res->whereToPlaceData; //from above
5930  if(node->__externProtoDeclares == NULL)
5931  node->__externProtoDeclares = newVector(struct X3D_Proto*,1);
5932  vector_pushBack(struct X3D_Proto*,node->__externProtoDeclares,libraryScene);
5933 
5934  if(node->__externProtoDeclares){
5935  int n = vectorSize(node->__externProtoDeclares);
5936  if(n){
5937  struct X3D_Proto *libraryScene = vector_get(struct X3D_Proto*,node->__externProtoDeclares,0);
5938  if(libraryScene->__protoDeclares){
5939  int m = vectorSize(libraryScene->__protoDeclares);
5940  if(m){
5941  int k;
5942  struct X3D_Proto* pDefinition;
5943  /* the specs say if there's no # in the url, take the first PROTO definition in the library file
5944  else match #name (afterpound in resitem)
5945  */
5946  if(node->__afterPound){
5947  for(k=0;k<m;k++){
5948  char *typename, *matchstring;
5949  //matchstring = node->__typename; //specs don't say this
5950  matchstring = node->__afterPound;
5951  pDefinition = vector_get(struct X3D_Proto*,libraryScene->__protoDeclares,k);
5952  typename = (char *)pDefinition->__typename;
5953  if(typename)
5954  if(!strcmp(matchstring,typename)){
5955  //found it - the library proto's user type name matches this extern proto's #name (afterPound)
5956  //now add this protoDeclare to our externProto's protoDeclare list in 1st position
5957  node->__protoDeclares = newVector(struct X3D_Proto*,1);
5958  vector_pushBack(struct X3D_Proto*,node->__protoDeclares,pDefinition);
5959  break;
5960  }
5961  } //for k
5962  }else{
5963  //no afterPound, so according to specs: take the first proto in the file
5964  pDefinition = vector_get(struct X3D_Proto*,libraryScene->__protoDeclares,0);
5965  node->__protoDeclares = newVector(struct X3D_Proto*,1);
5966  vector_pushBack(struct X3D_Proto*,node->__protoDeclares,pDefinition);
5967  } //else no afterPound
5968  } //if(m)
5969  } //if(libraryScene->__protoDeclares)
5970  } //if(n)
5971  } //if(node->__externProtoDeclares)
5972  node->__loadstatus = LOAD_STABLE;
5973  } //if (res->status == ress_parsed)
5974  } //if(res->complete)
5975  //end case LOAD_FETCHING_RESOURCE
5976  break;
5977 
5978  case LOAD_STABLE:
5979  break;
5980  }
5981 
5982  }
5983 }
5984 void load_externProtoInstance (struct X3D_Proto *node) {
5985  //resource_item_t *res;
5986  // printf ("load_externProto %u, loadStatus %d loadResource %u\n",node, node->__loadstatus, node->__loadResource);
5987 
5988  //printf ("load_externProto, node %p loadStatus %d\n",node,node->load);
5989  char flagInstance, flagExtern;
5990  flagInstance = ciflag_get(node->__protoFlags,2);
5991  flagExtern = ciflag_get(node->__protoFlags,3);
5992  if(flagInstance == 1 && flagExtern == 1) { //if protoInstance and extern
5993  struct X3D_Proto *pnode = NULL;
5994  if(node->__children.n) return; //externProtoInstance body node already instanced
5995  pnode = (struct X3D_Proto*)node->__prototype;
5996  if(pnode) {
5997  if(pnode->__loadstatus != LOAD_STABLE){
5998  // extern proto declare not loaded yet, give it a time slice to check its resource
5999  load_externProtoDeclare(pnode);
6000  }
6001  if(pnode->__loadstatus == LOAD_STABLE){
6002  // externProtoDeclare may already be loaded, if so, we just need to instance it
6003  if(pnode->__protoDeclares){
6004  int n = vectorSize(pnode->__protoDeclares);
6005  if(n){
6006  struct X3D_Proto *pdeclare, *pinstance;
6007  struct X3D_Node *nnode;
6008  pdeclare = vector_get(struct X3D_Proto*,pnode->__protoDeclares,0);
6009  pinstance = brotoInstance(pdeclare,1);
6010  if (pinstance != NULL) {
6011  struct ProtoDefinition *ed, *pd;
6012  struct Vector *ei, *pi;
6013  struct ProtoFieldDecl *ef, *pf;
6014 
6015  ed = node->__protoDef;
6016  ei = ed->iface;
6017  pd = pinstance->__protoDef;
6018  pi = pd->iface;
6019  add_node_to_broto_context(node,X3D_NODE(pinstance));
6020 
6021  //inject IS routes
6022  {
6023  int i,j;
6024  char *ename, *pname;
6025  struct Vector *p2p;
6026  struct pointer2pointer p2pentry;
6027 
6028  //match fields to create IStable
6029  for(i=0;i<ei->n;i++){
6030  ef = protoDefinition_getFieldByNum(ed, i);
6031  ename = ef->cname;
6032  for(j=0;j<pi->n;j++){
6033  pf = protoDefinition_getFieldByNum(pd, j);
6034  pname = pf->cname;
6035  if(!strcmp(ename,pname)){
6036  //name match
6037  //printf("ename = %s pname = %s\n",ename,pname);
6038  if(ef->type == pf->type){
6039  //type match
6040  //printf("etype = %d ptype = %d\n",ef->type, pf->type);
6041  //add IS
6042  broto_store_IS(node,ef->cname,ef->mode, i, ef->type, X3D_NODE(pinstance), pf->cname, pf->mode, j, 3);
6043  }
6044  }
6045  }
6046  }
6047  //convert IStable to browser routes
6048  p2p = newVector(struct pointer2pointer,1);
6049  //p2pentry = MALLOCV(sizeof(struct pointer2pointer));
6050  //nothing to look up, nuisance to re-use copy_IS
6051  p2pentry.pp = X3D_NODE(pinstance);
6052  p2pentry.pn = X3D_NODE(pinstance);
6053  vector_pushBack(struct pointer2pointer,p2p,p2pentry);
6054  copy_IS(node->__IS, node, p2p);
6055  deleteVector(struct pointer2pointer,p2p);
6056  }
6057  //copy EPI field initial values to contained PI
6058  {
6059  int i;
6060 
6061  Stack *istable = (Stack*) node->__IS;
6062  if(istable != NULL)
6063  for(i=0;i<istable->n;i++)
6064  {
6065  struct brotoIS* is;
6066  //int ifield, iprotofield;
6067  is = vector_get(struct brotoIS*, istable, i);
6068  if(is->pmode == PKW_inputOutput || is->pmode == PKW_initializeOnly){
6069  if(is->mode == PKW_inputOutput || is->mode == PKW_initializeOnly){
6070  ef = protoDefinition_getFieldByNum(ed, is->iprotofield);
6071  pf = protoDefinition_getFieldByNum(pd, is->ifield);
6072  if(ef->alreadySet ){
6073  // too shallow, crashes on exit during free: memcpy(&pf->defaultVal,&ef->defaultVal, sizeof(union anyVrml));
6074  shallow_copy_field(is->type, &ef->defaultVal, &pf->defaultVal);
6075  pf->alreadySet = TRUE; //in KelpForest scene, there's a CircleFish that gets its skin texture from a few levels of EPIs, and if this isn't set it doesn't go down both levels
6076  }
6077  }
6078  }
6079  }
6080  }
6081  //now copy broto body, which should cascade inital values down
6082  deep_copy_broto_body2(&pdeclare,&pinstance);
6083  nnode = X3D_NODE(pinstance);
6084  AddRemoveChildren(X3D_NODE(node), &node->__children, &nnode, 1, 1,__FILE__,__LINE__);
6085  add_parent(X3D_NODE(pinstance),X3D_NODE(node),__FILE__,__LINE__);
6086  } //if (pinstance != NULL)
6087  }
6088  }
6089  }
6090  }
6091  }
6092 }
6093 
6094 void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node){
6095  /* Adds node* to 2 lists:
6096  __nodes -for unregistering and freeing the body of an inline, scene or broto/protoInstance
6097  __subcontexts - for recursive unregistering of routes, scripts, sensors and nodes
6098  (nodes being registered in createNewX3DNode() in table used by startofloopnodeupdates())
6099  these lists need to be maintained whenever adding/removing nodes to/from a context
6100  - wrl and x3d scene parsing
6101  - EAI
6102  - javascript SAI addNode, removeNode, addProto, removeProto ...
6103  */
6104  if(context && hasContext(X3D_NODE(context))){
6105  Stack *__nodes;
6106  if(!context->__nodes)
6107  context->__nodes = newVector(struct X3D_Node*,4);
6108  __nodes = context->__nodes;
6109  node->_executionContext = (struct X3D_Node*)context;
6110  stack_push(struct X3D_Node*,__nodes,node);
6111  if(hasContext(node)){
6112  Stack *__subctxs;
6113  if(!context->__subcontexts)
6114  context->__subcontexts = newVector(struct X3D_Node*,4);
6115  __subctxs = context->__subcontexts;
6116  stack_push(struct X3D_Node*,__subctxs,node);
6117  }
6118  }
6119 }
6120 void remove_node_from_broto_context(struct X3D_Proto *context,struct X3D_Node *node){
6121  /* removes node* from a few lists (but does not free() node memory or otherwise alter node)
6122  __nodes
6123  __subcontexts (if its an inline, scene or protoinstance
6124  these lists need to be maintained whenever adding/removing nodes to/from a context
6125  - EAI
6126  - javascript SAI addNode, removeNode, addProto, removeProto ...
6127  (for unloading a whole inline body or scene body, see unload_broto
6128 
6129  */
6130  if(context && hasContext(X3D_NODE(context))){
6131  if(context->__nodes){
6132  int i;
6133  for(i=0;i<vectorSize(context->__nodes);i++){
6134  struct X3D_Node *ns = vector_get(struct X3D_Node*,context->__nodes,i);
6135  if(ns == node){
6136  vector_remove_elem(struct X3D_Node*,context->__nodes,i);
6137  break; //assumes its not added twice or more.
6138  }
6139  }
6140  }
6141  if(context->__subcontexts && hasContext(node) ){
6142  int i;
6143  for(i=0;i<vectorSize(context->__subcontexts);i++){
6144  struct X3D_Node *ns = vector_get(struct X3D_Node*,context->__subcontexts,i);
6145  if(ns == node){
6146  vector_remove_elem(struct X3D_Node*,context->__subcontexts,i);
6147  break;
6148  }
6149  }
6150  }
6151  }
6152 }
6153 void lock_and_do_routes_register();
6154 int unregister_broutes(struct X3D_Proto * node){
6155  //unregister regular routes from broto context
6156  int iret = FALSE;
6157  if(node && hasContext(X3D_NODE(node))){
6158  unsigned char depthflag = ciflag_get(node->__protoFlags,0);
6159  if(depthflag){
6160  //live scenery
6161  if(node->__ROUTES){
6162  int i;
6163  struct brotoRoute *route;
6164  for(i=0;i<vectorSize(node->__ROUTES);i++){
6165  route = vector_get(struct brotoRoute*,node->__ROUTES,i);
6166  if(route && route->lastCommand){
6167  CRoutes_RemoveSimpleB(route->from.node,route->from.ifield,route->to.node,route->to.ifield,route->ft);
6168  route->lastCommand = 0;
6169  }
6170  }
6171  iret = TRUE;
6172  }
6173  }
6174  }
6175  lock_and_do_routes_register();
6176  return iret;
6177 }
6178 //int unregister_bscripts(node){
6179 // //unregister scripts
6180 //
6181 //}
6182 
6183 
6184 void unRegisterTexture(struct X3D_Node *tmp);
6185 void unRegisterBindable (struct X3D_Node *node);
6186 void remove_OSCsensor(struct X3D_Node * node);
6187 void remove_picksensor(struct X3D_Node * node);
6188 void delete_first(struct X3D_Node *node);
6189 void removeNodeFromKeySensorList(struct X3D_Node* node);
6190 int unInitializeScript(struct X3D_Node *node);
6191 void delete_polyrep(struct X3D_Node *node);
6192 void unRegisterPolyRep(struct X3D_Node *node);
6193 void delete_glbuffers(struct X3D_Node *node);
6194 int unRegisterX3DAnyNode(struct X3D_Node *node){
6195  //this is for 'live' scenery, not protoDeclarations or proto library scenes
6196  //web3d has a concept of a browser. A browser contains and renders a scene.
6197  //as of early 2015, freewrl's browser consists of scattered 'tables' -simple flat arrays or vectors
6198  // scattered around global instance. During rendering, it does not 'recurse into sub-contexts' for
6199  // things like sensors, routes, node updating. Rather during parsing, live scenery is 'registered'
6200  // in the browser tables, and later/here unregisterd, for example when unloading an inline or scene
6201 
6202  /* Undo any node registration(s)
6203  From GeneratedCode.c createNewX3DNode():
6204  // is this a texture holding node?
6205  registerTexture(tmp);
6206  // Node Tracking
6207  registerX3DNode(tmp);
6208  // is this a bindable node?
6209  registerBindable(tmp);
6210  // is this a OSC sensor node?
6211  add_OSCsensor(tmp); // WANT_OSC
6212  // is this a pick sensor node?
6213  add_picksensor(tmp); // DJTRACK_PICKSENSORS
6214  // is this a time tick node?
6215  add_first(tmp);
6216  // possibly a KeySensor node?
6217  addNodeToKeySensorList(X3D_NODE(tmp));
6218  */
6219 
6220  //unRegisterPolyRep(node); //attn Disabler
6221  // is this a texture holding node?
6222  unRegisterTexture(node);
6223  // Node Tracking
6224  unRegisterX3DNode(node);
6225  // is this a bindable node?
6226  unRegisterBindable(node);
6227  // is this a OSC sensor node?
6228  remove_OSCsensor(node); // WANT_OSC
6229  // is this a pick sensor node?
6230  remove_picksensor(node); // DJTRACK_PICKSENSORS
6231  // is this a time tick node?
6232  delete_first(node);
6233  // possibly a KeySensor node?
6234  removeNodeFromKeySensorList(X3D_NODE(node));
6235 
6236  //as with kill_nodes, disable scripts
6237  unInitializeScript(node);
6238 
6239  //only live scenery has polyreps prepared, remove the polyrep
6240  delete_polyrep(node);
6241  delete_glbuffers(node);
6242  return TRUE;
6243 }
6244 int print_broto_stats(int level, struct X3D_Proto *node){
6245  char spaces[256];
6246  int i,nr,nn,nc;
6247  for(i=0;i<level;i++)
6248  spaces[i] = ' ';
6249  spaces[level] = '\0';
6250  nr = node->__ROUTES ? vectorSize(node->__ROUTES) : 0;
6251  nn = node->__nodes ? vectorSize(node->__nodes) : 0;
6252  nc = node->__subcontexts ? vectorSize(node->__subcontexts) : 0;
6253 
6254  printf("%sctx=%p routes=%d nodes=%d subcontexts=%d\n",spaces,node,nr,nn,nc);
6255  if(nc){
6256  int nextlevel = level + 1;
6257  for(i=0;i<nc;i++){
6258  struct X3D_Proto* sc = vector_get(struct X3D_Proto*,node->__subcontexts,i);
6259  print_broto_stats(nextlevel,sc);
6260  }
6261  }
6262  return 0;
6263 
6264 }
6265 int unregister_broto_instance(struct X3D_Proto* node){
6266  /* Nov 2014: during broto parsing, if it's live/instanced scenery, createNewX3DNode()
6267  is called instead of createNewX3DNode0() to register the node type in global/browser tables.
6268  Here we try to undo those registrations.
6269  Call this when anchoring to a new scene, cleaning up on exit, or unloading an Inline.
6270  A. unregister items registered in global/browser structs
6271 
6272  a remove registered sensors -need a __sensors array?
6273  b. remove registered scripts -see __scripts
6274  c. remove registered routes:
6275  c.i regular routes -from __ROUTES table
6276  c.ii IS construction routes - from __IStable - a function was developed but not yet tested: unregister_IStableRoutes
6277  d unregister nodes from table used by startofloopnodeupdates - see createNewX3DNode vs createNewX3DNode0 in generatedCode.c
6278 
6279 
6280  */
6281  int retval = 1; //TRUE;
6282  if(node && hasContext(X3D_NODE(node))){
6283  unsigned char depthflag = ciflag_get(node->__protoFlags,0);
6284  if(depthflag){
6285  /* live scenery, registered */
6286  //recurse to subcontexts
6287  if(node->__subcontexts){
6288  int i;
6289  for(i=0;i<vectorSize(node->__subcontexts);i++){
6290  struct X3D_Proto* subcontext = vector_get(struct X3D_Proto*,node->__subcontexts,i);
6291  unregister_broto_instance(subcontext);
6292  }
6293  }
6294  //unregister IS construction routes
6295  unregister_IStableRoutes((Stack*)node->__IS, node);
6296  //unregister regular routes
6297  unregister_broutes(node);
6298  //unregister scripts
6299  //unregister_bscripts(node);
6300  //unregister sensors and nodes
6301  if(node->__nodes){
6302  //printf("unregister size of __nodes=%d\n",vectorSize(node->__nodes));
6303  int i;
6304  for(i=0;i<vectorSize(node->__nodes);i++){
6305  struct X3D_Node* ns = vector_get(struct X3D_Node*,node->__nodes,i);
6306  unRegisterX3DAnyNode(ns);
6307  broto_clear_DEF_by_node(node,ns);
6308  }
6309  }
6310  }
6311  }
6312  return retval;
6313 }
6314 
6315 int gc_broto_instance(struct X3D_Proto* node){
6316  int i, iret = TRUE;
6317  //used for both live scenery -after unregistered from browser- and for protodeclarations and proto library scenes
6318  //does not free the __protoDef outward facing fields of a protoInstance, protoDeclare, nor the node itself
6319  // -- you do that generically from the containing context
6320  //recurse to free subcontexts: protoInstances, externProtoInstances, Inlines (which may instance this context's protoDeclares)
6321  //free protodeclares (recursive)
6322  //free externprotodeclares (recursive)
6323  //some of the following could be in a general GC malloc table per-context
6324  //in that case, still set the vector pointer to null because Inline re-uses itself on subsequent Inline.load = true
6325  //free routes
6326  if(node && hasContext(X3D_NODE(node))){
6327  node->__children.n = 0; //hide from other threads
6328  node->_sortedChildren.n = 0;
6329  if(node->__subcontexts){
6330  struct X3D_Proto *subctx;
6331  for(i=0;i<vectorSize(node->__subcontexts);i++){
6332  subctx = vector_get(struct X3D_Proto*,node->__subcontexts,i);
6333  gc_broto_instance(subctx);
6334  }
6335  deleteVector(struct X3D_Proto*,node->__subcontexts);
6336  }
6337 
6338  if(node->__ROUTES){
6339  for(i=0;i<vectorSize(node->__ROUTES);i++){
6340  struct brotoRoute* route = vector_get(struct brotoRoute*,node->__ROUTES,i);
6341  free_broute(route);
6342  FREE_IF_NZ(route);
6343  }
6344  deleteVector(struct brotoRoute *, node->__ROUTES);
6345  }
6346  //free scipts
6347  if(node->__scripts)
6348  deleteVector(struct X3D_Node *,node->__scripts);
6349  //free IStable
6350  if(node->__IS){
6351  for(i=0;i<vectorSize(node->__IS);i++) {
6352  struct brotoIS * bi = vector_get(struct brotoIS*,node->__IS,i);
6353  FREE_IF_NZ(bi);
6354  }
6355  deleteVector(struct brotoIS *,node->__IS);
6356  }
6357  //free DEFnames
6358  if(node->__DEFnames) {
6359  for(i=0;i<vectorSize(node->__DEFnames);i++) {
6360  struct brotoDefpair def = vector_get(struct brotoDefpair,node->__DEFnames,i);
6361  FREE_IF_NZ(def.name);
6362  }
6363  deleteVector(struct brotoDefpair,node->__DEFnames);
6364  }
6365  //free IMPORTS
6366  if(node->__IMPORTS)
6367  deleteVector(struct EXIMPORT *,node->__IMPORTS);
6368  //free EXPORTS
6369  if(node->__EXPORTS)
6370  deleteVector(struct EXIMPORT *,node->__EXPORTS);
6371  //free nodes
6372  if(node->__nodes){
6373  int i;
6374  struct X3D_Node* nx;
6375  //have we cleaned up all references to these nodes?
6376  //if not, and we free() them, freewrl browser will crash - in routing,
6377  //in startofloopnodeupdates, with binding stacks - anywhere we didn't deregister/clean up
6378  //which is a good test to make sure we cleaned up.
6379  //Apr 2015 also crashes if the same node is listed multiple times in the __nodes list, 2nd free(node) bombs
6380  int crash_challenge = 1;
6381  if(crash_challenge) {
6382  for(i=0;i<vectorSize(node->__nodes);i++){
6383  nx = vector_get(struct X3D_Node*,node->__nodes,i);
6384  freeMallocedNodeFields(nx);
6385  FREE_IF_NZ(nx);
6386  }
6387  }
6388  deleteVector(struct X3D_Node *,node->__nodes);
6389  }
6390  if(node->__protoDeclares){
6391  int i;
6392  struct X3D_Proto *subctx;
6393  char flagInstance, flagExtern;
6394  flagInstance = ciflag_get(node->__protoFlags,2);
6395  flagExtern = ciflag_get(node->__protoFlags,3);
6396  if(!(flagExtern && !flagInstance)) //don't delete library protos - we'll get them when we delete the library
6397  for(i=0;i<vectorSize(node->__protoDeclares);i++){
6398  subctx = vector_get(struct X3D_Proto*,node->__protoDeclares,i);
6399  //
6400  gc_broto_instance(subctx);
6401  freeMallocedNodeFields(X3D_NODE(subctx));
6402  FREE_IF_NZ(subctx);
6403  }
6404  deleteVector(void*,node->__protoDeclares);
6405  }
6406  if(node->__externProtoDeclares){
6407  int i;
6408  struct X3D_Proto *subctx;
6409  char flagInstance, flagExtern;
6410  flagInstance = ciflag_get(node->__protoFlags,2);
6411  flagExtern = ciflag_get(node->__protoFlags,3);
6412  if(!(flagExtern && !flagInstance)) //don't delete library protos - we'll get them when we delete the library
6413  for(i=0;i<vectorSize(node->__externProtoDeclares);i++){
6414  //Q. wait - what if its in a shared libararyScene?
6415  //Those persist beyond the coming and going of scenes and inlines and protoinstances
6416  //A. externProto is a local scene proxy for a libraryscene protodeclare
6417  subctx = vector_get(struct X3D_Proto*,node->__externProtoDeclares,i);
6418  gc_broto_instance(subctx);
6419  freeMallocedNodeFields(X3D_NODE(subctx));
6420  FREE_IF_NZ(subctx);
6421  }
6422  deleteVector(void*,node->__externProtoDeclares);
6423  }
6424  iret = TRUE;
6425  }
6426  return iret;
6427 }
6428 int unload_broto(struct X3D_Proto* node){
6429  /* code to unload a scene, inline, or protoInstance (a per-broto-context, recursive version of kill_nodes)
6430  the garbage collection part can be used on protoDeclares, externProtoDeclares,
6431  and extern proto library scenes. All these use X3D_Proto or X3D_Inline struct
6432  with a few .__protoFlags distinguishing their type at runtime.
6433  A. unregister items registered in global/browser structs
6434  a remove registered sensors -need a __sensors array?
6435  b. remove registered scripts -see __scripts
6436  c. remove registered routes:
6437  c.i regular routes -from __ROUTES table
6438  c.ii IS construction routes - from __IStable - a function was developed but not yet tested: unregister_IStableRoutes
6439  d unregister nodes from table used by startofloopnodeupdates - see createNewX3DNode vs createNewX3DNode0 in generatedCode.c
6440  B. deallocate context-specific heap:
6441  a nodes allocated -need a context-specific nodes heap
6442  a.0 recursively unload sub-contexts: inlines and protoInstances
6443  a.1 builtin nodes
6444  b. context vectors: __ROUTES, __IMPORTS, __EXPORTS, __DEFnames, __scripts, addChildren, removeChildren, _children
6445  c prototypes declared: __protoDeclares, __externProtoDeclares - use same recursive unload
6446  d string heap -need a string heap
6447  e malloc heap used for elements of __ vectors - need a context-specific malloc and heap ie fmalloc(context,sizeof)
6448  C. clear/reset scalar values so Inline can be re-used/re-loaded: (not sure, likely none to worry about)
6449  */
6450  int retval = FALSE;
6451  if(node && hasContext(X3D_NODE(node))){
6452  //print_broto_stats(0, node);
6453  unregister_broto_instance(node);
6454  gc_broto_instance(node);
6455  retval = TRUE;
6456  }
6457  return retval;
6458 }
6459 int unRegisterNodeRoutes(struct X3D_Proto *context, struct X3D_Node* node){
6460  //unregister any routes that are to/from a particular node
6461  int iret = 0;
6462  if(context && hasContext(X3D_NODE(context))){
6463  if(context->__ROUTES){
6464  int i,ii,nr;
6465  nr = vectorSize(context->__ROUTES);
6466  for(i=0;i<nr;i++){
6467  struct brotoRoute *route;
6468  ii = nr - i - 1; //start at end so we can pack without losing our index
6469  route = vector_get(struct brotoRoute*,context->__ROUTES,ii);
6470  if(route->from.node == node || route->to.node == node){
6471  if( route->lastCommand){
6472  CRoutes_RemoveSimpleB(route->from.node,route->from.ifield,route->to.node,route->to.ifield,route->ft);
6473  route->lastCommand = 0;
6474  }
6475  vector_remove_elem(struct X3D_Node*,context->__ROUTES,ii);
6476  iret++;
6477  }
6478  }
6479  }
6480  }
6481  return iret;
6482 }
6483 int remove_broto_node(struct X3D_Proto *context, struct X3D_Node* node){
6484  // used by js/SAI > executionContext.removeNamedNode(DEF)
6485  // to zap a node out of existence
6486  int iret = 0;
6487  if(context && hasContext(X3D_NODE(context))){
6488  if(node && hasContext(node))
6489  unload_broto(X3D_PROTO(node)); //cleanup its guts if its an inline or protoInstance
6490  unRegisterX3DAnyNode(node); //unregister from browser stacks and lists
6491  unRegisterNodeRoutes(context,node); //unregister any routes that are to/from the deleted node
6492  remove_node_from_broto_context(context,node); //remove from context.__nodes and __subcontexts
6493  FREE_IF_NZ(node);
6494  iret = 1;
6495  }
6496  return iret;
6497 }
6498 
6499 
6500 //void *createNewX3DNodeB(int nt, int intable, void *executionContext){
6501 // struct X3D_Node *node;
6502 // if(intable)
6503 // node = createNewX3DNode(nt);
6504 // else
6505 // node = createNewX3DNode0(nt);
6506 // if(node && executionContext)
6507 // node->_executionContext = executionContext;
6508 // return node;
6509 //}
Definition: headers.h:666
Definition: Vector.h:36