one can set $tvnext == NULL at the beginning to get a single traversal.
.TP
\fB$tvroot\fP : \fBnode_t\fP
indicates the starting node for a (directed or undirected)
-depth\(hyfirst traversal of the
+depth\(hyfirst or breadth\(hyfirst traversal of the
graph (cf. \fB$tvtype\fP below).
The default value is \fBNULL\fP for each input graph.
+After the traversal at the given root, if the value of \fB$tvroot\fP has changed,
+a new traversal will begin with the new value of \fB$tvroot\fP. Also, set \fB$tvnext\fP below.
+.TP
+\fB$tvnext\fP : \fBnode_t\fP
+indicates the next starting node for a (directed or undirected)
+depth\(hyfirst or breadth\(hyfirst traversal of the
+graph (cf. \fB$tvtype\fP below).
+If a traversal finishes and the \fB$tvroot\fP but the \fB$tvnext\fP has been
+set but not used, this node will be used as the next choice for \fB$tvroot\fP.
+The default value is \fBNULL\fP for each input graph.
.TP
\fB$tvedge\fP : \fBedge_t\fP
For BFS and DFS traversals, this is set to the edge used to arrive at the
return deref(pgm, x, ref->next, (Agobj_t *) state->tvroot,
state);
break;
+ case V_travnext:
+ return deref(pgm, x, ref->next, (Agobj_t *) state->tvnext,
+ state);
+ break;
case M_head:
if (!objp && !(objp = state->curobj)) {
exerror("Current object $ not defined");
case V_travroot:
v.integer = PTR2INT(state->tvroot);
break;
+ case V_travnext:
+ v.integer = PTR2INT(state->tvnext);
+ break;
case V_travedge:
v.integer = PTR2INT(state->tvedge);
break;
agnameof(np));
}
break;
+ case V_travnext:
+ np = INT2PTR(Agnode_t *, v.integer);
+ if (!np || (agroot(np) == state->curgraph)) {
+ state->tvnext = np;
+ state->flags |= GV_NEXT_SET;
+ } else {
+ error(1, "cannot set $tvnext, node %s not in $G : ignored",
+ agnameof(np));
+ }
+ break;
case V_tgtname:
if (!streq(state->tgtname, v.string)) {
vmfree(pgm->vm, state->tgtname);
V_tgtname "$tgtname" ID STRING 0 Y(S)
V_infname "$F" ID STRING 0 Y(S)
V_travroot "$tvroot" ID T_node 0 Y(V)
+V_travnext "$tvnext" ID T_node 0 Y(V)
V_travedge "$tvedge" ID T_edge 0 Y(E)
V_travtype "$tvtype" ID T_tvtyp 0 Y(TV)
V_ARGC "ARGC" ID INTEGER 0 Y(I)
state->tvt = TV_flat;
state->name_used = name_used;
state->tvroot = 0;
+ state->tvnext = 0;
state->tvedge = 0;
state->outFile = info->outFile;
state->argc = info->argc;
TV_prepostdfs, TV_prepostfwd, TV_prepostrev,
} trav_type;
+/* Bits for flags variable.
+ */
+ /* If set, gvpr calls exit() on errors */
+#define GV_USE_EXIT 1
+ /* If set, gvpr stores output graphs in gvpropts */
+#define GV_USE_OUTGRAPH 2
+#define GV_USE_JUMP 4
+
typedef struct {
Agraph_t *curgraph;
Agraph_t *nextgraph;
Agiodisc_t* dfltIO;
trav_type tvt;
Agnode_t *tvroot;
+ Agnode_t *tvnext;
Agedge_t *tvedge;
int name_used;
int argc;
#define DFLT_GVPRPATH "."
#endif
-#define GV_USE_JUMP 4
-
static char *Info[] = {
"gvpr", /* Program */
VERSION, /* Version */
if (state->tvroot != nodes->oldroot) {
np = nodes->oldroot = state->tvroot;
+ } else if (state->flags & GV_NEXT_SET) {
+ np = nodes->oldroot = state->tvroot = state->tvnext;
+ state->flags &= ~GV_NEXT_SET;
} else if (nodes->prev) {
np = nodes->prev = agnxtnode(state->curgraph, nodes->prev);
} else {
#include "ast_common.h"
#include "cgraph.h"
+/* Bits for flags variable in gvprstate_t.
+ * Included here so that calling programs can use the first
+ * two in gvpropts.flags
+ */
/* If set, gvpr calls exit() on errors */
#define GV_USE_EXIT 1
/* If set, gvpr stores output graphs in gvpropts */
#define GV_USE_OUTGRAPH 2
+ /* Use longjmp to return to top-level call in gvpr */
+#define GV_USE_JUMP 4
+ /* $tvnext has been set but not used */
+#define GV_NEXT_SET 8
+
typedef ssize_t (*gvprwr) (void*, const char *buf, size_t nbyte, void*);
typedef int (*gvpruserfn) (char *);