Graphviz 14.1.2~dev.20260119.0928
Loading...
Searching...
No Matches
tcldot-nodecmd.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 "tcldot.h"
15#include <stdlib.h>
16#include <string.h>
17#include <util/streq.h>
18
19static int nodecmd_internal(ClientData clientData, Tcl_Interp *interp, int argc,
20 char *argv[]) {
21 const char **argv2;
22 int i;
23 Agraph_t *g;
24 Agnode_t *n, *head;
25 Agedge_t *e;
26 Agsym_t *a;
27 gctx_t *gctx = (gctx_t *)clientData;
28
29 if (argc < 2) {
30 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
31 " option ?arg arg ...?\"", NULL);
32 return TCL_ERROR;
33 }
34 n = cmd2n(argv[0]);
35 if (!n) {
36 Tcl_AppendResult(interp, "node \"", argv[0], "\" not found", NULL);
37 return TCL_ERROR;
38 }
39 g = agraphof(n);
40
41 if (streq("addedge", argv[1])) {
42 if (argc < 3 || argc % 2 == 0) {
43 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
44 " addedge head ?attributename attributevalue? ?...?\"",
45 NULL);
46 return TCL_ERROR;
47 }
48 head = cmd2n(argv[2]);
49 if (!head) {
50 if (!(head = agfindnode(g, argv[2]))) {
51 Tcl_AppendResult(interp, "head node \"", argv[2], "\" not found.",
52 NULL);
53 return TCL_ERROR;
54 }
55 }
56 if (agroot(g) != agroot(agraphof(head))) {
57 Tcl_AppendResult(interp, "nodes ", argv[0], " and ", argv[2],
58 " are not in the same graph.", NULL);
59 return TCL_ERROR;
60 }
61 e = agedge(g, n, head, NULL, 1);
62 Tcl_AppendResult(interp, obj2cmd(e), NULL);
63 setedgeattributes(agroot(g), e, &argv[3], (Tcl_Size)argc - 3);
64 return TCL_OK;
65
66 } else if (streq("delete", argv[1])) {
67 deleteNode(gctx, g, n);
68 return TCL_OK;
69
70 } else if (streq("findedge", argv[1])) {
71 if (argc < 3) {
72 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
73 " findedge headnodename\"", NULL);
74 return TCL_ERROR;
75 }
76 if (!(head = agfindnode(g, argv[2]))) {
77 Tcl_AppendResult(interp, "head node \"", argv[2], "\" not found.", NULL);
78 return TCL_ERROR;
79 }
80 if (!agfindedge(g, n, head)) {
81 Tcl_AppendResult(interp, "edge \"", argv[0], " - ", obj2cmd(head),
82 "\" not found.", NULL);
83 return TCL_ERROR;
84 }
85 Tcl_AppendElement(interp, obj2cmd(head));
86 return TCL_OK;
87
88 } else if (streq("listattributes", argv[1])) {
89 listNodeAttrs(interp, g);
90 return TCL_OK;
91
92 } else if (streq("listedges", argv[1])) {
93 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
94 Tcl_AppendElement(interp, obj2cmd(e));
95 }
96 return TCL_OK;
97
98 } else if (streq("listinedges", argv[1])) {
99 for (e = agfstin(g, n); e; e = agnxtin(g, e)) {
100 Tcl_AppendElement(interp, obj2cmd(e));
101 }
102 return TCL_OK;
103
104 } else if (streq("listoutedges", argv[1])) {
105 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
106 Tcl_AppendElement(interp, obj2cmd(e));
107 }
108 return TCL_OK;
109
110 } else if (streq("queryattributes", argv[1])) {
111 for (i = 2; i < argc; i++) {
112 Tcl_Size argc2;
113 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
114 return TCL_ERROR;
115 for (Tcl_Size j = 0; j < argc2; j++) {
116 char *arg = strdup(argv2[j]);
117 if ((a = agfindnodeattr(g, arg))) {
118 Tcl_AppendElement(interp, agxget(n, a));
119 } else {
120 Tcl_AppendResult(interp, "no attribute named \"", arg, "\"", NULL);
121 free(arg);
122 Tcl_Free((char *)argv2);
123 return TCL_ERROR;
124 }
125 free(arg);
126 }
127 Tcl_Free((char *)argv2);
128 }
129 return TCL_OK;
130
131 } else if (streq("queryattributevalues", argv[1])) {
132 for (i = 2; i < argc; i++) {
133 Tcl_Size argc2;
134 if (Tcl_SplitList(interp, argv[i], &argc2, &argv2) != TCL_OK)
135 return TCL_ERROR;
136 for (Tcl_Size j = 0; j < argc2; j++) {
137 char *arg = strdup(argv2[j]);
138 if ((a = agfindnodeattr(g, arg))) {
139 Tcl_AppendElement(interp, arg);
140 Tcl_AppendElement(interp, agxget(n, a));
141 } else {
142 Tcl_AppendResult(interp, "no attribute named \"", arg, "\"", NULL);
143 free(arg);
144 Tcl_Free((char *)argv2);
145 return TCL_ERROR;
146 }
147 free(arg);
148 }
149 Tcl_Free((char *)argv2);
150 }
151 return TCL_OK;
152
153 } else if (streq("setattributes", argv[1])) {
154 g = agroot(g);
155 if (argc == 3) {
156 Tcl_Size argc2;
157 if (Tcl_SplitList(interp, argv[2], &argc2, &argv2) != TCL_OK)
158 return TCL_ERROR;
159 if (argc2 == 0 || argc2 % 2 != 0) {
160 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
161 "\" setattributes attributename attributevalue "
162 "?attributename attributevalue? ?...?",
163 NULL);
164 Tcl_Free((char *)argv2);
165 return TCL_ERROR;
166 }
167 char **argv2_copy = tcldot_argv_dup(argc2, argv2);
168 setnodeattributes(g, n, argv2_copy, argc2);
169 tcldot_argv_free(argc2, argv2_copy);
170 Tcl_Free((char *)argv2);
171 } else {
172 if (argc < 4 || argc % 2 != 0) {
173 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
174 "\" setattributes attributename attributevalue "
175 "?attributename attributevalue? ?...?",
176 NULL);
177 return TCL_ERROR;
178 }
179 setnodeattributes(g, n, &argv[2], (Tcl_Size)argc - 2);
180 }
181 return TCL_OK;
182
183 } else if (streq("showname", argv[1])) {
184 Tcl_SetResult(interp, agnameof(n), TCL_STATIC);
185 return TCL_OK;
186
187 } else {
188 Tcl_AppendResult(interp, "bad option \"", argv[1], "\": must be one of:",
189 "\n\taddedge, listattributes, listedges, listinedges,",
190 "\n\tlistoutedges, queryattributes, queryattributevalues,",
191 "\n\tsetattributes, showname.", NULL);
192 return TCL_ERROR;
193 }
194}
195
196int nodecmd(ClientData clientData, Tcl_Interp *interp, int argc,
197 const char *argv[]) {
198 char **argv_copy = tcldot_argv_dup((Tcl_Size)argc, argv);
199 int rc = nodecmd_internal(clientData, interp, argc, argv_copy);
200 tcldot_argv_free((Tcl_Size)argc, argv_copy);
201 return rc;
202}
#define head
Definition dthdr.h:15
void free(void *)
node NULL
Definition grammar.y:181
char * agxget(void *obj, Agsym_t *sym)
Definition attr.c:460
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:255
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Definition edge.c:73
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:28
#define agfindedge(g, t, h)
Definition types.h:609
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:98
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:43
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:89
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition edge.c:59
#define agfindnodeattr(g, a)
Definition types.h:615
#define agfindnode(g, n)
Definition types.h:611
Agraph_t * agraphof(void *obj)
Definition obj.c:187
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
Agraph_t * agroot(void *obj)
Definition obj.c:170
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
#define Tcl_Size
Definition tcl-compat.h:33
static int nodecmd_internal(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
int nodecmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
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 deleteNode(gctx_t *gctx, Agraph_t *g, Agnode_t *n)
Definition tcldot-util.c:97
char * obj2cmd(void *obj)
Definition tcldot-util.c:67
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)
Agnode_t * cmd2n(const char *cmd)
Definition tcldot-util.c:49