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