2
* Tcl extension for Dynamic Graphs by John Ellson (ellson@lucent.com)
4
* Builds on libincr + libgraph by Stephen North (north@research.att.com)
13
/* FIXME - not thread safe */
14
dgrInterp_t dgrInterp;
17
dgnew_cmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
19
dgrInterp_t *dg = (dgrInterp_t *)clientData;
27
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
28
" graphtype ?graphname? ?attributename attributevalue? ?...?\"",
33
length = strlen(argv[1]);
34
/* string matching order is important when leading chars match.
35
The shorter string must be tested first. */
36
if ((c == 'd') && (strncmp(argv[1], "digraph", length) == 0)) {
38
} else if ((c == 'd') && (strncmp(argv[1], "digraphstrict", length) == 0)) {
39
kind = Agstrictdirected;
40
} else if ((c == 'g') && (strncmp(argv[1], "graph", length) == 0)) {
42
} else if ((c == 'g') && (strncmp(argv[1], "graphstrict", length) == 0)) {
43
kind = Agstrictundirected;
44
} else if ((c == 's') && (strncmp(argv[1], "strictgraph", length) == 0)) {
45
kind = Agstrictundirected;
46
} else if ((c == 's') && (strncmp(argv[1], "strictdigraph", length) == 0)) {
47
kind = Agstrictdirected;
49
Tcl_AppendResult(interp, "bad graphtype \"", argv[1],
50
"\": must be one of:",
51
"\n\tdigraph, strictdigraph, graph, strictgraph.",
57
/* if odd number of args then argv[2] is name */
58
g = agopen(argv[2], kind, &gdisc);
61
g = agopen((char *) NULL, kind, &gdisc);
63
for (; i < argc; i = i + 2) {
64
if (!(sym = (Agsym_t *) agattrsym(g, argv[i]))) {
65
sym = agattr(g, AGRAPH, argv[i], "");
67
agxset(g, sym, argv[i + 1]);
69
dg_gpstruct_init (dg, g);
74
dgread_cmd(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
76
dgrInterp_t *dg = (dgrInterp_t *)clientData;
79
/* TCL_CHANNELS are available in tcl7.5 and later */
87
/* first use determines mode */
88
if (dg->object_commands == -1) {
89
dg->object_commands = 1;
90
Tcl_DeleteCommand(interp, "dg");
94
Tcl_AppendResult(interp, "wrong # args: should be \"",
95
argv[0], " fileHandle\"", (char *) NULL);
100
f = Tcl_GetChannel(interp, argv[1], &mode);
101
if (f == (Tcl_Channel) NULL) {
102
Tcl_AppendResult(interp, "unable to open channel: ",
103
argv[1], (char *) NULL);
107
if (Tcl_GetOpenFile(interp, argv[1], 0, 0, &f) != TCL_OK) {
108
Tcl_AppendResult(interp, "failed to find open file: ",
109
argv[1], (char *) NULL);
114
gdisc.io = &file_iodisc;
116
if (!(g = agconcat((Agraph_t *) NULL, f, &gdisc))) {
117
Tcl_AppendResult(interp, "failure reading file: ",
118
argv[1], (char *) NULL);
122
dg_gpfromdot_init(dg, g);
123
dg_gpstruct_init(dg, g);
128
dgstring_cmd(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
130
dgrInterp_t *dg = (dgrInterp_t *)clientData;
134
/* first use determines mode */
135
if (dg->object_commands == -1) {
136
dg->object_commands = 1;
137
Tcl_DeleteCommand(interp, "dg");
141
Tcl_AppendResult(interp, "wrong # args: should be \"",
142
argv[0], " dot_string\"", (char *) NULL);
146
gdisc.io = &string_iodisc;
148
/* s gets modified to point to 8K blocks in argv[1] */
150
if (!(g = agconcat((Agraph_t *) NULL, &s, &gdisc))) {
151
Tcl_AppendResult(interp, "failure reading string: ",
152
argv[1], (char *) NULL);
156
dg_gpfromdot_init(dg, g);
157
dg_gpstruct_init(dg, g);
162
* dgreset is intended for regression test use only. It resets the handle
163
* tables so that we get predictable handles that are independent of any
166
* dgreset will return an error if handles in the old tables are still in use
169
dgreset_cmd(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
171
dgrInterp_t *dg = (dgrInterp_t *)clientData;
173
if (tclhandleReset(dg->graphTable, 10) == TCL_ERROR) {
174
Tcl_AppendResult(interp, "graph handles still in use", (char *) NULL);
177
if (tclhandleReset(dg->nodeTable, 100) == TCL_ERROR) {
178
Tcl_AppendResult(interp, "node handles still in use", (char *) NULL);
181
if (tclhandleReset(dg->edgeTable, 100) == TCL_ERROR) {
182
Tcl_AppendResult(interp, "edge handles still in use", (char *) NULL);
189
dg_cmd(ClientData clientData, Tcl_Interp * interp, int argc, char *argv[])
192
dgrInterp_t *dg = (dgrInterp_t *)clientData;
194
/* first use determines mode */
195
if (dg->object_commands == -1) {
196
dg->object_commands = 0;
197
Tcl_DeleteCommand(interp, "dgnew");
198
Tcl_DeleteCommand(interp, "dgread");
199
Tcl_DeleteCommand(interp, "dgstring");
202
if ((argc < 2) || strlen(argv[1]) < 3) {
203
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
204
"\"method ...\"", "where method is one of:",
205
"\n\tread, graph, digraph, strictgraph, strictdigraph,",
206
"\n\t<graphhandle>, <nodehandle>, <edgehandle>.", (char *) NULL);
211
return nodecmd(clientData, interp, argc-1, &argv[1]);
212
} else if (c == 'E') {
213
return edgecmd(clientData, interp, argc-1, &argv[1]);
214
} else if (c == 'G') {
215
return graphcmd(clientData, interp, argc-1, &argv[1]);
216
} else if (strncmp(argv[1], "new", 3) == 0) {
217
return dgnew_cmd(clientData, interp, argc-1, &argv[1]);
218
} else if (strncmp(argv[1], "read", 4) == 0) {
219
return dgread_cmd(clientData, interp, argc-1, &argv[1]);
220
} else if (strncmp(argv[1], "string", 6) == 0) {
221
return dgstring_cmd(clientData, interp, argc-1, &argv[1]);
223
Tcl_AppendResult(interp, "invalid method: ", argv[1], (char *) NULL);
228
Tcldgr_Init(Tcl_Interp * interp)
230
dgrInterp_t *dg = &dgrInterp;
233
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
237
if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
241
if (Tcl_PkgProvide(interp, "Tcldgr", VERSION) != TCL_OK) {
245
/* FIXME - this is what we want
246
* dg = (dgrInterp_t *)Tcl_Alloc(sizeof(dgrInterp_t));
249
dg->object_commands = -1;
250
dg->graphTable = tclhandleInit("dgG",sizeof(dgGraph_t), 10);
251
dg->nodeTable = tclhandleInit("dgN",sizeof(Agnode_t *), 100);
252
dg->edgeTable = tclhandleInit("dgE",sizeof(Agedge_t *), 100);
255
Tcl_CreateCommand(interp, "dg", dg_cmd, (ClientData)dg,
256
(Tcl_CmdDeleteProc *) NULL);
257
Tcl_CreateCommand(interp, "dgnew", dgnew_cmd, (ClientData)dg,
258
(Tcl_CmdDeleteProc *) NULL);
259
Tcl_CreateCommand(interp, "dgread", dgread_cmd, (ClientData)dg,
260
(Tcl_CmdDeleteProc *) NULL);
261
Tcl_CreateCommand(interp, "dgstring", dgstring_cmd, (ClientData)dg,
262
(Tcl_CmdDeleteProc *) NULL);
263
Tcl_CreateCommand(interp, "dgreset", dgreset_cmd, (ClientData)dg,
264
(Tcl_CmdDeleteProc *) NULL);
270
Tcldgr_SafeInit(Tcl_Interp * interp)
272
return Tcldgr_Init(interp);