FreeWRL/FreeX3D  3.0.0
EAIEventsIn.c
1 /*
2 
3 
4 Handle incoming EAI (and java class) events with panache.
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 /* */
30 /* Design notes: */
31 /* FreeWRL is a server, the Java (or whatever) program is a client */
32 /* */
33 /* Commands come in, and get answered to, except for sendEvents; */
34 /* for these there is no response (makes system faster) */
35 /* */
36 /* Nodes that are registered for listening to, send async */
37 /* messages. */
38 /* */
39 /* very simple example: */
40 /* move a transform; Java code: */
41 /* */
42 /* EventInMFNode addChildren; */
43 /* EventInSFVec3f newpos; */
44 /* try { root = browser.getNode("ROOT"); } */
45 /* catch (InvalidNodeException e) { ... } */
46 /* */
47 /* newpos=(EventInSFVec3f)root.getEventIn("translation"); */
48 /* val[0] = 1.0; val[1] = 1.0; val[2] = 1.0; */
49 /* newpos.setValue(val); */
50 /* */
51 /* Three EAI commands sent: */
52 /* 1) GetNode ROOT */
53 /* returns a node identifier */
54 /* 2) GetType (nodeID) translation */
55 /* returns posn in memory, length, */
56 /* and data type */
57 /* */
58 /* 3) SendEvent posn-in-memory, len, data */
59 /* returns nothing - assumed to work. */
60 /* */
61 /************************************************************************/
62 
63 #include <config.h>
64 #include <system.h>
65 #include <display.h>
66 #include <internal.h>
67 
68 #include <libFreeWRL.h>
69 
70 #include "../vrml_parser/Structs.h"
71 #include "../main/headers.h"
72 #include "../vrml_parser/CParseGeneral.h"
73 #include "../vrml_parser/CParseLexer.h"
74 #include "../vrml_parser/CParseParser.h"
75 #include "../vrml_parser/CParse.h"
76 #include "../world_script/JScript.h"
77 #include "../world_script/CScripts.h"
78 #include "../world_script/fieldGet.h"
79 
80 #include "../input/EAIHeaders.h"
81 #include "../world_script/fieldSet.h"
82 #include "../scenegraph/Viewer.h"
83 #include "../opengl/OpenGL_Utils.h"
84 #include "../scenegraph/RenderFuncs.h"
85 #include "../opengl/OpenGL_Utils.h"
86 #include "../opengl/Textures.h"
87 #include "../x3d_parser/X3DParser.h"
88 #include "../vrml_parser/CRoutes.h"
89 
90 #include "EAIHelpers.h"
91 #include "EAIHeaders.h"
92 
93 #include <ctype.h> /* FIXME: config armor */
94 
95 #define EAI_BUFFER_CUR tg->EAICore.EAIbuffer[bufPtr]
96 
97 /* used for loadURL */
98 //struct X3D_Anchor EAI_AnchorNode;
99 //int waiting_for_anchor = FALSE;
100 
101 static void makeFIELDDEFret(int, int);
102 static void handleRoute (char command, char *bufptr, int repno);
103 static void handleGETNODE (char *bufptr, int repno);
104 static void handleGETNODEPARENTS (char *bufptr, int repno);
105 static void handleGETROUTES (char *bufptr, int repno);
106 static void handleGETEAINODETYPE (char *bufptr, int repno);
107 extern void dump_scene (FILE *fp, int level, struct X3D_Node* node); // in GeneratedCode.c
108 
109 
110 /******************************************************************************
111 *
112 * EAI_core_commands should only be called from
113 * fwl_EAI_handleBuffer(..) or
114 *
115 * there can be many commands waiting, so we loop through commands, and return
116 * a status of EACH command
117 *
118 * a Command starts off with a sequential number, a space, then a letter indicating
119 * the command, then the parameters of the command.
120 *
121 * the command names are #defined at the start of this file.
122 *
123 * some commands have sub commands (eg, get a value) to indicate data types,
124 * (eg, EAI_SFFLOAT); these sub types are indicated with a lower case letter; again,
125 * look to the top of this file for the #defines
126 *
127 *********************************************************************************/
128 
129 typedef struct pEAIEventsIn{
130 int oldCount; //=0;
131 int waiting_for_anchor; // = FALSE;
132 struct X3D_Anchor EAI_AnchorNode;
133 }* ppEAIEventsIn;
134 void *EAIEventsIn_constructor()
135 {
136  void *v = MALLOC(void *,sizeof(struct pEAIEventsIn));
137  memset(v,0,sizeof(struct pEAIEventsIn));
138  return v;
139 }
140 void EAIEventsIn_init(struct tEAIEventsIn* t)
141 {
142  //public
143  //struct X3D_Anchor EAI_AnchorNode; //null ok?
144 
145  //private
146  t->prv = EAIEventsIn_constructor();
147  {
148  ppEAIEventsIn p = (ppEAIEventsIn)t->prv;
149  p->waiting_for_anchor = FALSE;
150  p->oldCount=0;
151  }
152 }
153 
154 /*
155  * This code used to sit in the socket server, but
156  * the EAI buffer is no longer the same as the socket's buffer
157  * The EAI buffer may still need sharing and locking...
158  * Will leave that decision to the experts!!
159  */
160 typedef struct pEAICore{
161  pthread_mutex_t eaibufferlock;// = PTHREAD_MUTEX_INITIALIZER;
162 }* ppEAICore;
163 
164 void *EAICore_constructor()
165 {
166  void *v = MALLOC(void *,sizeof(struct pEAICore));
167  memset(v,0,sizeof(struct pEAICore));
168  return v;
169 }
170 void EAICore_init(struct tEAICore* t){
171  //private
172  t->prv = EAICore_constructor();
173  {
174  ppEAICore p = (ppEAICore)t->prv;
175  pthread_mutex_init(&(p->eaibufferlock), NULL);
176  }
177  //public
178  t->EAIbufsize = EAIREADSIZE ;
179 }
180 
181 struct X3D_Anchor* get_EAIEventsIn_AnchorNode()
182 {
183  ppEAIEventsIn p = (ppEAIEventsIn)gglobal()->EAIEventsIn.prv;
184  return (struct X3D_Anchor*)&p->EAI_AnchorNode;
185 }
186 
187 #if !defined(EXCLUDE_EAI)
188 int fwl_EAI_allDone() {
189  int eaiverbose;
190  int bufPtr;
191  int stillToDo;
192  ttglobal tg = gglobal();
193  bufPtr = tg->EAICore.EAIbufpos;
194  stillToDo = (int)strlen((&EAI_BUFFER_CUR));
195  eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
196  if (eaiverbose && stillToDo > 0) {
197  printf ("EAI_allDone still to do: strlen %d str :%s:\n",stillToDo, (&EAI_BUFFER_CUR));
198  }
199  return stillToDo;
200 }
201 
202 char * fwl_EAI_handleRest() {
203  int eaiverbose;
204  int bufPtr;
205  int stillToDo;
206  struct tEAIHelpers *th;
207  ttglobal tg = gglobal();
208  bufPtr = tg->EAICore.EAIbufpos;
209  stillToDo = (int)strlen((&EAI_BUFFER_CUR));
210  eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
211 
212  if(NULL == tg->EAICore.EAIbuffer) {
213  printf("fwl_EAI_handleRest() did not have a buffer, WTF!!") ;
214  return NULL ;
215  }
216  if(stillToDo > 0) {
217  if(eaiverbose) {
218  printf("%s:%d fwl_EAI_handleRest: Buffer at %p , bufPtr=%d , still to do=%d str :%s:\n",\
219  __FILE__,__LINE__,tg->EAICore.EAIbuffer,bufPtr,(int)strlen((&EAI_BUFFER_CUR)), (&EAI_BUFFER_CUR));
220  }
221 
222  EAI_core_commands() ;
223 
224  th = &tg->EAIHelpers;
225  return th->outBuffer ;
226  } else {
227  return "";
228  }
229 }
230 
231 char * EAI_handleBuffer(char *fromFront, bool useSockets) {
232  /* memcp from fromFront to &EAI_BUFFER_CUR */
233  int eaiverbose;
234  int len = (int)strlen(fromFront) ;
235  ttglobal tg = gglobal();
236  struct tEAIHelpers *th;
237  eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
238 
239  //we do not use sockets for data transfer and so we can ignore the 8192 packet size limit
240  //sent command is larger than bufsize
241  if(!useSockets)
242  {
243  //for memory economy we check if at some time we allocated a buffer bigger than READSIZE and we do not need it anymore
244  if(tg->EAICore.EAIbufsize > EAIREADSIZE && len < EAIREADSIZE)
245  {
246  if(eaiverbose) {
247  printf("EAI_handleBuffer() does not need that much space, so we clear at %p\n",tg->EAICore.EAIbuffer) ;
248  }
249 
250  //cleaning the existing buffer the standard workflow will take care of recreating it
251  if(NULL != tg->EAICore.EAIbuffer)
252  {
253  FREE(tg->EAICore.EAIbuffer);
254  tg->EAICore.EAIbuffer = NULL;
255  }
256 
257  //reset the buffer dimension request to default
258  tg->EAICore.EAIbufsize = EAIREADSIZE;
259  }
260  else if(len >= tg->EAICore.EAIbufsize) //if not, we check if we DO need a buffer bigger than READSIZE
261  {
262  if(eaiverbose) {
263  printf("EAI_handleBuffer() needs a larger buffer, so we clear one at %p\n",tg->EAICore.EAIbuffer) ;
264  }
265  //cleaning the existing buffer the standard workflow will take care of recreating it
266  if(NULL != tg->EAICore.EAIbuffer)
267  {
268  FREE(tg->EAICore.EAIbuffer);
269  tg->EAICore.EAIbuffer = NULL;
270  }
271 
272  //set the buffer dimension request to len + space for the null terminator
273  tg->EAICore.EAIbufsize = len+1;
274  }
275  }
276 
277 
278  if(NULL == tg->EAICore.EAIbuffer) {
279  tg->EAICore.EAIbuffer = MALLOC(char *, tg->EAICore.EAIbufsize * sizeof (char));
280  if(eaiverbose) {
281  printf("fwl_EAI_handleBuffer() did not have a buffer, so create one at %p\n",tg->EAICore.EAIbuffer) ;
282  }
283  }
284  if(eaiverbose) {
285  printf("%s:%d fwl_EAI_handleBuffer: Buffer at %p is %d chars,",__FILE__,__LINE__,fromFront,len);
286  printf("Copy to buffer at %p\n", tg->EAICore.EAIbuffer);
287  }
288 
289 
290  if(!useSockets || len <= EAIREADSIZE) { //go for standard command processing if we are not using sockets or buffer dimension is lesser than packet limit
291  //JAS printf ("EAI_handleBuffer, %d\n",__LINE__);
292 
293  tg->EAICore.EAIbuffer[len] = '\0';
294  memcpy(tg->EAICore.EAIbuffer, fromFront, len);
295 
296  //int EAIbufcount; /* pointer into buffer*/
297  //int EAIbufpos;
298  tg->EAICore.EAIbufpos = 0;
299  tg->EAICore.EAIbufcount = 0;
300 
301  EAI_core_commands() ;
302 
303  th = &tg->EAIHelpers;
304  return th->outBuffer ;
305  } else { //or stop socket reading if buffer dimension is greater than the packet limit
306  //JAS printf ("EAI_handleBuffer, %d\n",__LINE__);
307  fwlio_RxTx_control(CHANNEL_EAI,RxTx_STOP) ;
308  return "";
309  }
310 }
311 
312 
313 char * fwl_EAI_handleBufferNoSKT(char *fromFront)
314 {
315  return EAI_handleBuffer(fromFront, false);
316 }
317 
318 char * fwl_EAI_handleBuffer(char *fromFront) {
319  return EAI_handleBuffer(fromFront, true);
320 
322  //int eaiverbose;
323  //int len = (int)strlen(fromFront) ;
324  //ttglobal tg = gglobal();
325  //struct tEAIHelpers *th;
326  //eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
327 
328  //if(NULL == tg->EAICore.EAIbuffer) {
329  // tg->EAICore.EAIbuffer = MALLOC(char *, tg->EAICore.EAIbufsize * sizeof (char));
330  // if(eaiverbose) {
331  // printf("fwl_EAI_handleBuffer() did not have a buffer, so create one at %p\n",tg->EAICore.EAIbuffer) ;
332  // }
333  //}
334  //if(eaiverbose) {
335  // printf("%s:%d fwl_EAI_handleBuffer: Buffer at %p is %d chars,",__FILE__,__LINE__,fromFront,len);
336  // printf("Copy to buffer at %p\n", tg->EAICore.EAIbuffer);
337  //}
338 
339  //if(len <= EAIREADSIZE) {
340  // tg->EAICore.EAIbuffer[len] = '\0';
341  // memcpy(tg->EAICore.EAIbuffer, fromFront, len);
342 
343  // //int EAIbufcount; /* pointer into buffer*/
344  // //int EAIbufpos;
345  // tg->EAICore.EAIbufpos = 0;
346  // tg->EAICore.EAIbufcount = 0;
347 
348  // EAI_core_commands() ;
349 
350  // th = &tg->EAIHelpers;
351  // return th->outBuffer ;
352  //} else {
353  // fwlio_RxTx_control(CHANNEL_EAI,RxTx_STOP) ;
354  // return "";
355  //}
356 }
357 
358 void EAI_core_commands () {
359  /* char buf[EAIREADSIZE];*/
360  char ctmp[EAIREADSIZE]; /* temporary character buffer*/
361  char dtmp[EAIREADSIZE]; /* temporary character buffer*/
362  struct X3D_Group *retGroup;
363 
364  int count;
365  char command;
366  int bufPtr; /* where we are in the EAI input buffer */
367 
368  int ra,rb,rd; /* temps*/
369  int rc;
370  int tmp_a, tmp_b, tmp_c;
371 
372  int scripttype;
373  char *EOT; /* ptr to End of Text marker*/
374  int retint; /* used for getting retval for sscanf */
375 
376  struct X3D_Node *boxptr;
377  int ctype;
378  int xxx;
379 
380  char *dumpname ;
381  int dumpfsize ;
382  int dumpInt ;
383  FILE *dumpfd ;
384 
385  int eaiverbose;
386  ppEAIEventsIn p;
387  //ppEAICore ps;
388  struct tEAIHelpers *th;
389  ttglobal tg;
390 
391  UNUSED(retint); // for compiler warnings
392 
393  tg = gglobal();
394  p = (ppEAIEventsIn)tg->EAIEventsIn.prv;
395  eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
396  th = &tg->EAIHelpers;
397  //ps = tg->EAICore.prv;
398 
399  /* initialization */
400  bufPtr = tg->EAICore.EAIbufpos;
401 
402  /* output buffer - start off with it this size */
403  th->outBufferLen = EAIREADSIZE;
404  th->outBuffer = MALLOC(char *, th->outBufferLen);
405  th->outBuffer[0] = 0;
406 
407  if (EAI_BUFFER_CUR> 0) {
408  if (eaiverbose) {
409  printf ("EAI_core_commands: strlen %d str :%s:\n",(int)strlen((&EAI_BUFFER_CUR)), (&EAI_BUFFER_CUR));
410  }
411 
412  /* step 1, get the command sequence number */
413  if (sscanf ((&EAI_BUFFER_CUR),"%d",&count) != 1) {
414  printf ("EAI_core_commands, expected a sequence number on command :%s:\n",(&EAI_BUFFER_CUR));
415  count = 0;
416  }
417  if (eaiverbose) {
418  printf ("EAI - seq number %d\n",count);
419  }
420 
421  if (count != (p->oldCount+1)) {
422  printf ("COUNT MISMATCH, expected %d got %d\n",p->oldCount+1,count);
423  }
424  p->oldCount = count;
425 
426 
427  /* step 2, skip past the sequence number */
428  while (isdigit(EAI_BUFFER_CUR)) bufPtr++;
429  /* if (eaiverbose) {
430  printf("past sequence number, string:%s\n",(&EAI_BUFFER_CUR));
431  } */
432 
433  while (EAI_BUFFER_CUR == ' ') bufPtr++;
434  /* if (eaiverbose) {
435  printf ("past the space, string:%s\n",(&EAI_BUFFER_CUR));
436  } */
437 
438  /* step 3, get the command */
439 
440  command = EAI_BUFFER_CUR;
441  if (eaiverbose)
442  printf ("EAI command %s (%c) strlen %d\n",eaiPrintCommand(command), command,(int)strlen(&EAI_BUFFER_CUR));
443 
444  bufPtr++;
445 
446  /* return is something like: $hand->print("RE\n$reqid\n1\n$id\n");*/
447  if (eaiverbose) {
448  printf ("\n... %d ",count);
449  }
450 
451  switch (command) {
452  case DUMPSCENE: {
453  int throwAway;
454  int sendNameNotFile = 1 ;
455 
456  UNUSED(throwAway); // for compiler warnings
457 
458  dumpname = TEMPNAM(gglobal()->Mainloop.tmpFileLocation,"fwtmp");
459  dumpfd = fopen(dumpname,"w+");
460  dump_scene(dumpfd, 0, (struct X3D_Node*) rootNode());
461  fflush(dumpfd) ;
462  if (sendNameNotFile) {
463  fclose(dumpfd) ;
464  throwAway = sprintf (th->outBuffer,"RE\n%f\n%d\n%s",TickTime(),count,dumpname);
465  } else {
466  dumpfsize = (int) ftell(dumpfd) ;
467  fseek(dumpfd, 0L, SEEK_SET) ;
468 
469  th->outBuffer = REALLOC(th->outBuffer,dumpfsize+200);
470  dumpInt = sprintf (th->outBuffer,"RE\n%f\n%d\n",TickTime(),count);
471  throwAway = (int) fread(th->outBuffer+dumpInt, dumpfsize, 1, dumpfd);
472  dumpInt += dumpfsize;
473 
474  th->outBuffer[dumpInt] = '\0';
475  fclose(dumpfd) ;
476  unlink(dumpname) ;
477  }
478 
479  break;
480  }
481  case GETRENDPROP: {
482  s_renderer_capabilities_t *rdr_caps;
483  ttglobal tg = gglobal();
484  rdr_caps = (s_renderer_capabilities_t *)tg->display.rdr_caps;
485  sprintf (th->outBuffer,"RE\n%f\n%d\n%s %dx%d %d %s %d %f",TickTime(),count,
486  "SMOOTH", /* Shading */
487  rdr_caps->system_max_texture_size, rdr_caps->runtime_max_texture_size, /* Texture size */
488  rdr_caps->texture_units, /* texture units */
489  "FALSE", /* antialiased? */
490  tg->OpenGL_Utils.displayDepth, /* bit depth of display */
491  256.0 /* amount of memory left on card -
492  can not find this in OpenGL, so
493  just make it large... */
494  );
495  break;
496  }
497 
498  case GETNAME: {
499  sprintf (th->outBuffer,"RE\n%f\n%d\n%s",TickTime(),count,BrowserName);
500  break;
501  }
502  case GETVERSION: {
503  sprintf (th->outBuffer,"RE\n%f\n%d\n%s",TickTime(),count,libFreeWRL_get_version());
504  break;
505  }
506  case GETENCODING: {
507  sprintf (th->outBuffer,"RE\n%f\n%d\n%d",TickTime(),count,tg->Mainloop.currentFileVersion);
508  break;
509  }
510  case GETCURSPEED: {
511  /* get the BrowserSpeed variable updated */
512  getCurrentSpeed();
513  sprintf (th->outBuffer,"RE\n%f\n%d\n%f",TickTime(),count,gglobal()->Mainloop.BrowserSpeed);
514  break;
515  }
516  case GETFRAMERATE: {
517  sprintf (th->outBuffer,"RE\n%f\n%d\n%f",TickTime(),count,gglobal()->Mainloop.BrowserFPS);
518  break;
519  }
520  case GETURL: {
521  sprintf (th->outBuffer,"RE\n%f\n%d\n%s",TickTime(),count,BrowserFullPath);
522  break;
523  }
524  case GETNODE: {
525  handleGETNODE(&EAI_BUFFER_CUR,count);
526  break;
527  }
528  case GETROUTES: {
529  handleGETROUTES(&EAI_BUFFER_CUR,count);
530  break;
531  }
532 
533  case GETEAINODETYPE: {
534  handleGETEAINODETYPE(&EAI_BUFFER_CUR,count);
535  break;
536  }
537 
538  case GETNODETYPE: {
539  int cNode;
540  retint = sscanf(&EAI_BUFFER_CUR,"%d",(&cNode));
541  if (eaiverbose) { printf ("\n"); } /* need to fix the dangling printf before the case statement */
542  if (cNode != 0) {
543  boxptr = getEAINodeFromTable(cNode,-1);
544  sprintf (th->outBuffer,"RE\n%f\n%d\n%d",TickTime(),count,getSAI_X3DNodeType (
545  boxptr->_nodeType));
546  } else {
547  sprintf (th->outBuffer,"RE\n%f\n%d\n-1",TickTime(),count);
548  }
549  /* printf ("GETNODETYPE, for node %s, returns %s\n",(&EAI_BUFFER_CUR),buf); */
550 
551  break;
552  }
553 
554  case GETFIELDTYPE: {
555  int xtmp;
556 
557  /*format int seq# COMMAND int node# string fieldname string direction*/
558 
559  retint=sscanf (&EAI_BUFFER_CUR,"%d %s %s",&xtmp, ctmp,dtmp);
560  if (eaiverbose) { printf ("\n"); } /* need to fix the dangling printf before the case statement */
561  if (eaiverbose) {
562  printf ("GETFIELDTYPE cptr %d %s %s\n",xtmp, ctmp, dtmp);
563  }
564 
565  EAI_GetType (xtmp, ctmp, dtmp, &ra, &rb, &rc, &rd, &scripttype, &xxx);
566  sprintf (th->outBuffer,"RE\n%lf\n%d\n%d %d %d %c %d %s",TickTime(),count,(int)ra,(int)rb,(int)rc,(int)rd,
567  scripttype,stringKeywordType(xxx));
568  break;
569  }
570  case SENDEVENT: {
571  /*format int seq# COMMAND NODETYPE pointer offset data*/
572  setField_FromEAI (&EAI_BUFFER_CUR);
573  th->outBuffer[0] = 0;
574  if (eaiverbose) {
575  printf ("after SENDEVENT, strlen %d\n",(int)strlen(&EAI_BUFFER_CUR));
576  }
577  break;
578  }
579 
580  case CREATEVU:
581  case CREATEXS:
582  case CREATEVS: {
583  /*format int seq# COMMAND vrml text string EOT*/
584 
585  retGroup = createNewX3DNode(NODE_Group);
586  //JAS printf ("CREATEXS, created retGroup of %p\n",retGroup);
587 
588  if (command == CREATEVS || command == CREATEXS) {
589  int topWaitLimit=16;
590  int currentWaitCount=0;
591 
592  if (eaiverbose) {
593  if(command==CREATEVS) printf ("CREATEVS %s\n",&EAI_BUFFER_CUR);
594  if(command==CREATEXS) printf ("CREATEXS %s\n",&EAI_BUFFER_CUR);
595  }
596 
597  EOT = strstr(&EAI_BUFFER_CUR,"\nEOT\n");
598 /* if we do not have a string yet, we have to do this...
599 This is a problem. We cannot create the VRML until we have a whole stanza
600 which means we may have to block, because we cannot respond to the original request.
601 
602 However, nowadays we do not read any sockets directly....
603 */
604 
605  while (EOT == NULL && topWaitLimit >= currentWaitCount) {
606  if(fwlio_RxTx_control(CHANNEL_EAI,RxTx_REFRESH) == 0) {
607  /* Nothing to be done, maybe not even running */
608  usleep(10000);
609  currentWaitCount++;
610  } else {
611  if(fwlio_RxTx_waitfor(CHANNEL_EAI,"\nEOT\n") != (char *)NULL) {
612  char *tempEAIdata = fwlio_RxTx_getbuffer(CHANNEL_EAI) ;
613  if(tempEAIdata != (char *)NULL) {
614  strcat(&EAI_BUFFER_CUR,tempEAIdata) ;
615  /* tg->EAICore.EAIbuffer = ....*/
616  FREE(tempEAIdata) ;
617  }
618  } else {
619  usleep(10000);
620  currentWaitCount++;
621  }
622  }
623  EOT = strstr(&EAI_BUFFER_CUR,"\nEOT\n");
624  }
625  if (topWaitLimit <= currentWaitCount) {
626  /* Abandon Ship */
627  sprintf (th->outBuffer,"RE\n%f\n%d\n-1",TickTime(),count);
628  } else {
629 
630  *EOT = 0; /* take off the EOT marker*/
631  if(command==CREATEVS)
632  ra = EAI_CreateVrml("String",(&EAI_BUFFER_CUR),rootNode(),retGroup);
633  else //CREATEXS
634  ra = EAI_CreateX3d("String",(&EAI_BUFFER_CUR),rootNode(),retGroup);
635  /* finish this, note the pointer maths */
636  bufPtr = (int) (EOT+3-tg->EAICore.EAIbuffer);
637  }
638  } else {
639 /* char *filename = MALLOC(char *,1000); */
640  char *mypath;
641 
642  /* sanitize this string - remove leading and trailing garbage */
643  rb = 0;
644  while ((EAI_BUFFER_CUR!=0) && (EAI_BUFFER_CUR <= ' ')) bufPtr++;
645  while (EAI_BUFFER_CUR > ' ') { ctmp[rb] = EAI_BUFFER_CUR; rb ++; bufPtr++; }
646 
647  /* ok, lets make a real name from this; maybe it is local to us? */
648  ctmp[rb] = 0;
649 
650  /* get the current parent */
651  mypath = STRDUP(ctmp);
652  DEBUG_MSG("CREATEVU, mypath %s\n", mypath);
653 
654  /* and strip off the file name, leaving any path */
655 /* removeFilenameFromPath (mypath); */
656  /* printf ("CREATEVU, mypath sans file: %s\n",mypath); */
657 
658  /* add the two together */
659 /* makeAbsoluteFileName(filename,mypath,ctmp); */
660  /* printf ("CREATEVU, filename, %s\n",filename); */
661 
662 /* if (eaiverbose) { */
663 /* printf ("CREATEVU %s\n",filename); */
664 /* } */
665 
666  ra = EAI_CreateVrml("URL", mypath, rootNode(), retGroup);
667 /* FREE_IF_NZ(filename); */
668  FREE_IF_NZ(mypath);
669  }
670 
671  //JAS printf ("CREATEXS ok, we are going to return the following number of nodes: %d\n",retGroup->children.n);
672  sprintf (th->outBuffer,"RE\n%f\n%d\n",TickTime(),count);
673  for (rb = 0; rb < retGroup->children.n; rb++) {
674  struct X3D_Node *node;
675  node = X3D_NODE(retGroup->children.p[rb]);
676  //printf ("CREATEXS, child %d is %p\n",rb,node);
677 
678  sprintf (ctmp,"%d ", registerEAINodeForAccess(node));
679 
680  outBufferCat(ctmp);
681 
682  // now, ensure this ones parent is removed
683  remove_parent(node,X3D_NODE(retGroup));
684  }
685 
686  //printf ("CREATEXS, marking for dispose, group %p\n",X3D_NODE(retGroup));
687  markForDispose(X3D_NODE(retGroup),FALSE);
688  break;
689  }
690 
691  case SENDCHILD : {
692  struct X3D_Node *node;
693  char *address;
694 
695  /*format int seq# COMMAND int node# ParentNode field ChildNode*/
696 
697  retint=sscanf (&EAI_BUFFER_CUR,"%d %d %s %d",&ra,&rb,ctmp,&rc);
698 
699  node = getEAINodeFromTable(ra,rb);
700  address = getEAIMemoryPointer (ra,rb);
701 
702  if (eaiverbose) {
703  printf ("SENDCHILD Parent: %u ParentField: %u %s Child at: %d\n",(unsigned int) ra, (unsigned int)rb, ctmp, rc);
704  }
705 
706  /* we actually let the end of eventloop code determine whether this is an add or
707  remove, or whatever - it will handle the addChildren and removeChildren well
708  so the add/remove/replace parameter of getMFNodetype is always 1 here */
709 
710  getMFNodetype (getEAINodeFromTable(rc,-1),(struct Multi_Node *)address, node, 1);
711 
712  /* tell the routing table that this node is updated - used for RegisterListeners */
713  MARK_EVENT(node,getEAIActualOffset(ra,rb));
714 
715  sprintf (th->outBuffer,"RE\n%f\n%d\n0",TickTime(),count);
716  break;
717  }
718  case REGLISTENER: {
719  struct X3D_Node * node;
720  int offset;
721  int directionFlag = 0;
722 
723  /*143024848 88 8 e 6*/
724  retint=sscanf (&EAI_BUFFER_CUR,"%d %d %c %d",&tmp_a,&tmp_b,ctmp,&tmp_c);
725 printf ("REGLISTENER, calling getEAINodeFromTable(%d, %d)\n",tmp_a,tmp_b);
726  node = getEAINodeFromTable(tmp_a, tmp_b);
727 printf ("REGLISTENER, calling getEAIActualOffset(%d, %d)\n",tmp_a,tmp_b);
728  offset = getEAIActualOffset(tmp_a, tmp_b);
729 printf ("REGLISTENER, have node %p, offset %d (%s)\n",node,offset, stringNodeType(node->_nodeType));
730 printf ("REGLISTENER, ctmp tells us that type is %c\n",ctmp[0]);
731 
732  /* is this a script node? if so, get the actual string name in the table for this one */
733  if (node->_nodeType == NODE_Script) {
734  struct Shader_Script * sp;
735 
736  /* we send along the script number, not the node pointer */
737  sp = (struct Shader_Script *) (X3D_SCRIPT(node)->__scriptObj);
738 
739  /* some print statements here because this is a script node
740  printf ("ah! so noderef %d, node %u is script num %d\n",tmp_a,node,sp->num);
741  printf ("this is a script node in a REGLISTENER command! %d\n",tmp_b);
742  */
743 
744  node = offsetPointer_deref(struct X3D_Node *,0,sp->num);
745  directionFlag = FROM_SCRIPT;
746  }
747 
748  /* so, count = query id, tmp_a pointer, tmp_b, offset, ctmp[0] type, tmp_c, length*/
749  ctmp[1]=0;
750 
751  if (eaiverbose)
752  printf ("REGISTERLISTENER from %p foffset %d fieldlen %d type %s \n",
753  node, offset ,tmp_c,ctmp);
754 
755 
756  /* put the address of the listener area in a string format for registering
757  the route - the route propagation will copy data to here */
758 
759  /* set up the route from this variable to the handle Listener routine */
760  if (eaiverbose) printf ("going to register route for RegisterListener, have type %d\n",tmp_c);
761 
762 
763  // encode field type, node id, and field offset id here
764  struct EAI_Extra_Data *ed = MALLOC(struct EAI_Extra_Data *,sizeof(struct EAI_Extra_Data));
765  ed->field_type = mapEAItypeToFieldType(ctmp[0]);
766  ed->listener_id = count;
767  ed->field_id = tmp_b;
768  ed-> node_id = tmp_a;
769 
770 /*
771 {
772  int field_id;
773  int node_id;
774  int field_type;
775  int listener_id;
776 };
777 */
778 
779 printf ("registering, field_id %d, node_id %d, field_type %d, listener_id %d\n",ed->field_id, ed->node_id, ed->field_type, ed->listener_id);
780 
781 
782  CRoutes_Register (1,node, offset, NULL, 0, (int) tmp_c,(void *)
783  &EAIListener, directionFlag, ed);
784 /*
785 (mapEAItypeToFieldType(ctmp[0])<<24)
786  +(tmp_a<<8)
787  +tmp_b);
788 */
789 
790  sprintf (th->outBuffer,"RE\n%f\n%d\n0",TickTime(),count);
791  break;
792  }
793 
794  case UNREGLISTENER: {
795  struct X3D_Node * node;
796  int offset;
797  int directionFlag = 0;
798 
799  /*143024848 88 8 e 6*/
800  retint=sscanf (&EAI_BUFFER_CUR,"%d %d %c %d",&tmp_a,&tmp_b,ctmp,&tmp_c);
801  node = getEAINodeFromTable(tmp_a,tmp_b);
802  offset = getEAIActualOffset(tmp_a,tmp_b);
803 
804  if (node->_nodeType == NODE_Script) {
805  struct Shader_Script * sp;
806 
807  /* we send along the script number, not the node pointer */
808  sp = (struct Shader_Script *) (X3D_SCRIPT(node)->__scriptObj);
809 
810  /* some print statements here because this is a script node
811  printf ("ah! so noderef %d, node %u is script num %d\n",tmp_a,node,sp->num);
812  printf ("this is a script node in a REGLISTENER command! %d\n",tmp_b);
813  */
814 
815  node = offsetPointer_deref(struct X3D_Node *,0,sp->num);
816  directionFlag = FROM_SCRIPT;
817  }
818 
819  /* so, count = query id, tmp_a pointer, tmp_b, offset, ctmp[0] type, tmp_c, length*/
820  ctmp[1]=0;
821 
822  if (eaiverbose) printf ("UNREGISTERLISTENER from %p foffset %d fieldlen %d type %s \n",
823  node, offset ,tmp_c,ctmp);
824 
825 
826  /* put the address of the listener area in a string format for registering
827  the route - the route propagation will copy data to here */
828  /* set up the route from this variable to the handle Listener routine */
829  CRoutes_Register (0,node, offset, NULL, 0, (int) tmp_c,(void *)
830  &EAIListener, directionFlag, (count<<8)+mapEAItypeToFieldType(ctmp[0])); /* encode id and type here*/
831 
832  sprintf (th->outBuffer,"RE\n%f\n%d\n0",TickTime(),count);
833  break;
834  }
835 
836  case GETVALUE: {
837  handleEAIGetValue(command, &EAI_BUFFER_CUR,count);
838  break;
839  }
840  case REPLACEWORLD: {
841  EAI_RW(&EAI_BUFFER_CUR);
842  sprintf (th->outBuffer,"RE\n%f\n%d\n0",TickTime(),count);
843  break;
844  }
845 
846  case GETPROTODECL: {
847  sprintf (th->outBuffer,"RE\n%f\n%d\n%s",TickTime(),count,SAI_StrRetCommand ((char) command,&EAI_BUFFER_CUR));
848  break;
849  }
850  case REMPROTODECL:
851  case UPDPROTODECL:
852  case UPDNAMEDNODE:
853  case REMNAMEDNODE: {
854  if (eaiverbose) {
855  printf ("SV int ret command ..%s\n",&EAI_BUFFER_CUR);
856  }
857  sprintf (th->outBuffer,"RE\n%f\n%d\n%d",TickTime(),count,
858  SAI_IntRetCommand ((char) command,&EAI_BUFFER_CUR));
859  break;
860  }
861  case ADDROUTE:
862  case DELETEROUTE: {
863  handleRoute (command, &EAI_BUFFER_CUR,count);
864  break;
865  }
866 
867  case STOPFREEWRL: {
868  if (!RUNNINGASPLUGIN) {
869  fwl_doQuit(__FILE__,__LINE__);
870  break;
871  }
872  }
873  case VIEWPOINT: {
874  /* do the viewpoints. Note the spaces in the strings */
875  if (!strncmp(&EAI_BUFFER_CUR, " NEXT",5)) fwl_Next_ViewPoint();
876  if (!strncmp(&EAI_BUFFER_CUR, " FIRST",6)) fwl_First_ViewPoint();
877  if (!strncmp(&EAI_BUFFER_CUR, " LAST",5)) fwl_Last_ViewPoint();
878  if (!strncmp(&EAI_BUFFER_CUR, " PREV",5)) fwl_Prev_ViewPoint();
879 
880  sprintf (th->outBuffer,"RE\n%f\n%d\n0",TickTime(),count);
881  break;
882  }
883 
884  case LOADURL: {
885  /* signal that we want to send the Anchor pass/fail to the EAI code */
886  p->waiting_for_anchor = TRUE;
887 
888  /* make up the URL from what we currently know */
889  createLoadURL(&EAI_BUFFER_CUR);
890 
891 
892  /* prep the reply... */
893  sprintf (th->outBuffer,"RE\n%f\n%d\n",TickTime(),count);
894  /*
895  * Lots of pretending going on here....
896  *
897  * We prep (and send) the first portion of the reply
898  * but you will notice later on, we do not add an END_OF marker.
899  * So, then it is EAI_Anchor_Response() that sends the actual
900  * success/fail response with a END_OF marker.
901  *
902  * Therefore the client needs to be clever and glue the two-part
903  * reply back together again. This is easy in the socket code, but
904  * if you use functions, you need to be clever and wait for the
905  * async callback befor proceeding as if the request worked.
906  *
907  */
908 
909  /* now tell the fwl_RenderSceneUpdateScene that BrowserAction is requested... */
910  setAnchorsAnchor( get_EAIEventsIn_AnchorNode()); //&tg->EAIEventsIn.EAI_AnchorNode;
911  tg->RenderFuncs.BrowserAction = TRUE;
912  break;
913  }
914 
915  case CREATEPROTO:
916  case CREATENODE: {
917  /* sanitize this string - remove leading and trailing garbage */
918  rb = 0;
919  while ((EAI_BUFFER_CUR!=0) && (EAI_BUFFER_CUR <= ' ')) bufPtr++;
920  while (EAI_BUFFER_CUR > ' ') { ctmp[rb] = EAI_BUFFER_CUR; rb ++; bufPtr++; }
921 
922  ctmp[rb] = 0;
923  if (eaiverbose) {
924  printf ("CREATENODE/PROTO %s\n",ctmp);
925  }
926 
927  /* set up the beginnings of the return string... */
928  sprintf (th->outBuffer,"RE\n%f\n%d\n",TickTime(),count);
929 
930  retGroup = createNewX3DNode(NODE_Group);
931  if (command == CREATENODE) {
932  if (eaiverbose) {
933  printf ("CREATENODE, %s is this a simple node? %d\n",ctmp,findFieldInNODES(ctmp));
934  }
935 
936  ctype = findFieldInNODES(ctmp);
937  if (ctype > -1) {
938  /* yes, use C only to create this node */
939  sprintf (ctmp, "%ld",(long int) createNewX3DNode(ctype));
940  outBufferCat(ctmp);
941  /* set ra to 0 so that the sprintf below is not used */
942  ra = 0;
943  } else {
944  ra = EAI_CreateVrml("CREATENODE",ctmp,rootNode(),retGroup);
945  }
946  } else if (command == CREATEPROTO)
947  ra = EAI_CreateVrml("CREATEPROTO",ctmp,rootNode(),retGroup);
948  else
949  printf ("eai - huh????\n");
950 
951 
952  for (rb = 0; rb < retGroup->children.n; rb++) {
953  sprintf (ctmp,"%ld ", (long int) retGroup->children.p[rb]);
954  outBufferCat(ctmp);
955 printf ("Possible EAI problem, children of container group should have this parent removed\n");
956 
957  // now, ensure this ones parent is removed
958  //remove_parent(node,X3D_NODE(retGroup));
959  }
960  markForDispose(X3D_NODE(retGroup),FALSE);
961  break;
962  }
963 
964  case GETFIELDDEFS: {
965  /* get a list of fields of this node */
966  sscanf (&EAI_BUFFER_CUR,"%d",&ra);
967  makeFIELDDEFret(ra,count);
968  break;
969  }
970 
971  case GETNODEDEFNAME: {
972  /* return a def name for this node. */
973  sprintf (th->outBuffer,"RE\n%f\n%d\n%s",TickTime(),count,
974  SAI_StrRetCommand ((char) command,&EAI_BUFFER_CUR));
975 
976  break;
977  }
978  case GETNODEPARENTS:
979  {
980  handleGETNODEPARENTS(&EAI_BUFFER_CUR,count);
981  break;
982  }
983 
984  default: {
985  printf ("unhandled command :%c: %d\n",command,command);
986  outBufferCat( "unknown_EAI_command");
987  break;
988  }
989 
990  }
991 
992  /* skip to the next command */
993  while (EAI_BUFFER_CUR >= ' ') bufPtr++;
994  /* skip any new lines that may be there */
995  while ((EAI_BUFFER_CUR == 10) || (EAI_BUFFER_CUR == 13)) bufPtr++;
996 
997  if (eaiverbose) {
998  printf ("end of command, remainder %d chars ",(int)strlen(&EAI_BUFFER_CUR));
999 #ifdef _MSC_VER
1000  printf ("and :%s: thread %lu\n",(&EAI_BUFFER_CUR),(unsigned long) pthread_self().p);
1001 #else
1002  printf ("and :%s: thread %lu\n",(&EAI_BUFFER_CUR),(unsigned long) pthread_self());
1003 #endif
1004 
1005  }
1006  if (command == SENDEVENT ) {
1007  /* events don't send a reply as such so your code has to check for zerolength strings*/
1008  th->outBuffer[0] = 0;
1009  } else {
1010  /* send the response, but only a portion in the case of LOADURL */
1011  if (command != LOADURL) outBufferCat("\nRE_EOT"); /* Please read and digest the LOADURL case above */
1012  }
1013  }
1014  tg->EAICore.EAIbufpos = bufPtr;
1015 eaiverbose=FALSE; //JAS
1016 
1017  return ;
1018 }
1019 
1020 static void handleGETROUTES (char *bufptr, int repno) {
1021  int numRoutes;
1022  int count;
1023  struct X3D_Node *fromNode;
1024  struct X3D_Node *toNode;
1025  int fromOffset;
1026  int toOffset;
1027  char ctmp[200];
1028  struct tEAIHelpers* th = &gglobal()->EAIHelpers;
1029 
1030  sprintf (th->outBuffer,"RE\n%f\n%d\n",TickTime(),repno);
1031 
1032  numRoutes = getRoutesCount();
1033 
1034  if (numRoutes < 2) {
1035  outBufferCat("0");
1036  return;
1037  }
1038 
1039  /* tell how many routes there are */
1040  sprintf (ctmp,"%d ",numRoutes-2);
1041  outBufferCat(ctmp);
1042 
1043  /* remember, in the routing table, the first and last entres are invalid, so skip them */
1044  for (count = 1; count < (numRoutes-1); count++) {
1045  getSpecificRoute (count,&fromNode, &fromOffset, &toNode, &toOffset);
1046 
1047  sprintf (ctmp, "%p %s %p %s ",fromNode,
1048  findFIELDNAMESfromNodeOffset(fromNode,fromOffset),
1049  toNode,
1050  findFIELDNAMESfromNodeOffset(toNode,toOffset)
1051  );
1052  outBufferCat(ctmp);
1053  /* printf ("route %d is:%s:\n",count,ctmp); */
1054  }
1055 
1056  /* printf ("getRoutes returns %s\n",buf); */
1057 }
1058 
1059 static void handleGETNODE (char *bufptr, int repno) {
1060  int retint;
1061  char ctmp[200];
1062  struct tEAIHelpers* th;
1063  int eaiverbose;
1064  ttglobal tg = gglobal();
1065  eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
1066  th = &tg->EAIHelpers;
1067  /*format int seq# COMMAND string nodename*/
1068 
1069  UNUSED(retint); // for compiler warnings
1070 
1071  retint=sscanf (bufptr," %s",ctmp);
1072 
1073  if (eaiverbose) {
1074  printf ("GETNODE %s\n",ctmp);
1075  }
1076 
1077  /* is this the SAI asking for the root node? */
1078  if (strcmp(ctmp,SYSTEMROOTNODE)) {
1079  sprintf (th->outBuffer,"RE\n%f\n%d\n%d",TickTime(),repno, EAI_GetNode(ctmp));
1080  } else {
1081  /* yep i this is a call for the rootNode */
1082  sprintf (th->outBuffer,"RE\n%f\n%d\n%d",TickTime(),repno, EAI_GetRootNode());
1083  }
1084  if (eaiverbose) {
1085  printf ("GETNODE returns %s\n",th->outBuffer);
1086  }
1087 }
1088 
1089 static void handleGETNODEPARENTS (char *bufptr, int repno)
1090 {
1091  int nodeHandle;
1092  char parentAdr[10];
1093  char buffer[EAIREADSIZE];
1094  struct tEAIHelpers* th;
1095  int eaiverbose;
1096 
1097  int* parentArray;
1098  int result;
1099  int index;
1100 
1101  ttglobal tg = gglobal();
1102  eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
1103  th = &tg->EAIHelpers;
1104 
1105  nodeHandle = 0;
1106  parentArray = NULL;
1107  /*format int seq# COMMAND string nodename*/
1108 
1109  sscanf(bufptr,"%d",&nodeHandle);
1110 
1111  if (eaiverbose) {
1112  printf ("GETNODEPARENTS %d\n",nodeHandle);
1113  }
1114 
1115  result = EAI_GetNodeParents(nodeHandle,&parentArray);
1116 
1117  snprintf(buffer,EAIREADSIZE,"RE\n%f\n%d\n",TickTime(),repno);
1118 
1119  if(result > 0)
1120  {
1121  for(index = 0; index < result; index++)
1122  {
1123  snprintf(parentAdr,10,"%d ",parentArray[index]);
1124  strncat(buffer,parentAdr,strlen(parentAdr));
1125  }
1126  }
1127  else
1128  {
1129  snprintf(parentAdr,10,"%d ",result);
1130  strncat(buffer,parentAdr,strlen(parentAdr));
1131  }
1132 
1133  outBufferCat(buffer);
1134 
1135  if (eaiverbose) {
1136  printf ("GETNODE returns %s\n",th->outBuffer);
1137  }
1138 
1139  if(parentArray)
1140  free(parentArray);
1141 }
1142 
1143 
1144 /* get the actual node type, whether Group, IndexedFaceSet, etc, and its DEF name, if applicapable */
1145 static void handleGETEAINODETYPE (char *bufptr, int repno) {
1146  int wlen;
1147  int nodeHandle;
1148  struct X3D_Node * myNode;
1149  char *cptr;
1150  char *myNT;
1151  struct tEAIHelpers *th = &gglobal()->EAIHelpers;
1152  /*format int seq# COMMAND string nodename*/
1153 
1154  wlen=sscanf (bufptr," %d",&nodeHandle);
1155  if (wlen != 1) ConsoleMessage ("handleGETEAINODETYPE - expected to handle 1 number, got %d",wlen);
1156 
1157  myNode = getEAINodeFromTable(nodeHandle,-1);
1158 
1159  if (myNode == NULL) {
1160  printf ("Internal EAI error, node %d not found\n",nodeHandle);
1161  sprintf (th->outBuffer,"RE\n%f\n%d\n__UNDEFINED __UNDEFINED",TickTime(),repno);
1162  return;
1163  }
1164 
1165  /* so, this is a valid node, lets find out if it is DEFined or whatever... */
1166  /* Get the Node type. If it is a PROTO, get the proto def name, if not, just get the X3D node name */
1167  //if ((myNode->_nodeType == NODE_Group) && (X3D_GROUP(myNode)->FreeWRL__protoDef != INT_ID_UNDEFINED)) {
1168  if (isProto(myNode)) {
1169  myNT = parser_getPROTONameFromNode(myNode);
1170  if (myNT == NULL) {
1171  myNT = "XML_PROTO"; /* add this if we need to parse XML proto getTypes */
1172  }
1173  } else {
1174  myNT = (char *) stringNodeType(myNode->_nodeType);
1175  }
1176 
1177  /* Try to get X3D node name */
1178  #ifdef IPHONE
1179  cptr = NULL; /* no xml parsing for now in iphone */
1180  #else
1181  cptr = X3DParser_getNameFromNode(myNode);
1182  #endif
1183 
1184  if (cptr != NULL) {
1185  sprintf (th->outBuffer,"RE\n%f\n%d\n%s %s",TickTime(),repno,myNT, cptr);
1186  return;
1187  }
1188 
1189  /* Try to get VRML node name */
1190  cptr= parser_getNameFromNode(myNode);
1191  if (cptr != NULL) {
1192  /* Only one of these is right ..... */
1193  /* I think it is the first one, because we would have had to know the DEF name in the first place. */
1194  /* sprintf (th->outBuffer,"RE\n%f\n%d\n\\"%s\"",TickTime(),repno,myNT); */
1195  sprintf (th->outBuffer,"RE\n%f\n%d\n\"%s\" \"%s\"",TickTime(),repno,myNT, cptr);
1196  /* sprintf (th->outBuffer,"RE\n%f\n%d\n\"%s\"",TickTime(),repno, cptr); */
1197  return;
1198  }
1199 
1200  /* no, this node is just undefined */
1201  sprintf (th->outBuffer,"RE\n%f\n%d\n%s __UNDEFINED",TickTime(),repno,myNT);
1202 }
1203 
1204 
1205 /* add or delete a route */
1206 static void handleRoute (char command, char *bufptr, int repno) {
1207  struct X3D_Node *fromNode;
1208  struct X3D_Node *toNode;
1209  char fieldTemp[2000];
1210  int fromOffset, toOffset;
1211  int fromfieldType, fromfieldNode, fromretNode, fromretField, fromdataLen;
1212  int fromscripttype;
1213  int fromxxx;
1214  int tofieldNode, toretNode, toretField, todataLen, tofieldType;
1215  int toscripttype;
1216  int toxxx;
1217  char *x;
1218  int ftlen;
1219 
1220  int rv;
1221  int eaiverbose;
1222  struct tEAIHelpers *th = &gglobal()->EAIHelpers;
1223  eaiverbose = gglobal()->EAI_C_CommonFunctions.eaiverbose;
1224  /* assume that all is ok right now */
1225  rv = TRUE;
1226 
1227  /* get ready for the reply */
1228  sprintf (th->outBuffer,"RE\n%f\n%d\n",TickTime(),repno);
1229 
1230  if (eaiverbose) printf ("handleRoute, string %s\n",bufptr);
1231 
1232  /* ------- worry about the route from section -------- */
1233 
1234  /* read in the fromNode pointer */
1235  while (*bufptr == ' ') bufptr++;
1236 
1237  /* get the from Node */
1238  sscanf(bufptr, "%u", (unsigned int *)&fromfieldNode);
1239 
1240  /* copy the from field into the "fieldTemp" array */
1241  x = fieldTemp; ftlen = 0;
1242 
1243  /* skip to the beginning of the field name */
1244  while (*bufptr != ' ') bufptr++; while (*bufptr == ' ') bufptr++;
1245 
1246  /* copy the field over */
1247  while ((*bufptr > ' ') && (ftlen <1000)) { *x = *bufptr; x++; bufptr++; ftlen++;}
1248  *x = '\0';
1249 
1250  /* and, get the info for this one */
1251  EAI_GetType (fromfieldNode, fieldTemp, "outputOnly", &fromretNode, &fromretField, &fromdataLen, &fromfieldType, &fromscripttype, &fromxxx);
1252 
1253 
1254  /* skip past the first field, to get ready for the next one */
1255  while (*bufptr != ' ') bufptr++; while (*bufptr == ' ') bufptr++;
1256 
1257  /* ------- now, the route to section -------- */
1258  /* get the to Node */
1259 
1260  sscanf(bufptr, "%u", (unsigned int *)&tofieldNode);
1261 
1262  /* copy the to field into the "fieldTemp" array */
1263  x = fieldTemp; ftlen = 0;
1264 
1265  /* skip to the beginning of the field name */
1266  while (*bufptr != ' ') bufptr++; while (*bufptr == ' ') bufptr++;
1267 
1268  /* copy the field over */
1269  while ((*bufptr > ' ') && (ftlen <1000)) { *x = *bufptr; x++; bufptr++; ftlen++;}
1270  *x = '\0';
1271 
1272  /* and, get the info for this one */
1273  EAI_GetType (tofieldNode, fieldTemp, "inputOnly", &toretNode, &toretField, &todataLen, &tofieldType, &toscripttype, &toxxx);
1274 
1275  if (eaiverbose) printf ("so, we are routing from %d:%d to %d:%d, fieldtypes %d:%d, datalen %d:%d\n",
1276  fromretNode, toretNode, fromretField,
1277  toretField, fromfieldType,tofieldType, fromdataLen,todataLen);
1278 
1279  /* are both fieldtypes the same, and are both valid? */
1280  rv= ((fromfieldType==tofieldType) &&(fromfieldType != -1));
1281 
1282  /* ------- if we are ok, call the routing code -------- */
1283  if (rv) {
1284  /* get the C node and field offset for the nodes now */
1285  fromNode = (struct X3D_Node*) getEAINodeFromTable(fromretNode,fromretField);
1286  toNode = (struct X3D_Node*) getEAINodeFromTable(toretNode,toretField);
1287  fromOffset = getEAIActualOffset((int)fromretNode,fromretField);
1288  toOffset = getEAIActualOffset(toretNode,toretField);
1289 
1290  /* is this an add or delete route? */
1291  if (command == ADDROUTE) CRoutes_RegisterSimple(fromNode,fromOffset,toNode,toOffset,fromfieldType);
1292  else CRoutes_RemoveSimple(fromNode,fromOffset,toNode,toOffset,fromfieldType);
1293 
1294  outBufferCat( "0");
1295  } else {
1296  outBufferCat( "1");
1297  }
1298 }
1299 
1300 /* for a GetFieldTypes command for a node, we return a string giving the field types */
1301 
1302 static void makeFIELDDEFret(int myptr, int repno) {
1303  struct X3D_Node *boxptr;
1304  int myc;
1305  int *np;
1306  char myline[200];
1307  /* Used for heavy tracing with eaiverbose */
1308  char *tmpptr;
1309  int dtmp;
1310  char ctmp;
1311  char utilBuf[EAIREADSIZE];
1312  int errcount;
1313  ttglobal tg = gglobal();
1314  int eaiverbose;
1315  struct tEAIHelpers *th = &tg->EAIHelpers;
1316  eaiverbose = tg->EAI_C_CommonFunctions.eaiverbose;
1317 
1318  memset(utilBuf,'\0',sizeof(utilBuf));
1319 
1320  boxptr = getEAINodeFromTable(myptr,-1);
1321 
1322  if (eaiverbose) {
1323  printf ("GETFIELDDEFS, node %u -> %p\n",(unsigned int)myptr, boxptr);
1324  }
1325 
1326  if (boxptr == 0) {
1327  printf ("makeFIELDDEFret have null node here \n");
1328  sprintf (th->outBuffer,"RE\n%f\n%d\n0",TickTime(),repno);
1329  return;
1330  }
1331 
1332  printf ("node type is %s\n",stringNodeType(boxptr->_nodeType));
1333 
1334  /* Iterate over all the fields in the node */
1335  np = (int *) NODE_OFFSETS[boxptr->_nodeType];
1336  myc = 0;
1337  while (*np != -1) {
1338  /* is this a hidden field? */
1339  if (0 != strncmp(stringFieldType(np[0]), "_", 1) ) {
1340  if (eaiverbose) {
1341  ctmp = (char) mapFieldTypeToEAItype(np[2]) ;
1342  dtmp = mapEAItypeToFieldType(ctmp) ;
1343 
1344  tmpptr = offsetPointer_deref (char *, boxptr,np[1]);
1345  printf("%s,%d ",__FILE__,__LINE__) ;
1346  printf("Field %d %s , ", myc, stringFieldType(np[0])) ;
1347  printf("offset=%d bytes , ", np[1]) ;
1348 
1349  printf("field_type= %c (%d) , ", ctmp , dtmp) ;
1350  printf("Routing=%s , ", stringKeywordType(np[3])) ;
1351  printf("Spec=%d , ", np[4]) ;
1352 
1353  errcount = UtilEAI_Convert_mem_to_ASCII (dtmp,tmpptr, utilBuf);
1354  if (0 == errcount) {
1355  printf ("\t\tValue = %s\n",utilBuf);
1356  } else {
1357  printf ("\t\tValue = indeterminate....\n");
1358  }
1359  }
1360  myc ++;
1361  }
1362  np +=5;
1363  }
1364 
1365  sprintf (th->outBuffer,"RE\n%f\n%d\n",TickTime(),repno);
1366 
1367 /* AFAIK Mon May 10 21:04:48 BST 2010 The EAI no longer passes a count, nor array markers ([]) */
1368 /*
1369  sprintf (myline, "%d [",myc);
1370  outBufferCat( myline);
1371 */
1372 
1373  /* now go through and get the name, type, keyword */
1374  np = (int *) NODE_OFFSETS[boxptr->_nodeType];
1375  while (*np != -1) {
1376  /* if (strcmp (FIELDNAMES[*np],"_") != 0) { */
1377  if (0 != strncmp(stringFieldType(np[0]), "_", 1) ) {
1378  /*
1379  sprintf (myline,"%s %c %s ",stringFieldType(np[0]), (char) mapFieldTypeToEAItype(np[2]),
1380  stringKeywordType(np[3]));
1381  */
1382  sprintf (myline,"\"%s\" ",stringFieldType(np[0])) ;
1383  outBufferCat( myline);
1384  }
1385  np += 5;
1386  }
1387 /*
1388  sprintf (myline, "]");
1389  outBufferCat( myline);
1390 */
1391 }
1392 
1393 
1394 #endif //EXCLUDE_EAI
1395 
1396 
1397 
1398 /* EAI, replaceWorld. */
1399 void EAI_RW(char *str) {
1400  struct X3D_Node *newNode;
1401  int i;
1402 
1403  /* clean the slate! keep EAI running, though */
1404  printf("EAI replace world, calling kill_oldWorld\n");
1405  kill_oldWorld(FALSE,TRUE,__FILE__,__LINE__);
1406 
1407  /* go through the string, and send the nodes into the rootnode */
1408  /* first, remove the command, and get to the beginning of node */
1409  while ((*str != ' ') && (strlen(str) > 0)) str++;
1410  while (isspace(*str)) str++;
1411  while (strlen(str) > 0) {
1412  i = sscanf (str, "%u",(unsigned int *)&newNode);
1413 
1414  if (i>0) {
1415  AddRemoveChildren (X3D_NODE(rootNode()),offsetPointer_deref(void*,rootNode(),offsetof (struct X3D_Group, children)),&newNode,1,1,__FILE__,__LINE__);
1416  }
1417  while (isdigit(*str)) str++;
1418  while (isspace(*str)) str++;
1419  }
1420 }
1421 
1422 //#if !defined(EXCLUDE_EAI)
1423 
1424 void createLoadURL(char *bufptr) {
1425  #define strbrk " :loadURLStringBreak:"
1426  int count;
1427  char *spbrk;
1428  int retint; /* used to get retval from sscanf */
1429  ppEAIEventsIn p;
1430  UNUSED(retint); // for compiler warnings
1431 
1432  p = (ppEAIEventsIn)gglobal()->EAIEventsIn.prv;
1433 
1434  /* fill in Anchor parameters */
1435  p->EAI_AnchorNode.description = newASCIIString("From EAI");
1436 
1437  /* fill in length fields from string */
1438  while (*bufptr==' ') bufptr++;
1439  retint=sscanf (bufptr,"%d",&p->EAI_AnchorNode.url.n);
1440  while (*bufptr>' ') bufptr++;
1441  while (*bufptr==' ') bufptr++;
1442  retint=sscanf (bufptr,"%d",&p->EAI_AnchorNode.parameter.n);
1443  while (*bufptr>' ') bufptr++;
1444  while (*bufptr==' ') bufptr++;
1445 
1446  /* now, we should be at the strings. */
1447  bufptr--;
1448 
1449  /* MALLOC the sizes required */
1450  if (p->EAI_AnchorNode.url.n > 0) p->EAI_AnchorNode.url.p = MALLOC(struct Uni_String **, p->EAI_AnchorNode.url.n * sizeof (struct Uni_String));
1451  if (p->EAI_AnchorNode.parameter.n > 0) p->EAI_AnchorNode.parameter.p = MALLOC(struct Uni_String **, p->EAI_AnchorNode.parameter.n * sizeof (struct Uni_String));
1452 
1453  for (count=0; count<p->EAI_AnchorNode.url.n; count++) {
1454  bufptr += strlen(strbrk);
1455  /* printf ("scanning, at :%s:\n",bufptr); */
1456 
1457  /* nullify the next "strbrk" */
1458  spbrk = strstr(bufptr,strbrk);
1459  if (spbrk!=NULL) *spbrk='\0';
1460 
1461  p->EAI_AnchorNode.url.p[count] = newASCIIString(bufptr);
1462 
1463  if (spbrk!=NULL) bufptr = spbrk;
1464  }
1465  for (count=0; count<p->EAI_AnchorNode.parameter.n; count++) {
1466  bufptr += strlen(strbrk);
1467  /* printf ("scanning, at :%s:\n",bufptr); */
1468 
1469  /* nullify the next "strbrk" */
1470  spbrk = strstr(bufptr,strbrk);
1471  if (spbrk!=NULL) *spbrk='\0';
1472  if (p->EAI_AnchorNode.parameter.p != NULL)
1473  {
1474  p->EAI_AnchorNode.parameter.p[count] = newASCIIString(bufptr);
1475  }
1476  if (spbrk!=NULL) bufptr = spbrk;
1477  }
1478  /* EAI_AnchorNode.__parenturl = newASCIIString("./"); */
1479 }
1480 #if !defined(EXCLUDE_EAI)
1481 
1482 
1483 /* if we have a LOADURL command (loadURL in java-speak) we call Anchor code to do this.
1484  here we tell the EAI code of the success/fail of an anchor call, IF the EAI is
1485  expecting such a call */
1486 
1487 void EAI_Anchor_Response (int resp) {
1488  char myline[1000];
1489  ppEAIEventsIn p;
1490  //ppEAICore ps;
1491  ttglobal tg = gglobal();
1492  p = (ppEAIEventsIn)tg->EAIEventsIn.prv;
1493  //ps = (ppEAICore)tg->EAICore.prv;
1494  if (p->waiting_for_anchor) {
1495  if (resp) strcpy (myline,"OK\nRE_EOT");
1496  else strcpy (myline,"FAIL\nRE_EOT");
1497  fwlio_RxTx_sendbuffer (__FILE__,__LINE__,CHANNEL_EAI,myline);
1498  }
1499  p->waiting_for_anchor = FALSE;
1500 }
1501 #else
1502 void EAI_Anchor_Response (int resp) {
1503  char myline[1000];
1504  ppEAIEventsIn p;
1505  //ppEAICore ps;
1506  ttglobal tg = gglobal();
1507  p = (ppEAIEventsIn)tg->EAIEventsIn.prv;
1508  //ps = (ppEAICore)tg->EAICore.prv;
1509  p->waiting_for_anchor = FALSE;
1510 }
1511 #endif //EXCLUDE_EAI