1 /* struct::tree - critcl - layer 3 definitions.
2  *
3  * -> Method functions.
4  *    Implementations for all tree methods.
5  */
6 
7 #include <ctype.h>
8 #include <string.h>
9 #include "arc.h"
10 #include "attr.h"
11 #include "graph.h"
12 #include "methods.h"
13 #include "nacommon.h"
14 #include "node.h"
15 #include "util.h"
16 #include "walk.h"
17 
18 /* ..................................................
19  * Handling of all indices, numeric and 'end-x' forms.  Copied straight out of
20  * the Tcl core as this is not exported through the public API.
21  */
22 
23 static int TclGetIntForIndex (Tcl_Interp* interp, Tcl_Obj* objPtr,
24 			      int endValue, int* indexPtr);
25 
26 /* .................................................. */
27 
28 #define FAIL(x) if (!(x)) { return TCL_ERROR; }
29 
30 /* .................................................. */
31 /*
32  *---------------------------------------------------------------------------
33  *
34  * gm_GASSIGN --
35  *
36  *	Copies the argument graph over into this graph object. Uses direct
37  *	access to internal data structures for matching graph objects, and
38  *	goes through a serialize/deserialize combination otherwise.
39  *
40  * Results:
41  *	A standard Tcl result code.
42  *
43  * Side effects:
44  *	Only internal, memory allocation changes ...
45  *
46  *---------------------------------------------------------------------------
47  */
48 
49 int
gm_GASSIGN(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)50 gm_GASSIGN (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
51 {
52     /* Syntax: graph =   source
53      *	       [0]   [1] [2]
54      */
55 
56     if (objc != 3) {
57 	Tcl_WrongNumArgs (interp, 2, objv, "source");
58 	return TCL_ERROR;
59     }
60 
61     return g_ms_assign (interp, g, objv [2]);
62 }
63 
64 /*
65  *---------------------------------------------------------------------------
66  *
67  * gm_GSET --
68  *
69  *	Copies this graph over into the argument graph. Uses direct access to
70  *	internal data structures for matching graph objects, and goes through a
71  *	serialize/deserialize combination otherwise.
72  *
73  * Results:
74  *	A standard Tcl result code.
75  *
76  * Side effects:
77  *	Only internal, memory allocation changes ...
78  *
79  *---------------------------------------------------------------------------
80  */
81 
82 int
gm_GSET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)83 gm_GSET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
84 {
85     /* Syntax: graph --> dest(ination)
86      *	       [0]  [1]  [2]
87      */
88 
89     if (objc != 3) {
90 	Tcl_WrongNumArgs (interp, 2, objv, "dest");
91 	return TCL_ERROR;
92     }
93 
94     return g_ms_set (interp, objv[0], g, objv [2]);
95 }
96 
97 /*
98  *---------------------------------------------------------------------------
99  *
100  * gm_APPEND --
101  *
102  *	Appends a value to an attribute of the graph.
103  *	May create the attribute.
104  *
105  * Results:
106  *	A standard Tcl result code.
107  *
108  * Side effects:
109  *	May release and allocate memory.
110  *
111  *---------------------------------------------------------------------------
112  */
113 
114 int
gm_APPEND(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)115 gm_APPEND (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
116 {
117     /* Syntax: graph append key value
118      *	       [0]  [1]	    [2]	[3]
119      */
120 
121     if (objc != 4) {
122 	Tcl_WrongNumArgs (interp, 2, objv, "key value");
123 	return TCL_ERROR;
124     }
125 
126     g_attr_extend (&g->attr);
127     g_attr_append  (g->attr, interp, objv[2], objv[3]);
128     return TCL_OK;
129 }
130 
131 /*
132  *---------------------------------------------------------------------------
133  *
134  * gm_ARCS --
135  *
136  *
137  *
138  *
139  * Results:
140  *	A standard Tcl result code.
141  *
142  * Side effects:
143  *	May release and allocate memory.
144  *
145  *---------------------------------------------------------------------------
146  */
147 
148 int
gm_ARCS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)149 gm_ARCS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
150 {
151     /* Syntax: graph arcs                       | all arcs
152      *         graph arcs -in        NODE...    | arcs end in node in list
153      *         graph arcs -out       NODE...    | arcs start in node in list
154      *         graph arcs -adj       NODE...    | arcs start|end in node in list
155      *         graph arcs -inner     NODE...    | arcs start&end in node in list
156      *         graph arcs -embedding NODE...    | arcs start^end in node in list
157      *         graph arcs -key       KEY        | arcs have attribute KEY
158      *         graph arcs -value     VALUE      | arcs have KEY and VALUE
159      *         graph arcs -filter    CMDPREFIX  | arcs for which CMD returns True.
160      *	       [0]   [1]  [2]        [3]
161      *
162      * -value requires -key.
163      * -in/-out/-adj/-inner/-embedding are exclusive.
164      * Each option can be used at most once.
165      */
166 
167     return gc_filter (0, interp, objc, objv, &g->arcs,
168 		      (GN_GET_GC*) ga_get_arc, g);
169 }
170 
171 /*
172  *---------------------------------------------------------------------------
173  *
174  * gm_arc_APPEND --
175  *
176  *
177  *
178  *
179  * Results:
180  *	A standard Tcl result code.
181  *
182  * Side effects:
183  *	May release and allocate memory.
184  *
185  *---------------------------------------------------------------------------
186  */
187 
188 int
gm_arc_APPEND(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)189 gm_arc_APPEND (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
190 {
191     /* Syntax: graph arc append ARC KEY VALUE
192      *	       [0]   [1] [2]    [3] [4] [5]
193      */
194 
195     GA* a;
196 
197     if (objc != 6) {
198 	Tcl_WrongNumArgs (interp, 3, objv, "arc key value");
199 	return TCL_ERROR;
200     }
201 
202     a = ga_get_arc (g, objv [3], interp, objv [0]);
203     FAIL (a);
204 
205     g_attr_extend (&a->base.attr);
206     g_attr_append  (a->base.attr, interp, objv[4], objv[5]);
207     return TCL_OK;
208 }
209 
210 /*
211  *---------------------------------------------------------------------------
212  *
213  * gm_arc_GETUNWEIGH --
214  *
215  *
216  *
217  *
218  * Results:
219  *	A standard Tcl result code.
220  *
221  * Side effects:
222  *	May release and allocate memory.
223  *
224  *---------------------------------------------------------------------------
225  */
226 
227 int
gm_arc_GETUNWEIGH(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)228 gm_arc_GETUNWEIGH (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
229 {
230     /* Syntax: graph arc getunweighted
231      *	       [0]   [1] [2]
232      */
233 
234     GA* a;
235     Tcl_Obj** rv;
236     int       rc;
237 
238     if (objc != 3) {
239 	Tcl_WrongNumArgs (interp, 3, objv, NULL);
240 	return TCL_ERROR;
241     }
242 
243     rv = NALLOC (g->arcs.n, Tcl_Obj*);
244     rc = 0;
245 
246     for (a = (GA*) g->arcs.first; a ; a = (GA*) a->base.next) {
247 	if (a->weight) continue;
248 
249 	ASSERT_BOUNDS (rc, g->arcs.n);
250 
251 	rv [rc++] = a->base.name;
252     }
253 
254     Tcl_SetObjResult (interp, Tcl_NewListObj (rc, rv));
255 
256     ckfree ((char*) rv);
257     return TCL_OK;
258 }
259 
260 /*
261  *---------------------------------------------------------------------------
262  *
263  * gm_arc_GETWEIGHT --
264  *
265  *
266  *
267  *
268  * Results:
269  *	A standard Tcl result code.
270  *
271  * Side effects:
272  *	May release and allocate memory.
273  *
274  *---------------------------------------------------------------------------
275  */
276 
277 int
gm_arc_GETWEIGHT(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)278 gm_arc_GETWEIGHT (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
279 {
280     /* Syntax: graph arc getweight ARC
281      *	       [0]   [1] [2]       [3]
282      */
283 
284     GA* a;
285 
286     if (objc != 4) {
287 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
288 	return TCL_ERROR;
289     }
290 
291     a = ga_get_arc (g, objv [3], interp, objv [0]);
292     FAIL (a);
293 
294     if (!a->weight) {
295 	Tcl_AppendResult (interp,
296 			  "arc \"", Tcl_GetString (a->base.name), "\" has no weight",
297 			  NULL);
298 	return TCL_ERROR;
299     }
300 
301     Tcl_SetObjResult (interp, a->weight);
302     return TCL_OK;
303 }
304 
305 /*
306  *---------------------------------------------------------------------------
307  *
308  * gm_arc_SETUNWEIGH --
309  *
310  *
311  *
312  *
313  * Results:
314  *	A standard Tcl result code.
315  *
316  * Side effects:
317  *	May release and allocate memory.
318  *
319  *---------------------------------------------------------------------------
320  */
321 
322 int
gm_arc_SETUNWEIGH(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)323 gm_arc_SETUNWEIGH (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
324 {
325     /* Syntax: graph arc setunweighted ?weight?
326      *	       [0]   [1] [2]           [3]
327      */
328 
329     GA* a;
330     Tcl_Obj* weight;
331 
332     if ((objc != 3) && (objc != 4)) {
333 	Tcl_WrongNumArgs (interp, 3, objv, "?weight?");
334 	return TCL_ERROR;
335     }
336 
337     if (objc == 4) {
338 	weight = objv [3];
339     } else {
340 	weight = Tcl_NewIntObj (0);
341     }
342 
343     for (a = (GA*) g->arcs.first; a ; a = (GA*) a->base.next) {
344 	if (a->weight) continue;
345 
346 	a->weight = weight;
347 	Tcl_IncrRefCount (weight);
348     }
349 
350     return TCL_OK;
351 }
352 
353 /*
354  *---------------------------------------------------------------------------
355  *
356  * gm_arc_SETWEIGHT --
357  *
358  *
359  *
360  *
361  * Results:
362  *	A standard Tcl result code.
363  *
364  * Side effects:
365  *	May release and allocate memory.
366  *
367  *---------------------------------------------------------------------------
368  */
369 
370 int
gm_arc_SETWEIGHT(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)371 gm_arc_SETWEIGHT (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
372 {
373     /* Syntax: graph arc setweight ARC WEIGHT
374      *	       [0]   [1] [2]       [3] [4]
375      */
376 
377     GA* a;
378 
379     if (objc != 5) {
380 	Tcl_WrongNumArgs (interp, 3, objv, "arc weight");
381 	return TCL_ERROR;
382     }
383 
384     a = ga_get_arc (g, objv [3], interp, objv [0]);
385     FAIL (a);
386 
387     if (a->weight) {
388 	Tcl_DecrRefCount (a->weight);
389     }
390 
391     a->weight = objv [4];
392     Tcl_IncrRefCount (a->weight);
393 
394     Tcl_SetObjResult (interp, a->weight);
395     return TCL_OK;
396 }
397 
398 /*
399  *---------------------------------------------------------------------------
400  *
401  * gm_arc_UNSETWEIGH --
402  *
403  *
404  *
405  *
406  * Results:
407  *	A standard Tcl result code.
408  *
409  * Side effects:
410  *	May release and allocate memory.
411  *
412  *---------------------------------------------------------------------------
413  */
414 
415 int
gm_arc_UNSETWEIGH(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)416 gm_arc_UNSETWEIGH (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
417 {
418     /* Syntax: graph arc unsetweight ARC
419      *	       [0]   [1] [2]         [3]
420      */
421 
422     GA* a;
423 
424     if (objc != 4) {
425 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
426 	return TCL_ERROR;
427     }
428 
429     a = ga_get_arc (g, objv [3], interp, objv [0]);
430     FAIL (a);
431 
432     if (a->weight) {
433 	Tcl_DecrRefCount (a->weight);
434 	a->weight = NULL;
435     }
436 
437     return TCL_OK;
438 }
439 
440 /*
441  *---------------------------------------------------------------------------
442  *
443  * gm_arc_HASWEIGHT --
444  *
445  *
446  *
447  *
448  * Results:
449  *	A standard Tcl result code.
450  *
451  * Side effects:
452  *	May release and allocate memory.
453  *
454  *---------------------------------------------------------------------------
455  */
456 
457 int
gm_arc_HASWEIGHT(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)458 gm_arc_HASWEIGHT (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
459 {
460     /* Syntax: graph arc hasweight ARC
461      *	       [0]   [1] [2]       [3]
462      */
463 
464     GA* a;
465 
466     if (objc != 4) {
467 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
468 	return TCL_ERROR;
469     }
470 
471     a = ga_get_arc (g, objv [3], interp, objv [0]);
472     FAIL (a);
473 
474     Tcl_SetObjResult (interp, Tcl_NewIntObj (a->weight != NULL));
475     return TCL_OK;
476 }
477 
478 /*
479  *---------------------------------------------------------------------------
480  *
481  * gm_arc_WEIGHTS --
482  *
483  *
484  *
485  *
486  * Results:
487  *	A standard Tcl result code.
488  *
489  * Side effects:
490  *	May release and allocate memory.
491  *
492  *---------------------------------------------------------------------------
493  */
494 
495 int
gm_arc_WEIGHTS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)496 gm_arc_WEIGHTS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
497 {
498     /* Syntax: graph arc weights
499      *	       [0]   [1] [2]
500      */
501 
502     GA* a;
503     Tcl_Obj** rv;
504     int       rc, rcmax;
505 
506     if (objc != 3) {
507 	Tcl_WrongNumArgs (interp, 3, objv, NULL);
508 	return TCL_ERROR;
509     }
510 
511     rcmax = 2 * g->arcs.n;
512     rv = NALLOC (rcmax, Tcl_Obj*);
513     rc = 0;
514 
515     for (a = (GA*) g->arcs.first; a ; a = (GA*) a->base.next) {
516 	if (!a->weight) continue;
517 
518 	ASSERT_BOUNDS (rc,   rcmax);
519 	ASSERT_BOUNDS (rc+1, rcmax);
520 
521 	rv [rc++] = a->base.name;
522 	rv [rc++] = a->weight;
523     }
524 
525     Tcl_SetObjResult (interp, Tcl_NewListObj (rc, rv));
526 
527     ckfree ((char*) rv);
528     return TCL_OK;
529 }
530 
531 /*
532  *---------------------------------------------------------------------------
533  *
534  * gm_arc_ATTR --
535  *
536  *
537  *
538  *
539  * Results:
540  *	A standard Tcl result code.
541  *
542  * Side effects:
543  *	May release and allocate memory.
544  *
545  *---------------------------------------------------------------------------
546  */
547 
548 int
gm_arc_ATTR(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)549 gm_arc_ATTR (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
550 {
551     /* Syntax: graph arc attr KEY
552      *         graph arc attr KEY -arcs   LIST
553      *         graph arc attr KEY -glob   PATTERN
554      *         graph arc attr KEY -regexp PATTERN
555      *	       [0]   [1] [2]  [3] [4]     [5]
556      */
557 
558     static const char* types [] = {
559 	"-arcs", "-glob","-regexp", NULL
560     };
561     int modes [] = {
562 	A_LIST, A_GLOB, A_REGEXP
563     };
564 
565     int      mode;
566     Tcl_Obj* detail;
567 
568     if ((objc != 4) && (objc != 6)) {
569 	Tcl_WrongNumArgs (interp, 3, objv,
570 			  "key ?-arcs list|-glob pattern|-regexp pattern?");
571 	return TCL_ERROR;
572     }
573 
574     if (objc != 6) {
575 	detail = NULL;
576 	mode   = A_NONE;
577     } else {
578 	detail = objv [5];
579 	if (Tcl_GetIndexFromObj (interp, objv [4], types, "type",
580 				 0, &mode) != TCL_OK) {
581 	    return TCL_ERROR;
582 	}
583 	mode = modes [mode];
584     }
585 
586     return gc_attr (&g->arcs, mode, detail, interp, objv[3],
587 		    (GN_GET_GC*) ga_get_arc, g);
588 }
589 
590 /*
591  *---------------------------------------------------------------------------
592  *
593  * gm_arc_DELETE --
594  *
595  *
596  *
597  *
598  * Results:
599  *	A standard Tcl result code.
600  *
601  * Side effects:
602  *	May release and allocate memory.
603  *
604  *---------------------------------------------------------------------------
605  */
606 
607 int
gm_arc_DELETE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)608 gm_arc_DELETE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
609 {
610     /* Syntax: graph arc  delete ARC ARC...
611      *	       [0]   [1]  [2]    [3] [4+]
612      */
613 
614     GA* a;
615     int i, new;
616     Tcl_HashTable seen;
617 
618     if (objc < 4) {
619 	Tcl_WrongNumArgs (interp, 3, objv, "arc arc...");
620 	return TCL_ERROR;
621     }
622 
623     Tcl_InitHashTable (&seen, TCL_STRING_KEYS);
624     for (i=3; i<objc; i++) {
625 	a = ga_get_arc (g, objv[i], interp, objv[0]);
626 	if (a && (Tcl_FindHashEntry (&seen, Tcl_GetString (objv[i])) != NULL)) {
627 	    ga_err_missing (interp, objv[i], objv[0]);
628 	    a = NULL;
629 	}
630 	if (a == NULL) {
631 	    Tcl_DeleteHashTable (&seen);
632 	}
633 	FAIL (a);
634 	Tcl_CreateHashEntry (&seen, Tcl_GetString (objv[i]), &new);
635     }
636     Tcl_DeleteHashTable (&seen);
637 
638     for (i=3; i<objc; i++) {
639 	a = ga_get_arc (g, objv[i], interp, objv[0]);
640 	ga_delete (a);
641     }
642     return TCL_OK;
643 }
644 
645 /*
646  *---------------------------------------------------------------------------
647  *
648  * gm_arc_EXISTS --
649  *
650  *
651  *
652  *
653  * Results:
654  *	A standard Tcl result code.
655  *
656  * Side effects:
657  *	May release and allocate memory.
658  *
659  *---------------------------------------------------------------------------
660  */
661 
662 int
gm_arc_EXISTS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)663 gm_arc_EXISTS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
664 {
665     /* Syntax: graph arc exists NAME
666      *	       [0]   [1] [2]    [3]
667      */
668 
669     GA* a;
670 
671     if (objc != 4) {
672 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
673 	return TCL_ERROR;
674     }
675 
676     a = ga_get_arc (g, objv [3], NULL, NULL);
677 
678     Tcl_SetObjResult (interp, Tcl_NewIntObj (a != NULL));
679     return TCL_OK;
680 }
681 
682 /*
683  *---------------------------------------------------------------------------
684  *
685  * gm_arc_FLIP --
686  *
687  *
688  *
689  *
690  * Results:
691  *	A standard Tcl result code.
692  *
693  * Side effects:
694  *	May release and allocate memory.
695  *
696  *---------------------------------------------------------------------------
697  */
698 
699 int
gm_arc_FLIP(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)700 gm_arc_FLIP (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
701 {
702     /* Syntax: graph arc flip ARC
703      *	       [0]   [1] [2]  [3]
704      */
705 
706     GA*	a;
707     GN* src;
708     GN* dst;
709 
710     if (objc != 4) {
711 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
712 	return TCL_ERROR;
713     }
714 
715     a = ga_get_arc (g, objv [3], interp, objv [0]);
716     FAIL (a);
717 
718     src = a->start->n;
719     dst = a->end->n;
720 
721     if (src != dst) {
722 	ga_mv_src (a, dst);
723 	ga_mv_dst (a, src);
724     }
725     return TCL_OK;
726 }
727 
728 /*
729  *---------------------------------------------------------------------------
730  *
731  * gm_arc_GET --
732  *
733  *
734  *
735  *
736  * Results:
737  *	A standard Tcl result code.
738  *
739  * Side effects:
740  *	May release and allocate memory.
741  *
742  *---------------------------------------------------------------------------
743  */
744 
745 int
gm_arc_GET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)746 gm_arc_GET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
747 {
748     /* Syntax: graph arc get ARC KEY
749      *	       [0]   [1] [2] [3] [4]
750      */
751 
752     GA* a;
753 
754     if (objc != 5) {
755 	Tcl_WrongNumArgs (interp, 3, objv, "arc key");
756 	return TCL_ERROR;
757     }
758 
759     a = ga_get_arc (g, objv [3], interp, objv [0]);
760     FAIL (a);
761 
762     return g_attr_get (a->base.attr, interp, objv[4],
763 		       objv [3], "\" for arc \"");
764 }
765 
766 /*
767  *---------------------------------------------------------------------------
768  *
769  * gm_arc_GETALL --
770  *
771  *
772  *
773  *
774  * Results:
775  *	A standard Tcl result code.
776  *
777  * Side effects:
778  *	May release and allocate memory.
779  *
780  *---------------------------------------------------------------------------
781  */
782 
783 int
gm_arc_GETALL(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)784 gm_arc_GETALL (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
785 {
786     /* Syntax: graph arc getall ARC ?PATTERN?
787      *	       [0]   [1] [2]    [3] [4]
788      */
789 
790     GA* a;
791 
792     if ((objc != 4) && (objc != 5)) {
793 	Tcl_WrongNumArgs (interp, 3, objv, "arc ?pattern?");
794 	return TCL_ERROR;
795     }
796 
797     a = ga_get_arc (g, objv [3], interp, objv [0]);
798     FAIL (a);
799 
800     g_attr_getall (a->base.attr, interp, objc-4, objv+4);
801     return TCL_OK;
802 }
803 
804 /*
805  *---------------------------------------------------------------------------
806  *
807  * gm_arc_INSERT --
808  *
809  *
810  *
811  *
812  * Results:
813  *	A standard Tcl result code.
814  *
815  * Side effects:
816  *	May release and allocate memory.
817  *
818  *---------------------------------------------------------------------------
819  */
820 
821 int
gm_arc_INSERT(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)822 gm_arc_INSERT (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
823 {
824     /* Syntax: graph arc insert SOURCE TARGET ?ARC?
825      *	       [0]   [1] [2]    [3]    [4]    [5]
826      */
827 
828     GN* src;
829     GN* dst;
830     GA* a;
831     const char* name;
832 
833     if ((objc != 5) && (objc != 6)) {
834 	Tcl_WrongNumArgs (interp, 3, objv, "source target ?arc?");
835 	return TCL_ERROR;
836     }
837 
838     Tcl_AppendResult (interp, "source ", NULL);
839     src = gn_get_node (g, objv [3], interp, objv[0]);
840     FAIL (src);
841     Tcl_ResetResult (interp);
842 
843     Tcl_AppendResult (interp, "target ", NULL);
844     dst = gn_get_node (g, objv [4], interp, objv[0]);
845     FAIL (dst);
846     Tcl_ResetResult (interp);
847 
848     if (objc == 6) {
849 	/* Explicit arc name, must not exist */
850 
851 	if (ga_get_arc (g, objv [5], NULL, NULL)) {
852 	    ga_err_duplicate (interp, objv[5], objv[0]);
853 	    return TCL_ERROR;
854 	}
855 
856 	/* No matching arc found */
857 	/* Create arc with specified name, */
858 	/* then insert it */
859 
860 	name = Tcl_GetString (objv [5]);
861 
862     } else {
863 	/* Create a single new node with a generated name, */
864 	/* then insert it. */
865 
866 	name = g_newarcname (g);
867     }
868 
869     a = ga_new (g, name, src, dst);
870     Tcl_SetObjResult (interp, Tcl_NewListObj (1, &a->base.name));
871     return TCL_OK;
872 }
873 
874 /*
875  *---------------------------------------------------------------------------
876  *
877  * gm_arc_KEYEXISTS --
878  *
879  *
880  *
881  *
882  * Results:
883  *	A standard Tcl result code.
884  *
885  * Side effects:
886  *	May release and allocate memory.
887  *
888  *---------------------------------------------------------------------------
889  */
890 
891 int
gm_arc_KEYEXISTS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)892 gm_arc_KEYEXISTS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
893 {
894     /* Syntax: graph arc keyexists ARC KEY
895      *	       [0]   [1] [2]       [3] [4]
896      */
897 
898     GA*	a;
899 
900     if (objc != 5) {
901 	Tcl_WrongNumArgs (interp, 3, objv, "arc key");
902 	return TCL_ERROR;
903     }
904 
905     a = ga_get_arc (g, objv [3], interp, objv [0]);
906     FAIL (a);
907 
908     g_attr_kexists (a->base.attr, interp, objv[4]);
909     return TCL_OK;
910 }
911 
912 /*
913  *---------------------------------------------------------------------------
914  *
915  * gm_arc_KEYS --
916  *
917  *
918  *
919  *
920  * Results:
921  *	A standard Tcl result code.
922  *
923  * Side effects:
924  *	May release and allocate memory.
925  *
926  *---------------------------------------------------------------------------
927  */
928 
929 int
gm_arc_KEYS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)930 gm_arc_KEYS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
931 {
932     /* Syntax: graph arc keys ARC ?PATTERN?
933      *	       [0]  [1]	 [2]  [3] [4]
934      */
935 
936     GA* a;
937 
938     if ((objc != 4) && (objc != 5)) {
939 	Tcl_WrongNumArgs (interp, 3, objv, "arc ?pattern?");
940 	return TCL_ERROR;
941     }
942 
943     a = ga_get_arc (g, objv [3], interp, objv [0]);
944     FAIL (a);
945 
946     g_attr_keys (a->base.attr, interp, objc-4, objv+4);
947     return TCL_OK;
948 }
949 
950 /*
951  *---------------------------------------------------------------------------
952  *
953  * gm_arc_LAPPEND --
954  *
955  *
956  *
957  *
958  * Results:
959  *	A standard Tcl result code.
960  *
961  * Side effects:
962  *	May release and allocate memory.
963  *
964  *---------------------------------------------------------------------------
965  */
966 
967 int
gm_arc_LAPPEND(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)968 gm_arc_LAPPEND (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
969 {
970     /* Syntax: graph arc lappend ARC KEY VALUE
971      *	       [0]   [1] [2]     [3] [4] [5]
972      */
973 
974     GA* a;
975 
976     if (objc != 6) {
977 	Tcl_WrongNumArgs (interp, 3, objv, "arc key value");
978 	return TCL_ERROR;
979     }
980 
981     a = ga_get_arc (g, objv [3], interp, objv [0]);
982     FAIL (a);
983 
984     g_attr_extend (&a->base.attr);
985     g_attr_lappend (a->base.attr, interp, objv[4], objv[5]);
986     return TCL_OK;
987 }
988 
989 /*
990  *---------------------------------------------------------------------------
991  *
992  * gm_arc_MOVE --
993  *
994  *
995  *
996  *
997  * Results:
998  *	A standard Tcl result code.
999  *
1000  * Side effects:
1001  *	May release and allocate memory.
1002  *
1003  *---------------------------------------------------------------------------
1004  */
1005 
1006 int
gm_arc_MOVE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1007 gm_arc_MOVE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1008 {
1009     /* Syntax: graph arc move ARC NEWSRC NEWDST
1010      *	       [0]   [1] [2]  [3] [4]    [5]
1011      */
1012 
1013     GA*	a;
1014     GN* nsrc;
1015     GN* ndst;
1016 
1017     if (objc != 6) {
1018 	Tcl_WrongNumArgs (interp, 3, objv, "arc newsource newtarget");
1019 	return TCL_ERROR;
1020     }
1021 
1022     a = ga_get_arc (g, objv [3], interp, objv [0]);
1023     FAIL (a);
1024 
1025     nsrc = gn_get_node (g, objv [4], interp, objv [0]);
1026     FAIL (nsrc);
1027 
1028     ndst = gn_get_node (g, objv [5], interp, objv [0]);
1029     FAIL (ndst);
1030 
1031     ga_mv_src (a, nsrc);
1032     ga_mv_dst (a, ndst);
1033     return TCL_OK;
1034 }
1035 
1036 /*
1037  *---------------------------------------------------------------------------
1038  *
1039  * gm_arc_MOVE_SRC --
1040  *
1041  *
1042  *
1043  *
1044  * Results:
1045  *	A standard Tcl result code.
1046  *
1047  * Side effects:
1048  *	May release and allocate memory.
1049  *
1050  *---------------------------------------------------------------------------
1051  */
1052 
1053 int
gm_arc_MOVE_SRC(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1054 gm_arc_MOVE_SRC (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1055 {
1056     /* Syntax: graph arc move ARC NEWSRC
1057      *	       [0]   [1] [2]  [3] [4]
1058      */
1059 
1060     GA*	a;
1061     GN* nsrc;
1062 
1063     if (objc != 5) {
1064 	Tcl_WrongNumArgs (interp, 3, objv, "arc newsource");
1065 	return TCL_ERROR;
1066     }
1067 
1068     a = ga_get_arc (g, objv [3], interp, objv [0]);
1069     FAIL (a);
1070 
1071     nsrc = gn_get_node (g, objv [4], interp, objv [0]);
1072     FAIL (nsrc);
1073 
1074     ga_mv_src (a, nsrc);
1075     return TCL_OK;
1076 }
1077 
1078 /*
1079  *---------------------------------------------------------------------------
1080  *
1081  * gm_arc_MOVE_TARG --
1082  *
1083  *
1084  *
1085  *
1086  * Results:
1087  *	A standard Tcl result code.
1088  *
1089  * Side effects:
1090  *	May release and allocate memory.
1091  *
1092  *---------------------------------------------------------------------------
1093  */
1094 
1095 int
gm_arc_MOVE_TARG(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1096 gm_arc_MOVE_TARG (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1097 {
1098     /* Syntax: graph arc move ARC NEWDST
1099      *	       [0]   [1] [2]  [3] [4]
1100      */
1101 
1102     GA*	a;
1103     GN* ndst;
1104 
1105     if (objc != 5) {
1106 	Tcl_WrongNumArgs (interp, 3, objv, "arc newtarget");
1107 	return TCL_ERROR;
1108     }
1109 
1110     a = ga_get_arc (g, objv [3], interp, objv [0]);
1111     FAIL (a);
1112 
1113     ndst = gn_get_node (g, objv [4], interp, objv [0]);
1114     FAIL (ndst);
1115 
1116     ga_mv_dst (a, ndst);
1117     return TCL_OK;
1118 }
1119 
1120 /*
1121  *---------------------------------------------------------------------------
1122  *
1123  * gm_arc_RENAME --
1124  *
1125  *
1126  *
1127  *
1128  * Results:
1129  *	A standard Tcl result code.
1130  *
1131  * Side effects:
1132  *	May release and allocate memory.
1133  *
1134  *---------------------------------------------------------------------------
1135  */
1136 
1137 int
gm_arc_RENAME(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1138 gm_arc_RENAME (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1139 {
1140     /* Syntax: graph arc rename ARC NEW
1141      *	       [0]   [1] [2]    [3] [4]
1142      */
1143 
1144     GC* c;
1145 
1146     if (objc != 5) {
1147 	Tcl_WrongNumArgs (interp, 3, objv, "arc newname");
1148 	return TCL_ERROR;
1149     }
1150 
1151     c = (GC*) ga_get_arc (g, objv [3], interp, objv [0]);
1152     FAIL (c);
1153 
1154     if (ga_get_arc (g, objv [4], NULL, NULL)) {
1155 	ga_err_duplicate (interp, objv[4], objv[0]);
1156 	return TCL_ERROR;
1157     }
1158 
1159     gc_rename (c, &g->arcs, objv[4], interp);
1160     ga_shimmer_self ((GA*) c);
1161     return TCL_OK;
1162 }
1163 
1164 /*
1165  *---------------------------------------------------------------------------
1166  *
1167  * gm_arc_SET --
1168  *
1169  *
1170  *
1171  *
1172  * Results:
1173  *	A standard Tcl result code.
1174  *
1175  * Side effects:
1176  *	May release and allocate memory.
1177  *
1178  *---------------------------------------------------------------------------
1179  */
1180 
1181 int
gm_arc_SET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1182 gm_arc_SET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1183 {
1184     /* Syntax: graph arc set ARC KEY ?VALUE?
1185      *	       [0]   [1] [2] [3] [4] [5]
1186      */
1187 
1188     GA* a;
1189 
1190     if ((objc != 5) && (objc != 6)) {
1191 	Tcl_WrongNumArgs (interp, 3, objv, "arc key ?value?");
1192 	return TCL_ERROR;
1193     }
1194 
1195     a = ga_get_arc (g, objv [3], interp, objv [0]);
1196     FAIL (a);
1197 
1198     if (objc == 5) {
1199 	return g_attr_get (a->base.attr, interp, objv[4],
1200 			   objv [3], "\" for arc \"");
1201     } else {
1202 	g_attr_extend (&a->base.attr);
1203 	g_attr_set     (a->base.attr, interp, objv[4], objv[5]);
1204 	return TCL_OK;
1205     }
1206 }
1207 
1208 /*
1209  *---------------------------------------------------------------------------
1210  *
1211  * gm_arc_SOURCE --
1212  *
1213  *
1214  *
1215  *
1216  * Results:
1217  *	A standard Tcl result code.
1218  *
1219  * Side effects:
1220  *	May release and allocate memory.
1221  *
1222  *---------------------------------------------------------------------------
1223  */
1224 
1225 int
gm_arc_SOURCE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1226 gm_arc_SOURCE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1227 {
1228     /* Syntax: graph arc source ARC
1229      *	       [0]   [1] [2]    [3]
1230      */
1231 
1232     GA* a;
1233 
1234     if (objc != 4) {
1235 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
1236 	return TCL_ERROR;
1237     }
1238 
1239     a = ga_get_arc (g, objv [3], interp, objv [0]);
1240     FAIL (a);
1241 
1242     Tcl_SetObjResult (interp, a->start->n->base.name);
1243     return TCL_OK;
1244 }
1245 
1246 /*
1247  *---------------------------------------------------------------------------
1248  *
1249  * gm_arc_TARGET --
1250  *
1251  *
1252  *
1253  *
1254  * Results:
1255  *	A standard Tcl result code.
1256  *
1257  * Side effects:
1258  *	May release and allocate memory.
1259  *
1260  *---------------------------------------------------------------------------
1261  */
1262 
1263 int
gm_arc_TARGET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1264 gm_arc_TARGET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1265 {
1266     /* Syntax: graph arc target ARC
1267      *	       [0]   [1] [2]    [3]
1268      */
1269 
1270     GA* a;
1271 
1272     if (objc != 4) {
1273 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
1274 	return TCL_ERROR;
1275     }
1276 
1277     a = ga_get_arc (g, objv [3], interp, objv [0]);
1278     FAIL (a);
1279 
1280     Tcl_SetObjResult (interp, a->end->n->base.name);
1281     return TCL_OK;
1282 }
1283 
1284 /*
1285  *---------------------------------------------------------------------------
1286  *
1287  * gm_arc_NODES --
1288  *
1289  *
1290  *
1291  *
1292  * Results:
1293  *	A standard Tcl result code.
1294  *
1295  * Side effects:
1296  *	May release and allocate memory.
1297  *
1298  *---------------------------------------------------------------------------
1299  */
1300 
1301 int
gm_arc_NODES(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1302 gm_arc_NODES (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1303 {
1304     /* Syntax: graph arc target ARC
1305      *	       [0]   [1] [2]    [3]
1306      */
1307 
1308     GA* a;
1309     Tcl_Obj* nv[2];
1310 
1311     if (objc != 4) {
1312 	Tcl_WrongNumArgs (interp, 3, objv, "arc");
1313 	return TCL_ERROR;
1314     }
1315 
1316     a = ga_get_arc (g, objv [3], interp, objv [0]);
1317     FAIL (a);
1318 
1319     nv[0] = a->start->n->base.name;
1320     nv[1] = a->end->n->base.name;
1321 
1322     Tcl_SetObjResult (interp, Tcl_NewListObj (2, nv));
1323     return TCL_OK;
1324 }
1325 
1326 /*
1327  *---------------------------------------------------------------------------
1328  *
1329  * gm_arc_UNSET --
1330  *
1331  *
1332  *
1333  *
1334  * Results:
1335  *	A standard Tcl result code.
1336  *
1337  * Side effects:
1338  *	May release and allocate memory.
1339  *
1340  *---------------------------------------------------------------------------
1341  */
1342 
1343 int
gm_arc_UNSET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1344 gm_arc_UNSET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1345 {
1346     /* Syntax: graph arc unset ARC KEY
1347      *	       [0]   [1] [2]   [3] [4]
1348      */
1349 
1350     GA* a;
1351 
1352     if (objc != 5) {
1353 	Tcl_WrongNumArgs (interp, 3, objv, "arc key");
1354 	return TCL_ERROR;
1355     }
1356 
1357     a = ga_get_arc (g, objv [3], interp, objv [0]);
1358     FAIL (a);
1359 
1360     g_attr_unset (a->base.attr, objv [4]);
1361     return TCL_OK;
1362 }
1363 
1364 /*
1365  *---------------------------------------------------------------------------
1366  *
1367  * gm_DESERIALIZE --
1368  *
1369  *	Parses a Tcl value containing a serialized graph and copies it over
1370  *	the existing graph.
1371  *
1372  * Results:
1373  *	A standard Tcl result code.
1374  *
1375  * Side effects:
1376  *	May release and allocate memory.
1377  *
1378  *---------------------------------------------------------------------------
1379  */
1380 
1381 int
gm_DESERIALIZE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1382 gm_DESERIALIZE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1383 {
1384     /* Syntax: graph deserialize serial
1385      *	       [0]   [1]	 [2]
1386      *
1387      * SV   = { NODE ATTR/node ARCS ... ATTR/graph }
1388      *
1389      * using:
1390      *		ATTR/x = { key value ... }
1391      *		ARCS   = { { NAME targetNODEref ATTR/arc } ... }
1392      */
1393 
1394     if (objc != 3) {
1395 	Tcl_WrongNumArgs (interp, 2, objv, "serial");
1396 	return TCL_ERROR;
1397     }
1398 
1399     return g_deserialize (g, interp, objv [2]);
1400 }
1401 
1402 /*
1403  *---------------------------------------------------------------------------
1404  *
1405  * gm_DESTROY --
1406  *
1407  *	Destroys the whole graph object.
1408  *
1409  * Results:
1410  *	A standard Tcl result code.
1411  *
1412  * Side effects:
1413  *	Releases memory.
1414  *
1415  *---------------------------------------------------------------------------
1416  */
1417 
1418 int
gm_DESTROY(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1419 gm_DESTROY (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1420 {
1421     /* Syntax: graph destroy
1422      *	       [0]   [1]
1423      */
1424 
1425     if (objc != 2) {
1426 	Tcl_WrongNumArgs (interp, 2, objv, NULL);
1427 	return TCL_ERROR;
1428     }
1429 
1430     Tcl_DeleteCommandFromToken(interp, g->cmd);
1431     return TCL_OK;
1432 }
1433 
1434 /*
1435  *---------------------------------------------------------------------------
1436  *
1437  * gm_GET --
1438  *
1439  *	Returns the value of the named attribute in the graph.
1440  *
1441  * Results:
1442  *	A standard Tcl result code.
1443  *
1444  * Side effects:
1445  *	May release and allocate memory.
1446  *
1447  *---------------------------------------------------------------------------
1448  */
1449 
1450 int
gm_GET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1451 gm_GET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1452 {
1453     /* Syntax: graph get key
1454      *	       [0]   [1] [2]
1455      */
1456 
1457     if (objc != 3) {
1458 	Tcl_WrongNumArgs (interp, 2, objv, "key");
1459 	return TCL_ERROR;
1460     }
1461 
1462     return g_attr_get (g->attr, interp, objv[2],
1463 		       objv [0], "\" for graph \"");
1464 }
1465 
1466 /*
1467  *---------------------------------------------------------------------------
1468  *
1469  * gm_GETALL --
1470  *
1471  *	Returns a dictionary containing all attributes and their values of
1472  *	the graph.
1473  *
1474  * Results:
1475  *	A standard Tcl result code.
1476  *
1477  * Side effects:
1478  *	May release and allocate memory.
1479  *
1480  *---------------------------------------------------------------------------
1481  */
1482 
1483 int
gm_GETALL(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1484 gm_GETALL (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1485 {
1486     /* Syntax: graph getall ?pattern?
1487      *	       [0]   [1]    [2]
1488      */
1489 
1490     if ((objc != 2) && (objc != 3)) {
1491 	Tcl_WrongNumArgs (interp, 2, objv, "?pattern?");
1492 	return TCL_ERROR;
1493     }
1494 
1495     g_attr_getall (g->attr, interp, objc-2, objv+2);
1496     return TCL_OK;
1497 }
1498 
1499 /*
1500  *---------------------------------------------------------------------------
1501  *
1502  * gm_KEYEXISTS --
1503  *
1504  *	Returns a boolean value signaling whether the graph has the
1505  *	named attribute or not. True implies that the attribute exists.
1506  *
1507  * Results:
1508  *	A standard Tcl result code.
1509  *
1510  * Side effects:
1511  *	May release and allocate memory.
1512  *
1513  *---------------------------------------------------------------------------
1514  */
1515 
1516 int
gm_KEYEXISTS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1517 gm_KEYEXISTS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1518 {
1519     /* Syntax: graph keyexists key
1520      *	       [0]  [1]	       [2]
1521      */
1522 
1523     if (objc != 3) {
1524 	Tcl_WrongNumArgs (interp, 2, objv, "key");
1525 	return TCL_ERROR;
1526     }
1527 
1528     g_attr_kexists (g->attr, interp, objv[2]);
1529     return TCL_OK;
1530 }
1531 
1532 /*
1533  *---------------------------------------------------------------------------
1534  *
1535  * gm_KEYS --
1536  *
1537  *	Returns a list containing all attribute names matching the pattern
1538  *	for the attributes of the graph.
1539  *
1540  * Results:
1541  *	A standard Tcl result code.
1542  *
1543  * Side effects:
1544  *	May release and allocate memory.
1545  *
1546  *---------------------------------------------------------------------------
1547  */
1548 
1549 int
gm_KEYS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1550 gm_KEYS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1551 {
1552     /* Syntax: graph keys ?pattern?
1553      *	       [0]  [1]	  [2]
1554      */
1555 
1556     if ((objc != 2) && (objc != 3)) {
1557 	Tcl_WrongNumArgs (interp, 2, objv, "?pattern?");
1558 	return TCL_ERROR;
1559     }
1560 
1561     g_attr_keys (g->attr, interp, objc-2, objv+2);
1562     return TCL_OK;
1563 }
1564 
1565 /*
1566  *---------------------------------------------------------------------------
1567  *
1568  * gm_LAPPEND --
1569  *
1570  *	Appends a value as list element to an attribute of the graph.
1571  *	May create the attribute.
1572  *
1573  * Results:
1574  *	A standard Tcl result code.
1575  *
1576  * Side effects:
1577  *	May release and allocate memory.
1578  *
1579  *---------------------------------------------------------------------------
1580  */
1581 
1582 int
gm_LAPPEND(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1583 gm_LAPPEND (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1584 {
1585     /* Syntax: graph lappend key value
1586      *	       [0]  [1]	     [2] [3]
1587      */
1588 
1589     if (objc != 4) {
1590 	Tcl_WrongNumArgs (interp, 2, objv, "key value");
1591 	return TCL_ERROR;
1592     }
1593 
1594     g_attr_extend (&g->attr);
1595     g_attr_lappend (g->attr, interp, objv[2], objv[3]);
1596     return TCL_OK;
1597 }
1598 
1599 /*
1600  *---------------------------------------------------------------------------
1601  *
1602  * gm_NODES --
1603  *
1604  *
1605  *
1606  *
1607  * Results:
1608  *	A standard Tcl result code.
1609  *
1610  * Side effects:
1611  *	May release and allocate memory.
1612  *
1613  *---------------------------------------------------------------------------
1614  */
1615 
1616 int
gm_NODES(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1617 gm_NODES (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1618 {
1619     /* nwa = nodes with arc, st = starting, en = ending
1620      *
1621      * Syntax: graph nodes                       | all nodes
1622      *         graph nodes -in        NODE...    | nwa en    in node in list
1623      *         graph nodes -out       NODE...    | nwa st    in node in list
1624      *         graph nodes -adj       NODE...    | nwa st|en in node in list
1625      *         graph nodes -inner     NODE...    | nwa st&en in node in list
1626      *         graph nodes -embedding NODE...    | nwa st^en in node in list
1627      *         graph nodes -key       KEY        | nodes have attribute KEY
1628      *         graph nodes -value     VALUE      | nodes have KEY and VALUE
1629      *         graph nodes -filter    CMDPREFIX  | nodes for which CMD returns True.
1630      *	       [0]   [1]   [2]        [3]
1631      *
1632      * -in/-out/-adj/-inner/-embedding are exclusive.
1633      * -value requires -key.
1634      * Each option can be used at most once.
1635      */
1636 
1637     return gc_filter (1, interp, objc, objv, &g->nodes,
1638 		      (GN_GET_GC*) gn_get_node, g);
1639 }
1640 
1641 /*
1642  *---------------------------------------------------------------------------
1643  *
1644  * gm_node_APPEND --
1645  *
1646  *
1647  *
1648  *
1649  * Results:
1650  *	A standard Tcl result code.
1651  *
1652  * Side effects:
1653  *	May release and allocate memory.
1654  *
1655  *---------------------------------------------------------------------------
1656  */
1657 
1658 int
gm_node_APPEND(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1659 gm_node_APPEND (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1660 {
1661     /* Syntax: graph node append NODE KEY VALUE
1662      *	       [0]   [1]  [2]    [3]  [4] [5]
1663      */
1664 
1665     GN* n;
1666 
1667     if (objc != 6) {
1668 	Tcl_WrongNumArgs (interp, 3, objv, "node key value");
1669 	return TCL_ERROR;
1670     }
1671 
1672     n = gn_get_node (g, objv [3], interp, objv [0]);
1673     FAIL (n);
1674 
1675     g_attr_extend (&n->base.attr);
1676     g_attr_append  (n->base.attr, interp, objv[4], objv[5]);
1677     return TCL_OK;
1678 }
1679 
1680 /*
1681  *---------------------------------------------------------------------------
1682  *
1683  * gm_node_ATTR --
1684  *
1685  *
1686  *
1687  *
1688  * Results:
1689  *	A standard Tcl result code.
1690  *
1691  * Side effects:
1692  *	May release and allocate memory.
1693  *
1694  *---------------------------------------------------------------------------
1695  */
1696 
1697 int
gm_node_ATTR(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1698 gm_node_ATTR (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1699 {
1700     /* Syntax: graph node attr KEY
1701      *         graph node attr KEY -nodes   LIST
1702      *         graph node attr KEY -glob   PATTERN
1703      *         graph node attr KEY -regexp PATTERN
1704      *	       [0]   [1]  [2]  [3] [4]     [5]
1705      */
1706 
1707     static const char* types [] = {
1708 	"-glob", "-nodes", "-regexp", NULL
1709     };
1710     int modes [] = {
1711 	A_GLOB, A_LIST, A_REGEXP
1712     };
1713 
1714     int      mode;
1715     Tcl_Obj* detail;
1716 
1717     if ((objc != 4) && (objc != 6)) {
1718 	Tcl_WrongNumArgs (interp, 3, objv,
1719 			  "key ?-nodes list|-glob pattern|-regexp pattern?");
1720 	return TCL_ERROR;
1721     }
1722 
1723     if (objc != 6) {
1724 	detail = NULL;
1725 	mode   = A_NONE;
1726     } else {
1727 	detail = objv [5];
1728 	if (Tcl_GetIndexFromObj (interp, objv [4], types, "type",
1729 				 0, &mode) != TCL_OK) {
1730 	    return TCL_ERROR;
1731 	}
1732 	mode = modes [mode];
1733     }
1734 
1735     return gc_attr (&g->nodes, mode, detail, interp, objv[3],
1736 		    (GN_GET_GC*) gn_get_node, g);
1737 }
1738 
1739 /*
1740  *---------------------------------------------------------------------------
1741  *
1742  * gm_node_DEGREE --
1743  *
1744  *
1745  *
1746  *
1747  * Results:
1748  *	A standard Tcl result code.
1749  *
1750  * Side effects:
1751  *	May release and allocate memory.
1752  *
1753  *---------------------------------------------------------------------------
1754  */
1755 
1756 int
gm_node_DEGREE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1757 gm_node_DEGREE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1758 {
1759     /* Syntax: graph node degree -in|-out NODE
1760      *	       [0]   [1]  [2]    [3]      [4]
1761      *
1762      *         graph node degree NODE
1763      *	       [0]   [1]  [2]    [3]
1764      */
1765 
1766     GN*      n;
1767     int      dmode;
1768     int      degree;
1769     Tcl_Obj* node;
1770 
1771     static const char* dmode_s [] = {
1772 	"-in", "-out", NULL
1773     };
1774     enum dmode_e {
1775 	D_IN, D_OUT, D_ALL
1776     };
1777 
1778     if ((objc != 4) && (objc != 5)) {
1779 	Tcl_WrongNumArgs (interp, 3, objv, "?-in|-out? node");
1780 	return TCL_ERROR;
1781     }
1782 
1783     if (objc == 5) {
1784 	if (Tcl_GetIndexFromObj (interp, objv [3], dmode_s,
1785 				 "option", 0, &dmode) != TCL_OK) {
1786 	    return TCL_ERROR;
1787 	}
1788 
1789 	node  = objv [4];
1790     } else {
1791 	dmode = D_ALL;
1792 	node  = objv [3];
1793     }
1794 
1795     n = gn_get_node (g, node, interp, objv [0]);
1796     FAIL (n);
1797 
1798     switch (dmode) {
1799     case D_IN:  degree = n->in.n;            break;
1800     case D_OUT: degree = n->out.n;           break;
1801     case D_ALL: degree = n->in.n + n->out.n; break;
1802     }
1803 
1804     Tcl_SetObjResult (interp, Tcl_NewIntObj (degree));
1805     return TCL_OK;
1806 }
1807 
1808 /*
1809  *---------------------------------------------------------------------------
1810  *
1811  * gm_node_DELETE --
1812  *
1813  *
1814  *
1815  *
1816  * Results:
1817  *	A standard Tcl result code.
1818  *
1819  * Side effects:
1820  *	May release and allocate memory.
1821  *
1822  *---------------------------------------------------------------------------
1823  */
1824 
1825 int
gm_node_DELETE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1826 gm_node_DELETE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1827 {
1828     /* Syntax: graph node delete NODE NODE...
1829      *	       [0]   [1]  [2]    [3]  [4+]
1830      */
1831 
1832     int i, new;
1833     GN* n;
1834     Tcl_HashTable seen;
1835 
1836     if (objc < 4) {
1837 	Tcl_WrongNumArgs (interp, 3, objv, "node node...");
1838 	return TCL_ERROR;
1839     }
1840 
1841     Tcl_InitHashTable (&seen, TCL_STRING_KEYS);
1842     for (i=3; i< objc; i++) {
1843 	n = gn_get_node (g, objv [i], interp, objv [0]);
1844 	if (n && (Tcl_FindHashEntry (&seen, Tcl_GetString (objv[i])) != NULL)) {
1845 	    gn_err_missing (interp, objv[i], objv[0]);
1846 	    n = NULL;
1847 	}
1848 	if (n == NULL) {
1849 	    Tcl_DeleteHashTable (&seen);
1850 	}
1851 	FAIL (n);
1852 	Tcl_CreateHashEntry (&seen, Tcl_GetString (objv[i]), &new);
1853     }
1854     Tcl_DeleteHashTable (&seen);
1855 
1856     for (i=3; i< objc; i++) {
1857 	n = gn_get_node (g, objv [i], interp, objv [0]);
1858 	gn_delete (n);
1859     }
1860     return TCL_OK;
1861 }
1862 
1863 /*
1864  *---------------------------------------------------------------------------
1865  *
1866  * gm_node_EXISTS --
1867  *
1868  *
1869  *
1870  *
1871  * Results:
1872  *	A standard Tcl result code.
1873  *
1874  * Side effects:
1875  *	May release and allocate memory.
1876  *
1877  *---------------------------------------------------------------------------
1878  */
1879 
1880 int
gm_node_EXISTS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1881 gm_node_EXISTS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1882 {
1883     /* Syntax: graph node exists NAME
1884      *	       [0]   [1]  [2]    [3]
1885      */
1886 
1887     GN* n;
1888 
1889     if (objc != 4) {
1890 	Tcl_WrongNumArgs (interp, 3, objv, "node");
1891 	return TCL_ERROR;
1892     }
1893 
1894     n = gn_get_node (g, objv [3], NULL, NULL);
1895 
1896     Tcl_SetObjResult (interp, Tcl_NewIntObj (n != NULL));
1897     return TCL_OK;
1898 }
1899 
1900 /*
1901  *---------------------------------------------------------------------------
1902  *
1903  * gm_node_GET --
1904  *
1905  *
1906  *
1907  *
1908  * Results:
1909  *	A standard Tcl result code.
1910  *
1911  * Side effects:
1912  *	May release and allocate memory.
1913  *
1914  *---------------------------------------------------------------------------
1915  */
1916 
1917 int
gm_node_GET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1918 gm_node_GET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1919 {
1920     /* Syntax: graph node get ARC KEY
1921      *	       [0]   [1]  [2] [3] [4]
1922      */
1923 
1924     GN* n;
1925 
1926     if (objc != 5) {
1927 	Tcl_WrongNumArgs (interp, 3, objv, "node key");
1928 	return TCL_ERROR;
1929     }
1930 
1931     n = gn_get_node (g, objv [3], interp, objv [0]);
1932     FAIL (n);
1933 
1934     return g_attr_get (n->base.attr, interp, objv[4],
1935 		       objv [3], "\" for node \"");
1936 }
1937 
1938 /*
1939  *---------------------------------------------------------------------------
1940  *
1941  * gm_node_GETALL --
1942  *
1943  *
1944  *
1945  *
1946  * Results:
1947  *	A standard Tcl result code.
1948  *
1949  * Side effects:
1950  *	May release and allocate memory.
1951  *
1952  *---------------------------------------------------------------------------
1953  */
1954 
1955 int
gm_node_GETALL(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1956 gm_node_GETALL (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1957 {
1958     /* Syntax: graph arc getall ARC ?PATTERN?
1959      *	       [0]   [1] [2]    [3] [4]
1960      */
1961 
1962     GN* n;
1963 
1964     if ((objc != 4) && (objc != 5)) {
1965 	Tcl_WrongNumArgs (interp, 3, objv, "node ?pattern?");
1966 	return TCL_ERROR;
1967     }
1968 
1969     n = gn_get_node (g, objv [3], interp, objv [0]);
1970     FAIL (n);
1971 
1972     g_attr_getall (n->base.attr, interp, objc-4, objv+4);
1973     return TCL_OK;
1974 }
1975 
1976 /*
1977  *---------------------------------------------------------------------------
1978  *
1979  * gm_node_INSERT --
1980  *
1981  *
1982  *
1983  *
1984  * Results:
1985  *	A standard Tcl result code.
1986  *
1987  * Side effects:
1988  *	May release and allocate memory.
1989  *
1990  *---------------------------------------------------------------------------
1991  */
1992 
1993 int
gm_node_INSERT(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)1994 gm_node_INSERT (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
1995 {
1996     /* Syntax: graph node insert ?NODE...?
1997      *	       [0]   [1]  [2]    [3]
1998      */
1999 
2000     GN* n;
2001 
2002     if (objc < 3) {
2003 	Tcl_WrongNumArgs (interp, 3, objv, "?node...?");
2004 	return TCL_ERROR;
2005     }
2006 
2007     if (objc >= 4) {
2008 	int       lc, i, new;
2009 	Tcl_Obj** lv;
2010 	Tcl_HashTable seen;
2011 
2012 	/* Explicit node names, must not exist */
2013 	Tcl_InitHashTable (&seen, TCL_STRING_KEYS);
2014 	for (i=3; i<objc; i++) {
2015 	    if ((Tcl_FindHashEntry (&seen, Tcl_GetString (objv[i])) != NULL) ||
2016 		gn_get_node (g, objv [i], NULL, NULL)) {
2017 		gn_err_duplicate (interp, objv[i], objv[0]);
2018 		Tcl_DeleteHashTable (&seen);
2019 		return TCL_ERROR;
2020 	    }
2021 	    Tcl_CreateHashEntry (&seen, Tcl_GetString (objv[i]), &new);
2022 	}
2023 	Tcl_DeleteHashTable (&seen);
2024 
2025 	/* No matching nodes found. Create nodes with specified name, then
2026 	 * insert them
2027 	 */
2028 
2029 	lc = objc-3;
2030 	lv = NALLOC (lc, Tcl_Obj*);
2031 
2032 	for (i=3; i<objc; i++) {
2033 	    n = gn_new (g, Tcl_GetString (objv [i]));
2034 	    lv [i-3] = n->base.name;
2035 	}
2036 
2037 	Tcl_SetObjResult (interp, Tcl_NewListObj (lc, lv));
2038 	ckfree ((char*) lv);
2039 
2040     } else {
2041 	/* Create a single new node with a generated name, then insert it. */
2042 
2043 	n = gn_new (g, g_newnodename (g));
2044 	Tcl_SetObjResult (interp, Tcl_NewListObj (1, &n->base.name));
2045     }
2046 
2047     return TCL_OK;
2048 }
2049 
2050 /*
2051  *---------------------------------------------------------------------------
2052  *
2053  * gm_node_KEYEXISTS --
2054  *
2055  *
2056  *
2057  *
2058  * Results:
2059  *	A standard Tcl result code.
2060  *
2061  * Side effects:
2062  *	May release and allocate memory.
2063  *
2064  *---------------------------------------------------------------------------
2065  */
2066 
2067 int
gm_node_KEYEXISTS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2068 gm_node_KEYEXISTS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2069 {
2070     /* Syntax: graph node keyexists ARC KEY
2071      *	       [0]   [1]  [2]       [3] [4]
2072      */
2073 
2074     GN* n;
2075 
2076     if (objc != 5) {
2077 	Tcl_WrongNumArgs (interp, 3, objv, "node key");
2078 	return TCL_ERROR;
2079     }
2080 
2081     n = gn_get_node (g, objv [3], interp, objv [0]);
2082     FAIL (n);
2083 
2084     g_attr_kexists (n->base.attr, interp, objv[4]);
2085     return TCL_OK;
2086 }
2087 
2088 /*
2089  *---------------------------------------------------------------------------
2090  *
2091  * gm_node_KEYS --
2092  *
2093  *
2094  *
2095  *
2096  * Results:
2097  *	A standard Tcl result code.
2098  *
2099  * Side effects:
2100  *	May release and allocate memory.
2101  *
2102  *---------------------------------------------------------------------------
2103  */
2104 
2105 int
gm_node_KEYS(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2106 gm_node_KEYS (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2107 {
2108     /* Syntax: graph node keys NODE ?PATTERN?
2109      *	       [0]  [1]	  [2]  [3]  [4]
2110      */
2111 
2112     GN* n;
2113 
2114     if ((objc != 4) && (objc != 5)) {
2115 	Tcl_WrongNumArgs (interp, 3, objv, "node ?pattern?");
2116 	return TCL_ERROR;
2117     }
2118 
2119     n = gn_get_node (g, objv [3], interp, objv [0]);
2120     FAIL (n);
2121 
2122     g_attr_keys (n->base.attr, interp, objc-4, objv+4);
2123     return TCL_OK;
2124 }
2125 
2126 /*
2127  *---------------------------------------------------------------------------
2128  *
2129  * gm_node_LAPPEND --
2130  *
2131  *
2132  *
2133  *
2134  * Results:
2135  *	A standard Tcl result code.
2136  *
2137  * Side effects:
2138  *	May release and allocate memory.
2139  *
2140  *---------------------------------------------------------------------------
2141  */
2142 
2143 int
gm_node_LAPPEND(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2144 gm_node_LAPPEND (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2145 {
2146     /* Syntax: graph node lappend NODE KEY VALUE
2147      *	       [0]   [1]  [2]     [3]  [4] [5]
2148      */
2149 
2150     GN* n;
2151 
2152     if (objc != 6) {
2153 	Tcl_WrongNumArgs (interp, 3, objv, "node key value");
2154 	return TCL_ERROR;
2155     }
2156 
2157     n = gn_get_node (g, objv [3], interp, objv [0]);
2158     FAIL (n);
2159 
2160     g_attr_extend (&n->base.attr);
2161     g_attr_lappend (n->base.attr, interp, objv[4], objv[5]);
2162     return TCL_OK;
2163 }
2164 
2165 /*
2166  *---------------------------------------------------------------------------
2167  *
2168  * gm_node_OPPOSITE --
2169  *
2170  *
2171  *
2172  *
2173  * Results:
2174  *	A standard Tcl result code.
2175  *
2176  * Side effects:
2177  *	May release and allocate memory.
2178  *
2179  *---------------------------------------------------------------------------
2180  */
2181 
2182 int
gm_node_OPPOSITE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2183 gm_node_OPPOSITE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2184 {
2185     /* Syntax: graph node opposite NODE ARC
2186      *	       [0]   [1]  [2]      [3]  [4]
2187      */
2188 
2189     GN* n;
2190     GA* a;
2191 
2192     if (objc != 5) {
2193 	Tcl_WrongNumArgs (interp, 3, objv, "node arc");
2194 	return TCL_ERROR;
2195     }
2196 
2197     n = gn_get_node (g, objv [3], interp, objv [0]);
2198     FAIL (n);
2199 
2200     a = ga_get_arc (g, objv [4], interp, objv [0]);
2201     FAIL (a);
2202 
2203     if (a->start->n == n) {
2204 	Tcl_SetObjResult (interp, a->end->n->base.name);
2205     } else if (a->end->n == n) {
2206 	Tcl_SetObjResult (interp, a->start->n->base.name);
2207     } else {
2208 	Tcl_Obj* err = Tcl_NewObj ();
2209 
2210 	Tcl_AppendToObj	   (err, "node \"", -1);
2211 	Tcl_AppendObjToObj (err, n->base.name);
2212 	Tcl_AppendToObj	   (err, "\" and arc \"", -1);
2213 	Tcl_AppendObjToObj (err, a->base.name);
2214 	Tcl_AppendToObj	   (err, "\" are not connected in graph \"", -1);
2215 	Tcl_AppendObjToObj (err, objv [0]);
2216 	Tcl_AppendToObj	   (err, "\"", -1);
2217 
2218 	Tcl_SetObjResult (interp, err);
2219 	return TCL_ERROR;
2220     }
2221 
2222     return TCL_OK;
2223 }
2224 
2225 /*
2226  *---------------------------------------------------------------------------
2227  *
2228  * gm_node_RENAME --
2229  *
2230  *
2231  *
2232  *
2233  * Results:
2234  *	A standard Tcl result code.
2235  *
2236  * Side effects:
2237  *	May release and allocate memory.
2238  *
2239  *---------------------------------------------------------------------------
2240  */
2241 
2242 int
gm_node_RENAME(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2243 gm_node_RENAME (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2244 {
2245     /* Syntax: graph node rename NODE NEW
2246      *	       [0]   [1]  [2]    [3]  [4]
2247      */
2248 
2249     GC* c;
2250 
2251     if (objc != 5) {
2252 	Tcl_WrongNumArgs (interp, 3, objv, "node newname");
2253 	return TCL_ERROR;
2254     }
2255 
2256     c = (GC*) gn_get_node (g, objv [3], interp, objv [0]);
2257     FAIL (c);
2258 
2259     if (gn_get_node (g, objv [4], NULL, NULL)) {
2260 	gn_err_duplicate (interp, objv[4], objv[0]);
2261 	return TCL_ERROR;
2262     }
2263 
2264     gc_rename (c, &g->nodes, objv[4], interp);
2265     gn_shimmer_self ((GN*) c);
2266     return TCL_OK;
2267 }
2268 
2269 /*
2270  *---------------------------------------------------------------------------
2271  *
2272  * gm_node_SET --
2273  *
2274  *
2275  *
2276  *
2277  * Results:
2278  *	A standard Tcl result code.
2279  *
2280  * Side effects:
2281  *	May release and allocate memory.
2282  *
2283  *---------------------------------------------------------------------------
2284  */
2285 
2286 int
gm_node_SET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2287 gm_node_SET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2288 {
2289     /* Syntax: graph node set NODE KEY ?VALUE?
2290      *	       [0]   [1]  [2] [3]  [4] [5]
2291      */
2292 
2293     GC* c;
2294 
2295     if ((objc != 5) && (objc != 6)) {
2296 	Tcl_WrongNumArgs (interp, 3, objv, "node key ?value?");
2297 	return TCL_ERROR;
2298     }
2299 
2300     c = (GC*) gn_get_node (g, objv [3], interp, objv [0]);
2301     FAIL (c);
2302 
2303     if (objc == 5) {
2304 	return g_attr_get (c->attr, interp, objv[4],
2305 			   objv [3], "\" for node \"");
2306     } else {
2307 	g_attr_extend (&c->attr);
2308 	g_attr_set     (c->attr, interp, objv[4], objv[5]);
2309 	return TCL_OK;
2310     }
2311 }
2312 
2313 /*
2314  *---------------------------------------------------------------------------
2315  *
2316  * gm_node_UNSET --
2317  *
2318  *
2319  *
2320  *
2321  * Results:
2322  *	A standard Tcl result code.
2323  *
2324  * Side effects:
2325  *	May release and allocate memory.
2326  *
2327  *---------------------------------------------------------------------------
2328  */
2329 
2330 int
gm_node_UNSET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2331 gm_node_UNSET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2332 {
2333     /* Syntax: graph node unset NODE KEY
2334      *	       [0]   [1]  [2]   [3]  [4]
2335      */
2336 
2337     GC* c;
2338 
2339     if (objc != 5) {
2340 	Tcl_WrongNumArgs (interp, 3, objv, "node key");
2341 	return TCL_ERROR;
2342     }
2343 
2344     c = (GC*) gn_get_node (g, objv [3], interp, objv [0]);
2345     FAIL (c);
2346 
2347     g_attr_unset (c->attr, objv [4]);
2348     return TCL_OK;
2349 }
2350 
2351 /*
2352  *---------------------------------------------------------------------------
2353  *
2354  * gm_SERIALIZE --
2355  *
2356  *
2357  *
2358  *
2359  * Results:
2360  *	A standard Tcl result code.
2361  *
2362  * Side effects:
2363  *	May release and allocate memory.
2364  *
2365  *---------------------------------------------------------------------------
2366  */
2367 
2368 int
gm_SERIALIZE(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2369 gm_SERIALIZE (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2370 {
2371     /* Syntax: graph serialize NODE...
2372      *	       [0]   [1]       [2]
2373      *
2374      * SV   = { NODE ATTR/node ARCS ... ATTR/graph }
2375      *
2376      * using:
2377      *		ATTR/x = { key value ... }
2378      *		ARCS   = { { NAME targetNODEref ATTR/arc } ... }
2379      */
2380 
2381     Tcl_Obj* sv = g_ms_serialize (interp, objv[0], g, objc-2, objv+2);
2382 
2383     if (!sv) {
2384 	return TCL_ERROR;
2385     }
2386     Tcl_SetObjResult (interp, sv);
2387     return TCL_OK;
2388 }
2389 
2390 /*
2391  *---------------------------------------------------------------------------
2392  *
2393  * gm_SET --
2394  *
2395  *	Adds an attribute and its value to the graph. May replace an
2396  *	existing value.
2397  *
2398  * Results:
2399  *	A standard Tcl result code.
2400  *
2401  * Side effects:
2402  *	May release and allocate memory.
2403  *
2404  *---------------------------------------------------------------------------
2405  */
2406 
2407 int
gm_SET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2408 gm_SET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2409 {
2410     /* Syntax: graph set key ?value?
2411      *	       [0]  [1]  [2] [3]
2412      */
2413 
2414     if ((objc != 3) && (objc != 4)) {
2415 	Tcl_WrongNumArgs (interp, 2, objv, "key ?value?");
2416 	return TCL_ERROR;
2417     }
2418 
2419     if (objc == 3) {
2420 	return g_attr_get (g->attr, interp, objv[2],
2421 			   objv [0], "\" for graph \"");
2422     } else {
2423 	g_attr_extend (&g->attr);
2424 	g_attr_set     (g->attr, interp, objv[2], objv[3]);
2425 	return TCL_OK;
2426     }
2427 }
2428 
2429 /*
2430  *---------------------------------------------------------------------------
2431  *
2432  * gm_SWAP --
2433  *
2434  *	Swap the names of two nodes.
2435  *
2436  * Results:
2437  *	A standard Tcl result code.
2438  *
2439  * Side effects:
2440  *      None.
2441  *
2442  *---------------------------------------------------------------------------
2443  */
2444 
2445 int
gm_SWAP(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2446 gm_SWAP (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2447 {
2448     /* Syntax: graph swap a   b
2449      *	       [0]  [1]	  [2] [3]
2450      */
2451 
2452     GN*		  na;
2453     GN*		  nb;
2454     const char*   key;
2455 
2456     if (objc != 4) {
2457 	Tcl_WrongNumArgs (interp, 2, objv, "node1 node2");
2458 	return TCL_ERROR;
2459     }
2460 
2461     na = gn_get_node (g, objv [2], interp, objv [0]);
2462     FAIL (na);
2463 
2464     nb = gn_get_node (g, objv [3], interp, objv [0]);
2465     FAIL (nb);
2466 
2467     if (na == nb) {
2468 	Tcl_Obj* err = Tcl_NewObj ();
2469 
2470 	Tcl_AppendToObj	   (err, "cannot swap node \"", -1);
2471 	Tcl_AppendObjToObj (err, objv [2]);
2472 	Tcl_AppendToObj	   (err, "\" with itself", -1);
2473 
2474 	Tcl_SetObjResult (interp, err);
2475 	return TCL_ERROR;
2476     }
2477 
2478     {
2479 #define SWAP(a,b,t) t = a; a = b ; b = t
2480 #define SWAPS(x,t) SWAP(na->x,nb->x,t)
2481 
2482 	/* The two nodes flip all structural information around to trade places */
2483 	/* It might actually be easier to flip the non-structural data */
2484 	/* name, he, attr, data in the node map */
2485 
2486 	Tcl_Obj*       to;
2487 	Tcl_HashTable* ta;
2488 	Tcl_HashEntry* th;
2489 
2490 	SWAPS (base.name, to);
2491 	SWAPS (base.attr, ta);
2492 	SWAPS (base.he,   th);
2493 
2494 	Tcl_SetHashValue (na->base.he, (ClientData) na);
2495 	Tcl_SetHashValue (nb->base.he, (ClientData) nb);
2496     }
2497 
2498     return TCL_OK;
2499 }
2500 
2501 /*
2502  *---------------------------------------------------------------------------
2503  *
2504  * gm_UNSET --
2505  *
2506  *	Removes an attribute and its value from the graph.
2507  *
2508  * Results:
2509  *	A standard Tcl result code.
2510  *
2511  * Side effects:
2512  *	May release memory.
2513  *
2514  *---------------------------------------------------------------------------
2515  */
2516 
2517 int
gm_UNSET(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2518 gm_UNSET (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2519 {
2520     /* Syntax: graph unset key
2521      *	       [0]  [1]	   [2]
2522      */
2523 
2524     if (objc != 3) {
2525 	Tcl_WrongNumArgs (interp, 2, objv, "key");
2526 	return TCL_ERROR;
2527     }
2528 
2529     g_attr_unset (g->attr, objv [2]);
2530     return TCL_OK;
2531 }
2532 
2533 /*
2534  *---------------------------------------------------------------------------
2535  *
2536  * gm_WALK --
2537  *
2538  *
2539  *
2540  *
2541  * Results:
2542  *	A standard Tcl result code.
2543  *
2544  * Side effects:
2545  *	May release and allocate memory.
2546  *
2547  *---------------------------------------------------------------------------
2548  */
2549 
2550 int
gm_WALK(G * g,Tcl_Interp * interp,int objc,Tcl_Obj * const * objv)2551 gm_WALK (G* g, Tcl_Interp* interp, int objc, Tcl_Obj* const* objv)
2552 {
2553     /* Syntax: graph walk NODE ?-type TYPE? ?-order ORDER? ?-dir DIR? -command CMD
2554      *	       [0]   [1]  [2]  [3]    [4]   [5]     [6]    [7]   [8]  [9]      [10]
2555      *
2556      * TYPE  bfs|dfs
2557      * ORDER pre|post|both
2558      * DIR   backward|forward
2559      *
2560      * bfs => !post && !both
2561      */
2562 
2563     int       cc, type, order, dir;
2564     Tcl_Obj** cv;
2565     GN*       n;
2566 
2567     if (objc < 5) {
2568 	Tcl_WrongNumArgs (interp, 2, objv, W_USAGE);
2569 	return TCL_ERROR;
2570     }
2571 
2572     n = gn_get_node (g, objv [2], interp, objv [0]);
2573     FAIL(n);
2574 
2575     if (g_walkoptions (interp, objc, objv,
2576 		       &type, &order, &dir,
2577 		       &cc, &cv) != TCL_OK) {
2578 	return TCL_ERROR;
2579     }
2580 
2581     return g_walk (interp, objv[0], n, type, order, dir, cc, cv);
2582 }
2583 
2584 
2585 /* .................................................. */
2586 /* .................................................. */
2587 
2588 /*
2589  * Handling of all indices, numeric and 'end-x' forms.  Copied straight out of
2590  * the Tcl core as this is not exported through the public API.
2591  *
2592  * I.e. a full copy of TclGetIntForIndex, its Tcl_ObjType, and of several
2593  * supporting functions and macros internal to the core.  :(
2594  *
2595  * To avoid clashing with the object type in the core the object type here has
2596  * been given a different name.
2597  */
2598 
2599 #define UCHAR(c) ((unsigned char) (c))
2600 
2601 static void UpdateStringOfEndOffset _ANSI_ARGS_((Tcl_Obj* objPtr));
2602 static int SetEndOffsetFromAny _ANSI_ARGS_((Tcl_Interp* interp,
2603 					    Tcl_Obj* objPtr));
2604 
2605 static int TclCheckBadOctal (Tcl_Interp *interp, const char *value);
2606 static int TclFormatInt     (char *buffer, long n);
2607 
2608 
2609 Tcl_ObjType EndOffsetTypeGraph = {
2610     "tcllib/struct::graph/end-offset",	/* name */
2611     (Tcl_FreeInternalRepProc*) NULL,	/* freeIntRepProc */
2612     (Tcl_DupInternalRepProc*) NULL,	/* dupIntRepProc */
2613     UpdateStringOfEndOffset,		/* updateStringProc */
2614     SetEndOffsetFromAny
2615 };
2616 
2617 static int
TclGetIntForIndex(Tcl_Interp * interp,Tcl_Obj * objPtr,int endValue,int * indexPtr)2618 TclGetIntForIndex (Tcl_Interp* interp, Tcl_Obj* objPtr, int endValue, int* indexPtr)
2619 {
2620     if (Tcl_GetIntFromObj (NULL, objPtr, indexPtr) == TCL_OK) {
2621 	return TCL_OK;
2622     }
2623 
2624     if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
2625 	/*
2626 	 * If the object is already an offset from the end of the
2627 	 * list, or can be converted to one, use it.
2628 	 */
2629 
2630 	*indexPtr = endValue + objPtr->internalRep.longValue;
2631 
2632     } else {
2633 	/*
2634 	 * Report a parse error.
2635 	 */
2636 
2637 	if (interp != NULL) {
2638 	    char *bytes = Tcl_GetString(objPtr);
2639 	    /*
2640 	     * The result might not be empty; this resets it which
2641 	     * should be both a cheap operation, and of little problem
2642 	     * because this is an error-generation path anyway.
2643 	     */
2644 	    Tcl_ResetResult(interp);
2645 	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2646 				   "bad index \"", bytes,
2647 				   "\": must be integer or end?-integer?",
2648 				   (char *) NULL);
2649 	    if (!strncmp(bytes, "end-", 3)) {
2650 		bytes += 3;
2651 	    }
2652 	    TclCheckBadOctal(interp, bytes);
2653 	}
2654 
2655 	return TCL_ERROR;
2656     }
2657 
2658     return TCL_OK;
2659 }
2660 
2661 /*
2662  *----------------------------------------------------------------------
2663  *
2664  * UpdateStringOfEndOffset --
2665  *
2666  *	Update the string rep of a Tcl object holding an "end-offset"
2667  *	expression.
2668  *
2669  * Results:
2670  *	None.
2671  *
2672  * Side effects:
2673  *	Stores a valid string in the object's string rep.
2674  *
2675  * This procedure does NOT free any earlier string rep.	 If it is
2676  * called on an object that already has a valid string rep, it will
2677  * leak memory.
2678  *
2679  *----------------------------------------------------------------------
2680  */
2681 
2682 static void
UpdateStringOfEndOffset(objPtr)2683 UpdateStringOfEndOffset(objPtr)
2684      register Tcl_Obj* objPtr;
2685 {
2686     char buffer[TCL_INTEGER_SPACE + sizeof("end") + 1];
2687     register int len;
2688 
2689     strcpy(buffer, "end");
2690     len = sizeof("end") - 1;
2691     if (objPtr->internalRep.longValue != 0) {
2692 	buffer[len++] = '-';
2693 	len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue));
2694     }
2695     objPtr->bytes = ckalloc((unsigned) (len+1));
2696     strcpy(objPtr->bytes, buffer);
2697     objPtr->length = len;
2698 }
2699 
2700 /*
2701  *----------------------------------------------------------------------
2702  *
2703  * SetEndOffsetFromAny --
2704  *
2705  *	Look for a string of the form "end-offset" and convert it
2706  *	to an internal representation holding the offset.
2707  *
2708  * Results:
2709  *	Returns TCL_OK if ok, TCL_ERROR if the string was badly formed.
2710  *
2711  * Side effects:
2712  *	If interp is not NULL, stores an error message in the
2713  *	interpreter result.
2714  *
2715  *----------------------------------------------------------------------
2716  */
2717 
2718 static int
SetEndOffsetFromAny(interp,objPtr)2719 SetEndOffsetFromAny(interp, objPtr)
2720      Tcl_Interp* interp;	/* Tcl interpreter or NULL */
2721      Tcl_Obj* objPtr;		/* Pointer to the object to parse */
2722 {
2723     int offset;			/* Offset in the "end-offset" expression */
2724     Tcl_ObjType* oldTypePtr = objPtr->typePtr;
2725     /* Old internal rep type of the object */
2726     register char* bytes;	/* String rep of the object */
2727     int length;			/* Length of the object's string rep */
2728 
2729     /* If it's already the right type, we're fine. */
2730 
2731     if (objPtr->typePtr == &EndOffsetTypeGraph) {
2732 	return TCL_OK;
2733     }
2734 
2735     /* Check for a string rep of the right form. */
2736 
2737     bytes = Tcl_GetStringFromObj(objPtr, &length);
2738     if ((*bytes != 'e') || (strncmp(bytes, "end",
2739 				    (size_t)((length > 3) ? 3 : length)) != 0)) {
2740 	if (interp != NULL) {
2741 	    Tcl_ResetResult(interp);
2742 	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2743 				   "bad index \"", bytes,
2744 				   "\": must be end?-integer?",
2745 				   (char*) NULL);
2746 	}
2747 	return TCL_ERROR;
2748     }
2749 
2750     /* Convert the string rep */
2751 
2752     if (length <= 3) {
2753 	offset = 0;
2754     } else if ((length > 4) && (bytes[3] == '-')) {
2755 	/*
2756 	 * This is our limited string expression evaluator.  Pass everything
2757 	 * after "end-" to Tcl_GetInt, then reverse for offset.
2758 	 */
2759 	if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
2760 	    return TCL_ERROR;
2761 	}
2762 	offset = -offset;
2763     } else {
2764 	/*
2765 	 * Conversion failed.  Report the error.
2766 	 */
2767 	if (interp != NULL) {
2768 	    Tcl_ResetResult(interp);
2769 	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
2770 				   "bad index \"", bytes,
2771 				   "\": must be integer or end?-integer?",
2772 				   (char *) NULL);
2773 	}
2774 	return TCL_ERROR;
2775     }
2776 
2777     /*
2778      * The conversion succeeded. Free the old internal rep and set
2779      * the new one.
2780      */
2781 
2782     if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
2783 	oldTypePtr->freeIntRepProc(objPtr);
2784     }
2785 
2786     objPtr->internalRep.longValue = offset;
2787     objPtr->typePtr = &EndOffsetTypeGraph;
2788 
2789     return TCL_OK;
2790 }
2791 
2792 /*
2793  *----------------------------------------------------------------------
2794  *
2795  * TclCheckBadOctal --
2796  *
2797  *	This procedure checks for a bad octal value and appends a
2798  *	meaningful error to the interp's result.
2799  *
2800  * Results:
2801  *	1 if the argument was a bad octal, else 0.
2802  *
2803  * Side effects:
2804  *	The interpreter's result is modified.
2805  *
2806  *----------------------------------------------------------------------
2807  */
2808 
2809 static int
TclCheckBadOctal(interp,value)2810 TclCheckBadOctal(interp, value)
2811      Tcl_Interp *interp;		/* Interpreter to use for error reporting.
2812 				 * If NULL, then no error message is left
2813 				 * after errors. */
2814      const char *value;		/* String to check. */
2815 {
2816     register const char *p = value;
2817 
2818     /*
2819      * A frequent mistake is invalid octal values due to an unwanted
2820      * leading zero. Try to generate a meaningful error message.
2821      */
2822 
2823     while (isspace(UCHAR(*p))) {	/* INTL: ISO space. */
2824 	p++;
2825     }
2826     if (*p == '+' || *p == '-') {
2827 	p++;
2828     }
2829     if (*p == '0') {
2830 	while (isdigit(UCHAR(*p))) {	/* INTL: digit. */
2831 	    p++;
2832 	}
2833 	while (isspace(UCHAR(*p))) {	/* INTL: ISO space. */
2834 	    p++;
2835 	}
2836 	if (*p == '\0') {
2837 	    /* Reached end of string */
2838 	    if (interp != NULL) {
2839 		/*
2840 		 * Don't reset the result here because we want this result
2841 		 * to be added to an existing error message as extra info.
2842 		 */
2843 		Tcl_AppendResult(interp, " (looks like invalid octal number)",
2844 				 (char *) NULL);
2845 	    }
2846 	    return 1;
2847 	}
2848     }
2849     return 0;
2850 }
2851 
2852 /*
2853  *----------------------------------------------------------------------
2854  *
2855  * TclFormatInt --
2856  *
2857  *	This procedure formats an integer into a sequence of decimal digit
2858  *	characters in a buffer. If the integer is negative, a minus sign is
2859  *	inserted at the start of the buffer. A null character is inserted at
2860  *	the end of the formatted characters. It is the caller's
2861  *	responsibility to ensure that enough storage is available. This
2862  *	procedure has the effect of sprintf(buffer, "%d", n) but is faster.
2863  *
2864  * Results:
2865  *	An integer representing the number of characters formatted, not
2866  *	including the terminating \0.
2867  *
2868  * Side effects:
2869  *	The formatted characters are written into the storage pointer to
2870  *	by the "buffer" argument.
2871  *
2872  *----------------------------------------------------------------------
2873  */
2874 
2875 static int
TclFormatInt(buffer,n)2876 TclFormatInt(buffer, n)
2877      char *buffer;		/* Points to the storage into which the
2878 				 * formatted characters are written. */
2879      long n;			/* The integer to format. */
2880 {
2881     long intVal;
2882     int i;
2883     int numFormatted, j;
2884     char *digits = "0123456789";
2885 
2886     /*
2887      * Check first whether "n" is zero.
2888      */
2889 
2890     if (n == 0) {
2891 	buffer[0] = '0';
2892 	buffer[1] = 0;
2893 	return 1;
2894     }
2895 
2896     /*
2897      * Check whether "n" is the maximum negative value. This is
2898      * -2^(m-1) for an m-bit word, and has no positive equivalent;
2899      * negating it produces the same value.
2900      */
2901 
2902     if (n == -n) {
2903 	sprintf(buffer, "%ld", n);
2904 	return strlen(buffer);
2905     }
2906 
2907     /*
2908      * Generate the characters of the result backwards in the buffer.
2909      */
2910 
2911     intVal = (n < 0? -n : n);
2912     i = 0;
2913     buffer[0] = '\0';
2914     do {
2915 	i++;
2916 	buffer[i] = digits[intVal % 10];
2917 	intVal = intVal/10;
2918     } while (intVal > 0);
2919     if (n < 0) {
2920 	i++;
2921 	buffer[i] = '-';
2922     }
2923     numFormatted = i;
2924 
2925     /*
2926      * Now reverse the characters.
2927      */
2928 
2929     for (j = 0;	 j < i;	 j++, i--) {
2930 	char tmp = buffer[i];
2931 	buffer[i] = buffer[j];
2932 	buffer[j] = tmp;
2933     }
2934     return numFormatted;
2935 }
2936 
2937 /*
2938  * Local Variables:
2939  * mode: c
2940  * c-basic-offset: 4
2941  * fill-column: 78
2942  * End:
2943  */
2944