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 
12 /*
13  * Description:
14  * This module defines operations on several basic types:
15  * 1)  The gvar.   This is the executives basic handle for Objects.  It
16  *     gets put in the cache, held on to by Programs, etc.
17  * 2)  The Program.  It is the basic executable unit.  Parse trees are
18  *     turned into a Program, which contains lists of:
19  *     --  All inputs, outputs, and undefined variables
20  *     --  All variables used as either the above or intermediates
21  *     --  All functions (modules) that need execution
22  * Also, it provides the ability to turn a parse tree into a Program.
23  * _dxf_ExGraph is called with a parse tree.  It creates and returns a program
24  * ExGraphTraverse traverses a parse tree, resolving the easy cases
25  * ExGraphExpression handles the expression cases (x-1, ...)
26  * ExGraphCall  handles calls to either Modules or Macros.
27  */
28 
29 #include <dx/dx.h>
30 #include "pmodflags.h"
31 
32 #include "config.h"
33 #include "_macro.h"
34 #include "_variable.h"
35 #include "attribute.h"
36 #include "background.h"
37 #include "cache.h"
38 #include "graph.h"
39 #include "parse.h"
40 #include "utils.h"
41 #include "log.h"
42 #include "packet.h"
43 #include "path.h"
44 #include "context.h"
45 #include "graphIntr.h"
46 #include "obmodule.h"
47 #include "sysvars.h"
48 #include "distp.h"
49 #include "rq.h"
50 #include "function.h"
51 
52 #define DICT_SIZE 64
53 
54 static int graphing_error = FALSE;	/* error while constructing graph */
55 static int subgraph_id = 0;
56 EXDictionary _dxd_exGraphCache = NULL;
57 gfunc *_dxd_exCurrentFunc = NULL;
58 
59 typedef struct indexobj {
60     exo_object obj;
61     int      index;
62 } indexobj;
63 
64 typedef struct progobj {
65     exo_object obj;
66     Program    *p;
67 } progobj;
68 
69 typedef LIST(int) list_int;
70 
71 #ifdef ALLOC_UPFRONT
72 #define MAX_FREED 2
73 static Program *freedProgs[MAX_FREED] = {NULL};
74 #endif
75 
76 #define REINIT_LIST(list) ( (list).nused = 0 )
77 /*
78  * Stack of dictionaries used to resolve variable scope
79  */
80 
81 Group _dxfQueryImportInfo (char *filename);
82 
83 static void ExMakeGfunc(node_function ndfunc, _ntype type, int instance,
84 			_excache excache, node *n, node **inAttrs, Program *p,
85                         int *inArgs, list_int *out, Program *macro);
86 static void ExCopySubP(Program *toP, Program *fromP, int top);
87 static Program *GetNewMacro(Program *p, int *map, int *resolved);
88 static void ExGraphAssignment (Program *p, node *n, int top,
89 			       EXDictionary dict);
90 static void ExGraphTraverse (Program *p, node *n, int top, EXDictionary dict);
91 static void ExGraphCall (Program *p, node *n, int top, list_int *out,
92 			 EXDictionary dict, int *flags);
93 static void ExCreateSendModules (Program *p);
94 static void ExBuildSendModule (Program *p, gfunc *sgf, gfunc *tgf, int srcfn,
95 			       int tgfn, int in_tab, int out_tab, int *outdex);
96 static int GvarDelete (gvar *p);
97 static int progobjDelete (progobj *p);
98 static void ExRemapVars(Program *p, Program *subP, int *map, int *resolved, char *fname, int inst);
99 static void ExFixAsyncVarName(Program *p,
100 			ProgramVariable *pv, char *fname, int instance);
101 
102 static int _dxf_ExPathStringLen( ModPath *path );
103 static void _dxf_ExGFuncPathToStringBuf( gfunc *fnode, char *path_str );
104 static void _dxf_ExGFuncPathToCacheStringBuf( gfunc *fnode, char *path_str );
105 static void _dxf_ExPathSet( Program *p, char fname[], int instance, gfunc *fnode );
106 static void _dxf_ExPathPrepend( Program *p, char fname[], int instance,
107                                 gfunc *fnode );
108 static void _dxf_ExPathAppend( Program *p, char fname[], int instance,
109                                gfunc *fnode );
110 static int _dxf_ExPathCacheStringLen( ModPath *path );
111 
112 static char *_dxf_ExCacheStrPrepend( Program *p, char *name,
113                                int instance, char *path );
114 
m__badfunc(Object * in,Object * out)115 Error m__badfunc(Object *in, Object *out)
116 {
117     DXSetError(ERROR_NOT_IMPLEMENTED, "function does not exist");
118     return ERROR;
119 }
120 
121 static PFIP gvar_methods[] =
122 {
123     GvarDelete
124 };
125 
126 static PFIP progobj_methods[] =
127 {
128     progobjDelete
129 };
130 
ResetSubGraphIds()131 void ResetSubGraphIds()
132 {
133     subgraph_id = 0;
134 }
135 
NextSubGraphId()136 int NextSubGraphId()
137 {
138     int sgid;
139 
140     sgid = ++(subgraph_id);
141     return (sgid);
142 }
143 
144 
145 /*
146  * Initialize the code which constructs graphs from parse trees
147  */
148 void
_dxf_ExGraphInit(void)149 _dxf_ExGraphInit (void)
150 {
151     ExDebug("*1","In _dxf_ExGraphInit");
152     _dxd_exCurrentFunc = NULL;
153     graphing_error = FALSE;
154     _dxf_ExMacroRecursionInit ();
155     if (_dxd_exGraphCache == NULL)
156 	_dxd_exGraphCache = _dxf_ExDictionaryCreate (32, TRUE, FALSE);
157 }
158 
159 int
DXGetModulePathLen()160 DXGetModulePathLen()
161 {
162     return _dxf_ExPathStringLen( &_dxd_exCurrentFunc->mod_path );
163 }
164 
165 int
DXGetModulePath(char * path)166 DXGetModulePath(char *path)
167 {
168     _dxf_ExGFuncPathToStringBuf( _dxd_exCurrentFunc, path );
169     return(OK);
170 }
171 
172 int
DXGetModuleCacheStrLen()173 DXGetModuleCacheStrLen()
174 {
175     return _dxf_ExPathCacheStringLen( &_dxd_exCurrentFunc->mod_path );
176 }
177 
178 int
DXGetModuleCacheStr(char * path)179 DXGetModuleCacheStr(char *path)
180 {
181     _dxf_ExGFuncPathToCacheStringBuf( _dxd_exCurrentFunc, path );
182      return(OK);
183 }
184 
185 
186 
187 int
_dxf_ExGetCurrentInstance()188 _dxf_ExGetCurrentInstance()
189 {
190     return(_dxd_exCurrentFunc->instance);
191 }
192 
193 
194 /*
195  * Create a new gvar node.  These nodes represent the interconnections
196  * between the gfunc nodes which are the executable nodes.  They are used
197  * as place holders to allow an indirect access to the data.
198  */
CreateIndex(int ind)199 static indexobj *CreateIndex (int ind)
200 {
201     indexobj	*n;
202 
203     n = (indexobj *) _dxf_EXO_create_object_local (EXO_CLASS_TASK,
204 				    sizeof (indexobj),
205 				    NULL);
206     n->index = ind;
207     return (n);
208 }
209 
210 /*
211  * Create a new gvar node.  These nodes represent the interconnections
212  * between the gfunc nodes which are the executable nodes.  They are used
213  * as place holders to allow an indirect access to the data.
214  */
CreateProgobj(Program * p)215 static progobj *CreateProgobj (Program *p)
216 {
217     progobj	*n;
218 
219     n = (progobj *) _dxf_EXO_create_object_local (EXO_CLASS_TASK,
220 				    sizeof (progobj),
221 				    progobj_methods);
222     n->p = p;
223     return (n);
224 }
225 /*
226  * Create a new gvar node.  These nodes represent the interconnections
227  * between the gfunc nodes which are the executable nodes.  They are used
228  * as place holders to allow an indirect access to the data.
229  */
_dxf_ExCreateGvar(_gvtype type)230 gvar *_dxf_ExCreateGvar (_gvtype type)
231 {
232     gvar	*n;
233 
234     n = (gvar *) _dxf_EXO_create_object (EXO_CLASS_GVAR,
235 				    sizeof (gvar),
236 				    gvar_methods);
237     n->type = type;
238 
239     return (n);
240 }
241 
242 /*
243  * procId == 0		OK to delete, created somewhere, all global
244  * procId != pin proc	OK to delete, created somewhere and must
245  *				be all global since can't guarantee where
246  *				it will be run.
247  * procId == exJID		OK to delete, created here
248  * 1 processor		OK to delete, created here
249  */
250 
251 static void
DeleteGvarObj(gvar * var)252 DeleteGvarObj(gvar *var)
253 {
254     int		procId;
255     Object	obj = var->obj;
256 
257     if (obj != NULL)
258     {
259 	procId = var->procId;
260 	if (var->type != GV_CACHE	||
261 	    procId == 0			||
262 	    procId != EX_PIN_PROC	||
263 	    procId == exJID		||
264 	    DXProcessors (0) == 1)
265 	    DXDelete (obj);
266 	else
267 	{
268 #if 0
269     /*
270      * $$$$$ THIS IS A TEMPORARY SOLUTION BELOW, THE CORRECT IS DESCRIBED
271      * $$$$$ What we really need is to augment the ExReclaimDisable function
272      * $$$$$ so that it loops on a DXtry_lock, which if it doesn't get causes
273      * $$$$$ it to look for high priority jobs destined for its JID since
274      * $$$$$ they may be deletes issued from within some other invocation
275      * $$$$$ of the memory reclaimer that MUST run on that processor
276      * $$$$$ before the world, e.g. the running reclaimer, can really
277      * $$$$$ continue.
278      */
279 	    _dxf_ExRunOn (procId, DXDelete, (Pointer) obj, 0);
280 #endif
281 	    _dxf_ExRQEnqueue (DXDelete, (Pointer) obj, 1, 0, procId, TRUE);
282 	}
283     }
284 }
285 
286 
287 /*
288  * Defines a gvar to have a value.
289  */
290 void
_dxf_ExDefineGvar(gvar * gv,Object o)291 _dxf_ExDefineGvar (gvar *gv, Object o)
292 {
293     DXReference (o);
294 
295     if (gv->obj && gv->type != GV_UNRESOLVED)
296 	DeleteGvarObj(gv);
297 
298     gv->obj = o;
299     if (gv->type == GV_UNRESOLVED)
300 	gv->type = GV_DEFINED;
301 }
302 
303 /*
304  * Makes the gvar unresolved and deletes previous object
305  * leaves the reference counts alone.
306  */
307 void
_dxf_ExUndefineGvar(gvar * gv)308 _dxf_ExUndefineGvar (gvar *gv)
309 {
310     if (gv->obj && gv->type != GV_UNRESOLVED)
311 	DeleteGvarObj(gv);
312 
313     gv->obj = NULL;
314     gv->skip = GV_DONTSKIP;
315     gv->type = GV_UNRESOLVED;
316     gv->reccrc = 0;
317     gv->cost = 0;
318     gv->disable_cache = 0;
319     gv->procId = 0;
320 }
321 
322 /*
323  * DXDelete a gvar
324  */
325 static int
GvarDelete(gvar * var)326 GvarDelete (gvar *var)
327 {
328 #if OLD_DEBUG
329     ExDebug ("*6", "DELETING:  [%08x] with cache tag 0x%08x", var, var->reccrc);
330 #endif
331 
332     if (var->oneshot)
333     {
334 	DXDelete(var->oneshot);
335 	var->oneshot = NULL;
336     }
337     DeleteGvarObj(var);
338 
339 #if OLD_DEBUG
340     ExDebug ("*6", "DELETED:   [%08x]", var);
341 #endif
342     return (OK);
343 }
344 
345 static int
progobjDelete(progobj * var)346 progobjDelete (progobj *var)
347 {
348     _dxf_ExGraphDelete (var->p);
349 
350     return (OK);
351 }
352 
353 /*
354  * Create and initialize a new gfunc node.  These nodes represent the
355  * executable entities of the graph.
356  */
_dxf_ExInitGfunc(gfunc * n)357 gfunc *_dxf_ExInitGfunc (gfunc *n)
358 {
359     bzero (n, sizeof (gfunc));
360 
361     n->required = -1;
362     INIT_LIST(n->inputs);
363     INIT_LIST(n->outputs);
364     INIT_LIST(n->reroute);
365     INIT_LIST(n->cache_ddi);
366     return (n);
367 }
368 
369 #if 0
370 /*
371  * Delete a gfunc node and remove it from the enclosing graph
372  */
373 static int
374 exGfuncFree (gfunc *p)
375 {
376     char        s[100];
377     strcpy (s, ">GfDel ");
378     strcat (s, p->name);
379 
380     ExDebug ("*1", "DELETING:  [%08x] %d::%s", p, p->cpath);
381 
382     FREE_LIST(p->inputs);
383     FREE_LIST(p->outputs);
384     FREE_LIST(p->attrs);
385     DXFree(p->name);
386     DXDelete((Object)p->path);
387     ExDebug ("*1", "DELETED:   [%08x] <gone>", p);
388 
389     return (OK);
390 }
391 #endif
392 
InitProgram(Program * p)393 static void InitProgram(Program *p)
394 {
395     p->runable = 0;
396     p->deleted = FALSE;
397     p->loopctl.first = TRUE;
398     p->loopctl.done = TRUE;
399     p->loopctl.counter = 0;
400     p->loopctl.isdoneset = 0;
401     p->returnP = NULL;
402 }
403 
404 static Program *
AllocateProgram(void)405 AllocateProgram(void)
406 {
407     Program *p = NULL;
408 
409 #ifdef ALLOC_UPFRONT
410     int i;
411     for (i = 0; i < MAX_FREED; ++i)
412     {
413         if (freedProgs[i] != NULL)
414         {
415 	    p = freedProgs[i];
416 	    freedProgs[i] = NULL;
417 	    return (p);
418 	 }
419     }
420 #endif
421 
422     p = (Program*)DXAllocateZero (sizeof (Program));
423     if (p == NULL)
424 	return (NULL);
425 
426 #if ALLOC_UPFRONT
427     p->local = FALSE;
428 #endif
429     INIT_LIST (p->inputs);
430     INIT_LIST (p->outputs);
431     INIT_LIST (p->undefineds);
432     INIT_LIST (p->wiredvars);
433     INIT_LIST (p->macros);
434     INIT_LIST (p->async_vars);
435     INIT_LIST (p->vars);
436     INIT_LIST (p->funcs);
437     INIT_LIST (p->foreach_id);
438 
439     InitProgram(p);
440 
441     return (p);
442 }
443 
444 static Program *
AllocateProgramLocal(void)445 AllocateProgramLocal(void)
446 {
447     Program *p = NULL;
448     p = (Program*)DXAllocateLocalZero (sizeof (Program));
449     if (p == NULL)
450 	return (NULL);
451 
452 #if ALLOC_UPFRONT
453     p->local = TRUE;
454 #endif
455     if (INIT_LIST_LOCAL (ProgramRef, p->inputs) == NULL)
456 	return (NULL);
457     if (INIT_LIST_LOCAL (ProgramRef, p->outputs) == NULL)
458 	return (NULL);
459     if (INIT_LIST_LOCAL (ProgramRef, p->undefineds) == NULL)
460 	return (NULL);
461     if (INIT_LIST_LOCAL (int, p->wiredvars) == NULL)
462 	return (NULL);
463     if (INIT_LIST_LOCAL (MacroRef, p->macros) == NULL)
464 	return (NULL);
465     if (INIT_LIST_LOCAL (AsyncVars, p->async_vars) == NULL)
466 	return (NULL);
467     if (INIT_LIST_LOCAL (ProgramVariable, p->vars) == NULL)
468 	return (NULL);
469     if (INIT_LIST_LOCAL (gfunc, p->funcs) == NULL)
470 	return (NULL);
471     if (INIT_LIST_LOCAL (char *, p->foreach_id) == NULL)
472 	return (NULL);
473 
474     InitProgram(p);
475 
476     return (p);
477 }
478 
479 void
ExSubGraphDelete(Program * subp,int top)480 ExSubGraphDelete(Program *subp, int top)
481 {
482     gfunc *gf;
483     ProgramRef *pr;
484     int i, j, limit, jlimit;
485 
486     for (i = 0, limit = SIZE_LIST(subp->funcs); i < limit; ++i)
487     {
488 	gf = FETCH_LIST(subp->funcs, i);
489         if(gf->ftype == F_MACRO)
490 	    DXFree(gf->name);
491 	FREE_LIST(gf->inputs);
492 	FREE_LIST(gf->outputs);
493         FREE_LIST(gf->cache_ddi);
494         FREE_LIST(gf->reroute);
495         if((gf->ftype == F_MACRO) && gf->func.subP) {
496             jlimit = SIZE_LIST(gf->func.subP->undefineds);
497             for (j = 0; j < jlimit; ++j) {
498 	        pr = FETCH_LIST(gf->func.subP->undefineds, j);
499 	        DXFree(pr->name);
500 	        pr->name = NULL;
501             }
502             ExSubGraphDelete(gf->func.subP, top+1);
503 	    FREE_LIST(gf->func.subP->funcs);
504 	    FREE_LIST(gf->func.subP->undefineds);
505 	    FREE_LIST(gf->func.subP->wiredvars);
506             FREE_LIST(gf->func.subP->async_vars);
507 	    DXFree((Pointer)gf->func.subP);
508         }
509     }
510 }
511 
512 void
_dxf_ExGraphDelete(Program * p)513 _dxf_ExGraphDelete(Program *p)
514 {
515     ProgramVariable *pv;
516     ProgramRef *pr;
517     MacroRef *mr;
518     int i;
519     int limit;
520 
521 #ifdef ALLOC_UPFRONT
522     int delete;
523 #endif
524 
525     if (p == NULL)
526 	return;
527 
528     ExDebug("3", "In ExGraphDelete");
529     if (p == _dxd_exContext->program) {
530 	_dxd_exContext->program = NULL;
531         if(_dxd_exContext->subp) {
532             DXFree(_dxd_exContext->subp);
533             _dxd_exContext->subp = NULL;
534         }
535     }
536 
537     p->error = FALSE;
538 
539     for (i = 0, limit = SIZE_LIST(p->inputs); i < limit; ++i)
540     {
541 	pr = FETCH_LIST(p->inputs, i);
542 	DXFree(pr->name);
543 	pr->name = NULL;
544     }
545     for (i = 0, limit = SIZE_LIST(p->outputs); i < limit; ++i)
546     {
547 	pr = FETCH_LIST(p->outputs, i);
548 	DXFree(pr->name);
549 	pr->name = NULL;
550     }
551     for (i = 0, limit = SIZE_LIST(p->undefineds); i < limit; ++i)
552     {
553 	pr = FETCH_LIST(p->undefineds, i);
554 	DXFree(pr->name);
555 	pr->name = NULL;
556     }
557     for (i = 0, limit = SIZE_LIST(p->macros); i < limit; ++i)
558     {
559 	mr = FETCH_LIST(p->macros, i);
560 	DXFree(mr->name);
561 	mr->name = NULL;
562     }
563     for (i = 0, limit = SIZE_LIST(p->vars); i < limit; ++i)
564     {
565 	pv = FETCH_LIST(p->vars, i);
566 	if (pv->defined)
567 	    DXDelete(pv->obj);
568 	DXDelete(pv->dflt);
569 	pv->defined = FALSE;
570 	pv->obj = NULL;
571 
572 #ifdef CPV_DEBUG
573 if (pv->refs > 0 && pv->refs > pv->gv->object.refs)
574     printf("wierd during graph cleanup\n");
575 #endif
576 
577 	for (;pv->refs > 0; --pv->refs)
578 	    ExDelete(pv->gv);
579         FREE_LIST(pv->cts);
580 
581 	/* The execution code covers the following deletion
582 	 * 	ExDelete((FETCH_LIST(p->vars, i))->gv);
583 	 */
584     }
585 
586 #ifdef ALLOC_UPFRONT
587     delete = TRUE;
588     for (i = 0; !p->local && i < MAX_FREED; ++i)
589     {
590 	if (freedProgs[i] == NULL)
591 	{
592 	    freedProgs[i] = p;
593 	    delete = FALSE;
594 	    break;
595 	}
596     }
597 
598     if (delete)
599     {
600 #endif
601 	FREE_LIST(p->inputs);
602 	FREE_LIST(p->outputs);
603 	FREE_LIST(p->undefineds);
604 	FREE_LIST(p->wiredvars);
605 	FREE_LIST(p->macros);
606 	FREE_LIST(p->async_vars);
607 	FREE_LIST(p->vars);
608 	FREE_LIST(p->foreach_id);
609 #ifdef ALLOC_UPFRONT
610     }
611     else
612     {
613 	REINIT_LIST(p->inputs);
614 	REINIT_LIST(p->outputs);
615 	REINIT_LIST(p->undefineds);
616 	REINIT_LIST(p->wiredvars);
617 	REINIT_LIST(p->macros);
618 	REINIT_LIST(p->async_vars);
619 	REINIT_LIST(p->vars);
620 	REINIT_LIST(p->foreach_id);
621     }
622 #endif
623 
624     if(SIZE_LIST(p->funcs) > 0)
625         ExSubGraphDelete(p, 0);
626 
627 #ifdef ALLOC_UPFRONT
628     if (delete)
629     {
630 #endif
631 	FREE_LIST(p->funcs);
632 	DXFree((Pointer)p);
633 #ifdef ALLOC_UPFRONT
634     }
635     else
636     {
637 	REINIT_LIST(p->funcs);
638     }
639 #endif
640 }
641 
642 int
_dxf_ExGraphCompact(void)643 _dxf_ExGraphCompact (void)
644 {
645     if (exJID == 1 && _dxd_exGraphCache != NULL)
646     {
647 	if (_dxf_ExDictionaryPurge(_dxd_exGraphCache))
648 	    return (_dxf_ExDictionaryCompact(_dxd_exGraphCache));
649     }
650     return (FALSE);
651 
652 }
653 
654 /*
655  * Construct a graph from a parse tree.  The graph consists of 'gfunc' and
656  * 'gvar' nodes.  The 'gfunc' nodes represent the executable modules in the
657  * graph.  The 'gvar' nodes represent the connections between the executable
658  * nodes.
659  */
_dxf_ExGraph(node * n)660 Program *_dxf_ExGraph (node *n)
661 {
662     Program *p;
663     EXDictionary dict;
664 
665     ExMarkTime(0x10, ">_graph");
666     if (n == NULL)
667     {
668 	ExMarkTime(0x10, "<_graph");
669 	return (NULL);
670     }
671     p = AllocateProgram();
672     p->graphId = _dxf_NextGraphId();
673     ResetSubGraphIds();
674 
675     dict = _dxf_ExDictionaryCreate (DICT_SIZE, TRUE, FALSE);
676     ExGraphTraverse(p, n, 0, dict);
677 
678     _dxf_ExDictionaryDestroy (dict);
679 
680     if (graphing_error ||
681 	(SIZE_LIST(p->funcs) == 0 &&
682 	 SIZE_LIST(p->outputs) == 0))
683     {
684 	_dxf_ExGraphDelete(p);
685 	p = NULL;
686     }
687 
688     if (p != NULL && SIZE_LIST(p->outputs) != 0)
689 	_dxf_ExBackgroundChange();
690 
691     ExMarkTime(0x10, "<_graph");
692     return (p);
693 }
694 
695 /*
696  * Recursively traverse the parse tree and construct an equivalent
697  * graph structure which is more easily executed
698  */
ExGraphTraverse(Program * p,node * n,int top,EXDictionary dict)699 static void ExGraphTraverse (Program *p, node *n, int top, EXDictionary dict)
700 {
701     int		nout;
702     char	*name;
703     char	*is_are;
704     list_int	out;
705     int         flags;
706 
707     if (graphing_error)
708 	return;
709 
710     for (; n; n = n->next)
711     {
712 	switch (n->type)
713 	{
714 	    case NT_MACRO:				/* macro definition */
715 		_dxf_ExDictionaryPurge (_dxd_exGraphCache);
716 		_dxf_ExMacroInsert (n->v.macro.id->v.id.id, (EXObj) n);
717 		_dxf_ExBackgroundRedo();
718 		break;
719 
720 	    case NT_CALL:				/* function call */
721 		INIT_LIST(out);
722 		ExGraphCall (p, n, top, &out, dict, &flags);
723 		nout = SIZE_LIST(out);
724 		FREE_LIST(out);
725 		if ((nout != 0) && !(flags & MODULE_SIDE_EFFECT))
726 		{
727 		    name   = n->v.call.id->v.id.id;
728 		    is_are = (nout == 1) ? "value is" : "values are";
729 		    DXWarning ("#4730", is_are, name);
730 		}
731 
732 		break;
733 
734 	    case NT_ASSIGNMENT:			/* assignment statement */
735 		ExGraphAssignment (p, n, top, dict);
736 		break;
737 
738 	    case NT_PACKET:				/* packet command */
739 		_dxd_exContext->graphId = p->graphId = n->v.packet.number;
740 		switch (n->v.packet.type)
741 		{
742 		    case PK_INTERRUPT:
743 			break;
744 
745 		    case PK_SYSTEM:
746 		    case PK_MACRO:
747 		    case PK_FOREGROUND:
748 		    case PK_BACKGROUND:
749 			ExGraphTraverse (p, n->v.packet.packet, top, dict);
750 
751 		    case PK_LINQ:
752 		    case PK_SINQ:
753 		    case PK_VINQ:
754 			break;
755 
756 		    case PK_IMPORT:
757 		    {
758 			Group	info;
759 			int		i;
760 			int		len;
761 			String	string;
762 			char	*buffer;
763 			char	*p;
764 
765 			info = _dxfQueryImportInfo (n->v.packet.packet->v.data.data);
766 			if (info)
767 			{
768 			    DXReference ((Object) info);
769 			    len = 0;
770 			    for (i = 0; ; i++)
771 			    {
772 				string =
773 				    (String) DXGetEnumeratedMember (info, i, NULL);
774 				if (string == NULL)
775 				    break;
776 				len += strlen (DXGetString (string));
777 			    }
778 			    buffer = (char *) DXAllocateLocal (len + 1);
779 			    if (buffer == NULL)
780 			    {
781 				DXWarning ("#4740");
782 				return;
783 			    }
784 			    buffer[0] = '\0';
785 			    for (i = 0, p = buffer; ; i++)
786 			    {
787 				string =
788 				    (String) DXGetEnumeratedMember (info, i, NULL);
789 				if (string == NULL)
790 				    break;
791 
792 				strcat (p, DXGetString (string));
793 				p += strlen (p);
794 			    }
795 			    _dxf_ExSPack (PACK_IMPORTINFO, n->v.packet.number,
796 				  buffer, strlen (buffer));
797 			    DXFree ((Pointer) buffer);
798 			    DXDelete ((Object) info);
799 			}
800 			else
801 			{
802 			    _dxf_ExSPack (PACK_IMPORTINFO, n->v.packet.number, NULL, 0);
803 			}
804 			break;
805 		    }
806 		    default:
807 		        break;
808 		}
809 		break;
810 
811 	    default:
812 		DXWarning ("#4750", n->type);
813 		break;
814 	}
815     }
816 }
817 
ExParseExprLeaves(node * n,int loc,char * opstr,node * args)818 static int ExParseExprLeaves (node *n, int loc, char *opstr, node *args)
819 {
820     char	*id;
821     _op		op;
822     int		unary;
823     char	buf[64];
824 
825     if (n == NULL)
826 	return (loc);
827 
828     if (n->type != NT_LOGICAL && n->type != NT_ARITHMETIC)
829     {
830 	sprintf (buf, "$%d", loc);
831 	strcat (opstr, buf);
832 	args[loc].v.arg.val = n;
833 	return (loc + 1);
834     }
835 
836     op = n->v.expr.op;
837     unary = (op == AO_NEGATE || op == LO_NOT);
838 
839     strcat (opstr, "(");
840 
841     /*
842      * If we have a unary op it stores its single argument in the lhs rather
843      * than the rhs of the expression parse node.  This gives rise to the
844      * unary check here and below.
845      */
846 
847     if (! unary)
848 	loc = ExParseExprLeaves (n->v.expr.lhs, loc, opstr, args);
849 
850     switch (op)
851     {
852 	case LO_LT:	id = " < " ;	break;
853 	case LO_GT:	id = " > " ;	break;
854 	case LO_LEQ:	id = " <= ";	break;
855 	case LO_GEQ:	id = " >= ";	break;
856 	case LO_EQ:	id = " == ";	break;
857 	case LO_NEQ:	id = " != ";	break;
858 	case LO_AND:	id = " && ";	break;
859 	case LO_OR:	id = " || ";	break;
860 	case LO_NOT:	id = " ! " ;	break;
861 	case AO_EXP:	id = " ^ " ;	break;
862 	case AO_TIMES:	id = " * " ;	break;
863 	case AO_DIV:	id = " / " ;	break;
864 	case AO_IDIV:	id = " / " ;	break;
865 	case AO_MOD:	id = " % " ;	break;
866 	case AO_PLUS:	id = " + " ;	break;
867 	case AO_MINUS:	id = " - " ;	break;
868 	case AO_NEGATE:	id = " - " ;	break;
869 	default:	id = " ?? ";	break;
870     }
871     strcat (opstr, id);
872 
873     loc = ExParseExprLeaves (unary ? n->v.expr.lhs : n->v.expr.rhs,
874 			     loc, opstr, args);
875     strcat (opstr, ")");
876 
877     return (loc);
878 }
879 
880 
ExCountExprLeaves(node * n,int cnt)881 static int ExCountExprLeaves (node *n, int cnt)
882 {
883     _op		op;
884     int		unary;
885 
886     if (n == NULL)
887 	return (cnt);
888 
889     if (n->type != NT_LOGICAL && n->type != NT_ARITHMETIC)
890 	return (cnt + 1);
891 
892     op = n->v.expr.op;
893     unary = (op == AO_NEGATE || op == LO_NOT);
894 
895     if (! unary)
896 	cnt = ExCountExprLeaves (n->v.expr.lhs, cnt);
897 
898     cnt = ExCountExprLeaves (unary ? n->v.expr.lhs : n->v.expr.rhs, cnt);
899     return (cnt);
900 }
901 
902 
903 /*
904  * Convert a parse tree expression into the a call to Compute
905  */
906 
ExGraphExpression(Program * p,node * n,int top,list_int * out,EXDictionary dict)907 static void ExGraphExpression (Program *p, node *n, int top, list_int *out, EXDictionary dict)
908 {
909     int		cnt;
910     int		size;
911     char	*opstr	= NULL;
912     node	*nodes	= NULL;
913     node	*name;
914     node	*func;
915     node	*cons;
916     node	*args;
917     int		i, flags;
918 
919     cnt = ExCountExprLeaves (n, 0);
920 
921     /*
922      * We're assuming a varargs Compute here by allocating as many arg blocks
923      * as there are parameters.
924      * We allocate 4 extra, 1 for the name, 1 for the function call, 1 for
925      * the constant to hold the format string and 1 for the format string
926      * argument itself.
927      */
928 
929     if (cnt > 16)
930     {
931 	graphing_error = TRUE;
932 	DXWarning ("#4760");
933 	return;
934     }
935 
936     /*
937      * $$$$$
938      * $$$$$ Until the assumption is true we will have to check for > 16 args,
939      * $$$$$ hence the test above.
940      * $$$$$
941      */
942 
943     size  = (cnt + 4) * sizeof (node);
944     nodes = (node *) DXAllocateLocal (size);
945     if (nodes == NULL)
946 	goto error;
947     memset (nodes, 0, size);
948 
949     /*
950      * We'll be conservative and use 16 although each leaf of the expression
951      * probably won't add more than 6 characters to the operation description
952      * string.
953      */
954 
955     size  = cnt * 16;
956     opstr = (char *) DXAllocateLocal (size);
957     if (opstr == NULL)
958 	goto error;
959     memset (opstr, 0, size);
960 
961     /*
962      * Now we dummy up the parse tree nodes that we need to construct a
963      * call to Compute.
964      */
965 
966     name = nodes;
967     func = nodes + 1;
968     cons = nodes + 2;
969     args = nodes + 3;
970 
971     name->type		 = NT_ID;
972     name->v.id.id	 = "Compute";
973 
974     func->type		 = NT_CALL;
975     func->v.call.id	 = name;
976     func->v.call.arg	 = args;
977 
978     cons->type		 = NT_CONSTANT;
979     /* value filled in below */
980 
981     args[0].v.arg.val	 = cons;
982 
983     for (i = 0; i <= cnt; i++)
984     {
985 	args[i].type	= NT_ARGUMENT;
986 	args[i].next	= &args[i+1];
987 	args[i].prev	= &args[i-1];
988     }
989     args[0  ].prev 	= NULL;
990     args[cnt].next	= NULL;
991 
992     /*
993      * We reserve arg0 for the format string thus we must step forward by one.
994      */
995 
996     ExParseExprLeaves (n, 0, opstr, args + 1);
997 
998     cons->v.constant.obj = (Array)DXNewString(opstr);
999     if (!cons->v.constant.obj)
1000 	goto error;
1001 
1002     ExGraphCall (p, func, top, out, dict, &flags);
1003     DXFree ((Pointer) nodes);
1004     DXFree ((Pointer) opstr);
1005     return;
1006 
1007 error:
1008     _dxf_ExDie ("ExGraphExpression:  can't allocate memory");
1009     return;
1010 }
1011 
1012 
1013 /*
1014  * Convert a parse tree assignment into the proper graph structure.
1015  * Insert the assigned variables into the current dictionary.
1016  */
1017 static void
ExGraphAssignment(Program * p,node * n,int top,EXDictionary dict)1018 ExGraphAssignment (Program *p, node *n, int top, EXDictionary dict)
1019 {
1020     node	*lhs, *rhs;
1021     node	*function;
1022     int		rvals[64];
1023     int		i;
1024     _excache    excache;
1025     int         attr_flag;
1026     int         nout, flags;
1027 
1028     ProgramRef  r;
1029     ProgramVariable pv;
1030     ProgramVariable *ppv;
1031     indexobj	*ind;
1032     list_int	out;
1033 
1034     if (graphing_error)
1035 	return;
1036 
1037     INIT_LIST(out);
1038 
1039     /* Insert all outputs in either output list (if at top), or
1040      * local list.
1041      */
1042     for (i = 0, rhs = n->v.assign.rval;
1043 	 rhs && i < 64;
1044 	 ++i, rhs = rhs->next)
1045     {
1046 	switch (rhs->type)
1047 	{
1048 	case NT_CONSTANT:
1049 	    /* Create a variable and stick its index in rvals */
1050 	    INIT_PVAR(pv);
1051 	    pv.obj = DXReference ((Object) rhs->v.constant.obj);
1052 	    pv.defined = TRUE;
1053 	    APPEND_LIST (ProgramVariable, p->vars, pv);
1054 	    rvals[i] = SIZE_LIST (p->vars) - 1;
1055 	    break;
1056 
1057 	case NT_ID:
1058 	    /* Look up a variable and stick its index in rvals,
1059 	     * if it isn't found, stick a note in the "undefineds"
1060 	     */
1061 	    ind = (indexobj *)_dxf_ExVariableSearch (rhs->v.id.id, dict);
1062 	    if (ind == NULL)
1063 	    {
1064 		r.name = _dxf_ExCopyString/*Local*/ (rhs->v.id.id);
1065 		rvals[i] = r.index = SIZE_LIST (p->vars);
1066 		APPEND_LIST (ProgramRef, p->undefineds, r);
1067 		INIT_PVAR(pv);
1068 		APPEND_LIST (ProgramVariable, p->vars, pv);
1069 	    }
1070 	    else
1071 	    {
1072 		rvals[i] = ind->index;
1073 		ExDelete(ind);
1074 	    }
1075 	    break;
1076 
1077 	case NT_LOGICAL:
1078 	case NT_ARITHMETIC:
1079 	    /* Create a variable and stick its index in rvals.
1080 	     * Make up a (or set of) Compute operation(s), and stick
1081 	     * them in the list.
1082 	     */
1083 	    ExGraphExpression (p, rhs, top, &out, dict);
1084 	    if (graphing_error)
1085 		return;
1086 	    break;
1087 
1088 	case NT_CALL:
1089 	    function = n->v.assign.rval;
1090 	    ExGraphCall (p, function, top, &out, dict, &flags);
1091 	    if (graphing_error)
1092 		return;
1093             nout = SIZE_LIST(out);
1094             if (nout == 0)
1095                 DXWarning ("#4732", function->v.function.id->v.id.id);
1096 	    break;
1097 
1098 	default:
1099 	    DXWarning ("#4770");
1100 	    break;
1101 	}
1102     }
1103 
1104     /* Loop through the left hand sides, and set up the assignments
1105      */
1106     for (i = 0, lhs = n->v.assign.lval, rhs = n->v.assign.rval;
1107 	 lhs && i < 64;
1108 	 ++i, lhs = lhs->next)
1109     {
1110 	if (_dxf_ExHasIntegerAttribute (lhs->attr, ATTR_CACHE, (int *)&excache))
1111 	    attr_flag = TRUE;
1112 	else
1113         {
1114 	    excache = CACHE_ALL;
1115 	    attr_flag = FALSE;
1116 	}
1117 
1118 	/* If there is no rhs, make a null one */
1119 	if (rhs == NULL)
1120 	{
1121 	    /* Create a variable and stick its index in rvals */
1122 	    INIT_PVAR(pv);
1123 	    pv.obj = NULL;
1124 	    pv.defined = TRUE;
1125             pv.excache = excache;
1126             pv.cacheattr = attr_flag;
1127 	    APPEND_LIST (ProgramVariable, p->vars, pv);
1128 	    rvals[i] = SIZE_LIST (p->vars) - 1;
1129 	}
1130 	/* If the rhs is a module, */
1131 	else if (rhs->type == NT_CALL ||
1132 		 rhs->type == NT_LOGICAL ||
1133 		 rhs->type == NT_ARITHMETIC)
1134 	{
1135 	    /* if the module defines this output */
1136 	    if (i < SIZE_LIST(out))
1137 	    {
1138 		/* Create a variable and stick its index in rvals */
1139 		INIT_PVAR(pv);
1140                 pv.excache = excache;
1141                 pv.cacheattr = attr_flag;
1142 		APPEND_LIST (int, p->wiredvars, SIZE_LIST(p->vars));
1143 		APPEND_LIST (ProgramVariable, p->vars, pv);
1144 		rvals[i] = *FETCH_LIST(out, i);
1145                 ppv = FETCH_LIST(p->vars, rvals[i]);
1146                 ppv->excache = excache;
1147                 ppv->cacheattr = attr_flag;
1148 	    }
1149 	    /* if the module doesn't define this output (x,y,z = Compute...) */
1150 	    else
1151 	    {
1152 		/* Create a variable and stick its index in rvals */
1153 		INIT_PVAR(pv);
1154 		pv.obj = NULL;
1155 		pv.defined = TRUE;
1156                 pv.excache = excache;
1157                 pv.cacheattr = attr_flag;
1158 		APPEND_LIST (ProgramVariable, p->vars, pv);
1159 		rvals[i] = SIZE_LIST (p->vars) - 1;
1160 		rhs = NULL;
1161 	    }
1162 	}
1163 	/* Else we've got a simple assignment */
1164 	else
1165 	{
1166 	    rhs = rhs->next;
1167 	}
1168 
1169 	ind = CreateIndex(rvals[i]);
1170         /* Check to see if variable name is NULL, if we don't check here
1171          * we will get two warnings about NULL assignment, one now and
1172          * one later when the actual variable assignment happens.
1173 	 */
1174         if (strcmp (lhs->v.id.id, "NULL"))
1175             _dxf_ExVariableInsert (lhs->v.id.id, dict, (EXO_Object) ind);
1176 	if (top == 0)
1177 	{
1178 	    r.index = rvals[i];
1179 	    r.name = _dxf_ExCopyString/*Local*/(lhs->v.id.id);
1180 	    r.oneshot =
1181 		DXReference (_dxf_ExGetAttribute (lhs->attr, ATTR_ONESHOT));
1182 	    APPEND_LIST (ProgramRef, p->outputs, r);
1183 	}
1184     }
1185     if (SIZE_LIST(out) > 0)
1186 	FREE_LIST(out);
1187 }
1188 
1189 /*
1190  * Translate a parse tree call statment (macro expansion or module call)
1191  * into the appropriate graph structure.  This function takes a parse node,
1192  * program, and dictionary.  It modifies the program and produces a list
1193  * of indices into the programs "vars" list that are the functions
1194  * output.  "top" is used when recursing.
1195  */
1196 static void
ExGraphCall(Program * p,node * n,int top,list_int * out,EXDictionary dict,int * flags)1197 ExGraphCall (Program *p, node *n, int top, list_int *out, EXDictionary dict, int *flags)
1198 {
1199     char		*fname;
1200     char		*name;
1201     node		*function=NULL;
1202     node		*formal;
1203     node		*arg;
1204     int			slot;
1205     gfunc		fnode;
1206     gfunc		*pFnode;
1207     node		*val;
1208     _ntype		t;
1209     int			instance;
1210     _excache		excache;
1211     char                *macro_procgroupid;
1212     int                 keep_caching;
1213     int			*inArgs;
1214     node		**inAttrs = NULL;
1215     ReRouteMap          *reroutem, rr_map;
1216     int			nin;
1217     int			namedArgs;
1218     int			prehidden;
1219     int			posthidden;
1220     node_function	localFunct;
1221     _ntype		functionType;
1222     int			i, j;
1223 
1224     ProgramVariable	pv;
1225     ProgramRef		pr;
1226     MacroRef            mr;
1227     AsyncVars 		*avars, av;
1228     indexobj		*ind;
1229     list_int		subOut;
1230 
1231     Program		*subP, *copyP;
1232     EXDictionary	subDict;
1233     progobj		*pobj;
1234     int			*mapping;
1235     int			*resolved, numresolved;
1236     ProgramVariable	*pPv;
1237     ProgramRef		*pPr;
1238     int			ilimit;
1239     int			jlimit;
1240 
1241     if (graphing_error)
1242 	goto graphing_error_return;
1243 
1244     /*
1245      * Look up the identifier in the function dictionary.
1246      */
1247     fname = name    = n->v.call.id->v.id.id;
1248 #ifdef INPUT_TIMING
1249     DXMarkTimeLocal (name);
1250 #endif
1251 
1252     function = (node *)_dxf_ExMacroSearch (name);
1253     if (function == NULL)
1254     {
1255         char *modname;
1256         modname = DXAllocateLocal(strlen(name) + 1);
1257         strcpy(modname, name);
1258         DXAddModule(modname, m__badfunc, 0,
1259             21, "input1", "input2", "input3", "input4", "input5", "input6",
1260             "input7", "input8", "input9", "input10", "input11", "input12",
1261             "input13", "input14", "input15", "input16", "input17", "input18",
1262             "input19", "input20", "input21",
1263             21, "output", "output1", "output2", "output3", "output4", "output5",
1264             "output6", "output7", "output8", "output9", "output10", "output11",
1265             "output12", "output13", "output14", "output15", "output16",
1266             "output17", "output18", "output19", "output20");
1267         function = (node *)_dxf_ExMacroSearch (name);
1268     }
1269     if(function->v.function.def.func == m__badfunc) {
1270         if(!_dxd_exRemoteSlave)
1271     	    DXUIMessage ("ERROR", "%s: function does not exist", name);
1272         else
1273     	    DXUIMessage ("ERROR",
1274             "%s: function does not exist on host %s", name, _dxd_exHostName);
1275     }
1276 
1277     functionType = function->type;
1278 
1279     if (_dxf_ExMacroRecursionCheck (name, functionType))
1280     {
1281 	graphing_error = TRUE;
1282 	goto graphing_error_return;
1283     }
1284 
1285     localFunct = function->v.function;
1286     *flags = localFunct.flags;
1287 
1288     /*
1289      * Setup positional formal inputs
1290      */
1291 #ifdef INPUT_TIMING
1292     DXMarkTimeLocal ("init inputs");
1293 #endif
1294 
1295     nin = fnode.nin = localFunct.nin;
1296     prehidden = localFunct.prehidden;
1297     posthidden = localFunct.posthidden;
1298 
1299     fnode.nout = localFunct.nout;
1300     inArgs = (int*) DXAllocateLocal (nin * sizeof (int));
1301     inAttrs = (node **) DXAllocateLocal (nin * sizeof (node*));
1302 
1303     for (i = 0; i < nin; ++i) {
1304         inArgs[i]  = -1;
1305         inAttrs[i] = NULL;
1306     }
1307 
1308     for (i = 0, formal = localFunct.in;
1309          i < prehidden;
1310          ++i, formal = formal->next);
1311 
1312     namedArgs = FALSE;
1313     for (arg = n->v.call.arg, slot = prehidden;
1314 	 slot < nin - posthidden;
1315 	 arg = (arg) ? arg->next : arg, slot++,formal = formal->next)
1316     {
1317 	/* A name substitution has been found, no more positional args */
1318 	if (arg)
1319 	{
1320 	    if (arg->v.arg.id)  {
1321 		namedArgs = TRUE;
1322             }
1323 	    else if (namedArgs)
1324 		DXWarning ("#4780", fname);
1325 	}
1326 
1327 	/*
1328 	 * If an constant argument was specified, create a defined variable.
1329 	 * If it is an ID, look it up in the dictionary (defining it to be
1330 	 * undefined if it's not there).
1331 	 * If it's an expression, recurse.
1332 	 */
1333 	if (!namedArgs && arg)
1334 	{
1335 	    val = arg->v.arg.val;
1336 	    t = val->type;
1337 
1338 	    switch (t)
1339 	    {
1340 	    case NT_CONSTANT:
1341 		INIT_PVAR(pv);
1342 		pv.obj = DXReference ((Object) val->v.constant.obj);
1343 		pv.defined = TRUE;
1344 		APPEND_LIST (ProgramVariable, p->vars, pv);
1345 		inArgs[slot] = SIZE_LIST(p->vars) - 1;
1346                 inAttrs[slot] = (node *) formal->attr;
1347 		break;
1348 
1349 	    case NT_ID:
1350 		ind = (indexobj *)_dxf_ExVariableSearch (val->v.id.id, dict);
1351 		if (ind == NULL)
1352 		{
1353 		    pr.name = _dxf_ExCopyString/*Local*/ (val->v.id.id);
1354             pr.oneshot = NULL;
1355 		    inArgs[slot] = pr.index = SIZE_LIST (p->vars);
1356                     ExDebug("1","pr.name %s, pr.index %d\n", pr.name, pr.index);
1357 		    APPEND_LIST (ProgramRef, p->undefineds, pr);
1358 		    INIT_PVAR(pv);
1359                     inAttrs[slot] = (node *) formal->attr;
1360 		    APPEND_LIST (ProgramVariable, p->vars, pv);
1361 		}
1362 		else
1363 		{
1364 		    inArgs[slot] = ind->index;
1365                     inAttrs[slot] = (node *) formal->attr;
1366 		    ExDelete (ind);
1367 		}
1368 		break;
1369 
1370 	    case NT_LOGICAL:
1371 	    case NT_ARITHMETIC:
1372 		INIT_LIST(subOut);
1373 		ExGraphExpression (p, val, top, &subOut, dict);
1374 		if (graphing_error)
1375 		    goto graphing_error_return;
1376 		inArgs[slot] = *FETCH_LIST(subOut, 0);
1377 		FREE_LIST(subOut);
1378 		break;
1379 
1380 	    default:
1381                 if(!_dxd_exRemoteSlave)
1382 		    DXUIMessage ("ERROR",
1383 		       "_graphCall Internal:  invalid argument type = %d", t);
1384 		graphing_error = TRUE;
1385 		goto call_error;
1386 	    }
1387 	}
1388     }
1389     if (arg)
1390 	DXWarning ("#4790", fname);
1391 #ifdef INPUT_TIMING
1392     DXMarkTimeLocal ("inited unnamed");
1393 #endif
1394 
1395     /*
1396      * Setup explicitly named formals
1397      */
1398     if (namedArgs)
1399     {
1400 	for (arg = n->v.call.arg; arg; arg = arg->next)
1401 	{
1402 	    /*
1403 	     * this is not a name substitution argument, don't bother
1404 	     */
1405 	    if (! arg->v.arg.id)
1406 		continue;
1407 
1408 	    /*
1409 	     * look up formal name in formal list
1410 	     */
1411 	    for (slot = 0, formal = localFunct.in;
1412 		formal;
1413 		formal = formal->next, slot++)
1414 	    {
1415 		if (strcmp (arg->v.arg.id->v.id.id, formal->v.id.id) == 0)
1416 		{
1417 		    break;
1418 		}
1419 	    }
1420 
1421 	    if (slot >= nin)
1422 	    {
1423 		DXWarning ("#4800", fname, arg->v.arg.id->v.id.id);
1424 		continue;
1425 	    }
1426 
1427 	    /*
1428 	     * If an constant argument was specified,
1429 	     * create a defined variable.
1430 	     * If it is an ID, look it up in the dictionary (defining it to be
1431 	     * undefined if it's not there).
1432 	     * If it's an expression, recurse.
1433 	     */
1434 	    val = arg->v.arg.val;
1435 	    t = val->type;
1436 	    switch (t)
1437 	    {
1438 	    case NT_CONSTANT:
1439 		INIT_PVAR(pv);
1440 		pv.obj = DXReference ((Object) val->v.constant.obj);
1441 		pv.defined = TRUE;
1442 		APPEND_LIST (ProgramVariable, p->vars, pv);
1443 		inArgs[slot] = SIZE_LIST(p->vars) - 1;
1444                 inAttrs[slot] = (node *) formal->attr;
1445 		break;
1446 
1447 	    case NT_ID:
1448 		ind = (indexobj *)_dxf_ExVariableSearch (val->v.id.id, dict);
1449 		if (ind == NULL)
1450 		{
1451 		    pr.name = _dxf_ExCopyString/*Local*/ (val->v.id.id);
1452 		    inArgs[slot] = pr.index = SIZE_LIST (p->vars);
1453                     ExDebug("1","pr.name %s, pr.index %d\n", pr.name, pr.index);
1454 		    APPEND_LIST (ProgramRef, p->undefineds, pr);
1455 		    INIT_PVAR(pv);
1456                     inAttrs[slot] = (node *) formal->attr;
1457 		    APPEND_LIST (ProgramVariable, p->vars, pv);
1458 		}
1459 		else
1460 		{
1461 		    inArgs[slot] = ind->index;
1462                     inAttrs[slot] = (node *) formal->attr;
1463 		    ExDelete (ind);
1464 		}
1465 		break;
1466 
1467 	    case NT_LOGICAL:
1468 	    case NT_ARITHMETIC:
1469 		INIT_LIST(subOut);
1470 		ExGraphExpression (p, val, top, &subOut, dict);
1471 		if (graphing_error)
1472 		    goto graphing_error_return;
1473 		inArgs[slot] = *FETCH_LIST(subOut, 0);
1474 		break;
1475 
1476 	    default:
1477                 if(!_dxd_exRemoteSlave)
1478 		    DXUIMessage ("ERROR",
1479 		       "_graphCall Internal:  invalid argument type = %d", t);
1480 		graphing_error = TRUE;
1481 		goto call_error;
1482 	    }
1483 	}
1484     }
1485 
1486     /*
1487      * Fill in defaults, where they exist.  Set the default value even if
1488      * something has been assigned to this input, because if it ends up
1489      * being evaluated to NULL, the default should be used instead.
1490      */
1491     for (formal = localFunct.in, slot = 0;
1492 	 slot < nin;
1493 	 ++slot, formal = formal->next)
1494     {
1495 	/*
1496 	 * if no default, don't bother
1497 	 */
1498 	if (!formal->v.id.dflt)
1499 	    continue;
1500 
1501 
1502 	if (inArgs[slot] < 0)
1503 	{
1504 	    INIT_PVAR(pv);
1505 	    APPEND_LIST (ProgramVariable, p->vars, pv);
1506 	    inArgs[slot] = SIZE_LIST(p->vars) - 1;
1507 	}
1508 	pPv = FETCH_LIST(p->vars, inArgs[slot]);
1509 	if (formal->v.id.dflt->type != NT_CONSTANT)
1510 	{
1511             if(!_dxd_exRemoteSlave)
1512 	        DXUIMessage ("ERROR",
1513 			 "%s:  default values must be constants", fname);
1514 	    graphing_error = TRUE;
1515 	    goto call_error;
1516 	}
1517 	else
1518 	{
1519 	    pPv->dflt =
1520 		DXReference ((Object)formal->v.id.dflt->v.constant.obj);
1521 	}
1522     }
1523 #ifdef INPUT_TIMING
1524     DXMarkTimeLocal ("inited named");
1525 #endif
1526 
1527     /*
1528      * Find the function's attributes, e.g. instance and caching if it
1529      * has any attributed to it
1530      */
1531     instance = _dxf_ExGetIntegerAttribute (n->attr, ATTR_INSTANCE);
1532 
1533     if (! _dxf_ExHasIntegerAttribute (n->attr, ATTR_CACHE, (int *)&excache))
1534 	excache = CACHE_ALL;
1535 
1536     /*
1537      * ExNoCachePush expects an on/off flag. Since all values > 0 imply some
1538      * kind of caching, pass a 1 to ExNoCachePush for all values > 0, and
1539      * set excache to the cache attr value unless a 0 is returned, in which
1540      * case caching should be suppressed. (is this OK? )
1541      */
1542     keep_caching = _dxf_ExNoCachePush (excache != CACHE_OFF);
1543     if (!keep_caching)
1544 	excache = CACHE_OFF;
1545 
1546     /*
1547      * Macro calls are expanded recursively.  Module calls create input
1548      * and output lists, and insert the gfunc structure into the program.
1549      */
1550     switch (functionType)
1551     {
1552     case NT_MACRO:
1553 
1554 	/* Look up the macro in the graph cache, and make one (inserting
1555 	 * it) if it's not found.
1556 	 */
1557 
1558         macro_procgroupid = _dxf_ExGetStringAttribute (n->attr, ATTR_PGRP);
1559 
1560 	pobj = (progobj*) _dxf_ExDictionarySearch (_dxd_exGraphCache, name);
1561 	if (pobj == NULL)
1562 	{
1563 #ifdef INPUT_TIMING
1564 	    DXMarkTimeLocal ("init formals");
1565 #endif
1566 	    /* Create sub{dictionary,program} */
1567 	    subDict = _dxf_ExDictionaryCreate (DICT_SIZE, TRUE, FALSE);
1568 	    subP = AllocateProgramLocal();
1569 
1570 	    /* Insert supplied inputs into new local dictionary */
1571 	    for (formal = localFunct.in, slot = 0;
1572 			formal;
1573 			formal = formal->next, slot++)
1574 	    {
1575 		pr.index = SIZE_LIST(subP->vars);
1576 		pr.name = _dxf_ExCopyString/*Local*/ (formal->v.id.id);
1577                 ExDebug("1","pr.name %s, pr.index %d\n", pr.name, pr.index);
1578 		APPEND_LIST (ProgramRef, subP->inputs, pr);
1579 		ind = CreateIndex(pr.index);
1580 		_dxf_ExVariableInsert (pr.name, subDict, (EXObj) ind);
1581 		INIT_PVAR (pv);
1582 		APPEND_LIST (ProgramVariable, subP->vars, pv);
1583 	    }
1584 
1585 #ifdef INPUT_TIMING
1586 	    DXMarkTimeLocal ("inited formals");
1587 #endif
1588 	    /* Recurse */
1589 	    ExGraphTraverse (subP, localFunct.def.stmt, top + 1, subDict);
1590             if(graphing_error)
1591                 goto graphing_error_return;
1592 
1593             /* add itself to it's list of macros */
1594             mr.name = _dxf_ExCopyString(name);
1595             mr.index = localFunct.index;
1596             APPEND_LIST(MacroRef, subP->macros, mr);
1597 
1598 	    /* Extract outputs from the dictionary and put them in the
1599 	     * output list
1600 	     */
1601 	    for (formal = localFunct.out, slot = 0;
1602 			formal;
1603 			formal = formal->next, slot++)
1604 	    {
1605 		ind = (indexobj*) _dxf_ExVariableSearch (formal->v.id.id,
1606 							 subDict);
1607 		/* If there was no definition for this output, set to null */
1608 		if (ind == NULL)
1609 		{
1610 		    INIT_PVAR (pv);
1611 		    pv.defined = TRUE;
1612 		    APPEND_LIST (ProgramVariable, subP->vars, pv);
1613 		    i = SIZE_LIST (subP->vars) - 1;
1614 		}
1615 		else
1616 		{
1617 		    i = ind->index;
1618 		    ExDelete(ind);
1619 		}
1620 		pr.index = i;
1621 		pr.name = _dxf_ExCopyString/*Local*/ (formal->v.id.id);
1622                 ExDebug("1","pr.name %s, pr.index %d\n", pr.name, pr.index);
1623 		APPEND_LIST (ProgramRef, subP->outputs, pr);
1624 	    }
1625 
1626 	    /* Clean up the dictionary and create the cached object */
1627 	    _dxf_ExDictionaryDestroy (subDict);
1628 	    pobj = CreateProgobj (subP);
1629 	    ExReference (pobj);
1630 
1631 	    if (top == 0)
1632 	    {
1633 	        /* Insert any SendModules that may be required */
1634 		ExDebug("*1","Before ExCreateSendModules with nbr gfuncs = %d",
1635 			SIZE_LIST(subP->funcs));
1636 		ExCreateSendModules(subP);
1637 		ExDebug("*1","After ExCreateSendModules with nbr gfuncs = %d",
1638 		    SIZE_LIST(subP->funcs));
1639 	    }
1640 	    _dxf_ExDictionaryInsert (_dxd_exGraphCache, name, (EXObj)pobj);
1641 	}
1642 	else
1643 	    subP = pobj->p;
1644 
1645         /* parent program gets a copy of all macros in it's children */
1646 	GROW_LIST(MacroRef, p->macros, SIZE_LIST(subP->macros));
1647 
1648 	for (i = 0, ilimit = SIZE_LIST(subP->macros); i < ilimit; ++i)
1649         {
1650             MacroRef *macro;
1651 	    macro = FETCH_LIST(subP->macros, i);
1652             mr.name = _dxf_ExCopyString(macro->name);
1653             mr.index = macro->index;
1654             APPEND_LIST(MacroRef, p->macros, mr);
1655         }
1656 	/* From here on, we're copying the relocatable (compiled) version
1657 	 * of the macro into the caller's program.
1658 	 *
1659 	 * Start by Create a mapping array... mapping [i] is valid
1660 	 * iff resolved[i] is TRUE.  p->vars[mapping[subPindex]]
1661 	 */
1662 	mapping  = (int*)DXAllocateLocal     (SIZE_LIST(subP->vars) *
1663 					      sizeof(int));
1664 	resolved = (int*)DXAllocateLocalZero (SIZE_LIST(subP->vars) *
1665 					      sizeof(int));
1666         numresolved = 0;
1667 	if (mapping == NULL || resolved == NULL)
1668 	{
1669 	    graphing_error = TRUE;
1670 	    _dxf_ExDie ("ExGraphCall:  can't allocate memory");
1671 	}
1672 
1673 	/* Define mappings for the inputs in the caller's variable list */
1674 	for (i = 0, ilimit = SIZE_LIST(subP->inputs); i < ilimit; ++i)
1675 	{
1676 	    pPr = FETCH_LIST(subP->inputs, i);
1677 	    mapping [pPr->index] = inArgs[i];
1678 	    resolved[pPr->index] = TRUE;
1679             numresolved++;
1680 	}
1681 
1682 	/* Try to define all undefineds.  If it exists in the caller's
1683 	 * dictionary, define the value (that's the new mapping).  If it's not
1684 	 * there, create a new undefined.
1685 	 */
1686 	GROW_LIST(ProgramVariable, p->vars, SIZE_LIST(subP->undefineds));
1687 	GROW_LIST(ProgramRef, p->undefineds, SIZE_LIST(subP->undefineds));
1688 	for (i = 0, ilimit = SIZE_LIST(subP->undefineds); i < ilimit; ++i)
1689 	{
1690 	    pPr = FETCH_LIST(subP->undefineds, i);
1691 	    ind = (indexobj *) _dxf_ExVariableSearch(pPr->name, dict);
1692 	    if (ind == NULL)
1693 	    {
1694 		pr.index = SIZE_LIST(p->vars);
1695 		pr.name  = _dxf_ExCopyString/*Local*/ (pPr->name);
1696                 ExDebug("1","pr.name %s, pr.index %d\n", pr.name, pr.index);
1697 		mapping [pPr->index] = pr.index;
1698 		resolved[pPr->index] = TRUE;
1699                 numresolved++;
1700 		pPv = FETCH_LIST(subP->vars, pPr->index);
1701 		pv = *pPv;
1702 		if (pPv->defined)
1703 		    DXReference (pPv->obj);
1704 		if (pPv->dflt != NULL)
1705 		    DXReference (pPv->dflt);
1706 		APPEND_LIST (ProgramVariable, p->vars, pv);
1707 		APPEND_LIST (ProgramRef,      p->undefineds, pr);
1708 	    }
1709 	    else
1710 	    {
1711 		mapping [pPr->index] = ind->index;
1712 		resolved[pPr->index] = TRUE;
1713                 numresolved++;
1714 		ExDelete (ind);
1715 	    }
1716 	}
1717 
1718 	/* Loop through and create mappings for the other variables */
1719         ilimit = SIZE_LIST(subP->vars);
1720         GROW_LIST(ProgramVariable, p->vars, ilimit-numresolved);
1721 	for (i = 0; i < ilimit; ++i)
1722 	{
1723 	    pPv = FETCH_LIST(subP->vars, i);
1724 	    if (!resolved[i])
1725 	    {
1726 		pv = *pPv;
1727 		mapping [i] = SIZE_LIST(p->vars);
1728 		resolved[i] = TRUE;
1729 		APPEND_LIST (ProgramVariable, p->vars, pv);
1730 		if (pPv->defined)
1731 		    DXReference (pPv->obj);
1732 		if (pPv->dflt != NULL)
1733 		    DXReference (pPv->dflt);
1734 	    }
1735 	}
1736 
1737 	/* Put the outputs in the "out" list which is used by the
1738 	 * macro caller.
1739 	 */
1740 	for (i = 0, ilimit = SIZE_LIST(subP->outputs); i < ilimit; ++i)
1741 	{
1742 	    pPr = FETCH_LIST(subP->outputs, i);
1743 	    APPEND_LIST(int, *out, mapping[pPr->index]);
1744 	}
1745 
1746         /* parent program gets a copy of all async variable in it's children */
1747 	for (i = 0, ilimit = SIZE_LIST(subP->async_vars); i < ilimit; ++i)
1748         {
1749 	    avars = FETCH_LIST(subP->async_vars, i);
1750             av.nameindx = mapping[avars->nameindx];
1751             av.valueindx = mapping[avars->valueindx];
1752             APPEND_LIST(int, p->wiredvars, av.valueindx);
1753             APPEND_LIST(AsyncVars, p->async_vars, av);
1754         }
1755 
1756         /* We will copy each function into a separate subprogram that will
1757          * be referenced from the caller's program.
1758 	 */
1759 
1760         copyP = GetNewMacro(subP, mapping, resolved);
1761         if(top == 0)
1762             copyP->subgraphId = NextSubGraphId();
1763 
1764         for(i = 0; i < SIZE_LIST(subP->async_vars); i++) {
1765             avars = FETCH_LIST(subP->async_vars, i);
1766 	    slot = avars->nameindx;
1767             if(slot != -1) {
1768 	        if (!resolved[slot])
1769 	            _dxf_ExDie ("Executive inconsistency -- ExGraphCall 001");
1770                 av.nameindx = mapping[slot];
1771             }
1772             else av.nameindx = slot;
1773             pPv = FETCH_LIST(p->vars, mapping[slot]);
1774             ExFixAsyncVarName(p, pPv, fname, instance);
1775 
1776 	    slot = avars->valueindx;
1777             if(slot != -1) {
1778 	        if (!resolved[slot])
1779 	            _dxf_ExDie ("Executive inconsistency -- ExGraphCall 002");
1780                 av.valueindx = mapping[slot];
1781             }
1782             else av.valueindx = slot;
1783             APPEND_LIST (AsyncVars, copyP->async_vars, av);
1784         }
1785 
1786 	GROW_LIST(gfunc, copyP->funcs, SIZE_LIST(subP->funcs));
1787 
1788 	for (i = 0, ilimit = SIZE_LIST(subP->funcs); i < ilimit; ++i)
1789 	{
1790 	    pFnode = FETCH_LIST(subP->funcs, i);
1791 	    fnode = *pFnode;
1792             if(fnode.ftype == F_MACRO) {
1793                 Program *newp;
1794                 newp = AllocateProgram();
1795                 ExCopySubP(newp, fnode.func.subP, top);
1796                 if(top == 0)
1797                     newp->subgraphId = NextSubGraphId();
1798                 ExRemapVars(p, newp, mapping, resolved, fname, instance);
1799                 fnode.name = _dxf_ExCopyString(pFnode->name);
1800                 fnode.func.subP = newp;
1801                 if(fnode.flags & MODULE_SIDE_EFFECT)
1802                     localFunct.flags |= MODULE_SIDE_EFFECT;
1803                 /* we are going to make state macros ASYNCLOCAL */
1804                 /* so that they get the extra 2 hidden inputs   */
1805                 /* added. They are a bit different but share    */
1806                 /* enough code that they should use this flag.  */
1807                 if(fnode.flags & MODULE_CONTAINS_STATE) {
1808                     localFunct.flags |= MODULE_CONTAINS_STATE;
1809                     localFunct.flags |= MODULE_ASYNCLOCAL;
1810                 }
1811                 if(fnode.flags & MODULE_CHANGES_STATE) {
1812                     localFunct.flags |= MODULE_CONTAINS_STATE;
1813                     localFunct.flags |= MODULE_ASYNCLOCAL;
1814                 }
1815             }
1816             else {
1817                 if(fnode.flags & MODULE_CHANGES_STATE) {
1818                     localFunct.flags |= MODULE_CHANGES_STATE;
1819                     localFunct.flags |= MODULE_ASYNCLOCAL;
1820                 }
1821                 if(fnode.flags & MODULE_SIDE_EFFECT)
1822                     localFunct.flags |= MODULE_SIDE_EFFECT;
1823             }
1824 
1825 	    /*
1826 	     * make changes to the copy of the fnode just created.
1827              */
1828 	    _dxf_ExPathPrepend( subP, fname, instance, &fnode );
1829 
1830 
1831 	    /*
1832 	     * macro process group assignments override individual settings.
1833 	     * included function if it has one.
1834 	     */
1835             if (macro_procgroupid)
1836                 fnode.procgroupid = _dxf_ExCopyString (macro_procgroupid);
1837 
1838 
1839 	    INIT_LIST (fnode.inputs);
1840 	    INIT_LIST (fnode.outputs);
1841 	    INIT_LIST (fnode.reroute);
1842 	    INIT_LIST (fnode.cache_ddi);
1843 
1844 	    GROW_LIST(int, fnode.inputs, SIZE_LIST(pFnode->inputs));
1845 	    GROW_LIST(int, fnode.outputs, SIZE_LIST(pFnode->outputs));
1846 	    GROW_LIST(ReRouteMap, fnode.reroute, SIZE_LIST(pFnode->reroute));
1847 	    GROW_LIST(int, fnode.cache_ddi, SIZE_LIST(pFnode->cache_ddi));
1848 
1849 	    for (j = 0, jlimit = SIZE_LIST(pFnode->inputs); j < jlimit; ++j)
1850 	    {
1851 		slot = *FETCH_LIST(pFnode->inputs, j);
1852 		if (slot == -1)
1853 		{
1854 		    APPEND_LIST(int, fnode.inputs, slot);
1855 		}
1856 		else
1857 		{
1858 		    if (!resolved[slot])
1859 		        _dxf_ExDie ("Executive inconsistency -- ExGraphCall 003");
1860 		    APPEND_LIST(int, fnode.inputs, mapping[slot]);
1861 		}
1862 	    }
1863 
1864             /* The name of the async variable is fixed for ASYNC modules */
1865             /* above in the call to ExFixAsyncVarName. Here we already   */
1866             /* fixed the path name of the module so we just use that.    */
1867             if(fnode.flags & MODULE_ASYNCLOCAL) {
1868 		Object new_path;
1869 
1870                 slot = *FETCH_LIST(fnode.inputs, fnode.nin - 2);
1871                 pPv = FETCH_LIST(p->vars, slot);
1872 
1873 		new_path = (Object)DXNewString( _dxf_ExGFuncPathToCacheString(&fnode) );
1874 		DXReference ((Object)new_path);
1875                 if(pPv->obj)
1876                     DXDelete((Object)pPv->obj);
1877                 pPv->obj = new_path;
1878             }
1879 
1880 	    for (j = 0, jlimit = SIZE_LIST(pFnode->outputs); j < jlimit; ++j)
1881 	    {
1882 		slot = *FETCH_LIST(pFnode->outputs, j);
1883 		if (slot == -1)
1884 		{
1885 		    APPEND_LIST(int, fnode.outputs, slot);
1886 		}
1887 		else
1888 		{
1889 		    if (!resolved[slot])
1890 			_dxf_ExDie ("Executive inconsistency -- ExGraphCall 004");
1891 		    APPEND_LIST(int, fnode.outputs, mapping[slot]);
1892 		}
1893 	    }
1894 
1895 	    for (j = 0, jlimit = SIZE_LIST(pFnode->reroute); j < jlimit; ++j)
1896             {
1897 		reroutem = FETCH_LIST(pFnode->reroute, j);
1898                 rr_map = *reroutem;
1899 	        APPEND_LIST(ReRouteMap, fnode.reroute, rr_map);
1900             }
1901 
1902 	    for (j = 0, jlimit = SIZE_LIST(pFnode->cache_ddi); j < jlimit; ++j)
1903             {
1904 		slot = *FETCH_LIST(pFnode->cache_ddi, j);
1905 	        APPEND_LIST(int, fnode.cache_ddi, slot);
1906             }
1907 
1908 
1909 	    APPEND_LIST(gfunc, copyP->funcs, fnode);
1910 	}
1911 
1912         ExMakeGfunc(localFunct, NT_MACRO, instance, excache, n, inAttrs, p,
1913                     inArgs, out, copyP);
1914 
1915 	ExDelete (pobj);
1916 	DXFree ((Pointer)mapping);
1917 	DXFree ((Pointer)resolved);
1918 	break;
1919 
1920     case NT_MODULE:
1921 #ifdef INPUT_TIMING
1922 	DXMarkTimeLocal ("create gfunc");
1923 #endif
1924         ExMakeGfunc(localFunct, NT_MODULE, instance, excache, n, inAttrs, p,
1925                     inArgs, out, NULL);
1926 
1927 #ifdef INPUT_TIMING
1928 	DXMarkTimeLocal ("created gfunc");
1929 #endif
1930 	break;
1931 
1932     default:
1933 	break;
1934     }
1935 
1936 call_error:
1937     _dxf_ExNoCachePop ();
1938     _dxf_ExMacroRecursionPop (name, functionType);
1939     DXFree ((Pointer) inArgs);
1940     DXFree ((Pointer) inAttrs);
1941 
1942 
1943 graphing_error_return:
1944 
1945     ExDelete(function);
1946 
1947 #ifdef INPUT_TIMING
1948     DXMarkTimeLocal (fname);
1949 #endif
1950 }
1951 
GetNewMacro(Program * p,int * map,int * resolved)1952 static Program *GetNewMacro(Program *p, int *map, int *resolved)
1953 {
1954     Program *newp;
1955     int i, slot;
1956     ProgramRef pr, *pPr;
1957 
1958     newp = AllocateProgram();
1959     GROW_LIST(ProgramRef, newp->undefineds, SIZE_LIST(p->undefineds));
1960     for(i = 0; i < SIZE_LIST(p->undefineds); i++) {
1961         pPr = FETCH_LIST(p->undefineds, i);
1962 	slot = pPr->index;
1963         if(slot != -1) {
1964 	    if (!resolved[slot])
1965 	        _dxf_ExDie ("Executive inconsistency -- GetNewMacro 001");
1966             pr.index = map[slot];
1967         }
1968         else pr.index = slot;
1969         pr.name = _dxf_ExCopyString(pPr->name);
1970         pr.oneshot = NULL;
1971         ExDebug("1","pr.name %s, pr.index %d\n", pr.name, pr.index);
1972         APPEND_LIST (ProgramRef, newp->undefineds, pr);
1973     }
1974 
1975     GROW_LIST(int, newp->wiredvars, SIZE_LIST(p->wiredvars));
1976     for(i = 0; i < SIZE_LIST(p->wiredvars); i++) {
1977         slot = *FETCH_LIST(p->wiredvars, i);
1978         if(slot != -1) {
1979             if(!resolved[slot])
1980 	        _dxf_ExDie ("Executive inconsistency -- GetNewMacro 001");
1981 
1982             APPEND_LIST(int, newp->wiredvars, map[slot]);
1983         }
1984         else APPEND_LIST(int, newp->wiredvars, slot);
1985     }
1986 
1987     COPY_LIST(newp->macros, p->macros);
1988     newp->vars = p->vars;
1989     newp->loopctl = p->loopctl;
1990     return(newp);
1991 }
1992 
ExCopySubP(Program * toP,Program * fromP,int top)1993 static void ExCopySubP(Program *toP, Program *fromP, int top)
1994 {
1995     Program *mp;
1996     gfunc *pFnode, fnode;
1997     int i, ilimit, j, jlimit, slot;
1998     ReRouteMap *reroutem, rr_map;
1999     ProgramRef pr, *pPr;
2000     AsyncVars *avars, av;
2001 
2002     *toP = *fromP;
2003     INIT_LIST(toP->undefineds);
2004     GROW_LIST(ProgramRef, toP->undefineds, SIZE_LIST(fromP->undefineds));
2005     for(i = 0; i < SIZE_LIST(fromP->undefineds); i++) {
2006         pPr = FETCH_LIST(fromP->undefineds, i);
2007         pr.index = pPr->index;
2008         pr.name = _dxf_ExCopyString(pPr->name);
2009         pr.oneshot = NULL;
2010         ExDebug("1","pr.name %s, pr.index %d\n", pr.name, pr.index);
2011         APPEND_LIST (ProgramRef, toP->undefineds, pr);
2012     }
2013 
2014     INIT_LIST(toP->wiredvars);
2015     GROW_LIST(int, toP->wiredvars, SIZE_LIST(fromP->wiredvars));
2016     for(i = 0; i < SIZE_LIST(fromP->wiredvars); i++) {
2017         slot = *FETCH_LIST(fromP->wiredvars, i);
2018         APPEND_LIST (int, toP->wiredvars, slot);
2019     }
2020 
2021     INIT_LIST(toP->async_vars);
2022     GROW_LIST(AsyncVars, toP->async_vars, SIZE_LIST(fromP->async_vars));
2023     for(i = 0; i < SIZE_LIST(fromP->async_vars); i++) {
2024         avars = FETCH_LIST(fromP->async_vars, i);
2025         av.nameindx = avars->nameindx;
2026         av.valueindx = avars->valueindx;
2027         APPEND_LIST (AsyncVars, toP->async_vars, av);
2028     }
2029     COPY_LIST(toP->macros, fromP->macros);
2030     INIT_LIST (toP->funcs);
2031 
2032     GROW_LIST(gfunc, toP->funcs, SIZE_LIST(fromP->funcs));
2033 
2034     for (i = 0, ilimit = SIZE_LIST(fromP->funcs); i < ilimit; ++i)
2035     {
2036         pFnode = FETCH_LIST(fromP->funcs, i);
2037         fnode = *pFnode;
2038 
2039         if(fnode.ftype == F_MACRO) {
2040             fnode.name = _dxf_ExCopyString(pFnode->name);
2041             mp = AllocateProgram();
2042             ExCopySubP(mp, fnode.func.subP, top);
2043             if(top == 0)
2044                 mp->subgraphId = NextSubGraphId();
2045             fnode.func.subP = mp;
2046         }
2047 
2048         INIT_LIST (fnode.inputs);
2049         INIT_LIST (fnode.outputs);
2050         INIT_LIST (fnode.reroute);
2051         INIT_LIST (fnode.cache_ddi);
2052 
2053         GROW_LIST(int, fnode.inputs, SIZE_LIST(pFnode->inputs));
2054 	GROW_LIST(int, fnode.outputs, SIZE_LIST(pFnode->outputs));
2055 	GROW_LIST(ReRouteMap, fnode.reroute, SIZE_LIST(pFnode->reroute));
2056 	GROW_LIST(int, fnode.cache_ddi, SIZE_LIST(pFnode->cache_ddi));
2057 
2058         for (j = 0, jlimit = SIZE_LIST(pFnode->inputs); j < jlimit; ++j)
2059         {
2060 	    slot = *FETCH_LIST(pFnode->inputs, j);
2061    	    APPEND_LIST(int, fnode.inputs, slot);
2062 	}
2063 
2064 	for (j = 0, jlimit = SIZE_LIST(pFnode->outputs); j < jlimit; ++j)
2065 	{
2066 	    slot = *FETCH_LIST(pFnode->outputs, j);
2067 	    APPEND_LIST(int, fnode.outputs, slot);
2068         }
2069 
2070 	for (j = 0, jlimit = SIZE_LIST(pFnode->reroute); j < jlimit; ++j)
2071         {
2072 	    reroutem = FETCH_LIST(pFnode->reroute, j);
2073             rr_map = *reroutem;
2074 	    APPEND_LIST(ReRouteMap, fnode.reroute, rr_map);
2075         }
2076 
2077 	for (j = 0, jlimit = SIZE_LIST(pFnode->cache_ddi); j < jlimit; ++j)
2078         {
2079 	    slot = *FETCH_LIST(pFnode->cache_ddi, j);
2080 	    APPEND_LIST(int, fnode.cache_ddi, slot);
2081         }
2082 
2083         APPEND_LIST(gfunc, toP->funcs, fnode);
2084     }
2085 }
2086 
ExMakeGfunc(node_function ndfunc,_ntype type,int instance,_excache excache,node * n,node ** inAttrs,Program * p,int * inArgs,list_int * out,Program * macro)2087 static void ExMakeGfunc(node_function ndfunc, _ntype type, int instance,
2088                         _excache excache, node *n, node **inAttrs, Program *p,
2089                         int *inArgs, list_int *out, Program *macro)
2090 {
2091     gfunc fnode;
2092     int slot, i;
2093     ProgramVariable pv;
2094     ProgramRef *pr;
2095     node *nodep;
2096     int nin = ndfunc.nin;
2097     int nout = ndfunc.nout;
2098     int found = FALSE;
2099 
2100     _dxf_ExInitGfunc(&fnode);
2101 
2102     switch(type) {
2103 	case NT_MACRO:				/* macro definition */
2104             fnode.ftype = F_MACRO;
2105             fnode.func.subP = macro;
2106             fnode.name = _dxf_ExCopyString(ndfunc.id->v.id.id);
2107             break;
2108 	case NT_MODULE:				/* module definition */
2109             fnode.ftype    = F_MODULE;
2110             fnode.func.module = ndfunc.def.func;
2111 #if 0
2112             if(ndfunc.flags & MODULE_SIDE_EFFECT)
2113                 p->loopctl.side_effects = TRUE;
2114 #endif
2115             fnode.name = ndfunc.id->v.id.id;
2116             break;
2117         default:
2118 	    break;
2119     }
2120     fnode.instance = instance;
2121     fnode.excache = excache;
2122 
2123     _dxf_ExPathSet( p, n->v.call.id->v.id.id, instance, &fnode );
2124 
2125     fnode.procgroupid =
2126 	    _dxf_ExCopyString (_dxf_ExGetStringAttribute (n->attr, ATTR_PGRP));
2127 
2128 #if 0
2129     fnode.led[0] = ndfunc.led[0];
2130     fnode.led[1] = ndfunc.led[1];
2131     fnode.led[2] = ndfunc.led[2];
2132     fnode.led[3] = ndfunc.led[3];
2133 #endif
2134     fnode.flags = ndfunc.flags;
2135 #if 0
2136     if(fnode.ftype == F_MACRO && (macro->loopctl.side_effects ||
2137                                   (ndfunc.nout == 0 && ndfunc.nin == 0))) {
2138         fnode.flags = MODULE_SIDE_EFFECT;
2139         p->loopctl.side_effects = TRUE;
2140     }
2141 #endif
2142     if(fnode.ftype == F_MACRO && ndfunc.nout == 0 && ndfunc.nin == 0)
2143         fnode.flags = MODULE_SIDE_EFFECT;
2144     fnode.nout = ndfunc.nout;
2145     fnode.nin = ndfunc.nin;
2146 
2147     if(fnode.ftype == F_MODULE) {
2148         /*
2149          * if asynchronous, the last two inputs are special and need to
2150          * have their default values modified.
2151          */
2152 
2153         if (ndfunc.flags & (MODULE_ASYNC | MODULE_ASYNCLOCAL))
2154         {
2155             AsyncVars avars;
2156             slot = nin - 2;
2157             if (inArgs[slot] < 0)
2158             {
2159 		Object new_path;
2160 
2161 	        INIT_PVAR(pv);
2162 	        avars.nameindx = inArgs[slot] = SIZE_LIST(p->vars);
2163                 pv.defined = TRUE;
2164 
2165 		new_path = (Object)DXNewString( _dxf_ExGFuncPathToString(&fnode) );
2166 		DXReference ((Object)new_path);
2167 		pv.obj = new_path;
2168                 APPEND_LIST (ProgramVariable, p->vars, pv);
2169 	    }
2170 
2171 	    slot = nin - 1;
2172 	    if (inArgs[slot] < 0)
2173 	    {
2174 	        INIT_PVAR(pv);
2175 	        avars.valueindx = inArgs[slot] = SIZE_LIST(p->vars);
2176 	        APPEND_LIST (int, p->wiredvars, avars.valueindx);
2177 	        APPEND_LIST (ProgramVariable, p->vars, pv);
2178 	    }
2179             if(ndfunc.flags & MODULE_ASYNC)
2180                 APPEND_LIST(AsyncVars, p->async_vars, avars);
2181         }
2182 
2183         /*
2184          * mark these as special, because unlike other modules, you have to
2185          * compute part of their inputs before you can tell which of their
2186          * other inputs/outputs should be generated.
2187          */
2188 
2189         if (strcmp (fnode.name, "Switch") == 0)
2190             fnode.flowtype = SwitchFlag;
2191         else if (strcmp (fnode.name, "Route") == 0)
2192 	    fnode.flowtype = RouteFlag;
2193 
2194 	if (ndfunc.flags & MODULE_REROUTABLE) {
2195             Object _attr;
2196             ReRouteMap rr_map;
2197 
2198 	    for (i = 0; i < nin; ++i) {
2199                 nodep = inAttrs[i];
2200                 if(nodep == NULL)
2201                     continue;
2202 
2203                 _attr = _dxf_ExGetAttribute(nodep, ATTR_DIREROUTE);
2204                 if (_attr)
2205                 {
2206                     DXExtractInteger(_attr, &(rr_map.output_n));
2207                     rr_map.input_n = i;
2208 	            APPEND_LIST(ReRouteMap, fnode.reroute, rr_map);
2209                 }
2210 
2211                 _attr = _dxf_ExGetAttribute(nodep, ATTR_CACHE);
2212                 /* for inputs the cache value is always 2. I am only
2213                  * storing which input # needs to be cached and not
2214                  * the integer value of the cache attribute since it
2215                  * is currently never used.
2216                  */
2217                 if(_attr)
2218 	            APPEND_LIST(int, fnode.cache_ddi, i);
2219             }
2220         }
2221     } /* type is F_MODULE */
2222 
2223     /* Add each input to the function's input array, and define new
2224      * variables for each output.
2225      */
2226 
2227     GROW_LIST(int, fnode.inputs, nin);
2228 
2229     for (i = 0; i < nin; ++i) {
2230         if (fnode.ftype == F_MODULE &&
2231             (ndfunc.flags & (MODULE_ASYNC | MODULE_ASYNCLOCAL))) {
2232             int rerun_attr;
2233 	    if(_dxf_ExHasIntegerAttribute(inAttrs[i], ATTR_RERUNKEY, &rerun_attr)) {
2234                 if(found)
2235                     DXWarning("Multiple rerun keys found for module %s, using first occurence of rerun key");
2236                 else {
2237                     fnode.flags |= MODULE_ASYNCNAMED;
2238                     fnode.rerun_index = i;
2239                     found = TRUE;
2240                 }
2241 	    }
2242         }
2243         APPEND_LIST(int, fnode.inputs, inArgs[i]);
2244     }
2245 
2246     /* do not append to input list if macro has no input and no outputs */
2247     /* ie. main() */
2248     if(fnode.ftype == F_MACRO && !(nin == 0 && nout == 0)) {
2249         /* add named undefineds to end of input list */
2250         for (i = 0; i < SIZE_LIST(macro->undefineds); i++) {
2251             pr = FETCH_LIST(macro->undefineds, i);
2252             if (strcmp(pr->name, "NULL") != 0) {
2253                 APPEND_LIST(int, fnode.inputs, pr->index);
2254                 fnode.nin++;
2255             }
2256         }
2257         /* add last 2 inputs for macros marked asynclocal */
2258         if (ndfunc.flags & MODULE_ASYNCLOCAL)
2259         {
2260             Object new_path;
2261 
2262 	    INIT_PVAR(pv);
2263             pv.defined = TRUE;
2264 
2265 	    new_path = (Object)DXNewString( _dxf_ExGFuncPathToCacheString(&fnode) );
2266 	    DXReference ((Object)new_path);
2267 	    pv.obj = new_path;
2268 
2269             APPEND_LIST(int, fnode.inputs, SIZE_LIST(p->vars));
2270             fnode.nin++;
2271             APPEND_LIST (ProgramVariable, p->vars, pv);
2272 	    INIT_PVAR(pv);
2273             APPEND_LIST(int, fnode.inputs, SIZE_LIST(p->vars));
2274             fnode.nin++;
2275 	    APPEND_LIST (int, p->wiredvars, SIZE_LIST(p->vars));
2276 	    APPEND_LIST (ProgramVariable, p->vars, pv);
2277 	}
2278     }
2279 
2280     for (i = 0; i < nout; ++i)
2281     {
2282         if(fnode.ftype == F_MODULE) {
2283             INIT_PVAR(pv);
2284             APPEND_LIST(int, p->wiredvars, SIZE_LIST(p->vars));
2285             APPEND_LIST(ProgramVariable, p->vars, pv);
2286             APPEND_LIST(int, *out, SIZE_LIST(p->vars) - 1);
2287             APPEND_LIST(int, fnode.outputs, SIZE_LIST(p->vars) - 1);
2288         }
2289         else {
2290             slot = *FETCH_LIST(*out, i);
2291             APPEND_LIST(int, p->wiredvars, slot);
2292             APPEND_LIST(int, fnode.outputs, slot);
2293         }
2294     }
2295 
2296     APPEND_LIST(gfunc, p->funcs, fnode);
2297 }
2298 
2299 /*
2300  * Generate SEND modules where outputs to modules are inputs to modules
2301  * that cross process groups.
2302  *
2303  *  For each output of each gfunc:
2304  *    Match var index # against var index # of each input of each
2305  *    other gfunc. When match, compare process group name, and create
2306  *    a SEND module when they don't match.
2307  */
ExCreateSendModules(Program * p)2308 static void ExCreateSendModules(Program *p)
2309 {
2310     int		srcfn, tgfn, in_tab, out_tab;
2311     int		*index, *outdex;
2312     gfunc	*sgf, *tgf;
2313 
2314     for (srcfn = 0; srcfn < SIZE_LIST(p->funcs); ++srcfn)  {
2315 	sgf = FETCH_LIST(p->funcs,srcfn);
2316 	if(!strcmp(sgf->name, "DPSEND"))
2317 	    continue;
2318 
2319 	for (tgfn = srcfn + 1; tgfn < SIZE_LIST(p->funcs); ++tgfn) {
2320 	    tgf = FETCH_LIST(p->funcs,tgfn);
2321             /* if target and source functions belong to same execution
2322              * group then we don't need to build a DPSEND module.
2323              */
2324 	    if (sgf->procgroupid == NULL && tgf->procgroupid == NULL)
2325                 continue;
2326 	    if (sgf->procgroupid != NULL && tgf->procgroupid != NULL &&
2327                 !strcmp(sgf->procgroupid, tgf->procgroupid))
2328                 continue;
2329 
2330 	    for (out_tab = 0; out_tab < SIZE_LIST(sgf->outputs); ++out_tab) {
2331 		outdex = FETCH_LIST (sgf->outputs, out_tab);
2332 		if (outdex == NULL)
2333                     _dxf_ExDie("Inconsistency building distributed graph");
2334                 if (*outdex < 0)
2335                     continue;
2336 
2337 		for (in_tab = 0; in_tab < SIZE_LIST(tgf->inputs); ++in_tab) {
2338 		    index = FETCH_LIST (tgf->inputs, in_tab);
2339 	            if (index == NULL)
2340                         _dxf_ExDie("Inconsistency building distributed graph");
2341                     if (*index < 0)
2342                         continue;
2343 		    if (*index == *outdex) {
2344 	                ExBuildSendModule(p, sgf, tgf, srcfn, tgfn,
2345 		                          in_tab, out_tab, outdex);
2346                         /* new module was inserted in list and list may
2347                          * have been moved to new location in memory
2348                          * so do list lookup again.
2349                          */
2350 	                sgf = FETCH_LIST(p->funcs,srcfn);
2351                         tgfn++; /* to account for module inserted in list */
2352 	                tgf = FETCH_LIST(p->funcs,tgfn);
2353 	            }  /* output of one mod points to input of other */
2354 	        } /* end of input loop for inner-most function */
2355 
2356 	    }  /* end of output loop for outer-most function */
2357 
2358 	}  /* end of inner-most function loop */
2359 
2360     }  /* end of outer-most function loop */
2361 
2362 
2363     if(_dxd_exDebug) {
2364 	for (srcfn = 0; srcfn < SIZE_LIST(p->funcs); ++srcfn)  {
2365 	    sgf = FETCH_LIST(p->funcs,srcfn);
2366 	    printf("%s ", sgf->name);
2367 	}
2368 	if(srcfn > 0)
2369 	    printf("\n");
2370     }
2371 }
2372 
2373 static void
ExBuildSendModule(Program * p,gfunc * sgf,gfunc * tgf,int srcfn,int tgfn,int in_tab,int out_tab,int * outdex)2374 ExBuildSendModule(Program *p,
2375 		  gfunc *sgf,
2376 		  gfunc *tgf,
2377 		  int srcfn,
2378 		  int tgfn,
2379 		  int in_tab,
2380 		  int out_tab,
2381 		  int *outdex)
2382 {
2383     gfunc		fnode;
2384     int		 	invars[2];
2385     int			*inArgs;
2386     int			i;
2387     ProgramVariable	pv;
2388     node                *val;
2389     int                 slot,*index;
2390 
2391     ExDebug("*1","In ExBuildSendModule:");
2392     ExDebug("*1",
2393 	 "Sending ouput %d from module %s in procgroup %s at var index %d to:",
2394           out_tab, _dxf_ExGFuncPathToString(sgf), sgf->procgroupid, *outdex);
2395 
2396     ExDebug("*1", "input %d of module %s in procgroup %s ",
2397             in_tab, _dxf_ExGFuncPathToString(tgf), tgf->procgroupid);
2398 
2399     _dxf_ExInitGfunc(&fnode);
2400 
2401     /* will never be calling a function in execGnode for DPSENDs */
2402     fnode.ftype       = F_MODULE;
2403     fnode.func.module = NULL;
2404     fnode.name        = _dxf_ExCopyString/*Local*/ ("DPSEND");
2405     fnode.instance    = 0;
2406     fnode.excache     = CACHE_ALL;
2407     fnode.procgroupid = _dxf_ExCopyString (sgf->procgroupid);
2408 
2409 
2410     /* fix this */
2411     /*  FIXME:  Assumes these are in the same program (common string table)  */
2412     _dxf_ExPathCopy( &fnode.mod_path, &sgf->mod_path );
2413     _dxf_ExPathAppend( p, fnode.name, fnode.instance, &fnode );
2414 
2415     fnode.nin         = 5;
2416     fnode.nout        = 1;
2417     fnode.flags       = MODULE_ERR_CONT;
2418     invars[0]         = tgfn;
2419     invars[1]         = in_tab;
2420 
2421     inArgs = (int*) DXAllocate/*Local*/ (fnode.nin * sizeof (int));
2422 
2423  /* Create PVARs for DPSEND module inputs  */
2424  /* 0th = target module procid */
2425  /* 1st = source module procid */
2426  /* 2nd = target module gfunc# */
2427  /* 3rd = target module input tab nbr */
2428  /* 4th = index# of pvar being sent   */
2429 
2430     for (i = 0; i < fnode.nin - 1 ; ++i)
2431     {
2432 	INIT_PVAR(pv);
2433         if (i == 0) {
2434 	    pv.obj = DXReference ((Object) DXNewString(tgf->procgroupid));
2435         }
2436         else if (i == 1) {
2437 	    pv.obj = DXReference ((Object) DXNewString(sgf->procgroupid));
2438         }
2439         else {
2440             _dxf_ExEvaluateConstants (FALSE);
2441             val = _dxf_ExPCreateConst (TYPE_INT, CATEGORY_REAL, 1,
2442 				       (Pointer) &invars[i-2]);
2443             _dxf_ExEvaluateConstants (TRUE);
2444 	    pv.obj = DXReference ((Object) val->v.constant.obj);
2445 	}
2446 	pv.defined = TRUE;
2447 	APPEND_LIST (ProgramVariable, p->vars, pv);
2448 	inArgs[i] = SIZE_LIST(p->vars) - 1;
2449         APPEND_LIST(int, fnode.inputs, inArgs[i]);
2450         if (i > 2 ) {
2451           ExDebug("*1",
2452 		  "Appending fnode.input at %d with index (%d) to input %d",
2453                   i, inArgs[i], invars[i-2]);
2454         }
2455     }
2456 
2457     /* input object is output (pointed to by outdex) being sent   */
2458     APPEND_LIST(int, fnode.inputs, *outdex);
2459 
2460     /* create an output object */
2461     INIT_PVAR(pv);
2462     pv.obj = NULL;
2463     APPEND_LIST (ProgramVariable, p->vars, pv);
2464     slot = SIZE_LIST(p->vars) - 1;
2465     APPEND_LIST(int, p->wiredvars, slot);
2466     APPEND_LIST(int, fnode.outputs, slot);
2467 
2468 /* also need to update the var index of the input tab of the target gfunc */
2469     index = FETCH_LIST(tgf->inputs,in_tab);
2470     ExDebug("*1","Changing index # of %s/%d from %d to %d in BuildSendModule",
2471             _dxf_ExGFuncPathToString(tgf), in_tab, *index,slot);
2472 
2473     UPDATE_LIST(tgf->inputs,slot,in_tab);
2474     if(tgf->ftype == F_MACRO) {
2475         gfunc *mstartgf;
2476         /* We know that MacroStart is the first module in macro */
2477         mstartgf = FETCH_LIST(tgf->func.subP->funcs, 0);
2478         /* The first input to MacroStart is a count so we must use in_tab+1 */
2479         UPDATE_LIST(mstartgf->inputs, slot, in_tab+1);
2480     }
2481 
2482     INSERT_LIST(gfunc, p->funcs, fnode, srcfn+1);
2483     DXFree ((Pointer) inArgs);
2484 }
2485 
2486 static void
ExRemapVars(Program * p,Program * subP,int * map,int * resolved,char * fname,int inst)2487 ExRemapVars(Program *p, Program *subP, int *map, int *resolved, char *fname, int inst)
2488 {
2489     int i, ilimit, j, jlimit, slot;
2490     gfunc *gf;
2491     ProgramRef *pr;
2492     ProgramVariable *pv;
2493     AsyncVars *avars;
2494 
2495     for (i = 0, ilimit = SIZE_LIST(subP->funcs); i < ilimit; ++i) {
2496         gf = FETCH_LIST(subP->funcs, i);
2497         if(gf->ftype == F_MACRO)
2498             ExRemapVars(p, gf->func.subP, map, resolved, fname, inst);
2499 	for (j = 0, jlimit = SIZE_LIST(gf->inputs); j < jlimit; ++j) {
2500             slot = *FETCH_LIST(gf->inputs, j);
2501 	    if (slot != -1) {
2502                 if (!resolved[slot])
2503 		    _dxf_ExDie ("Executive inconsistency -- ExRemapVars 001");
2504 		UPDATE_LIST(gf->inputs, map[slot], j);
2505 	    }
2506         }
2507         for (j = 0, jlimit = SIZE_LIST(gf->outputs); j < jlimit; ++j) {
2508 	    slot = *FETCH_LIST(gf->outputs, j);
2509 	    if (slot != -1) {
2510 	        if (!resolved[slot])
2511 	            _dxf_ExDie ("Executive inconsistency -- ExRemapVars 002");
2512 	        UPDATE_LIST(gf->outputs, map[slot], j);
2513 	    }
2514         }
2515 	_dxf_ExPathPrepend( subP, fname, inst, gf );
2516 
2517         if(gf->flags & (MODULE_ASYNC | MODULE_ASYNCLOCAL)) {
2518 	    Object new_path;
2519 
2520             slot = *FETCH_LIST(gf->inputs, gf->nin - 2);
2521             pv = FETCH_LIST(p->vars, slot);
2522 
2523 	    new_path = (Object)DXNewString( _dxf_ExGFuncPathToCacheString(gf) );
2524 	    DXReference ((Object)new_path);
2525             if(pv->obj)
2526                 DXDelete((Object)pv->obj);
2527             pv->obj = new_path;
2528         }
2529     }
2530     for (i = 0, ilimit = SIZE_LIST(subP->undefineds); i < ilimit; ++i)
2531     {
2532 	pr = FETCH_LIST(subP->undefineds, i);
2533 	slot = pr->index;
2534         if(slot != -1) {
2535 	    if (!resolved[slot])
2536 	        _dxf_ExDie ("Executive inconsistency -- ExRemapVars 003");
2537             pr->index = map[slot];
2538         }
2539     }
2540 
2541     for (i = 0, ilimit = SIZE_LIST(subP->wiredvars); i < ilimit; ++i)
2542     {
2543 	slot = *FETCH_LIST(subP->wiredvars, i);
2544         if(slot != -1) {
2545 	    if (!resolved[slot])
2546 	        _dxf_ExDie ("Executive inconsistency -- ExRemapVars 003");
2547 	    UPDATE_LIST(subP->wiredvars, map[slot], i);
2548         }
2549     }
2550 
2551     for(i = 0; i < SIZE_LIST(subP->async_vars); i++) {
2552         avars = FETCH_LIST(subP->async_vars, i);
2553         slot = avars->nameindx;
2554         if(slot != -1) {
2555             if (!resolved[slot])
2556                 _dxf_ExDie ("Executive inconsistency -- ExRemapVars 004");
2557             avars->nameindx = map[slot];
2558         }
2559         else avars->nameindx = slot;
2560 
2561         slot = avars->valueindx;
2562         if(slot != -1) {
2563             if (!resolved[slot])
2564                 _dxf_ExDie ("Executive inconsistency -- ExRemapVars 005");
2565             avars->valueindx = map[slot];
2566         }
2567         else avars->valueindx = slot;
2568     }
2569 }
2570 
2571 static void
ExFixAsyncVarName(Program * program,ProgramVariable * pv,char * fname,int instance)2572 ExFixAsyncVarName(Program *program, ProgramVariable *pv, char *fname, int instance)
2573 {
2574     Object saveobj;
2575     char *path;
2576 
2577     if(!pv->obj)
2578         _dxf_ExDie("Executive inconsistency -- bad async variable name");
2579     saveobj = pv->obj;
2580     path = DXGetString((String)pv->obj);
2581     pv->obj = (Object)DXNewString (_dxf_ExCacheStrPrepend(program, fname, instance, path));
2582     DXReference ((Object)pv->obj);
2583     DXDelete((Object)saveobj);
2584 }
2585 
2586 /*----------------------------------------------------------------------------*/
2587 
2588 #define ARRAY_LEN(a) (sizeof(a)/sizeof(a[0]))
2589 
2590 struct mod_name_info {
2591     PseudoKey key;     /* psuedokey:  based on string contents */
2592     char     *str;     /*     value:  actual string value      */
2593     int       index;   /*       key:  string index             */
2594 };
2595 
2596 static lock_type    *mod_name_tables_lock;
2597 static LIST(char *) *mod_name_str_table;     /*  FIXME: Attach to pgm  */
2598 static HashTable     mod_name_hash;          /*  FIXME: Attach to pgm  */
2599 
2600 
2601 
hashCompare(Key search,Element matched)2602 static int hashCompare(Key search, Element matched)
2603 {
2604     return (strcmp(((struct mod_name_info *)search)->str,
2605                   ((struct mod_name_info *)matched)->str));
2606 }
2607 
hashFunc(char * str)2608 static PseudoKey hashFunc(char *str)
2609 {
2610     unsigned long h = 1;
2611     while(*str)
2612        h = (17*h + *str++);
2613     return (PseudoKey)h;
2614 
2615 }
2616 
_dxf_ModNameTablesInit()2617 Error _dxf_ModNameTablesInit()
2618 {
2619   /*  Initialize mutex lock  */
2620   if ((mod_name_tables_lock =
2621        (lock_type *) DXAllocate (sizeof (lock_type))) == NULL) {
2622     _dxf_ExDie ("_dxf_ModNameTablesInit:  lock create failed");
2623     return ERROR;
2624   }
2625 
2626   DXcreate_lock(mod_name_tables_lock, NULL);
2627 
2628   /*  FIXME:  Attach this list and its hash to the program structure  */
2629   mod_name_str_table = DXAllocate( sizeof( LIST(char *) ) );
2630 
2631   INIT_LIST(*mod_name_str_table);
2632 
2633   mod_name_hash = DXCreateHash( sizeof( struct mod_name_info ), NULL,
2634                                 hashCompare );
2635   if ( !mod_name_hash ) {
2636     _dxf_ExDie("_dxf_ModNameTablesInit:  hash create failed");
2637     return ERROR;
2638   }
2639   return OK;
2640 }
2641 
_dxf_ExGraphInsertAndLookupName(Program * p,char name[])2642 static uint32 _dxf_ExGraphInsertAndLookupName( Program *p, char name[] )
2643 {
2644   uint32 i;
2645   char  *new;
2646   struct mod_name_info search, *found, info;
2647 
2648   DXlock (mod_name_tables_lock, 0);
2649 
2650   /*  See if string is already in the list (via hash table)  */
2651   search.key = hashFunc(name);
2652   search.str = name;
2653 
2654   if ((found = (struct mod_name_info *)
2655                DXQueryHashElement( mod_name_hash,
2656                                    (Pointer)&search)) != NULL)
2657   {
2658     DXunlock (mod_name_tables_lock, 0);
2659     return found->index;
2660   }
2661 
2662   /*  It's not there, so add it to the list, and to the lookup hash  */
2663   new = (char *) DXAllocate (strlen (name) + 1);
2664   if ( !new ) {
2665     _dxf_ExDie("_dxf_ExGraphInsertAndLookupName:  DXAllocate failed");
2666     DXunlock (mod_name_tables_lock, 0);
2667     return (uint32) -1;
2668   }
2669   strcpy (new, name);
2670 
2671   APPEND_LIST( char *, *mod_name_str_table, new );
2672 
2673   i = SIZE_LIST( *mod_name_str_table ) - 1;
2674 
2675   info.key   = hashFunc( name );
2676   info.str   = new;
2677   info.index = i;
2678 
2679   if ( !DXInsertHashElement( mod_name_hash, (Pointer)&info) ) {
2680     _dxf_ExDie("_dxf_ExGraphInsertAndLookupName:  DXInsertHashElement failed");
2681     DXunlock (mod_name_tables_lock, 0);
2682     return (uint32) -1;
2683   }
2684 
2685   DXunlock (mod_name_tables_lock, 0);
2686 
2687   return info.index;
2688 }
2689 
2690 /*  FIXME:  These are duplicated in path.c  */
2691 #define        EX_I_SEP        ':'             /* instance #   separator       */
2692 #define        EX_M_SEP        '/'             /* macro/module separator       */
2693 
2694 
_dxf_BuildInstanceNumString(int instance)2695 static char *_dxf_BuildInstanceNumString(int instance)
2696 {
2697     static char localstr[10];
2698     char *tail = localstr;
2699     int np;
2700 
2701     if (instance < 0 || instance > 999)
2702     {
2703     	/* sprintf automatically puts a \0 at the end of a string
2704     	   so why print a second one? */
2705         /* sprintf(tail, "%d\0", instance); */
2706         sprintf(tail, "%d", instance);
2707         tail += strlen(tail);
2708     }
2709     else if (instance > 99)
2710     {
2711        np = instance / 100;
2712        *(tail++) = np + '0';
2713        instance -= np * 100;
2714        np = instance / 10;
2715        *(tail++) = np + '0';
2716        instance -= np * 10;
2717        *(tail++) = instance + '0';
2718     }
2719     else if (instance > 9)
2720     {
2721        np = instance / 10;
2722        *(tail++) = np + '0';
2723        instance -= np * 10;
2724        *(tail++) = instance + '0';
2725     }
2726     else
2727        *(tail++) = instance + '0';
2728     *(tail) = '\0';
2729 
2730     return localstr;
2731 }
2732 
_dxf_GetInstanceNumStringLen(int instance)2733 static int _dxf_GetInstanceNumStringLen(int instance)
2734 {
2735   if ( instance < 0 || instance > 999 )
2736     return strlen( _dxf_BuildInstanceNumString( instance ) );
2737   else if ( instance > 99 )
2738     return 3;
2739   else if ( instance > 9 )
2740     return 2;
2741   else
2742     return 1;
2743 }
2744 
2745 
_dxf_ExPathStringLen(ModPath * path)2746 static int _dxf_ExPathStringLen( ModPath *path )
2747 {
2748   int32 i;
2749   int      len = 0;
2750 
2751   for ( i = path->num_comp-1; i >= 0; i-- )
2752     len += 1 /*EX_M_SEP*/ +
2753            strlen( *FETCH_LIST( *mod_name_str_table, path->modules[i] ) ) +
2754            1 /*EX_I_SEP*/ +
2755            _dxf_GetInstanceNumStringLen( path->instances[i] ) +
2756            1 /*'\0'*/;
2757 
2758   return len;
2759 }
2760 
_dxf_ExPathToStringBuf(ModPath * path,char * path_str)2761 static void _dxf_ExPathToStringBuf( ModPath *path, char *path_str )
2762 {
2763   int32    i;
2764   char    *p = path_str;
2765   char    *module_name;
2766 
2767   for ( i = path->num_comp-1; i >= 0; i-- ) {
2768     module_name = *FETCH_LIST( *mod_name_str_table, path->modules[i] );
2769     p[0] = EX_M_SEP;
2770     strcpy( p+1, module_name );
2771     p += strlen(p);
2772     p[0] = EX_I_SEP;
2773     strcpy( p+1, _dxf_BuildInstanceNumString( path->instances[i] ) );
2774     p += strlen(p);
2775   }
2776 }
2777 
_dxf_ExPathToString(ModPath * path)2778 char *_dxf_ExPathToString( ModPath *path )
2779 {
2780   static char str[ MAX_PATH_STR_LEN ];
2781   int len;
2782 
2783   len = _dxf_ExPathStringLen( path );
2784 
2785   if ( len >= sizeof(str) ) {
2786     _dxf_ExDie ("_dxf_ExPathToString:  Path is too long");
2787     return NULL;
2788   }
2789 
2790   _dxf_ExPathToStringBuf( path, str );
2791   return str;
2792 }
2793 
2794 static char *
int16tohex(char * buf,int16 l)2795 int16tohex (char *buf, int16 l)
2796 {
2797     static char *htab = "0123456789abcdef";
2798 
2799     buf[4] = '\0';
2800     buf[3] = htab[l & 0xf]; l >>= 4;
2801     buf[2] = htab[l & 0xf]; l >>= 4;
2802     buf[1] = htab[l & 0xf]; l >>= 4;
2803     buf[0] = htab[l & 0xf];
2804 
2805     return (buf + 4);
2806 }
2807 
2808 static int16
hextoint16(char * buf)2809 hextoint16 (char *buf)
2810 {
2811     static char *htab = "0123456789abcdef";
2812     int16  val = 0;
2813     int    i;
2814 
2815     for ( i = 0; i < 4; i++ )
2816       val = ( val << 4 ) | ( strchr( htab, buf[i] ) - htab );
2817     return val;
2818 }
2819 
2820 #define MODPATH_COMP_STR_LEN  \
2821            (sizeof(_dxd_exCurrentFunc->mod_path.modules  [0]) * 2 + \
2822             sizeof(_dxd_exCurrentFunc->mod_path.instances[0]) * 2)
2823 
2824 
2825 /* compare the macro portion of two module ids
2826  */
DXCompareModuleMacroBase(Pointer id1,Pointer id2)2827 Error DXCompareModuleMacroBase(Pointer id1, Pointer id2)
2828 {
2829     int len;
2830     char *str1 = (char *)id1;
2831     char *str2 = (char *)id2;
2832 
2833     if (str1 == NULL || str2 == NULL)
2834        return ERROR;
2835 
2836     /*  Module ID's are hexified ModPaths: <mod1><inst1><mod2><inst2>...,  */
2837     /*    stored from highest call level to lowest.                        */
2838     len = strlen(str1);
2839     if ( len < MODPATH_COMP_STR_LEN )
2840        return ERROR;
2841 
2842     return ((strncmp(str1, str2,
2843                      len - MODPATH_COMP_STR_LEN) == 0) ? OK : ERROR);
2844 }
2845 
2846 /* obtain a string for the i'th component of the module ID (e.g. "GetLocal")
2847  */
DXGetModuleComponentName(Pointer id,int index)2848 const char *DXGetModuleComponentName(Pointer id, int index)
2849 {
2850   int   i;
2851   int   len = strlen(id);
2852   int   num_comp;
2853   char *str = (char *)id;
2854 
2855   /*  First, determine which component.  Support Python-like negative  */
2856   /*    indices to count back from the end.                            */
2857   if ( !str || ( len % MODPATH_COMP_STR_LEN ) != 0 )
2858     return NULL;
2859 
2860   num_comp = strlen(str) / MODPATH_COMP_STR_LEN;
2861 
2862   if (( index >= num_comp ) || ( index < -num_comp ))
2863     return NULL;
2864   else if ( index >= 0 )
2865     i = index;
2866   else
2867     i = num_comp + index;
2868   i *= MODPATH_COMP_STR_LEN;
2869 
2870   return *FETCH_LIST( *mod_name_str_table, hextoint16( &str[i] ) );
2871 }
2872 
2873 
_dxf_ExPathCacheStringLen(ModPath * path)2874 static int _dxf_ExPathCacheStringLen( ModPath *path )
2875 {
2876   return (path->num_comp * MODPATH_COMP_STR_LEN);
2877 }
2878 
2879 
_dxf_ExPathToCacheStringBuf(ModPath * path,char * path_str)2880 static void _dxf_ExPathToCacheStringBuf( ModPath *path, char *path_str )
2881 {
2882   int32    i;
2883   char    *p = path_str;
2884 
2885   for ( i = path->num_comp-1; i >= 0; i-- ) {
2886     p = int16tohex( p, path->modules[i] );
2887     p = int16tohex( p, path->instances[i] );
2888   }
2889 }
2890 
_dxf_ExPathToCacheString(ModPath * path)2891 char *_dxf_ExPathToCacheString( ModPath *path )
2892 {
2893   static char str[ MAX_PATH_STR_LEN ];
2894 
2895   _dxf_ExPathToCacheStringBuf( path, str );
2896   return str;
2897 }
2898 
_dxf_ExCacheStrPrepend(Program * program,char * name,int instance,char * path)2899 static char *_dxf_ExCacheStrPrepend( Program *program,
2900                                      char *name, int instance, char *path )
2901 {
2902   static char str[ MAX_PATH_STR_LEN ];
2903   static char tmp[ MAX_PATH_STR_LEN ];
2904   char        *p = str, *colon;
2905 
2906   /*  This oddball cache-string hacking rtn is only used in one place.  */
2907 
2908   /*  Prepend the IDs for the module name and instance as specified.  */
2909   p = int16tohex( p, _dxf_ExGraphInsertAndLookupName( program, name ) );
2910   p = int16tohex( p, instance );
2911 
2912   strcpy(tmp, path);
2913   /*
2914   if (tmp[0] != '/')
2915       s = tmp;
2916   else
2917       s = tmp + 1;
2918   */
2919 
2920   colon = strchr(tmp, ':');
2921   if (colon)
2922       *colon = '\0';
2923 
2924   p = int16tohex( p, _dxf_ExGraphInsertAndLookupName( program, tmp+1 ));
2925 
2926   if (colon)
2927       p = int16tohex( p, atoi(colon+1));
2928   else
2929       p = int16tohex( p, 0);
2930 
2931   /*
2932   strcpy( p, path );
2933   */
2934   return str;
2935 }
2936 
2937 #ifdef TESTING
_dxf_ExPathPrint(Program * p,gfunc * fnode,char * header)2938 static void _dxf_ExPathPrint( Program *p, gfunc *fnode, char *header )
2939 {
2940   int i;
2941   ModPath *path = &fnode->mod_path;
2942 
2943   if ( header )
2944     printf( "\t%s:  ", header );
2945   else
2946     printf( "\t" );
2947 
2948   for ( i = path->num_comp-1; i >= 0; i-- )
2949     printf( "/%s:%d",
2950             *FETCH_LIST( *mod_name_str_table, path->modules[i] ),
2951             path->instances[i] );
2952   printf( "\n" );
2953 }
2954 #endif
2955 
_dxf_ExPathSet(Program * p,char fname[],int instance,gfunc * fnode)2956 static void _dxf_ExPathSet( Program *p, char fname[], int instance, gfunc *fnode )
2957 {
2958   uint32   fname_key;
2959   ModPath *path = &fnode->mod_path;
2960 
2961   /*  Note, we store paths in reverse order in mod_path,  */
2962   /*    so prepend is actually append.                    */
2963   fname_key = _dxf_ExGraphInsertAndLookupName( p, fname );
2964 
2965   path->modules  [ 0 ] = fname_key;
2966   path->instances[ 0 ] = instance;
2967   path->num_comp = 1;
2968 
2969 #ifdef TESTING
2970   _dxf_ExPathPrint( p, fnode, "_dxf_ExPathSet" );
2971 #endif
2972 }
2973 
2974 
2975 
2976 
_dxf_ExPathPrepend(Program * p,char fname[],int instance,gfunc * fnode)2977 static void _dxf_ExPathPrepend( Program *p, char fname[], int instance,
2978                                 gfunc *fnode )
2979 {
2980   uint32   fname_key;
2981   ModPath *path = &fnode->mod_path;
2982 
2983   /*  Note, we store paths in reverse order in mod_path,  */
2984   /*    so prepend is fast (it's an append).              */
2985   if ( path->num_comp >= ARRAY_LEN( path->modules ) )
2986   {
2987     DXSetError(ERROR_NOT_IMPLEMENTED, "gfunc execution path too deep");
2988     printf( "gfunc execution path too deep: %d", path->num_comp );
2989     _dxf_ExDie("gfunc execution path too deep");
2990     return;
2991   }
2992 
2993   fname_key = _dxf_ExGraphInsertAndLookupName( p, fname );
2994 
2995   path->modules  [ path->num_comp ] = fname_key;
2996   path->instances[ path->num_comp ] = instance;
2997   path->num_comp++;
2998 
2999 #ifdef TESTING
3000   _dxf_ExPathPrint( p, fnode, "_dxf_ExPathPrepend" );
3001 #endif
3002 }
3003 
_dxf_ExPathAppend(Program * p,char fname[],int instance,gfunc * fnode)3004 static void _dxf_ExPathAppend( Program *p, char fname[], int instance,
3005                                gfunc *fnode )
3006 {
3007   uint32   fname_key;
3008   ModPath *path = &fnode->mod_path;
3009 
3010   /*  Note, we store paths in reverse order in mod_path,  */
3011   /*    so append is really a prepend.                    */
3012   if ( path->num_comp >= ARRAY_LEN( path->modules ) )
3013   {
3014     DXSetError(ERROR_NOT_IMPLEMENTED, "gfunc execution path too deep");
3015     printf( "gfunc execution path too deep: %d", path->num_comp );
3016     _dxf_ExDie("gfunc execution path too deep");
3017     return;
3018   }
3019 
3020   fname_key = _dxf_ExGraphInsertAndLookupName( p, fname );
3021 
3022   memmove( &path->modules[1], &path->modules[0],
3023            sizeof(path->modules[0]) * path->num_comp );
3024 
3025   path->modules  [ 0 ] = fname_key;
3026   path->instances[ 0 ] = instance;
3027   path->num_comp++;
3028 
3029 #ifdef TESTING
3030   _dxf_ExPathPrint( p, fnode, "_dxf_ExPathAppend" );
3031 #endif
3032 }
3033 
_dxf_ExPathsEqual(ModPath * p1,ModPath * p2)3034 int _dxf_ExPathsEqual( ModPath *p1, ModPath *p2 )
3035 {
3036   int cmp;
3037 
3038   /*  We use the same string table for all ModPaths, so this comparison  */
3039   /*    is quick and simple.  f                                          */
3040   cmp = ( p1->num_comp == p2->num_comp ) &&
3041         ( memcmp( p1->modules, p2->modules,
3042                   sizeof(p1->modules[0]) * p1->num_comp   ) == 0 ) &&
3043         ( memcmp( p1->instances, p2->instances,
3044                   sizeof(p1->instances[0]) * p1->num_comp ) == 0 );
3045   return cmp;
3046 }
3047 
_dxf_ExPathCopy(ModPath * dest,ModPath * src)3048 void _dxf_ExPathCopy( ModPath *dest, ModPath *src )
3049 {
3050   memcpy( dest, src, sizeof( *dest ) );
3051 }
3052 
_dxf_ExGFuncPathToString(gfunc * fnode)3053 char *_dxf_ExGFuncPathToString( gfunc *fnode )
3054 {
3055   return _dxf_ExPathToString( &fnode->mod_path );
3056 }
3057 
_dxf_ExGFuncPathToStringBuf(gfunc * fnode,char * path_str)3058 static void _dxf_ExGFuncPathToStringBuf( gfunc *fnode, char *path_str )
3059 {
3060   _dxf_ExPathToStringBuf( &fnode->mod_path, path_str );
3061 }
3062 
_dxf_ExGFuncPathToCacheStringBuf(gfunc * fnode,char * path_str)3063 static void _dxf_ExGFuncPathToCacheStringBuf( gfunc *fnode, char *path_str )
3064 {
3065   _dxf_ExPathToCacheStringBuf( &fnode->mod_path, path_str );
3066 }
3067 
_dxf_ExGFuncPathToCacheString(gfunc * fnode)3068 char *_dxf_ExGFuncPathToCacheString( gfunc *fnode )
3069 {
3070   return _dxf_ExPathToCacheString( &fnode->mod_path );
3071 }
3072 
3073