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