Graphviz 13.0.0~dev.20250424.1043
Loading...
Searching...
No Matches
tcldot-util.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 <math.h>
13#include <stddef.h>
14#include "tcldot.h"
15#include <gvc/gvc.h>
16#include <util/alloc.h>
17#include <util/strcasecmp.h>
18#include <util/unreachable.h>
19
20size_t Tcldot_string_writer(GVJ_t *job, const char *s, size_t len)
21{
22 tcldot_context_t *context = job->context;
23 Tcl_AppendResult(context->interp, s, NULL);
24 return len;
25}
26
27size_t Tcldot_channel_writer(GVJ_t *job, const char *s, size_t len)
28{
30 const Tcl_Size written = Tcl_Write((Tcl_Channel)job->output_file, s, l);
31 if (written < 0) {
32 return 0;
33 }
34 return (size_t)written;
35}
36
37/* handles (tcl commands) to obj* */
38
39Agraph_t *cmd2g(const char *cmd) {
40 Agraph_t *g = NULL;
41
42 if (sscanf(cmd, "graph%p", &g) != 1 || !g)
43 return NULL;
44 return g;
45}
46Agnode_t *cmd2n(const char *cmd) {
47 Agnode_t *n = NULL;
48
49 if (sscanf(cmd, "node%p", &n) != 1 || !n)
50 return NULL;
51 return n;
52}
53Agedge_t *cmd2e(const char *cmd) {
54 Agedge_t *e = NULL;
55
56 if (sscanf(cmd, "edge%p", &e) != 1 || !e)
57 return NULL;
58 return e;
59}
60
61
62/* obj* to handles (tcl commands) */
63
64char *obj2cmd (void *obj) {
65 static char buf[32];
66
67 switch (AGTYPE(obj)) {
68 case AGRAPH: snprintf(buf, sizeof(buf), "graph%p", obj); break;
69 case AGNODE: snprintf(buf, sizeof(buf), "node%p", obj); break;
70 case AGINEDGE:
71 case AGOUTEDGE: snprintf(buf, sizeof(buf), "edge%p", obj); break;
72 default: UNREACHABLE();
73 }
74 return buf;
75}
76
77
78void deleteEdge(gctx_t *gctx, Agraph_t * g, Agedge_t *e)
79{
80 (void)g;
81
82 char *hndl;
83
84 hndl = obj2cmd(e);
85 agdelete(gctx->g, e); /* delete edge from root graph */
86 Tcl_DeleteCommand(gctx->ictx->interp, hndl);
87}
88static void deleteNodeEdges(gctx_t *gctx, Agraph_t *g, Agnode_t *n)
89{
90 Agedge_t *e, *e1;
91
92 e = agfstedge(g, n);
93 while (e) {
94 e1 = agnxtedge(g, e, n);
95 deleteEdge(gctx, g, e);
96 e = e1;
97 }
98}
99void deleteNode(gctx_t * gctx, Agraph_t *g, Agnode_t *n)
100{
101 (void)g;
102
103 char *hndl;
104
105 deleteNodeEdges(gctx, gctx->g, n); /* delete all edges to/from node in root graph */
106
107 hndl = obj2cmd(n);
108 agdelete(gctx->g, n); /* delete node from root graph */
109 Tcl_DeleteCommand(gctx->ictx->interp, hndl);
110}
111static void deleteGraphNodes(gctx_t * gctx, Agraph_t *g)
112{
113 Agnode_t *n, *n1;
114
115 n = agfstnode(g);
116 while (n) {
117 n1 = agnxtnode(g, n);
118 deleteNode(gctx, g, n);
119 n = n1;
120 }
121}
123{
124 Agraph_t *sg;
125 char *hndl;
126
127 for (sg = agfstsubg (g); sg; sg = agnxtsubg (sg)) {
128 deleteGraph(gctx, sg);
129 }
130 deleteGraphNodes(gctx, g);
131
132 hndl = obj2cmd(g);
133 if (g == agroot(g)) {
134 agclose(g);
135 } else {
136 agdelsubg(agroot(g), g);
137 }
138 Tcl_DeleteCommand(gctx->ictx->interp, hndl);
139}
140
141static void myagxset(void *obj, Agsym_t *a, const char *val) {
142 char *hs;
143
144 if (strcmp(a->name, "label") == 0 && val[0] == '<') {
145 size_t len = strlen(val);
146 if (val[len-1] == '>') {
147 hs = strdup(val+1);
148 *(hs+len-2) = '\0';
149 val = agstrdup_html(agraphof(obj),hs);
150 free(hs);
151 }
152 }
153 agxset(obj, a, val);
154}
155
156void setgraphattributes(Agraph_t *g, char *argv[], Tcl_Size argc) {
157 Agsym_t *a;
158
159 for (Tcl_Size i = 0; i < argc; i++) {
160 if (!(a = agfindgraphattr(agroot(g), argv[i])))
161 a = agattr_text(agroot(g), AGRAPH, argv[i], "");
162 myagxset(g, a, argv[++i]);
163 }
164}
165
166void setedgeattributes(Agraph_t *g, Agedge_t *e, char *argv[], Tcl_Size argc) {
167 Agsym_t *a;
168
169 for (Tcl_Size i = 0; i < argc; i++) {
170 /* silently ignore attempts to modify "key" */
171 if (strcmp(argv[i], "key") == 0) {
172 i++;
173 continue;
174 }
175 if (e) {
176 if (!(a = agfindedgeattr(g, argv[i])))
177 a = agattr_text(agroot(g), AGEDGE, argv[i], "");
178 myagxset(e, a, argv[++i]);
179 }
180 else {
181 agattr_text(g, AGEDGE, argv[i], argv[i + 1]);
182 i++;
183 }
184 }
185}
186
187void setnodeattributes(Agraph_t *g, Agnode_t *n, char *argv[], Tcl_Size argc) {
188 Agsym_t *a;
189
190 for (Tcl_Size i = 0; i < argc; i++) {
191 if (n) {
192 if (!(a = agfindnodeattr(g, argv[i])))
193 a = agattr_text(agroot(g), AGNODE, argv[i], "");
194 myagxset(n, a, argv[++i]);
195 }
196 else {
197 agattr_text(g, AGNODE, argv[i], argv[i + 1]);
198 i++;
199 }
200 }
201}
202
203void listGraphAttrs (Tcl_Interp * interp, Agraph_t* g)
204{
205 Agsym_t *a = NULL;
206 while ((a = agnxtattr(g, AGRAPH, a))) {
207 Tcl_AppendElement(interp, a->name);
208 }
209}
210void listNodeAttrs (Tcl_Interp * interp, Agraph_t* g)
211{
212 Agsym_t *a = NULL;
213 while ((a = agnxtattr(g, AGNODE, a))) {
214 Tcl_AppendElement(interp, a->name);
215 }
216}
217void listEdgeAttrs (Tcl_Interp * interp, Agraph_t* g)
218{
219 Agsym_t *a = NULL;
220 while ((a = agnxtattr(g, AGEDGE, a))) {
221 Tcl_AppendElement(interp, a->name);
222 }
223}
224
225void tcldot_layout(GVC_t *gvc, Agraph_t * g, const char *engine)
226{
227 gvFreeLayout(gvc, g); /* in case previously drawn */
228
229/* support old behaviors if engine isn't specified*/
230 if (!engine || *engine == '\0') {
231 if (agisdirected(g))
232 engine = "dot";
233 else
234 engine = "neato";
235 }
236 else {
237 if (strcasecmp(engine, "nop") == 0) {
238 Nop = 2;
240 engine = "neato";
241 }
242 }
243 gvLayout(gvc, g, engine);
244}
245
246char **tcldot_argv_dup(int argc, const char *argv[]) {
247 assert(argc > 0);
248 char **argv_ret = gv_calloc((size_t)argc, sizeof(char *));
249 for (int i = 0; i < argc; ++i) {
250 argv_ret[i] = gv_strdup(argv[i]);
251 }
252 return argv_ret;
253}
254
255void tcldot_argv_free(int argc, char *argv[]) {
256 for (int i = 0; i < argc; ++i) {
257 free(argv[i]);
258 }
259 free(argv);
260}
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
Definition alloc.h:101
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static char * cmd
Definition acyclic.c:40
#define POINTS_PER_INCH
Definition geom.h:58
int Nop
Definition globals.h:55
double PSinputscale
Definition globals.h:56
static double len(glCompPoint p)
Definition glutils.c:150
void free(void *)
node NULL
Definition grammar.y:163
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:357
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
permits traversing the list of attributes of a given type
Definition attr.c:386
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:546
#define agfindedgeattr(g, a)
Definition types.h:617
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:94
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:85
#define agfindgraphattr(g, a)
Definition types.h:613
int agisdirected(Agraph_t *g)
Definition graph.c:180
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:97
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
#define agfindnodeattr(g, a)
Definition types.h:615
Agraph_t * agraphof(void *obj)
Definition obj.c:185
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:20
Agraph_t * agroot(void *obj)
Definition obj.c:168
@ AGOUTEDGE
Definition cgraph.h:207
@ AGEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGINEDGE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
char * agstrdup_html(Agraph_t *, const char *)
returns a pointer to a reference-counted HTML-like copy of the argument string, creating one if neces...
Definition refstr.c:395
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:75
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:80
int agdelsubg(Agraph_t *g, Agraph_t *sub)
Definition subg.c:96
int gvFreeLayout(GVC_t *gvc, graph_t *g)
Definition gvlayout.c:105
int gvLayout(GVC_t *gvc, graph_t *g, const char *engine)
Definition gvc.c:52
static GVC_t * gvc
Definition gv.cpp:23
Graphviz context library.
static gvloadimage_engine_t engine
platform abstraction for case-insensitive string functions
graph or subgraph
Definition cgraph.h:424
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:651
char * name
Definition cgraph.h:653
Definition gvcint.h:81
void * context
Definition gvcjob.h:295
FILE * output_file
Definition gvcjob.h:277
Agraph_t * g
Definition tcldot.h:37
ictx_t * ictx
Definition tcldot.h:38
Tcl_Interp * interp
Definition tcldot.h:29
context used to convey information between commands and a renderer
Definition tcl_context.h:14
struct Tcl_Interp * interp
TCL interpreter.
Definition tcl_context.h:16
#define TCL_SIZE_MAX
Definition tcl-compat.h:18
#define Tcl_Size
Definition tcl-compat.h:33
void tcldot_layout(GVC_t *gvc, Agraph_t *g, const char *engine)
static void myagxset(void *obj, Agsym_t *a, const char *val)
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)
void deleteEdge(gctx_t *gctx, Agraph_t *g, Agedge_t *e)
Definition tcldot-util.c:78
void deleteNode(gctx_t *gctx, Agraph_t *g, Agnode_t *n)
Definition tcldot-util.c:99
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)
static void deleteGraphNodes(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)
Agedge_t * cmd2e(const char *cmd)
Definition tcldot-util.c:53
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)
static void deleteNodeEdges(gctx_t *gctx, Agraph_t *g, Agnode_t *n)
Definition tcldot-util.c:88
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
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30