Graphviz 13.0.0~dev.20250511.0440
Loading...
Searching...
No Matches
tcldot-graphcmd.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "../tcl-compat.h"
12#include "tcldot.h"
13#include <stdbool.h>
14#include <stdlib.h>
15#include <string.h>
16#include <util/streq.h>
17
18static int graphcmd_internal(ClientData clientData, Tcl_Interp *interp,
19 int argc, char *argv[]) {
20 Agraph_t *g, *sg;
21 Agnode_t *n, *tail, *head;
22 Agedge_t *e;
23 gctx_t *gctx = (gctx_t *)clientData;
24 ictx_t *ictx = gctx->ictx;
25 Agsym_t *a;
26 char buf[12];
27 const char **argv2;
28 GVC_t *gvc = ictx->gvc;
29
30 if (argc < 2) {
31 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
32 " option ?arg arg ...?\"", NULL);
33 return TCL_ERROR;
34 }
35 g = cmd2g(argv[0]);
36 if (!g) {
37 Tcl_AppendResult(interp, "graph \"", argv[0], "\" not found", NULL);
38 return TCL_ERROR;
39 }
40
41 if (streq("addedge", argv[1])) {
42 if (argc < 4 || argc % 2 != 0) {
43 Tcl_AppendResult(
44 interp, "wrong # args: should be \"", argv[0],
45 " addedge tail head ?attributename attributevalue? ?...?\"", NULL);
46 return TCL_ERROR;
47 }
48 tail = cmd2n(argv[2]);
49 if (!tail) {
50 if (!(tail = agfindnode(g, argv[2]))) {
51 Tcl_AppendResult(interp, "tail node \"", argv[2], "\" not found.",
52 NULL);
53 return TCL_ERROR;
54 }
55 }
56 if (agroot(g) != agroot(agraphof(tail))) {
57 Tcl_AppendResult(interp, "tail node ", argv[2], " is not in the graph.",
58 NULL);
59 return TCL_ERROR;
60 }
61 head = cmd2n(argv[3]);
62 if (!head) {
63 if (!(head = agfindnode(g, argv[3]))) {
64 Tcl_AppendResult(interp, "head node \"", argv[3], "\" not found.",
65 NULL);
66 return TCL_ERROR;
67 }
68 }
69 if (agroot(g) != agroot(agraphof(head))) {
70 Tcl_AppendResult(interp, "head node ", argv[3], " is not in the graph.",
71 NULL);
72 return TCL_ERROR;
73 }
74 e = agedge(g, tail, head, NULL, 1);
75 Tcl_AppendResult(interp, obj2cmd(e), NULL);
76 setedgeattributes(agroot(g), e, &argv[4], (Tcl_Size)argc - 4);
77 return TCL_OK;
78
79 } else if (streq("addnode", argv[1])) {
80 int i;
81 if (argc % 2) {
82 /* if odd number of args then argv[2] is name */
83 n = agnode(g, argv[2], 1);
84 i = 3;
85 } else {
86 n = agnode(g, NULL, 1); /* anon node */
87 i = 2;
88 }
89 Tcl_AppendResult(interp, obj2cmd(n), NULL);
90 setnodeattributes(agroot(g), n, &argv[i], (Tcl_Size)argc - i);
91 return TCL_OK;
92
93 } else if (streq("addsubgraph", argv[1])) {
94 int i;
95 if (argc < 2) {
96 Tcl_AppendResult(
97 interp, "wrong # args: should be \"", argv[0],
98 "\" addsubgraph ?name? ?attributename attributevalue? ?...?", NULL);
99 }
100 if (argc % 2) {
101 /* if odd number of args then argv[2] is name */
102 sg = agsubg(g, argv[2], 1);
103 Tcl_AppendResult(interp, obj2cmd(sg), NULL);
104 i = 3;
105 } else {
106 sg = agsubg(g, NULL, 1); /* anon subgraph */
107 i = 2;
108 }
109 setgraphattributes(sg, &argv[i], (Tcl_Size)argc - i);
110 return TCL_OK;
111
112 } else if (streq("countnodes", argv[1])) {
113 snprintf(buf, sizeof(buf), "%d", agnnodes(g));
114 Tcl_AppendResult(interp, buf, NULL);
115 return TCL_OK;
116
117 } else if (streq("countedges", argv[1])) {
118 snprintf(buf, sizeof(buf), "%d", agnedges(g));
119 Tcl_AppendResult(interp, buf, NULL);
120 return TCL_OK;
121
122 } else if (streq("delete", argv[1])) {
123 deleteGraph(gctx, g);
124 return TCL_OK;
125
126 } else if (streq("findedge", argv[1])) {
127 if (argc < 4) {
128 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
129 " findedge tailnodename headnodename\"", NULL);
130 return TCL_ERROR;
131 }
132 if (!(tail = agfindnode(g, argv[2]))) {
133 Tcl_AppendResult(interp, "tail node \"", argv[2], "\" not found.", NULL);
134 return TCL_ERROR;
135 }
136 if (!(head = agfindnode(g, argv[3]))) {
137 Tcl_AppendResult(interp, "head node \"", argv[3], "\" not found.", NULL);
138 return TCL_ERROR;
139 }
140 if (!(e = agfindedge(g, tail, head))) {
141 Tcl_AppendResult(interp, "edge \"", argv[2], " - ", argv[3],
142 "\" not found.", NULL);
143 return TCL_ERROR;
144 }
145 Tcl_AppendElement(interp, obj2cmd(e));
146 return TCL_OK;
147
148 } else if (streq("findnode", argv[1])) {
149 if (argc < 3) {
150 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
151 " findnode nodename\"", NULL);
152 return TCL_ERROR;
153 }
154 if (!(n = agfindnode(g, argv[2]))) {
155 Tcl_AppendResult(interp, "node not found.", NULL);
156 return TCL_ERROR;
157 }
158 Tcl_AppendResult(interp, obj2cmd(n), NULL);
159 return TCL_OK;
160
161 } else if (streq("layout", argv[1])) {
162 g = agroot(g);
163 if (!aggetrec(g, "Agraphinfo_t", 0))
164 tcldot_layout(gvc, g, (argc > 2) ? argv[2] : NULL);
165 return TCL_OK;
166
167 } else if (streq("listattributes", argv[1])) {
168 listGraphAttrs(interp, g);
169 return TCL_OK;
170
171 } else if (streq("listedgeattributes", argv[1])) {
172 listEdgeAttrs(interp, g);
173 return TCL_OK;
174
175 } else if (streq("listnodeattributes", argv[1])) {
176 listNodeAttrs(interp, g);
177 return TCL_OK;
178
179 } else if (streq("listedges", argv[1])) {
180 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
181 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
182 Tcl_AppendElement(interp, obj2cmd(e));
183 }
184 }
185 return TCL_OK;
186
187 } else if (streq("listnodes", argv[1])) {
188 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
189 Tcl_AppendElement(interp, obj2cmd(n));
190 }
191 return TCL_OK;
192
193 } else if (streq("listnodesrev", argv[1])) {
194 for (n = aglstnode(g); n; n = agprvnode(g, n)) {
195 Tcl_AppendElement(interp, obj2cmd(n));
196 }
197 return TCL_OK;
198
199 } else if (streq("listsubgraphs", argv[1])) {
200 for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
201 Tcl_AppendElement(interp, obj2cmd(sg));
202 }
203 return TCL_OK;
204
205 } else if (streq("queryattributes", argv[1])) {
206 for (int i = 2; i < argc; i++) {
207 Tcl_Size argc2;
208 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
209 return TCL_ERROR;
210 for (Tcl_Size j = 0; j < argc2; j++) {
211 char *arg = strdup(argv2[j]);
212 if (arg == NULL) {
213 Tcl_Free((char *)argv2);
214 return TCL_ERROR;
215 }
216 if ((a = agfindgraphattr(g, arg))) {
217 Tcl_AppendElement(interp, agxget(g, a));
218 } else {
219 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
220 free(arg);
221 Tcl_Free((char *)argv2);
222 return TCL_ERROR;
223 }
224 free(arg);
225 }
226 Tcl_Free((char *)argv2);
227 }
228 return TCL_OK;
229
230 } else if (streq("queryattributevalues", argv[1])) {
231 for (int i = 2; i < argc; i++) {
232 Tcl_Size argc2;
233 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
234 return TCL_ERROR;
235 for (Tcl_Size j = 0; j < argc2; j++) {
236 char *arg = strdup(argv2[j]);
237 if (arg == NULL) {
238 Tcl_Free((char *)argv2);
239 return TCL_ERROR;
240 }
241 if ((a = agfindgraphattr(g, arg))) {
242 Tcl_AppendElement(interp, arg);
243 Tcl_AppendElement(interp, agxget(g, a));
244 } else {
245 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
246 free(arg);
247 Tcl_Free((char *)argv2);
248 return TCL_ERROR;
249 }
250 free(arg);
251 }
252 Tcl_Free((char *)argv2);
253 }
254 return TCL_OK;
255
256 } else if (streq("queryedgeattributes", argv[1])) {
257 for (int i = 2; i < argc; i++) {
258 Tcl_Size argc2;
259 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
260 return TCL_ERROR;
261 for (Tcl_Size j = 0; j < argc2; j++) {
262 char *arg = strdup(argv2[j]);
263 if (arg == NULL) {
264 Tcl_Free((char *)argv2);
265 return TCL_ERROR;
266 }
267 if ((a = agfindedgeattr(g, arg))) {
268 Tcl_AppendElement(interp, agxget(g, a));
269 } else {
270 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
271 free(arg);
272 Tcl_Free((char *)argv2);
273 return TCL_ERROR;
274 }
275 free(arg);
276 }
277 Tcl_Free((char *)argv2);
278 }
279 return TCL_OK;
280
281 } else if (streq("queryedgeattributevalues", argv[1])) {
282 for (int i = 2; i < argc; i++) {
283 Tcl_Size argc2;
284 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
285 return TCL_ERROR;
286 for (Tcl_Size j = 0; j < argc2; j++) {
287 char *arg = strdup(argv2[j]);
288 if (arg == NULL) {
289 Tcl_Free((char *)argv2);
290 return TCL_ERROR;
291 }
292 if ((a = agfindedgeattr(g, arg))) {
293 Tcl_AppendElement(interp, arg);
294 Tcl_AppendElement(interp, agxget(g, a));
295 } else {
296 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
297 free(arg);
298 Tcl_Free((char *)argv2);
299 return TCL_ERROR;
300 }
301 free(arg);
302 }
303 Tcl_Free((char *)argv2);
304 }
305 return TCL_OK;
306
307 } else if (streq("querynodeattributes", argv[1])) {
308 for (int i = 2; i < argc; i++) {
309 Tcl_Size argc2;
310 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
311 return TCL_ERROR;
312 for (Tcl_Size j = 0; j < argc2; j++) {
313 char *arg = strdup(argv2[j]);
314 if (arg == NULL) {
315 Tcl_Free((char *)argv2);
316 return TCL_ERROR;
317 }
318 if ((a = agfindnodeattr(g, arg))) {
319 Tcl_AppendElement(interp, agxget(g, a));
320 } else {
321 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
322 free(arg);
323 Tcl_Free((char *)argv2);
324 return TCL_ERROR;
325 }
326 free(arg);
327 }
328 Tcl_Free((char *)argv2);
329 }
330 return TCL_OK;
331
332 } else if (streq("querynodeattributevalues", argv[1])) {
333 for (int i = 2; i < argc; i++) {
334 Tcl_Size argc2;
335 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
336 return TCL_ERROR;
337 for (Tcl_Size j = 0; j < argc2; j++) {
338 char *arg = strdup(argv2[j]);
339 if (arg == NULL) {
340 Tcl_Free((char *)argv2);
341 return TCL_ERROR;
342 }
343 if ((a = agfindnodeattr(g, arg))) {
344 Tcl_AppendElement(interp, arg);
345 Tcl_AppendElement(interp, agxget(g, a));
346 } else {
347 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
348 free(arg);
349 Tcl_Free((char *)argv2);
350 return TCL_ERROR;
351 }
352 free(arg);
353 }
354 Tcl_Free((char *)argv2);
355 }
356 return TCL_OK;
357
358 } else if (streq("render", argv[1])) {
359 const char *canvas;
360
361 if (argc < 3) {
362 canvas = "$c";
363 } else {
364 canvas = argv[2];
365 }
366
368 tcldot_context_t context = {.canvas = canvas, .interp = interp};
369
370 /* make sure that layout is done */
371 g = agroot(g);
372 if (!aggetrec(g, "Agraphinfo_t", 0) || argc > 3)
373 tcldot_layout(gvc, g, (argc > 3) ? argv[3] : NULL);
374
375 /* render graph TK canvas commands */
376 gvc->common.viewNum = 0;
377 if (gvRenderContext(gvc, g, "tk", &context) != 0) {
378 return TCL_ERROR;
379 }
380 fflush(stdout);
381 return TCL_OK;
382
383 } else if (streq("setattributes", argv[1])) {
384 if (argc == 3) {
385 Tcl_Size argc2;
386 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
387 return TCL_ERROR;
388 if (argc2 == 0 || argc2 % 2 != 0) {
389 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
390 "\" setattributes attributename attributevalue "
391 "?attributename attributevalue? ?...?",
392 NULL);
393 Tcl_Free((char *)argv2);
394 return TCL_ERROR;
395 }
396 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
397 setgraphattributes(g, argv2_copy, argc2);
398 tcldot_argv_free(argc2, argv2_copy);
399 Tcl_Free((char *)argv2);
400 }
401 if (argc == 4 && streq(argv[2], "viewport")) {
402 /* special case to allow viewport to be set without resetting layout */
403 setgraphattributes(g, &argv[2], (Tcl_Size)argc - 2);
404 } else {
405 if (argc < 4 || argc % 2 != 0) {
406 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
407 "\" setattributes attributename attributevalue "
408 "?attributename attributevalue? ?...?",
409 NULL);
410 return TCL_ERROR;
411 }
412 setgraphattributes(g, &argv[2], (Tcl_Size)argc - 2);
413 }
414 return TCL_OK;
415
416 } else if (streq("setedgeattributes", argv[1])) {
417 if (argc == 3) {
418 Tcl_Size argc2;
419 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
420 return TCL_ERROR;
421 if (argc2 == 0 || argc2 % 2 != 0) {
422 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
423 "\" setedgeattributes attributename attributevalue "
424 "?attributename attributevalue? ?...?",
425 NULL);
426 Tcl_Free((char *)argv2);
427 return TCL_ERROR;
428 }
429 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
430 setedgeattributes(g, NULL, argv2_copy, argc2);
431 tcldot_argv_free(argc2, argv2_copy);
432 Tcl_Free((char *)argv2);
433 } else {
434 if (argc < 4 || argc % 2 != 0) {
435 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
436 "\" setedgeattributes attributename attributevalue "
437 "?attributename attributevalue? ?...?",
438 NULL);
439 }
440 setedgeattributes(g, NULL, &argv[2], (Tcl_Size)argc - 2);
441 }
442 return TCL_OK;
443
444 } else if (streq("setnodeattributes", argv[1])) {
445 if (argc == 3) {
446 Tcl_Size argc2;
447 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
448 return TCL_ERROR;
449 if (argc2 == 0 || argc2 % 2 != 0) {
450 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
451 "\" setnodeattributes attributename attributevalue "
452 "?attributename attributevalue? ?...?",
453 NULL);
454 Tcl_Free((char *)argv2);
455 return TCL_ERROR;
456 }
457 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
458 setnodeattributes(g, NULL, argv2_copy, argc2);
459 tcldot_argv_free(argc2, argv2_copy);
460 Tcl_Free((char *)argv2);
461 } else {
462 if (argc < 4 || argc % 2 != 0) {
463 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
464 "\" setnodeattributes attributename attributevalue "
465 "?attributename attributevalue? ?...?",
466 NULL);
467 }
468 setnodeattributes(g, NULL, &argv[2], (Tcl_Size)argc - 2);
469 }
470 return TCL_OK;
471
472 } else if (streq("showname", argv[1])) {
473 Tcl_SetResult(interp, agnameof(g), TCL_STATIC);
474 return TCL_OK;
475 } else if (streq("write", argv[1])) {
476 g = agroot(g);
477 if (argc < 3) {
478 Tcl_AppendResult(
479 interp, "wrong # args: should be \"", argv[0],
480 " write fileHandle ?language ?DOT|NEATO|TWOPI|FDP|CIRCO|NOP??\"",
481 NULL);
482 return TCL_ERROR;
483 }
484
486
487 Tcl_Channel chan;
488 {
489 int mode;
490
491 chan = Tcl_GetChannel(interp, argv[2], &mode);
492
493 if (!chan) {
494 Tcl_AppendResult(interp, "channel not open: \"", argv[2], NULL);
495 return TCL_ERROR;
496 }
497 if (!(mode & TCL_WRITABLE)) {
498 Tcl_AppendResult(interp, "channel not writable: \"", argv[2], NULL);
499 return TCL_ERROR;
500 }
501 }
502
503 /* make sure that layout is done - unless canonical output */
504 if (!aggetrec(g, "Agraphinfo_t", 0) || argc > 4)
505 tcldot_layout(gvc, g, (argc > 4) ? argv[4] : NULL);
506
507 gvc->common.viewNum = 0;
508 if (gvRender(gvc, g, argc < 4 ? "dot" : argv[3], (FILE *)chan) != 0) {
509 return TCL_ERROR;
510 }
511 return TCL_OK;
512
513 } else {
514 Tcl_AppendResult(
515 interp, "bad option \"", argv[1], "\": must be one of:",
516 "\n\taddedge, addnode, addsubgraph, countedges, countnodes,",
517 "\n\tlayout, listattributes, listedgeattributes, listnodeattributes,",
518 "\n\tlistedges, listnodes, listsubgraphs, render, rendergd,",
519 "\n\tqueryattributes, queryedgeattributes, querynodeattributes,",
520 "\n\tqueryattributevalues, queryedgeattributevalues, "
521 "querynodeattributevalues,",
522 "\n\tsetattributes, setedgeattributes, setnodeattributes,",
523 "\n\tshowname, write.", NULL);
524 return TCL_ERROR;
525 }
526} /* graphcmd */
527
528int graphcmd(ClientData clientData, Tcl_Interp *interp, int argc,
529 const char *argv[]) {
530 char **argv_copy = tcldot_argv_dup((Tcl_Size)argc, argv);
531 int rc = graphcmd_internal(clientData, interp, argc, argv_copy);
532 tcldot_argv_free((Tcl_Size)argc, argv_copy);
533 return rc;
534}
mode
Definition cvtgxl.c:33
#define head
Definition dthdr.h:15
void free(void *)
node NULL
Definition grammar.y:163
int agnedges(Agraph_t *g)
Definition graph.c:165
int agnnodes(Agraph_t *g)
Definition graph.c:159
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:482
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:256
#define agfindedgeattr(g, a)
Definition types.h:617
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
#define agfindedge(g, t, h)
Definition types.h:609
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
#define agfindgraphattr(g, a)
Definition types.h:613
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:140
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agprvnode(Agraph_t *g, Agnode_t *n)
Definition node.c:62
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
Agnode_t * aglstnode(Agraph_t *g)
Definition node.c:55
#define agfindnodeattr(g, a)
Definition types.h:615
#define agfindnode(g, n)
Definition types.h:611
Agraph_t * agraphof(void *obj)
Definition obj.c:185
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
Agraph_t * agroot(void *obj)
Definition obj.c:168
Agrec_t * aggetrec(void *obj, const char *name, int move_to_front)
find record in circular list and do optional move-to-front and lock
Definition rec.c:41
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:75
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:80
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:55
int gvRender(GVC_t *gvc, graph_t *g, const char *format, FILE *out)
Definition gvc.c:84
int gvRenderContext(GVC_t *gvc, graph_t *g, const char *format, void *context)
Definition gvc.c:143
static GVC_t * gvc
Definition gv.cpp:23
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
graph or subgraph
Definition cgraph.h:424
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:651
int viewNum
rendering state
Definition gvcommon.h:29
Definition gvcint.h:81
GVCOMMON_t common
Definition gvcint.h:82
size_t(* write_fn)(GVJ_t *job, const char *s, size_t len)
Definition gvcint.h:104
ictx_t * ictx
Definition tcldot.h:38
GVC_t * gvc
Definition tcldot.h:30
context used to convey information between commands and a renderer
Definition tcl_context.h:14
const char * canvas
TCL canvas to render to.
Definition tcl_context.h:15
#define Tcl_Size
Definition tcl-compat.h:33
int graphcmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
static int graphcmd_internal(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
void tcldot_layout(GVC_t *gvc, Agraph_t *g, const char *engine)
void tcldot_argv_free(Tcl_Size argc, char *argv[])
free the strings pointed to by argv
void listNodeAttrs(Tcl_Interp *interp, Agraph_t *g)
void listGraphAttrs(Tcl_Interp *interp, Agraph_t *g)
void setgraphattributes(Agraph_t *g, char *argv[], Tcl_Size argc)
size_t Tcldot_channel_writer(GVJ_t *job, const char *s, size_t len)
Definition tcldot-util.c:28
char * obj2cmd(void *obj)
Definition tcldot-util.c:65
Agraph_t * cmd2g(const char *cmd)
Definition tcldot-util.c:40
void deleteGraph(gctx_t *gctx, Agraph_t *g)
size_t Tcldot_string_writer(GVJ_t *job, const char *s, size_t len)
Definition tcldot-util.c:21
void listEdgeAttrs(Tcl_Interp *interp, Agraph_t *g)
void setnodeattributes(Agraph_t *g, Agnode_t *n, char *argv[], Tcl_Size argc)
char ** tcldot_argv_dup(Tcl_Size argc, const char *argv[])
duplicate the strings pointed to by argv as non-const strings
void setedgeattributes(Agraph_t *g, Agedge_t *e, char *argv[], Tcl_Size argc)
Agnode_t * cmd2n(const char *cmd)
Definition tcldot-util.c:47