Graphviz 13.0.0~dev.20250607.1528
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/itos.h>
17#include <util/streq.h>
18
19static int graphcmd_internal(ClientData clientData, Tcl_Interp *interp,
20 int argc, char *argv[]) {
21 Agraph_t *g, *sg;
22 Agnode_t *n, *tail, *head;
23 Agedge_t *e;
24 gctx_t *gctx = (gctx_t *)clientData;
25 ictx_t *ictx = gctx->ictx;
26 Agsym_t *a;
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 Tcl_AppendResult(interp, ITOS(agnnodes(g)), NULL);
114 return TCL_OK;
115
116 } else if (streq("countedges", argv[1])) {
117 Tcl_AppendResult(interp, ITOS(agnedges(g)), NULL);
118 return TCL_OK;
119
120 } else if (streq("delete", argv[1])) {
121 deleteGraph(gctx, g);
122 return TCL_OK;
123
124 } else if (streq("findedge", argv[1])) {
125 if (argc < 4) {
126 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
127 " findedge tailnodename headnodename\"", NULL);
128 return TCL_ERROR;
129 }
130 if (!(tail = agfindnode(g, argv[2]))) {
131 Tcl_AppendResult(interp, "tail node \"", argv[2], "\" not found.", NULL);
132 return TCL_ERROR;
133 }
134 if (!(head = agfindnode(g, argv[3]))) {
135 Tcl_AppendResult(interp, "head node \"", argv[3], "\" not found.", NULL);
136 return TCL_ERROR;
137 }
138 if (!(e = agfindedge(g, tail, head))) {
139 Tcl_AppendResult(interp, "edge \"", argv[2], " - ", argv[3],
140 "\" not found.", NULL);
141 return TCL_ERROR;
142 }
143 Tcl_AppendElement(interp, obj2cmd(e));
144 return TCL_OK;
145
146 } else if (streq("findnode", argv[1])) {
147 if (argc < 3) {
148 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
149 " findnode nodename\"", NULL);
150 return TCL_ERROR;
151 }
152 if (!(n = agfindnode(g, argv[2]))) {
153 Tcl_AppendResult(interp, "node not found.", NULL);
154 return TCL_ERROR;
155 }
156 Tcl_AppendResult(interp, obj2cmd(n), NULL);
157 return TCL_OK;
158
159 } else if (streq("layout", argv[1])) {
160 g = agroot(g);
161 if (!aggetrec(g, "Agraphinfo_t", 0))
162 tcldot_layout(gvc, g, (argc > 2) ? argv[2] : NULL);
163 return TCL_OK;
164
165 } else if (streq("listattributes", argv[1])) {
166 listGraphAttrs(interp, g);
167 return TCL_OK;
168
169 } else if (streq("listedgeattributes", argv[1])) {
170 listEdgeAttrs(interp, g);
171 return TCL_OK;
172
173 } else if (streq("listnodeattributes", argv[1])) {
174 listNodeAttrs(interp, g);
175 return TCL_OK;
176
177 } else if (streq("listedges", argv[1])) {
178 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
179 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
180 Tcl_AppendElement(interp, obj2cmd(e));
181 }
182 }
183 return TCL_OK;
184
185 } else if (streq("listnodes", argv[1])) {
186 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
187 Tcl_AppendElement(interp, obj2cmd(n));
188 }
189 return TCL_OK;
190
191 } else if (streq("listnodesrev", argv[1])) {
192 for (n = aglstnode(g); n; n = agprvnode(g, n)) {
193 Tcl_AppendElement(interp, obj2cmd(n));
194 }
195 return TCL_OK;
196
197 } else if (streq("listsubgraphs", argv[1])) {
198 for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
199 Tcl_AppendElement(interp, obj2cmd(sg));
200 }
201 return TCL_OK;
202
203 } else if (streq("queryattributes", argv[1])) {
204 for (int i = 2; i < argc; i++) {
205 Tcl_Size argc2;
206 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
207 return TCL_ERROR;
208 for (Tcl_Size j = 0; j < argc2; j++) {
209 char *arg = strdup(argv2[j]);
210 if (arg == NULL) {
211 Tcl_Free((char *)argv2);
212 return TCL_ERROR;
213 }
214 if ((a = agfindgraphattr(g, arg))) {
215 Tcl_AppendElement(interp, agxget(g, a));
216 } else {
217 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
218 free(arg);
219 Tcl_Free((char *)argv2);
220 return TCL_ERROR;
221 }
222 free(arg);
223 }
224 Tcl_Free((char *)argv2);
225 }
226 return TCL_OK;
227
228 } else if (streq("queryattributevalues", argv[1])) {
229 for (int i = 2; i < argc; i++) {
230 Tcl_Size argc2;
231 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
232 return TCL_ERROR;
233 for (Tcl_Size j = 0; j < argc2; j++) {
234 char *arg = strdup(argv2[j]);
235 if (arg == NULL) {
236 Tcl_Free((char *)argv2);
237 return TCL_ERROR;
238 }
239 if ((a = agfindgraphattr(g, arg))) {
240 Tcl_AppendElement(interp, arg);
241 Tcl_AppendElement(interp, agxget(g, a));
242 } else {
243 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
244 free(arg);
245 Tcl_Free((char *)argv2);
246 return TCL_ERROR;
247 }
248 free(arg);
249 }
250 Tcl_Free((char *)argv2);
251 }
252 return TCL_OK;
253
254 } else if (streq("queryedgeattributes", argv[1])) {
255 for (int i = 2; i < argc; i++) {
256 Tcl_Size argc2;
257 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
258 return TCL_ERROR;
259 for (Tcl_Size j = 0; j < argc2; j++) {
260 char *arg = strdup(argv2[j]);
261 if (arg == NULL) {
262 Tcl_Free((char *)argv2);
263 return TCL_ERROR;
264 }
265 if ((a = agfindedgeattr(g, arg))) {
266 Tcl_AppendElement(interp, agxget(g, a));
267 } else {
268 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
269 free(arg);
270 Tcl_Free((char *)argv2);
271 return TCL_ERROR;
272 }
273 free(arg);
274 }
275 Tcl_Free((char *)argv2);
276 }
277 return TCL_OK;
278
279 } else if (streq("queryedgeattributevalues", argv[1])) {
280 for (int i = 2; i < argc; i++) {
281 Tcl_Size argc2;
282 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
283 return TCL_ERROR;
284 for (Tcl_Size j = 0; j < argc2; j++) {
285 char *arg = strdup(argv2[j]);
286 if (arg == NULL) {
287 Tcl_Free((char *)argv2);
288 return TCL_ERROR;
289 }
290 if ((a = agfindedgeattr(g, arg))) {
291 Tcl_AppendElement(interp, arg);
292 Tcl_AppendElement(interp, agxget(g, a));
293 } else {
294 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
295 free(arg);
296 Tcl_Free((char *)argv2);
297 return TCL_ERROR;
298 }
299 free(arg);
300 }
301 Tcl_Free((char *)argv2);
302 }
303 return TCL_OK;
304
305 } else if (streq("querynodeattributes", argv[1])) {
306 for (int i = 2; i < argc; i++) {
307 Tcl_Size argc2;
308 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
309 return TCL_ERROR;
310 for (Tcl_Size j = 0; j < argc2; j++) {
311 char *arg = strdup(argv2[j]);
312 if (arg == NULL) {
313 Tcl_Free((char *)argv2);
314 return TCL_ERROR;
315 }
316 if ((a = agfindnodeattr(g, arg))) {
317 Tcl_AppendElement(interp, agxget(g, a));
318 } else {
319 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
320 free(arg);
321 Tcl_Free((char *)argv2);
322 return TCL_ERROR;
323 }
324 free(arg);
325 }
326 Tcl_Free((char *)argv2);
327 }
328 return TCL_OK;
329
330 } else if (streq("querynodeattributevalues", argv[1])) {
331 for (int i = 2; i < argc; i++) {
332 Tcl_Size argc2;
333 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
334 return TCL_ERROR;
335 for (Tcl_Size j = 0; j < argc2; j++) {
336 char *arg = strdup(argv2[j]);
337 if (arg == NULL) {
338 Tcl_Free((char *)argv2);
339 return TCL_ERROR;
340 }
341 if ((a = agfindnodeattr(g, arg))) {
342 Tcl_AppendElement(interp, arg);
343 Tcl_AppendElement(interp, agxget(g, a));
344 } else {
345 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
346 free(arg);
347 Tcl_Free((char *)argv2);
348 return TCL_ERROR;
349 }
350 free(arg);
351 }
352 Tcl_Free((char *)argv2);
353 }
354 return TCL_OK;
355
356 } else if (streq("render", argv[1])) {
357 const char *canvas;
358
359 if (argc < 3) {
360 canvas = "$c";
361 } else {
362 canvas = argv[2];
363 }
364
366 tcldot_context_t context = {.canvas = canvas, .interp = interp};
367
368 /* make sure that layout is done */
369 g = agroot(g);
370 if (!aggetrec(g, "Agraphinfo_t", 0) || argc > 3)
371 tcldot_layout(gvc, g, (argc > 3) ? argv[3] : NULL);
372
373 /* render graph TK canvas commands */
374 gvc->common.viewNum = 0;
375 if (gvRenderContext(gvc, g, "tk", &context) != 0) {
376 return TCL_ERROR;
377 }
378 fflush(stdout);
379 return TCL_OK;
380
381 } else if (streq("setattributes", argv[1])) {
382 if (argc == 3) {
383 Tcl_Size argc2;
384 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
385 return TCL_ERROR;
386 if (argc2 == 0 || argc2 % 2 != 0) {
387 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
388 "\" setattributes attributename attributevalue "
389 "?attributename attributevalue? ?...?",
390 NULL);
391 Tcl_Free((char *)argv2);
392 return TCL_ERROR;
393 }
394 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
395 setgraphattributes(g, argv2_copy, argc2);
396 tcldot_argv_free(argc2, argv2_copy);
397 Tcl_Free((char *)argv2);
398 }
399 if (argc == 4 && streq(argv[2], "viewport")) {
400 /* special case to allow viewport to be set without resetting layout */
401 setgraphattributes(g, &argv[2], (Tcl_Size)argc - 2);
402 } else {
403 if (argc < 4 || argc % 2 != 0) {
404 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
405 "\" setattributes attributename attributevalue "
406 "?attributename attributevalue? ?...?",
407 NULL);
408 return TCL_ERROR;
409 }
410 setgraphattributes(g, &argv[2], (Tcl_Size)argc - 2);
411 }
412 return TCL_OK;
413
414 } else if (streq("setedgeattributes", argv[1])) {
415 if (argc == 3) {
416 Tcl_Size argc2;
417 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
418 return TCL_ERROR;
419 if (argc2 == 0 || argc2 % 2 != 0) {
420 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
421 "\" setedgeattributes attributename attributevalue "
422 "?attributename attributevalue? ?...?",
423 NULL);
424 Tcl_Free((char *)argv2);
425 return TCL_ERROR;
426 }
427 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
428 setedgeattributes(g, NULL, argv2_copy, argc2);
429 tcldot_argv_free(argc2, argv2_copy);
430 Tcl_Free((char *)argv2);
431 } else {
432 if (argc < 4 || argc % 2 != 0) {
433 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
434 "\" setedgeattributes attributename attributevalue "
435 "?attributename attributevalue? ?...?",
436 NULL);
437 }
438 setedgeattributes(g, NULL, &argv[2], (Tcl_Size)argc - 2);
439 }
440 return TCL_OK;
441
442 } else if (streq("setnodeattributes", argv[1])) {
443 if (argc == 3) {
444 Tcl_Size argc2;
445 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
446 return TCL_ERROR;
447 if (argc2 == 0 || argc2 % 2 != 0) {
448 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
449 "\" setnodeattributes attributename attributevalue "
450 "?attributename attributevalue? ?...?",
451 NULL);
452 Tcl_Free((char *)argv2);
453 return TCL_ERROR;
454 }
455 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
456 setnodeattributes(g, NULL, argv2_copy, argc2);
457 tcldot_argv_free(argc2, argv2_copy);
458 Tcl_Free((char *)argv2);
459 } else {
460 if (argc < 4 || argc % 2 != 0) {
461 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
462 "\" setnodeattributes attributename attributevalue "
463 "?attributename attributevalue? ?...?",
464 NULL);
465 }
466 setnodeattributes(g, NULL, &argv[2], (Tcl_Size)argc - 2);
467 }
468 return TCL_OK;
469
470 } else if (streq("showname", argv[1])) {
471 Tcl_SetResult(interp, agnameof(g), TCL_STATIC);
472 return TCL_OK;
473 } else if (streq("write", argv[1])) {
474 g = agroot(g);
475 if (argc < 3) {
476 Tcl_AppendResult(
477 interp, "wrong # args: should be \"", argv[0],
478 " write fileHandle ?language ?DOT|NEATO|TWOPI|FDP|CIRCO|NOP??\"",
479 NULL);
480 return TCL_ERROR;
481 }
482
484
485 Tcl_Channel chan;
486 {
487 int mode;
488
489 chan = Tcl_GetChannel(interp, argv[2], &mode);
490
491 if (!chan) {
492 Tcl_AppendResult(interp, "channel not open: \"", argv[2], NULL);
493 return TCL_ERROR;
494 }
495 if (!(mode & TCL_WRITABLE)) {
496 Tcl_AppendResult(interp, "channel not writable: \"", argv[2], NULL);
497 return TCL_ERROR;
498 }
499 }
500
501 /* make sure that layout is done - unless canonical output */
502 if (!aggetrec(g, "Agraphinfo_t", 0) || argc > 4)
503 tcldot_layout(gvc, g, (argc > 4) ? argv[4] : NULL);
504
505 gvc->common.viewNum = 0;
506 if (gvRender(gvc, g, argc < 4 ? "dot" : argv[3], (FILE *)chan) != 0) {
507 return TCL_ERROR;
508 }
509 return TCL_OK;
510
511 } else {
512 Tcl_AppendResult(
513 interp, "bad option \"", argv[1], "\": must be one of:",
514 "\n\taddedge, addnode, addsubgraph, countedges, countnodes,",
515 "\n\tlayout, listattributes, listedgeattributes, listnodeattributes,",
516 "\n\tlistedges, listnodes, listsubgraphs, render, rendergd,",
517 "\n\tqueryattributes, queryedgeattributes, querynodeattributes,",
518 "\n\tqueryattributevalues, queryedgeattributevalues, "
519 "querynodeattributevalues,",
520 "\n\tsetattributes, setedgeattributes, setnodeattributes,",
521 "\n\tshowname, write.", NULL);
522 return TCL_ERROR;
523 }
524} /* graphcmd */
525
526int graphcmd(ClientData clientData, Tcl_Interp *interp, int argc,
527 const char *argv[]) {
528 char **argv_copy = tcldot_argv_dup((Tcl_Size)argc, argv);
529 int rc = graphcmd_internal(clientData, interp, argc, argv_copy);
530 tcldot_argv_free((Tcl_Size)argc, argv_copy);
531 return rc;
532}
mode
Definition cvtgxl.c:33
#define head
Definition dthdr.h:15
void free(void *)
node NULL
Definition grammar.y:180
int agnedges(Agraph_t *g)
Definition graph.c:163
int agnnodes(Agraph_t *g)
Definition graph.c:157
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:472
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:253
#define agfindedgeattr(g, a)
Definition types.h:617
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:26
#define agfindedge(g, t, h)
Definition types.h:609
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
#define agfindgraphattr(g, a)
Definition types.h:613
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:141
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agprvnode(Agraph_t *g, Agnode_t *n)
Definition node.c:63
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
Agnode_t * aglstnode(Agraph_t *g)
Definition node.c:56
#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:73
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:78
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:53
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
#define ITOS(i)
Definition itos.h:43
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