42#define DFLT_GVPRPATH "."
52 " [-o <ofile>] [-a <args>] ([-f <prog>] | 'prog') [files]\n\
53 -c - use source graph for output\n\
54 -f <pfile> - find program in file <pfile>\n\
55 -i - create node induced subgraph\n\
56 -a <args> - string arguments available as ARGV[0..]\n\
57 -o <ofile> - write output to <ofile>; stdout by default\n\
58 -n - no read-ahead of input graphs\n\
59 -q - turn off warning messages\n\
60 -V - print version info\n\
61 -? - print usage info\n\
62If no files are specified, stdin is used\n";
79 FILE *outs = fopen(name,
"w");
106 if ((c = *rs) ==
'\0')
111 }
else if (!q && ((c ==
'"') || (c ==
'\''))) {
113 }
else if (c ==
'\\') {
120 "backslash in argument followed by no character - ignored");
157 "at most %d arguments allowed per -a flag - ignoring rest",
167 av =
gv_recalloc(*argv, (
size_t)oldcnt, (
size_t)argc,
sizeof(
char *));
168 for (i = 0; i <
cnt; i++)
175#if defined(_WIN32) && !defined(__MINGW32__)
183static char *
concat(
char *pfx,
char *sfx) {
207 path = getenv(
"GVPRPATH");
209 path = getenv(
"GPRPATH");
219 fprintf(stderr,
"PATH: %s\n",
path);
229 sz = (size_t)(cp -
path);
239 if (access(
s, R_OK) == 0) {
250 fprintf(stderr,
"file %s resolved to %s\n", arg,
fname);
254static char *
getOptarg(
int c,
char **argp,
int *argip,
int argc,
char **argv) {
264 }
else if (argi < argc) {
286 while ((c = *arg++)) {
289 opts->compflags.srcout =
true;
292 opts->compflags.srcout =
true;
293 opts->compflags.clone =
true;
296 if ((optarg =
getOptarg(c, &arg, &argi, argc, argv)) &&
303 opts->compflags.induce =
true;
309 if ((optarg =
getOptarg(c, &arg, &argi, argc, argv))) {
315 if (!(optarg =
getOptarg(c, &arg, &argi, argc, argv)) ||
326 fprintf(stderr,
"%s version %s (%s)\n",
Info[0],
Info[1],
Info[2]);
330 if (optopt ==
'\0' || optopt ==
'?')
331 fprintf(stderr,
"Usage: gvpr%s",
usage);
347 fclose(
opts.outFile);
351 for (
int i = 0; i <
opts.argc; i++)
365 opts.cmdName = argv[0];
371 strs_t input_filenames = {0};
374 for (
int i = 1; i < argc;) {
383 strs_append(&input_filenames, arg);
387 if (
opts.useFile == 0) {
388 if (strs_is_empty(&input_filenames)) {
392 opts.program = strs_pop_front(&input_filenames);
395 if (strs_is_empty(&input_filenames)) {
397 strs_free(&input_filenames);
399 strs_append(&input_filenames,
NULL);
400 opts.inFiles = strs_detach(&input_filenames);
404 opts.outFile = stdout;
407 if (
opts.state <= 0) {
410 strs_free(&input_filenames);
422 for (
size_t i = 0; i < xprog->
n_estmts; i++) {
444 for (
size_t i = 0; i < xprog->
n_nstmts; i++) {
472 state->
flags &= ~GV_NEXT_SET;
473 }
else if (nodes->
prev) {
481#define MARKED(x) (((x)->iu.integer) & 1)
482#define MARK(x) (((x)->iu.integer) = 1)
483#define ONSTACK(x) (((x)->iu.integer) & 2)
484#define PUSH(x, e) (((x)->iu.integer) |= 2, (x)->ine = (e))
485#define POP(x) (((x)->iu.integer) &= (~2))
520 node_queue_t q = {0};
529 while ((n =
nextNode(state, &nodes))) {
534 node_queue_push_back(&q, n);
535 while (!node_queue_is_empty(&q)) {
536 n = node_queue_pop_front(&q);
540 state->tvedge = nd->ine;
541 if (!
evalNode(state, prog, xprog, n))
543 for (cure =
agfstedge(g, n); cure; cure = nxte) {
548 if (!
evalEdge(state, prog, xprog, cure))
551 node_queue_push_back(&q, cure->
node);
566 edge_stack_t stk = {0};
577 while ((n =
nextNode(state, &nodes))) {
585 state->tvedge = cure = 0;
593 cure = fns->nxtedge(state->curgraph, cure, curn);
595 cure = fns->fstedge(state->curgraph, curn);
597 if (entry ==
agopp(cure))
605 if (fns->undirected) {
612 edge_stack_push_back(&stk, entry);
613 state->tvedge = entry = cure;
627 entry = edge_stack_is_empty(&stk) ?
NULL : edge_stack_pop_back(&stk);
628 if (entry == &(
seed.out))
631 state->tvedge = entry;
640 edge_stack_free(&stk);
661 for (e =
agfstout(g, n); e; e = nexte) {
676 if (!
evalNode(state, prog, xprog, n))
679 for (e =
agfstout(g, n); e; e = nexte) {
727 switch (state->
tvt) {
834 if (
data->lock.locked)
835 data->lock.zombie =
true;
862 const char *fmt, ...) {
866 errorv((discipline && handle) ? *((
char **)handle) : (
char *)handle, level,
875 longjmp(state->
jbuf, 1);
944 bool incoreGraphs = uopts && uopts->
ingraphs;
947 fprintf(stderr,
"Parse/compile/init: %.2f secs.\n",
gvelapsed_sec());
965 fprintf(stderr,
"Read graph: %.2f secs.\n",
gvelapsed_sec());
994 fprintf(stderr,
"Finish graph: %.2f secs.\n",
gvelapsed_sec());
1023 fprintf(stderr,
"Read graph: %.2f secs.\n",
gvelapsed_sec());
1047 int rv =
gvpr_core(argc, argv, uopts, &gvpr_state);
Agobj_t * cloneO(Agraph_t *g, Agobj_t *obj)
int sfioWrite(Agraph_t *g, FILE *fp)
double gvelapsed_sec(void)
static void agxbfree(agxbuf *xb)
free any malloced resources
static size_t agxbput_n(agxbuf *xb, const char *s, size_t ssz)
append string s of length ssz into xb
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static WUR char * agxbuse(agxbuf *xb)
static char * agxbdisown(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
static char * gv_strdup(const char *original)
abstract graph C library, Cgraph API
comp_prog * compileProg(parse_prog *inp, Gpr_t *state, compflags_t flags)
Agraph_t * openSubg(Agraph_t *g, char *name)
void freeCompileProg(comp_prog *p)
Agraph_t * readG(FILE *fp)
void setTraceLevel(int i)
void errorv(const char *id, int level, const char *s, va_list ap)
void setErrorId(char *id)
void setErrorErrors(int errors)
Extype_t exeval(Expr_t *ex, Exnode_t *exnode, void *env)
static NORETURN void graphviz_exit(int status)
static void cleanup(void)
void initGPRState(Gpr_t *state)
void addBindings(Gpr_t *state, gvprbinding *bindings)
Gpr_t * openGPRState(gpr_info *info)
void closeGPRState(Gpr_t *state)
static int cnt(Dict_t *d, Dtlink_t **set)
int agnnodes(Agraph_t *g)
#define agopp(e)
opposite edge: flip Agedgepair_s.out ⇄ Agedgepair_s.in/*#end#*/
Agedge_t * agsubedge(Agraph_t *g, Agedge_t *e, int createflag)
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Agnode_t * agfstnode(Agraph_t *g)
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Agraph_t * agroot(void *obj)
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
replacements for ctype.h functions
static bool gv_isspace(int c)
static void freeOpts(options opts)
static char * concat(char *pfx, char *sfx)
static char * resolve(char *arg, int verbose)
static Agobj_t * evalNode(Gpr_t *state, Expr_t *prog, comp_block *xprog, Agnode_t *n)
static void gvexitf(void *env, int v)
int gvpr(int argc, char *argv[], gvpropts *uopts)
static void chkClose(Agraph_t *g)
static void travNodes(Gpr_t *state, Expr_t *prog, comp_block *xprog)
static void doCleanup(Agraph_t *g)
static char * gettok(char **sp)
static FILE * openOut(char *name)
static bool traverse(Gpr_t *state, Expr_t *prog, comp_block *bp, bool cleanup)
static Agedge_t * agnxtin_(Agraph_t *g, Agedge_t *e, Agnode_t *ignored)
agnxtin wrapper to tweak calling convention
Agedge_t *(* nxttedgefn_t)(Agraph_t *, Agedge_t *, Agnode_t *)
static options scanArgs(int argc, char **argv)
static void travDFS(Gpr_t *state, Expr_t *prog, comp_block *xprog, trav_fns *fns)
static void travBFS(Gpr_t *state, Expr_t *prog, comp_block *xprog)
static void travFlat(Gpr_t *state, Expr_t *prog, comp_block *xprog)
static void travEdges(Gpr_t *state, Expr_t *prog, comp_block *xprog)
static Agnode_t * nextNode(Gpr_t *state, nodestream *nodes)
static void addOutputGraph(Gpr_t *state, gvpropts *uopts)
static int gvpr_core(int argc, char *argv[], gvpropts *uopts, gvpr_state_t *gs)
static int doFlags(char *arg, int argi, int argc, char **argv, options *opts)
static void gverrorf(Expr_t *handle, Exdisc_t *discipline, int level, const char *fmt,...)
Agedge_t *(* fstedgefn_t)(Agraph_t *, Agnode_t *)
static Agedge_t * agnxtout_(Agraph_t *g, Agedge_t *e, Agnode_t *ignored)
agnxtout wrapper to tweak calling convention
static Agraph_t * ing_read(void *fp)
static const char * usage
static Agobj_t * evalEdge(Gpr_t *state, Expr_t *prog, comp_block *xprog, Agedge_t *e)
static int parseArgs(char *s, int argc, char ***argv)
static char * getOptarg(int c, char **argp, int *argip, int argc, char **argv)
graph pattern scanning and processing language API, main function gvpr
char * fileName(ingraph_state *sp)
Return name of current file being processed.
void closeIngraph(ingraph_state *sp)
Agraph_t * nextGraph(ingraph_state *sp)
ingraph_state * newIng(ingraph_state *sp, char **files, Agraph_t *(*readf)(void *))
ingraph_state * newIngGraphs(ingraph_state *sp, Agraph_t **graphs, Agraph_t *(*readf)(void *))
supports user-supplied data
#define DEFINE_LIST(name, type)
void freeParseProg(parse_prog *prog)
parse_prog * parseProg(char *input, int isFile)
parses input into gpr sections
a generic header of Agraph_s, Agnode_s and Agedge_s
bool does_walk_graph
does this block have a node or edge statement?
bool uses_graph
does this program use the input graph?
collective managed state used in gvpr_core
size_t n_outgraphs
if GV_USE_OUTGRAPH set, output graphs