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