1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #include <fcntl.h>
16
17 #include <dx/dx.h>
18
19 #if defined(HAVE_UNISTD_H)
20 #include <unistd.h>
21 #endif
22
23 #include "config.h"
24 #include "pmodflags.h"
25 #include "utils.h"
26 #include "distp.h"
27 #include "parse.h"
28 #include "parsemdf.h"
29 #include "_macro.h"
30 #include "remote.h"
31 #include "loader.h"
32 #include "graph.h"
33 #include "function.h"
34
35 static Error do_mdf_load(struct moddef *mp);
36
37 /* this has to be in global memory for MP systems
38 * since adding run-time modules has to happen on
39 * all processors
40 */
newmod()41 static struct moddef *newmod()
42 {
43 struct moddef *mp;
44
45 mp = DXAllocateZero (sizeof(struct moddef));
46 if (!mp)
47 return NULL;
48
49 return mp;
50 }
51
52
delmod(struct moddef * mp)53 static Error delmod(struct moddef *mp)
54 {
55 struct modargs *map, *next;
56 int i;
57
58 if (!mp)
59 return OK;
60
61 if (mp->m_name)
62 DXFree ((Pointer)mp->m_name);
63 if (mp->m_exec)
64 DXFree ((Pointer)mp->m_exec);
65 if (mp->m_host)
66 DXFree ((Pointer)mp->m_host);
67 if (mp->m_loadfile)
68 DXFree ((Pointer)mp->m_loadfile);
69
70 /* follow the chains here and delete the char strings */
71 for (i=0, map = mp->m_innames; i<mp->m_nin; i++, map=next) {
72 if (!map)
73 break;
74
75 next = map->nextarg;
76 DXFree ((Pointer)map->thisarg);
77 DXFree ((Pointer)map->deflt);
78 DXFree ((Pointer)map);
79 }
80 for (i=0, map = mp->m_outnames; i<mp->m_nout; i++, map=next) {
81 if (!map)
82 break;
83
84 next = map->nextarg;
85 DXFree ((Pointer)map->thisarg);
86 DXFree ((Pointer)map->deflt);
87 DXFree ((Pointer)map);
88 }
89
90 DXFree ((Pointer)mp);
91 return OK;
92 }
93
94 #define INPUTARG 1
95 #define OUTPUTARG 2
96
addarg(struct moddef * mp,int type,char * name,char * def)97 static Error addarg(struct moddef *mp, int type, char *name, char *def)
98 {
99 struct modargs *map, *newmap;
100
101 if (!mp)
102 return OK;
103
104 newmap = (struct modargs *)DXAllocateZero (sizeof(struct modargs));
105 if (!newmap)
106 return ERROR;
107
108 newmap->thisarg = name;
109 newmap->deflt = def;
110
111 if (type == INPUTARG)
112 {
113 mp->m_nin++;
114 if (!mp->m_innames)
115 {
116 mp->m_innames = newmap;
117 return OK;
118 }
119 map = mp->m_innames;
120 }
121 else
122 {
123 mp->m_nout++;
124 if (!mp->m_outnames)
125 {
126 mp->m_outnames = newmap;
127 return OK;
128 }
129 map = mp->m_outnames;
130 }
131
132 while (map->nextarg)
133 map = map->nextarg;
134
135 map->nextarg = newmap;
136 return OK;
137 }
138
139
argdup(struct moddef * mp,int type,int repcount)140 static Error argdup(struct moddef *mp, int type, int repcount)
141 {
142 int i;
143 int startrep;
144 struct modargs *map;
145 char *name, *value;
146
147 if (type == INPUTARG) {
148 startrep = mp->m_nin - repcount;
149 map = mp->m_innames;
150 } else {
151 startrep = mp->m_nout - repcount;
152 map = mp->m_outnames;
153 }
154 if (startrep < 0) {
155 DXSetError(ERROR_DATA_INVALID, "invalid repeat count");
156 return ERROR;
157 }
158
159 for (i=0; i<startrep; i++, map=map->nextarg)
160 ;
161
162 for (i=0; i<repcount*REPCOUNT; i++) {
163 name = NULL;
164 if (map->thisarg) {
165 name = DXAllocateZero (strlen(map->thisarg) + 4);
166 if (!name)
167 return ERROR;
168 sprintf(name, "%s%d", map->thisarg, i);
169 }
170
171 value = NULL;
172 if (map->deflt) {
173 value = DXAllocateZero (strlen(map->deflt) + 1);
174 if (!value)
175 return ERROR;
176 }
177
178 if (!addarg(mp, type, name, value))
179 return ERROR;
180 }
181
182 return OK;
183 }
184
185
186
187 /*
188 * DXAddModuleV (name, func, flags, nin, inlist, nout, outlist, exec, host)
189 *
190 * struct moddef {
191 * char * m_name;
192 * PFI m_func;
193 * int m_flags;
194 * int m_nin;
195 * struct modargs * m_innames;
196 * int m_nout;
197 * struct modargs * m_outnames;
198 * char * m_exec;
199 * char * m_host;
200 * int m_pflags;
201 * char * m_loadfile;
202 * }
203 */
204
205 static Error
callmdf_remote(char * fname)206 callmdf_remote(char *fname)
207 {
208 if (! DXLoadAndRunObjFile(fname, "MODULES"))
209 return ERROR;
210 else
211 return OK;
212 }
213
callmdf(struct moddef * mp,int doremote)214 static Error callmdf(struct moddef *mp, int doremote)
215 {
216 int rc;
217
218
219 /* check the parms against the already defined module */
220 if (mp->m_pflags == PF_RELOAD) {
221 /* add code here */
222 if (!(mp->m_pflags & PF_LOADABLE) && !(mp->m_pflags & PF_OUTBOARD)) {
223 /* set error code here? we are going to ignore this defn */
224 DXMessage("ignoring redefinition of module %s", mp->m_name);
225 return OK;
226 }
227 /* fall through - it's ok to reload an outboard or runtime loadable */
228 }
229
230 if (mp->m_pflags & PF_LOADABLE) {
231 /* on an MP machine, we have to load the code into the
232 * running exec for each process.
233 */
234
235 if (DXProcessors(0) > 1 && _dxd_exGoneMP) {
236
237 #ifdef DXD_NO_MP_RUNTIME
238 if (_dxd_exGoneMP) {
239 /* can't do runtime loadable after forking on sgi or solaris */
240 #define LONGHELP "Runtime-loadable modules cannot be added after startup when running with more than 1 processor. Either specify -mdf on the startup command line, or run -processors 1"
241 DXSetError(ERROR_DATA_INVALID, LONGHELP);
242 return ERROR;
243 }
244 #endif
245
246 if (_dxf_ExRunOnAll (callmdf_remote, mp->m_loadfile,
247 strlen(mp->m_loadfile)+1) == ERROR) {
248 DXAddMessage("module %s", mp->m_name);
249 return ERROR;
250 }
251 } else {
252 /* do the load for a single process machine, or MP machine
253 * before the fork.
254 */
255 if (!DXLoadAndRunObjFile(mp->m_loadfile, "DXMODULES")) {
256 DXAddMessage("module %s", mp->m_name);
257 return ERROR;
258 }
259 }
260 return OK;
261 }
262
263 if (mp->m_flags & MODULE_OUTBOARD)
264 mp->m_func = DXOutboard;
265
266 if (mp->m_func == NULL) {
267 DXSetError(ERROR_DATA_INVALID,
268 "module %s must have an OUTBOARD or LOADABLE entry to be added at run time",
269 mp->m_name);
270 return ERROR;
271 }
272
273 /* mark this module as being loaded at run time instead of being
274 * known at compile time. i don't think any one cares, but just
275 * in case it turns out to be useful...
276 */
277 mp->m_flags |= RUNTIMELOAD;
278
279
280 /* the work happens here.
281 */
282 if (DXProcessors(0) == 1 || _dxd_exGoneMP == 0)
283 rc = do_mdf_load(mp);
284 else
285 rc = _dxf_ExRunOn (1, do_mdf_load, (Pointer)mp, 0);
286
287
288 /* if running distributed, tell the others about the new module.
289 */
290 if (doremote)
291 _dxf_ExDistributeMsg(DM_LOADMDF, (Pointer)mp, 0, TOSLAVES);
292
293 return rc;
294 }
295
296
do_mdf_load(struct moddef * mp)297 static Error do_mdf_load(struct moddef *mp)
298 {
299 int i;
300 char **inlist = NULL, **outlist = NULL;
301 struct modargs *map;
302 Error rc;
303
304 if (mp->m_nin) {
305 inlist = (char **)DXAllocateZero(mp->m_nin * sizeof (char *));
306 if (!inlist)
307 return ERROR;
308 }
309 if (mp->m_nout) {
310 outlist = (char **)DXAllocateZero(mp->m_nout * sizeof (char *));
311 if (!outlist) {
312 DXFree((Pointer)inlist);
313 return ERROR;
314 }
315 }
316
317 for (i=0, map=mp->m_innames; i<mp->m_nin; i++, map=map->nextarg)
318 inlist[i] = map->thisarg;
319
320 for (i=0, map=mp->m_outnames; i<mp->m_nout; i++, map=map->nextarg)
321 outlist[i] = map->thisarg;
322
323
324 /* this loads the executive jump table.
325 */
326 rc = DXAddModuleV(mp->m_name, mp->m_func, mp->m_flags,
327 mp->m_nin, inlist,
328 mp->m_nout, outlist,
329 mp->m_exec, mp->m_host);
330
331
332 /* we may have some graph with these functions built in already.
333 * this forces us to rebuild all graphs with the new mdf defintion.
334 */
335 if ((node *)_dxf_ExMacroSearch (mp->m_name) != NULL)
336 _dxf_ExDictionaryPurge (_dxd_exGraphCache);
337
338
339 DXFree((Pointer)inlist);
340 DXFree((Pointer)outlist);
341
342 return rc;
343 }
344
345
346 /* communicating with remote execs for distributed.
347 */
348
_dxf_ExSendMdfPkg(Pointer * data,int tofd)349 void _dxf_ExSendMdfPkg(Pointer *data, int tofd)
350 {
351 int i, len;
352 struct moddef *mp;
353 struct modargs *map;
354
355 mp = (struct moddef *)data;
356
357 len = (mp->m_name) ? strlen(mp->m_name) : 0;
358 _dxf_ExWriteSock(tofd, &len, sizeof(int));
359 if (len > 0)
360 _dxf_ExWriteSock(tofd, mp->m_name, len);
361 _dxf_ExWriteSock(tofd, &mp->m_flags, sizeof(int));
362
363 _dxf_ExWriteSock(tofd, &mp->m_nin, sizeof(int));
364 map = mp->m_innames;
365 for (i=0, map=mp->m_innames; i<mp->m_nin; i++, map=map->nextarg) {
366 len = (map->thisarg) ? strlen(map->thisarg) : 0;
367 _dxf_ExWriteSock(tofd, &len, sizeof(int));
368 if (len > 0)
369 _dxf_ExWriteSock(tofd, map->thisarg, len);
370 /* i'm NOT writing the default value here because they are not
371 * supported yet. this will have to be added sometime.
372 */
373 }
374
375 _dxf_ExWriteSock(tofd, &mp->m_nout, sizeof(int));
376 map = mp->m_outnames;
377 for (i=0, map=mp->m_outnames; i<mp->m_nout; i++, map=map->nextarg) {
378 len = (map->thisarg) ? strlen(map->thisarg) : 0;
379 _dxf_ExWriteSock(tofd, &len, sizeof(int));
380 if (len > 0)
381 _dxf_ExWriteSock(tofd, map->thisarg, len);
382 /* i'm NOT writing the default value here because they are not
383 * supported yet. this will have to be added sometime.
384 */
385 }
386
387 len = (mp->m_exec) ? strlen(mp->m_exec) : 0;
388 _dxf_ExWriteSock(tofd, &len, sizeof(int));
389 if (len > 0)
390 _dxf_ExWriteSock(tofd, mp->m_exec, len);
391 len = (mp->m_host) ? strlen(mp->m_host) : 0;
392 _dxf_ExWriteSock(tofd, &len, sizeof(int));
393 if (len > 0)
394 _dxf_ExWriteSock(tofd, mp->m_host, len);
395
396 _dxf_ExWriteSock(tofd, &mp->m_pflags, sizeof(int));
397 len = (mp->m_loadfile) ? strlen(mp->m_loadfile) : 0;
398 _dxf_ExWriteSock(tofd, &len, sizeof(int));
399 if (len > 0)
400 _dxf_ExWriteSock(tofd, mp->m_loadfile, len);
401
402 return;
403 }
404
405
_dxf_ExRecvMdfPkg(int fromfd,int swap)406 Error _dxf_ExRecvMdfPkg(int fromfd, int swap)
407 {
408 int i, len, num;
409 struct moddef *mp;
410 char *argname;
411
412
413 if ((mp = newmod()) == NULL)
414 return ERROR;
415
416 _dxf_ExReceiveBuffer(fromfd, &len, 1, TYPE_INT, swap);
417 if (len > 0) {
418 mp->m_name = DXAllocateZero(len+1);
419 _dxf_ExReceiveBuffer(fromfd, mp->m_name, len, TYPE_UBYTE, swap);
420 }
421 _dxf_ExReceiveBuffer(fromfd, &mp->m_flags, 1, TYPE_INT, swap);
422
423 _dxf_ExReceiveBuffer(fromfd, &num, 1, TYPE_INT, swap);
424 for (i=0; i<num; i++) {
425 _dxf_ExReceiveBuffer(fromfd, &len, 1, TYPE_INT, swap);
426 if (len > 0) {
427 argname = DXAllocateZero(len+1);
428 _dxf_ExReceiveBuffer(fromfd, argname, len, TYPE_UBYTE, swap);
429 addarg(mp, INPUTARG, argname, NULL);
430 }
431 }
432
433 _dxf_ExReceiveBuffer(fromfd, &num, 1, TYPE_INT, swap);
434 for (i=0; i<num; i++) {
435 _dxf_ExReceiveBuffer(fromfd, &len, 1, TYPE_INT, swap);
436 if (len > 0) {
437 argname = DXAllocateZero(len+1);
438 _dxf_ExReceiveBuffer(fromfd, argname, len, TYPE_UBYTE, swap);
439 addarg(mp, OUTPUTARG, argname, NULL);
440 }
441 }
442
443 _dxf_ExReceiveBuffer(fromfd, &len, 1, TYPE_INT, swap);
444 if (len > 0) {
445 mp->m_exec = DXAllocateZero(len+1);
446 _dxf_ExReceiveBuffer(fromfd, mp->m_exec, len, TYPE_UBYTE, swap);
447 }
448
449 _dxf_ExReceiveBuffer(fromfd, &len, 1, TYPE_INT, swap);
450 if (len > 0) {
451 mp->m_host = DXAllocateZero(len+1);
452 _dxf_ExReceiveBuffer(fromfd, mp->m_host, len, TYPE_UBYTE, swap);
453 }
454
455 _dxf_ExReceiveBuffer(fromfd, &mp->m_pflags, 1, TYPE_INT, swap);
456 _dxf_ExReceiveBuffer(fromfd, &len, 1, TYPE_INT, swap);
457 if (len > 0) {
458 mp->m_loadfile = DXAllocateZero(len+1);
459 _dxf_ExReceiveBuffer(fromfd, mp->m_loadfile, len, TYPE_UBYTE, swap);
460 }
461
462
463 if (!callmdf(mp, 0))
464 goto error;
465
466 delmod(mp);
467 return OK;
468
469 error:
470 if (mp)
471 delmod(mp);
472 return ERROR;
473 }
474
475
476
477
478 /*
479 * utility type routines.
480 */
481
482 /* return pointer to start of next line. if flag is set, assume you are
483 * in the middle of a line and always search forward. if flag is zero,
484 * assume you could already be at the start of the line and only space
485 * forward if the line is empty or a comment.
486 */
nextline(char * str,int forward,int * lineno)487 static char *nextline(char *str, int forward, int *lineno)
488 {
489 char *cp = str;
490
491 if (!cp)
492 return NULL;
493
494 again:
495 (*lineno)++;
496
497 if (!forward) {
498 if (*cp != '#' && *cp != '\n' && *cp != '\r')
499 return cp;
500
501 forward = 1;
502 }
503
504 while (*cp != '\0' && *cp != '\n' && *cp != '\r')
505 cp++;
506
507 if (*cp == '\0')
508 return NULL;
509
510 if (*cp == '\n' || *cp == '\r')
511 {
512 while (*cp == '\n' || *cp == '\r')
513 cp ++;
514
515 forward = 0;
516 goto again;
517 }
518
519 if (*cp == '#')
520 goto again;
521
522 return cp;
523 }
524
525
526 /* return a pointer to the next char which matches. this is different
527 * than strindex or strstr because it won't space past a newline.
528 * return NULL if there isn't a match before the next newline or
529 * end of file (actually, end of string).
530 */
find_next(char * str,char find)531 static char *find_next(char *str, char find)
532 {
533 char *cp = str;
534
535 if (cp == NULL)
536 return NULL;
537
538 while (*cp != '\0' && *cp != '\n' && *cp != find)
539 cp++;
540
541 return (*cp == find) ? cp : NULL;
542 }
543
end_of_line(char * str)544 static char *end_of_line(char *str)
545 {
546 return find_next(str, '\n');
547 }
548
549 /*
550 * return start of next whitespace separated token. return NULL if
551 * end-of-line or end-of-string encountered first. if semi is set,
552 * allow semicolons to be considered as whitespace.
553 */
find_next_token(char * str,int semi)554 static char *find_next_token(char *str, int semi)
555 {
556 char *cp = str;
557
558 if (cp == NULL)
559 return NULL;
560
561 /* find whitespace (or semi)
562 */
563 if (semi)
564 while (*cp != '\0' && *cp != '\n' &&
565 *cp != ' ' && *cp != '\t' &&
566 *cp != '\r' && *cp != ';')
567 cp++;
568 else
569 while (*cp != '\0' && *cp != '\n' &&
570 *cp != ' ' && *cp != '\t' &&
571 *cp != '\r')
572 cp++;
573
574 if (*cp == '\r')
575 cp++;
576
577 if (*cp == '\0' || *cp == '\n')
578 return NULL;
579
580 /* now find non-whitespace
581 */
582 if (semi && *cp == ';')
583 cp++;
584
585 while (*cp != '\0' && *cp != '\n' &&
586 *cp != '\r' && (*cp == ' ' || *cp == '\t'))
587 cp++;
588
589 if (*cp == '\r')
590 cp++;
591
592 if (*cp == '\0' || *cp == '\n')
593 return NULL;
594
595 return cp;
596 }
597
598 /* return the end of the current string of chars, delimited by either
599 * end-of-line, end-of-string, whitespace or semicolon.
600 */
find_token_end(char * str)601 static char *find_token_end(char *str)
602 {
603 char *cp = str;
604
605 if (cp == NULL)
606 return NULL;
607
608 while (*cp != '\0' && *cp != '\n' &&
609 *cp != ' ' && *cp != '\t' &&
610 *cp != '\r' && *cp != ';')
611 cp++;
612
613 return cp;
614 }
615
616 /* names have to start with an alpha, and then
617 * contain only alphas or digits
618 */
IsGoodIdentifier(char * name)619 static int IsGoodIdentifier(char *name)
620 {
621 char *cp = name;
622
623 if (!isalpha(*cp++))
624 return FALSE;
625
626 while (*cp) {
627 if (!isalnum(*cp))
628 return FALSE;
629 cp++;
630 }
631
632 return TRUE;
633 }
634
635 /* allocate space for and make a copy of the next string up to the
636 * next ';', ' ' or end of line
637 */
AllocToken(char * str)638 static char *AllocToken(char *str)
639 {
640 char *newbuf;
641 char *strend;
642
643 strend = find_token_end(str);
644
645 newbuf = DXAllocate(strend - str + 1);
646 if (!newbuf)
647 return NULL;
648
649 strncpy(newbuf, str, strend-str);
650 newbuf[strend-str] = '\0';
651
652 return newbuf;
653 }
654
655 /* allocate space for and make a copy of the next string up to the
656 * next '"'
657 */
AllocQuote(char * str)658 static char *AllocQuote(char *str)
659 {
660 char *newbuf;
661 char *strend;
662 char *last;
663
664 last = end_of_line(str);
665 strend = find_next(str, '"');
666 if (!strend || (last && strend > last)) {
667 strend = last;
668 if (!strend) {
669 DXSetError(ERROR_DATA_INVALID,
670 "missing name or mismatched quotes");
671 return NULL;
672 }
673 }
674
675 newbuf = DXAllocate(strend - str + 1);
676 if (!newbuf)
677 return NULL;
678
679 strncpy(newbuf, str, strend-str);
680 newbuf[strend-str] = '\0';
681
682 return newbuf;
683 }
684
685 /* allocate space for and make a copy of the next string up to the
686 * next ';' or end of line, including looking for attributes and squeezing
687 * any intervening spaces from them. (should this be necessary?
688 * why doesn't the exec code handle spaces?)
689 */
AllocVariable(char * str)690 static char *AllocVariable(char *str)
691 {
692 char *newbuf;
693 char *strend;
694 char *cp, *dest;
695
696 strend = find_token_end(str);
697 if (!strend)
698 return NULL;
699
700 cp = strend;
701 while (*cp == ' ')
702 cp++;
703 if(*cp == '[') {
704 strend = strchr(cp, ']');
705 if(!strend)
706 return NULL;
707 strend++;
708 }
709
710 newbuf = DXAllocate(strend - str + 1);
711 if (!newbuf)
712 return NULL;
713
714 for (cp = str, dest = newbuf; cp < strend; cp++)
715 if (!isspace(*cp))
716 *dest++ = *cp;
717
718 *dest = '\0';
719
720 return newbuf;
721 }
722
IDKeyword(char * str)723 static int IDKeyword(char *str)
724 {
725 if (!str || str[0] == '\0')
726 return T_NONE;
727
728 if (!strncmp(str, "MODULE", sizeof("MODULE")-1))
729 return T_MODULE;
730
731 if (!strncmp(str, "CATEGORY", sizeof("CATEGORY")-1))
732 return T_CATEGORY;
733
734 if (!strncmp(str, "DESCRIPTION", sizeof("DESCRIPTION")-1))
735 return T_DESCRIPTION;
736
737 if (!strncmp(str, "INPUT", sizeof("INPUT")-1))
738 return T_INPUT;
739
740 if (!strncmp(str, "REPEAT", sizeof("REPEAT")-1))
741 return T_REPEAT;
742
743 if (!strncmp(str, "OUTPUT", sizeof("OUTPUT")-1))
744 return T_OUTPUT;
745
746 if (!strncmp(str, "OPTIONS", sizeof("OPTIONS")-1))
747 return T_OPTIONS;
748
749 if (!strncmp(str, "FLAGS", sizeof("FLAGS")-1))
750 return T_FLAGS;
751
752 if (!strncmp(str, "OUTBOARD", sizeof("OUTBOARD")-1))
753 return T_OUTBOARD;
754
755 if (!strncmp(str, "LOADABLE", sizeof("LOADABLE")-1))
756 return T_LOADABLE;
757
758 return T_ERROR;
759 }
760
IDFlag(char * str)761 static int IDFlag(char *str)
762 {
763 if (!str || str[0] == '\0')
764 return 0;
765
766 #if 0
767 if (!strncmp(str, "SERIAL", sizeof("SERIAL")-1))
768 return MODULE_SERIAL;
769
770 if (!strncmp(str, "SEQUENCED", sizeof("SEQUENCED")-1))
771 return MODULE_SEQUENCED;
772 #endif
773
774 if (!strncmp(str, "PIN", sizeof("PIN")-1))
775 return MODULE_PIN;
776
777 #if 0
778 if (!strncmp(str, "ASSIGN", sizeof("ASSIGN")-1))
779 return MODULE_ASSIGN;
780 #endif
781
782 if (!strncmp(str, "SIDE_EFFECT", sizeof("SIDE_EFFECT")-1))
783 return MODULE_SIDE_EFFECT;
784
785 if (!strncmp(str, "LOOP", sizeof("LOOP")-1))
786 return MODULE_LOOP;
787
788 #if 0
789 if (!strncmp(str, "JOIN", sizeof("JOIN")-1))
790 return MODULE_JOIN;
791 #endif
792
793 if (!strncmp(str, "ERR_CONT", sizeof("ERR_CONT")-1))
794 return MODULE_ERR_CONT;
795
796 if (!strncmp(str, "REROUTABLE", sizeof("REROUTABLE")-1))
797 return MODULE_REROUTABLE;
798
799 if (!strncmp(str, "REACH", sizeof("REACH")-1))
800 return MODULE_REACH;
801
802 if (!strncmp(str, "OUTBOARD", sizeof("OUTBOARD")-1))
803 return MODULE_OUTBOARD;
804
805 if (!strncmp(str, "PERSISTENT", sizeof("PERSISTENT")-1))
806 return MODULE_PERSISTENT;
807
808 if (!strncmp(str, "ASYNC", sizeof("ASYNC")-1))
809 return MODULE_ASYNC;
810
811 if (!strncmp(str, "ASYNCHRONOUS", sizeof("ASYNCHRONOUS")-1))
812 return MODULE_ASYNC;
813
814 if (!strncmp(str, "ASYNCLOCAL", sizeof("ASYNCLOCAL")-1))
815 return MODULE_ASYNCLOCAL;
816
817 return 0;
818 }
819
820 /*
821 * parse the string into lines, and call DXAddModuleV for each new
822 * module definition.
823 */
ExParseMDF(char * str)824 static Error ExParseMDF(char *str)
825 {
826 int lineno = 0;
827 int modflag;
828 int repcount;
829 int id;
830 int argtype = -1;
831 char *tempc;
832 char *nextc;
833 struct moddef *mp = NULL;
834
835
836 /* start at the first non-comment line in the string */
837 nextc = nextline(str, 0, &lineno);
838
839 while ((id = IDKeyword(nextc)) != T_NONE) {
840 switch (id) {
841 case T_MODULE:
842 /* output previous module definition */
843 if (mp) {
844
845 if (!callmdf(mp, 1))
846 goto error;
847
848 delmod(mp);
849 }
850 /* start new definition */
851 mp = newmod();
852 if (!mp)
853 goto error;
854
855 nextc = find_next_token(nextc, 0);
856 if (!nextc) {
857 DXSetError(ERROR_DATA_INVALID,
858 "missing module name, line %d", lineno);
859 goto error;
860 }
861 mp->m_name = AllocToken(nextc);
862 if (!IsGoodIdentifier(mp->m_name)) {
863 DXSetError(ERROR_DATA_INVALID,
864 "module names must start with a letter and contain "
865 "only letters and numbers, line %d", lineno);
866 goto error;
867 }
868
869 #if 0 /* reload == 0, so that's the default */
870 /* does it already exist? */
871 if ((node *)_dxf_ExMacroSearch (mp->m_name) != NULL)
872 mp->m_pflags |= PF_RELOAD;
873 #endif
874
875 break;
876
877 /* get name only; ignore type, default & description. */
878 case T_INPUT:
879 case T_OUTPUT:
880 nextc = find_next_token(nextc, 1);
881 if (!nextc) {
882 DXSetError(ERROR_DATA_INVALID,
883 "missing %s parameter name, line %d",
884 (id==T_INPUT) ? "input" : "output", lineno);
885 goto error;
886 }
887
888 tempc = AllocVariable(nextc);
889 if (!tempc)
890 goto error;
891
892 if (!addarg(mp, (id==T_INPUT) ? INPUTARG : OUTPUTARG, tempc, NULL))
893 goto error;
894
895 /* save this for later, if handling repeats */
896 argtype = id;
897 break;
898
899 case T_ERROR:
900 /* could this be more helpful? */
901 DXSetError(ERROR_DATA_INVALID,
902 "unrecognized keyword on line %d", lineno);
903 return ERROR;
904
905 case T_OUTBOARD:
906 /* get the exec and host name */
907 tempc = find_next(nextc, '"');
908 if (!tempc) {
909 nextc = find_next_token(nextc, 1);
910 if (!nextc) {
911 DXSetError(ERROR_DATA_INVALID,
912 "missing outboard execution name, line %d",
913 lineno);
914 goto error;
915 }
916 mp->m_exec = AllocToken(nextc);
917 }
918 else
919 mp->m_exec = AllocQuote(++tempc);
920
921 if (!mp->m_exec) {
922 DXSetError(ERROR_DATA_INVALID,
923 "missing outboard execution name, line %d",
924 lineno);
925 goto error;
926 }
927
928 tempc = find_next(nextc, ';');
929 if (tempc) {
930 nextc = tempc;
931 tempc = find_next_token(nextc, 1);
932 if (tempc) {
933 mp->m_host = AllocToken(tempc);
934 nextc = tempc;
935 }
936 }
937
938 mp->m_flags |= MODULE_OUTBOARD;
939 mp->m_pflags |= PF_OUTBOARD;
940 break;
941
942 case T_LOADABLE:
943 /* get the executable filename */
944 tempc = find_next(nextc, '"');
945 if (!tempc) {
946 nextc = find_next_token(nextc, 1);
947 if (!nextc) {
948 DXSetError(ERROR_DATA_INVALID,
949 "missing loadable module filename, line %d",
950 lineno);
951 goto error;
952 }
953 mp->m_loadfile = AllocToken(nextc);
954 }
955 else
956 mp->m_loadfile = AllocQuote(++tempc);
957
958 if (!mp->m_loadfile) {
959 DXSetError(ERROR_DATA_INVALID,
960 "missing loadable module filename, line %d",
961 lineno);
962 goto error;
963 }
964
965 mp->m_pflags |= PF_LOADABLE;
966 break;
967
968 case T_FLAGS:
969 tempc = find_next_token(nextc, 0);
970 while ((modflag = IDFlag(tempc)) != F_NONE) {
971 mp->m_flags |= modflag;
972 nextc = tempc;
973 tempc = find_next_token(tempc, 0);
974 }
975 break;
976
977 case T_REPEAT:
978 nextc = find_next_token(nextc, 0);
979 if (!nextc) {
980 DXSetError(ERROR_DATA_INVALID,
981 "missing repeat count, line %d", lineno);
982 goto error;
983 }
984 repcount = atoi(nextc);
985 if (argtype == T_INPUT) {
986 if (repcount <= 0 || repcount > mp->m_nin) {
987 DXSetError(ERROR_DATA_INVALID,
988 "invalid input repeat count, line %d", lineno);
989 goto error;
990 }
991 if (!argdup(mp, INPUTARG, repcount)) {
992 DXAddMessage("line %d", lineno);
993 goto error;
994 }
995
996 } else if (argtype == T_OUTPUT) {
997 if (repcount <= 0 || repcount > mp->m_nout) {
998 DXSetError(ERROR_DATA_INVALID,
999 "invalid output repeat count, line %d", lineno);
1000 goto error;
1001 }
1002 if (!argdup(mp, OUTPUTARG, repcount)) {
1003 DXAddMessage("line %d", lineno);
1004 goto error;
1005 }
1006
1007 } else {
1008 DXSetError(ERROR_DATA_INVALID,
1009 "misplaced REPEAT line, line %d", lineno);
1010 }
1011 break;
1012
1013 case T_CATEGORY:
1014 case T_DESCRIPTION:
1015 case T_OPTIONS:
1016 /* ignore rest of line */
1017 break;
1018 }
1019
1020 nextc = nextline(nextc, 1, &lineno);
1021 }
1022
1023 /* at end-of-string, finish current definition if there is one */
1024 if (mp) {
1025 if (!callmdf(mp, 1))
1026 goto error;
1027
1028 delmod(mp);
1029 }
1030
1031 return OK;
1032
1033 error:
1034 if (mp)
1035 delmod(mp);
1036
1037 return ERROR;
1038 }
1039
1040 /* if file, read into memory and then parse the same way a string obj
1041 * would be parsed.
1042 */
DXLoadMDFFile(char * filename)1043 Error DXLoadMDFFile(char *filename)
1044 {
1045 int fd;
1046 int len, rlen;
1047 int rc = ERROR;
1048 char *foundname = NULL;
1049 char *cp = NULL;
1050
1051 if (_dxf_fileSearch(filename, &foundname, "mdf", "DXMODULES") == ERROR)
1052 return ERROR;
1053
1054 fd = open(foundname, O_RDONLY);
1055 if (fd < 0) {
1056 DXSetError(ERROR_DATA_INVALID, "cannot open %s as MDF file", foundname);
1057 goto error;
1058 }
1059
1060 len = lseek(fd, 0, 2); /* find length of file */
1061 if (len <= 0) {
1062 DXSetError(ERROR_DATA_INVALID, "error reading from %s", foundname);
1063 goto error;
1064 }
1065 lseek(fd, 0, 0);
1066
1067 cp = (char *)DXAllocate(len+1);
1068 if (!cp)
1069 goto error;
1070
1071 rlen = read(fd, cp, len);
1072 if (rlen != len) {
1073 DXSetError(ERROR_DATA_INVALID, "error reading from %s", foundname);
1074 goto error;
1075 }
1076 cp[len] = '\0';
1077
1078 close (fd);
1079
1080 rc = ExParseMDF(cp);
1081
1082 error:
1083 DXFree((Pointer)cp);
1084 DXFree((Pointer)foundname);
1085 return rc;
1086 }
1087
DXLoadMDFString(char * cp)1088 Error DXLoadMDFString(char *cp)
1089 {
1090 return ExParseMDF(cp);
1091 }
1092
1093