Graphviz 13.0.0~dev.20241220.2304
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 <limits.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{
29 if (len > INT_MAX) {
30 len = INT_MAX;
31 }
32 const int written = Tcl_Write((Tcl_Channel)(job->output_file), s, (int)len);
33 if (written < 0) {
34 return 0;
35 }
36 return (size_t)written;
37}
38
39/* handles (tcl commands) to obj* */
40
41Agraph_t *cmd2g(const char *cmd) {
42 Agraph_t *g = NULL;
43
44 if (sscanf(cmd, "graph%p", &g) != 1 || !g)
45 return NULL;
46 return g;
47}
48Agnode_t *cmd2n(const char *cmd) {
49 Agnode_t *n = NULL;
50
51 if (sscanf(cmd, "node%p", &n) != 1 || !n)
52 return NULL;
53 return n;
54}
55Agedge_t *cmd2e(const char *cmd) {
56 Agedge_t *e = NULL;
57
58 if (sscanf(cmd, "edge%p", &e) != 1 || !e)
59 return NULL;
60 return e;
61}
62
63
64/* obj* to handles (tcl commands) */
65
66char *obj2cmd (void *obj) {
67 static char buf[32];
68
69 switch (AGTYPE(obj)) {
70 case AGRAPH: snprintf(buf, sizeof(buf), "graph%p", obj); break;
71 case AGNODE: snprintf(buf, sizeof(buf), "node%p", obj); break;
72 case AGINEDGE:
73 case AGOUTEDGE: snprintf(buf, sizeof(buf), "edge%p", obj); break;
74 default: UNREACHABLE();
75 }
76 return buf;
77}
78
79
80void deleteEdge(gctx_t *gctx, Agraph_t * g, Agedge_t *e)
81{
82 (void)g;
83
84 char *hndl;
85
86 hndl = obj2cmd(e);
87 agdelete(gctx->g, e); /* delete edge from root graph */
88 Tcl_DeleteCommand(gctx->ictx->interp, hndl);
89}
90static void deleteNodeEdges(gctx_t *gctx, Agraph_t *g, Agnode_t *n)
91{
92 Agedge_t *e, *e1;
93
94 e = agfstedge(g, n);
95 while (e) {
96 e1 = agnxtedge(g, e, n);
97 deleteEdge(gctx, g, e);
98 e = e1;
99 }
100}
101void deleteNode(gctx_t * gctx, Agraph_t *g, Agnode_t *n)
102{
103 (void)g;
104
105 char *hndl;
106
107 deleteNodeEdges(gctx, gctx->g, n); /* delete all edges to/from node in root graph */
108
109 hndl = obj2cmd(n);
110 agdelete(gctx->g, n); /* delete node from root graph */
111 Tcl_DeleteCommand(gctx->ictx->interp, hndl);
112}
113static void deleteGraphNodes(gctx_t * gctx, Agraph_t *g)
114{
115 Agnode_t *n, *n1;
116
117 n = agfstnode(g);
118 while (n) {
119 n1 = agnxtnode(g, n);
120 deleteNode(gctx, g, n);
121 n = n1;
122 }
123}
125{
126 Agraph_t *sg;
127 char *hndl;
128
129 for (sg = agfstsubg (g); sg; sg = agnxtsubg (sg)) {
130 deleteGraph(gctx, sg);
131 }
132 deleteGraphNodes(gctx, g);
133
134 hndl = obj2cmd(g);
135 if (g == agroot(g)) {
136 agclose(g);
137 } else {
138 agdelsubg(agroot(g), g);
139 }
140 Tcl_DeleteCommand(gctx->ictx->interp, hndl);
141}
142
143static void myagxset(void *obj, Agsym_t *a, char *val)
144{
145 char *hs;
146
147 if (strcmp(a->name, "label") == 0 && val[0] == '<') {
148 size_t len = strlen(val);
149 if (val[len-1] == '>') {
150 hs = strdup(val+1);
151 *(hs+len-2) = '\0';
152 val = agstrdup_html(agraphof(obj),hs);
153 free(hs);
154 }
155 }
156 agxset(obj, a, val);
157}
158void setgraphattributes(Agraph_t * g, char *argv[], int argc)
159{
160 int i;
161 Agsym_t *a;
162
163 for (i = 0; i < argc; i++) {
164 if (!(a = agfindgraphattr(agroot(g), argv[i])))
165 a = agattr(agroot(g), AGRAPH, argv[i], "");
166 myagxset(g, a, argv[++i]);
167 }
168}
169
170void setedgeattributes(Agraph_t * g, Agedge_t * e, char *argv[], int argc)
171{
172 int i;
173 Agsym_t *a;
174
175 for (i = 0; i < argc; i++) {
176 /* silently ignore attempts to modify "key" */
177 if (strcmp(argv[i], "key") == 0) {
178 i++;
179 continue;
180 }
181 if (e) {
182 if (!(a = agfindedgeattr(g, argv[i])))
183 a = agattr(agroot(g), AGEDGE, argv[i], "");
184 myagxset(e, a, argv[++i]);
185 }
186 else {
187 agattr(g, AGEDGE, argv[i], argv[i+1]);
188 i++;
189 }
190 }
191}
192
193void setnodeattributes(Agraph_t * g, Agnode_t * n, char *argv[], int argc)
194{
195 int i;
196 Agsym_t *a;
197
198 for (i = 0; i < argc; i++) {
199 if (n) {
200 if (!(a = agfindnodeattr(g, argv[i])))
201 a = agattr(agroot(g), AGNODE, argv[i], "");
202 myagxset(n, a, argv[++i]);
203 }
204 else {
205 agattr(g, AGNODE, argv[i], argv[i+1]);
206 i++;
207 }
208 }
209}
210
211void listGraphAttrs (Tcl_Interp * interp, Agraph_t* g)
212{
213 Agsym_t *a = NULL;
214 while ((a = agnxtattr(g, AGRAPH, a))) {
215 Tcl_AppendElement(interp, a->name);
216 }
217}
218void listNodeAttrs (Tcl_Interp * interp, Agraph_t* g)
219{
220 Agsym_t *a = NULL;
221 while ((a = agnxtattr(g, AGNODE, a))) {
222 Tcl_AppendElement(interp, a->name);
223 }
224}
225void listEdgeAttrs (Tcl_Interp * interp, Agraph_t* g)
226{
227 Agsym_t *a = NULL;
228 while ((a = agnxtattr(g, AGEDGE, a))) {
229 Tcl_AppendElement(interp, a->name);
230 }
231}
232
233void tcldot_layout(GVC_t *gvc, Agraph_t * g, const char *engine)
234{
235 gvFreeLayout(gvc, g); /* in case previously drawn */
236
237/* support old behaviors if engine isn't specified*/
238 if (!engine || *engine == '\0') {
239 if (agisdirected(g))
240 engine = "dot";
241 else
242 engine = "neato";
243 }
244 else {
245 if (strcasecmp(engine, "nop") == 0) {
246 Nop = 2;
248 engine = "neato";
249 }
250 }
251 gvLayout(gvc, g, engine);
252}
253
254char **tcldot_argv_dup(int argc, const char *argv[]) {
255 assert(argc > 0);
256 char **argv_ret = gv_calloc((size_t)argc, sizeof(char *));
257 for (int i = 0; i < argc; ++i) {
258 argv_ret[i] = gv_strdup(argv[i]);
259 }
260 return argv_ret;
261}
262
263void tcldot_argv_free(int argc, char *argv[]) {
264 for (int i = 0; i < argc; ++i) {
265 free(argv[i]);
266 }
267 free(argv);
268}
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:64
int Nop
Definition globals.h:54
double PSinputscale
Definition globals.h:55
static double len(glCompPoint p)
Definition glutils.c:150
void free(void *)
node NULL
Definition grammar.y:163
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:338
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
permits traversing the list of attributes of a given type
Definition attr.c:353
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:478
#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:190
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:102
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 *)
Definition refstr.c:135
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:78
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:83
int agdelsubg(Agraph_t *g, Agraph_t *sub)
Definition subg.c:99
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:425
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:637
char * name
Definition cgraph.h:639
Definition gvcint.h:80
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
void tcldot_layout(GVC_t *gvc, Agraph_t *g, const char *engine)
void setgraphattributes(Agraph_t *g, char *argv[], int argc)
void listNodeAttrs(Tcl_Interp *interp, Agraph_t *g)
void listGraphAttrs(Tcl_Interp *interp, Agraph_t *g)
void deleteEdge(gctx_t *gctx, Agraph_t *g, Agedge_t *e)
Definition tcldot-util.c:80
void deleteNode(gctx_t *gctx, Agraph_t *g, Agnode_t *n)
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:66
Agraph_t * cmd2g(const char *cmd)
Definition tcldot-util.c:41
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:55
static void myagxset(void *obj, Agsym_t *a, char *val)
void setnodeattributes(Agraph_t *g, Agnode_t *n, char *argv[], int argc)
void setedgeattributes(Agraph_t *g, Agedge_t *e, char *argv[], int argc)
static void deleteNodeEdges(gctx_t *gctx, Agraph_t *g, Agnode_t *n)
Definition tcldot-util.c:90
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:48
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30