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