Graphviz 13.0.0~dev.20250424.1043
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)) {
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("layoutedges", 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("layoutnodes", argv[1])) {
168 g = agroot(g);
169 if (!aggetrec(g, "Agraphinfo_t", 0))
170 tcldot_layout(gvc, g, (argc > 2) ? argv[2] : NULL);
171 return TCL_OK;
172
173 } else if (streq("listattributes", argv[1])) {
174 listGraphAttrs(interp, g);
175 return TCL_OK;
176
177 } else if (streq("listedgeattributes", argv[1])) {
178 listEdgeAttrs(interp, g);
179 return TCL_OK;
180
181 } else if (streq("listnodeattributes", argv[1])) {
182 listNodeAttrs(interp, g);
183 return TCL_OK;
184
185 } else if (streq("listedges", argv[1])) {
186 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
187 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
188 Tcl_AppendElement(interp, obj2cmd(e));
189 }
190 }
191 return TCL_OK;
192
193 } else if (streq("listnodes", argv[1])) {
194 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
195 Tcl_AppendElement(interp, obj2cmd(n));
196 }
197 return TCL_OK;
198
199 } else if (streq("listnodesrev", argv[1])) {
200 for (n = aglstnode(g); n; n = agprvnode(g, n)) {
201 Tcl_AppendElement(interp, obj2cmd(n));
202 }
203 return TCL_OK;
204
205 } else if (streq("listsubgraphs", argv[1])) {
206 for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
207 Tcl_AppendElement(interp, obj2cmd(sg));
208 }
209 return TCL_OK;
210
211 } else if (streq("queryattributes", argv[1])) {
212 for (int i = 2; i < argc; i++) {
213 Tcl_Size argc2;
214 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
215 return TCL_ERROR;
216 for (Tcl_Size j = 0; j < argc2; j++) {
217 char *arg = strdup(argv2[j]);
218 if (arg == NULL) {
219 Tcl_Free((char *)argv2);
220 return TCL_ERROR;
221 }
222 if ((a = agfindgraphattr(g, arg))) {
223 Tcl_AppendElement(interp, agxget(g, a));
224 } else {
225 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
226 free(arg);
227 Tcl_Free((char *)argv2);
228 return TCL_ERROR;
229 }
230 free(arg);
231 }
232 Tcl_Free((char *)argv2);
233 }
234 return TCL_OK;
235
236 } else if (streq("queryattributevalues", argv[1])) {
237 for (int i = 2; i < argc; i++) {
238 Tcl_Size argc2;
239 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
240 return TCL_ERROR;
241 for (Tcl_Size j = 0; j < argc2; j++) {
242 char *arg = strdup(argv2[j]);
243 if (arg == NULL) {
244 Tcl_Free((char *)argv2);
245 return TCL_ERROR;
246 }
247 if ((a = agfindgraphattr(g, arg))) {
248 Tcl_AppendElement(interp, arg);
249 Tcl_AppendElement(interp, agxget(g, a));
250 } else {
251 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
252 free(arg);
253 Tcl_Free((char *)argv2);
254 return TCL_ERROR;
255 }
256 free(arg);
257 }
258 Tcl_Free((char *)argv2);
259 }
260 return TCL_OK;
261
262 } else if (streq("queryedgeattributes", argv[1])) {
263 for (int i = 2; i < argc; i++) {
264 Tcl_Size argc2;
265 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
266 return TCL_ERROR;
267 for (Tcl_Size j = 0; j < argc2; j++) {
268 char *arg = strdup(argv2[j]);
269 if (arg == NULL) {
270 Tcl_Free((char *)argv2);
271 return TCL_ERROR;
272 }
273 if ((a = agfindedgeattr(g, arg))) {
274 Tcl_AppendElement(interp, agxget(g, a));
275 } else {
276 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
277 free(arg);
278 Tcl_Free((char *)argv2);
279 return TCL_ERROR;
280 }
281 free(arg);
282 }
283 Tcl_Free((char *)argv2);
284 }
285 return TCL_OK;
286
287 } else if (streq("queryedgeattributevalues", argv[1])) {
288 for (int i = 2; i < argc; i++) {
289 Tcl_Size argc2;
290 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
291 return TCL_ERROR;
292 for (Tcl_Size j = 0; j < argc2; j++) {
293 char *arg = strdup(argv2[j]);
294 if (arg == NULL) {
295 Tcl_Free((char *)argv2);
296 return TCL_ERROR;
297 }
298 if ((a = agfindedgeattr(g, arg))) {
299 Tcl_AppendElement(interp, arg);
300 Tcl_AppendElement(interp, agxget(g, a));
301 } else {
302 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
303 free(arg);
304 Tcl_Free((char *)argv2);
305 return TCL_ERROR;
306 }
307 free(arg);
308 }
309 Tcl_Free((char *)argv2);
310 }
311 return TCL_OK;
312
313 } else if (streq("querynodeattributes", argv[1])) {
314 for (int i = 2; i < argc; i++) {
315 Tcl_Size argc2;
316 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
317 return TCL_ERROR;
318 for (Tcl_Size j = 0; j < argc2; j++) {
319 char *arg = strdup(argv2[j]);
320 if (arg == NULL) {
321 Tcl_Free((char *)argv2);
322 return TCL_ERROR;
323 }
324 if ((a = agfindnodeattr(g, arg))) {
325 Tcl_AppendElement(interp, agxget(g, a));
326 } else {
327 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
328 free(arg);
329 Tcl_Free((char *)argv2);
330 return TCL_ERROR;
331 }
332 free(arg);
333 }
334 Tcl_Free((char *)argv2);
335 }
336 return TCL_OK;
337
338 } else if (streq("querynodeattributevalues", argv[1])) {
339 for (int i = 2; i < argc; i++) {
340 Tcl_Size argc2;
341 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
342 return TCL_ERROR;
343 for (Tcl_Size j = 0; j < argc2; j++) {
344 char *arg = strdup(argv2[j]);
345 if (arg == NULL) {
346 Tcl_Free((char *)argv2);
347 return TCL_ERROR;
348 }
349 if ((a = agfindnodeattr(g, arg))) {
350 Tcl_AppendElement(interp, arg);
351 Tcl_AppendElement(interp, agxget(g, a));
352 } else {
353 Tcl_AppendResult(interp, " No attribute named \"", arg, "\"", NULL);
354 free(arg);
355 Tcl_Free((char *)argv2);
356 return TCL_ERROR;
357 }
358 free(arg);
359 }
360 Tcl_Free((char *)argv2);
361 }
362 return TCL_OK;
363
364 } else if (streq("render", argv[1])) {
365 const char *canvas;
366
367 if (argc < 3) {
368 canvas = "$c";
369 } else {
370 canvas = argv[2];
371 }
372
374 tcldot_context_t context = {.canvas = canvas, .interp = interp};
375
376 /* make sure that layout is done */
377 g = agroot(g);
378 if (!aggetrec(g, "Agraphinfo_t", 0) || argc > 3)
379 tcldot_layout(gvc, g, (argc > 3) ? argv[3] : NULL);
380
381 /* render graph TK canvas commands */
382 gvc->common.viewNum = 0;
383 if (gvRenderContext(gvc, g, "tk", &context) != 0) {
384 return TCL_ERROR;
385 }
386 fflush(stdout);
387 return TCL_OK;
388
389 } else if (streq("setattributes", argv[1])) {
390 if (argc == 3) {
391 Tcl_Size argc2;
392 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
393 return TCL_ERROR;
394 if ((argc2 == 0) || (argc2 % 2)) {
395 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
396 "\" setattributes attributename attributevalue "
397 "?attributename attributevalue? ?...?",
398 NULL);
399 Tcl_Free((char *)argv2);
400 return TCL_ERROR;
401 }
402 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
403 setgraphattributes(g, argv2_copy, argc2);
404 tcldot_argv_free(argc2, argv2_copy);
405 Tcl_Free((char *)argv2);
406 }
407 if (argc == 4 && streq(argv[2], "viewport")) {
408 /* special case to allow viewport to be set without resetting layout */
409 setgraphattributes(g, &argv[2], (Tcl_Size)argc - 2);
410 } else {
411 if ((argc < 4) || (argc % 2)) {
412 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
413 "\" setattributes attributename attributevalue "
414 "?attributename attributevalue? ?...?",
415 NULL);
416 return TCL_ERROR;
417 }
418 setgraphattributes(g, &argv[2], (Tcl_Size)argc - 2);
419 }
420 return TCL_OK;
421
422 } else if (streq("setedgeattributes", argv[1])) {
423 if (argc == 3) {
424 Tcl_Size argc2;
425 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
426 return TCL_ERROR;
427 if ((argc2 == 0) || (argc2 % 2)) {
428 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
429 "\" setedgeattributes attributename attributevalue "
430 "?attributename attributevalue? ?...?",
431 NULL);
432 Tcl_Free((char *)argv2);
433 return TCL_ERROR;
434 }
435 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
436 setedgeattributes(g, NULL, argv2_copy, argc2);
437 tcldot_argv_free(argc2, argv2_copy);
438 Tcl_Free((char *)argv2);
439 } else {
440 if ((argc < 4) || (argc % 2)) {
441 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
442 "\" setedgeattributes attributename attributevalue "
443 "?attributename attributevalue? ?...?",
444 NULL);
445 }
446 setedgeattributes(g, NULL, &argv[2], (Tcl_Size)argc - 2);
447 }
448 return TCL_OK;
449
450 } else if (streq("setnodeattributes", argv[1])) {
451 if (argc == 3) {
452 Tcl_Size argc2;
453 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
454 return TCL_ERROR;
455 if ((argc2 == 0) || (argc2 % 2)) {
456 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
457 "\" setnodeattributes attributename attributevalue "
458 "?attributename attributevalue? ?...?",
459 NULL);
460 Tcl_Free((char *)argv2);
461 return TCL_ERROR;
462 }
463 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
464 setnodeattributes(g, NULL, argv2_copy, argc2);
465 tcldot_argv_free(argc2, argv2_copy);
466 Tcl_Free((char *)argv2);
467 } else {
468 if ((argc < 4) || (argc % 2)) {
469 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
470 "\" setnodeattributes attributename attributevalue "
471 "?attributename attributevalue? ?...?",
472 NULL);
473 }
474 setnodeattributes(g, NULL, &argv[2], (Tcl_Size)argc - 2);
475 }
476 return TCL_OK;
477
478 } else if (streq("showname", argv[1])) {
479 Tcl_SetResult(interp, agnameof(g), TCL_STATIC);
480 return TCL_OK;
481 } else if (streq("write", argv[1])) {
482 g = agroot(g);
483 if (argc < 3) {
484 Tcl_AppendResult(
485 interp, "wrong # args: should be \"", argv[0],
486 " write fileHandle ?language ?DOT|NEATO|TWOPI|FDP|CIRCO|NOP??\"",
487 NULL);
488 return TCL_ERROR;
489 }
490
492
493 Tcl_Channel chan;
494 {
495 int mode;
496
497 chan = Tcl_GetChannel(interp, argv[2], &mode);
498
499 if (!chan) {
500 Tcl_AppendResult(interp, "channel not open: \"", argv[2], NULL);
501 return TCL_ERROR;
502 }
503 if (!(mode & TCL_WRITABLE)) {
504 Tcl_AppendResult(interp, "channel not writable: \"", argv[2], NULL);
505 return TCL_ERROR;
506 }
507 }
508
509 /* make sure that layout is done - unless canonical output */
510 if (!aggetrec(g, "Agraphinfo_t", 0) || argc > 4)
511 tcldot_layout(gvc, g, (argc > 4) ? argv[4] : NULL);
512
513 gvc->common.viewNum = 0;
514 if (gvRender(gvc, g, argc < 4 ? "dot" : argv[3], (FILE *)chan) != 0) {
515 return TCL_ERROR;
516 }
517 return TCL_OK;
518
519 } else {
520 Tcl_AppendResult(
521 interp, "bad option \"", argv[1], "\": must be one of:",
522 "\n\taddedge, addnode, addsubgraph, countedges, countnodes,",
523 "\n\tlayout, listattributes, listedgeattributes, listnodeattributes,",
524 "\n\tlistedges, listnodes, listsubgraphs, render, rendergd,",
525 "\n\tqueryattributes, queryedgeattributes, querynodeattributes,",
526 "\n\tqueryattributevalues, queryedgeattributevalues, "
527 "querynodeattributevalues,",
528 "\n\tsetattributes, setedgeattributes, setnodeattributes,",
529 "\n\tshowname, write.", NULL);
530 return TCL_ERROR;
531 }
532} /* graphcmd */
533
534int graphcmd(ClientData clientData, Tcl_Interp *interp, int argc,
535 const char *argv[]) {
536 char **argv_copy = tcldot_argv_dup(argc, argv);
537 int rc = graphcmd_internal(clientData, interp, argc, argv_copy);
538 tcldot_argv_free(argc, argv_copy);
539 return rc;
540}
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 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:27
char * obj2cmd(void *obj)
Definition tcldot-util.c:64
Agraph_t * cmd2g(const char *cmd)
Definition tcldot-util.c:39
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:20
void listEdgeAttrs(Tcl_Interp *interp, Agraph_t *g)
void setnodeattributes(Agraph_t *g, Agnode_t *n, char *argv[], Tcl_Size argc)
void setedgeattributes(Agraph_t *g, Agedge_t *e, char *argv[], Tcl_Size argc)
void tcldot_argv_free(int argc, char *argv[])
free the strings pointed to by argv
char ** tcldot_argv_dup(int argc, const char *argv[])
duplicate the strings pointed to by argv as non-const strings
Agnode_t * cmd2n(const char *cmd)
Definition tcldot-util.c:46