]> granicus.if.org Git - graphviz/commitdiff
Make gvpr into a library.
authorerg <devnull@localhost>
Tue, 23 Jun 2009 22:12:55 +0000 (22:12 +0000)
committererg <devnull@localhost>
Tue, 23 Jun 2009 22:12:55 +0000 (22:12 +0000)
25 files changed:
cmd/gvpr/Makefile.am
cmd/gvpr/Makefile.old
cmd/gvpr/gvprmain.c [new file with mode: 0644]
configure.ac
lib/Makefile.am
lib/gvpr/Makefile.am [new file with mode: 0644]
lib/gvpr/Makefile.old [new file with mode: 0644]
lib/gvpr/actions.c [moved from cmd/gvpr/actions.c with 93% similarity]
lib/gvpr/actions.h [moved from cmd/gvpr/actions.h with 100% similarity]
lib/gvpr/compile.c [moved from cmd/gvpr/compile.c with 91% similarity]
lib/gvpr/compile.h [moved from cmd/gvpr/compile.h with 96% similarity]
lib/gvpr/gdefs.h [new file with mode: 0644]
lib/gvpr/gprdata [moved from cmd/gvpr/gprdata with 100% similarity]
lib/gvpr/gprstate.c [moved from cmd/gvpr/gprstate.c with 71% similarity]
lib/gvpr/gprstate.h [moved from cmd/gvpr/gprstate.h with 86% similarity]
lib/gvpr/gvpr.c [moved from cmd/gvpr/gvpr.c with 56% similarity]
lib/gvpr/gvpr.h [new file with mode: 0644]
lib/gvpr/libgvpr.pc.in [new file with mode: 0644]
lib/gvpr/mkdefs.c [moved from cmd/gvpr/mkdefs.c with 100% similarity]
lib/gvpr/parse.c [moved from cmd/gvpr/parse.c with 87% similarity]
lib/gvpr/parse.h [moved from cmd/gvpr/parse.h with 96% similarity]
lib/gvpr/queue.c [moved from cmd/gvpr/queue.c with 100% similarity]
lib/gvpr/queue.h [moved from cmd/gvpr/queue.h with 100% similarity]
lib/gvpr/trie.c [new file with mode: 0644]
lib/gvpr/trieFA.h [new file with mode: 0644]

index b57dd71ff0ec6a378f9a89b32c7ba71c530619fc..dedaed705d6e71366895652e1a24148a090f169a 100644 (file)
@@ -3,10 +3,11 @@
 
 pdfdir = $(pkgdatadir)/doc/pdf
 
+
 AM_CPPFLAGS = \
-        -I$(top_srcdir) \
-        -I$(top_srcdir)/lib/expr \
-        -I$(top_builddir)/lib/expr \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/lib/expr \
+       -I$(top_builddir)/lib/expr \
        -I$(top_srcdir)/lib/vmalloc \
        -I$(top_srcdir)/lib/sfio \
        -I$(top_srcdir)/lib/ast \
@@ -14,34 +15,35 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/lib/cgraph \
        -I$(top_srcdir)/lib/cdt
 
+if ENABLE_STATIC
+bin_PROGRAMS = gvpr gvpr_static
+else
 bin_PROGRAMS = gvpr
-noinst_PROGRAMS = mkdefs
-noinst_HEADERS = actions.h compile.h gprstate.h parse.h queue.h
+endif
+
 man_MANS = gvpr.1
 pdf_DATA = gvpr.1.pdf
 
-gvpr_SOURCES = actions.c compile.c gvpr.c gprstate.c parse.c queue.c
-
-gvpr_LDADD = \
-       $(top_builddir)/lib/vmalloc/libvmalloc_C.la \
-       $(top_builddir)/lib/sfio/libsfio_C.la \
-        $(top_builddir)/lib/ingraphs/libingraphs_C.la \
-       $(top_builddir)/lib/expr/libexpr_C.la \
-       $(top_builddir)/lib/cgraph/libcgraph.la @MATH_LIBS@
-
-gvpr_DEPENDENCIES = \
-       $(top_builddir)/lib/ast/libast_C.la
-
-$(gvpr_OBJECTS): gdefs.h
-
-mkdefs_SOURCES = mkdefs.c
-
-gdefs.h: $(top_srcdir)/cmd/gvpr/gprdata mkdefs
-       ./mkdefs gdefs.h < $(top_srcdir)/cmd/gvpr/gprdata
+gvpr_SOURCES = gvprmain.c
+gvpr_CPPFLAGS = $(AM_CPPFLAGS)
+gvpr_LDADD = $(top_builddir)/lib/gvpr/libgvpr.la
 
 gvpr.1.pdf: $(srcdir)/gvpr.1
        - @GROFF@ -Tps -man $(srcdir)/gvpr.1 | @PS2PDF@ - - >gvpr.1.pdf
 
-EXTRA_DIST = $(man_MANS) $(pdf_DATA) lib Makefile.old gprdata mkdefs.c gdefs.h gvpr.vcproj
+gvpr_static_SOURCES = gvprmain.c
+gvpr_static_CPPFLAGS = $(AM_CPPFLAGS)
+gvpr_static_LDADD = \
+       $(top_builddir)/lib/gvpr/libgvpr_C.la \
+       $(top_builddir)/lib/expr/libexpr_C.la \
+       $(top_builddir)/lib/sfio/libsfio_C.la \
+       $(top_builddir)/lib/vmalloc/libvmalloc_C.la \
+       $(top_builddir)/lib/ingraphs/libingraphs_C.la \
+       $(top_builddir)/lib/ast/libast_C.la \
+       $(top_builddir)/lib/cgraph/libcgraph_C.la \
+       $(top_builddir)/lib/cdt/libcdt_C.la \
+               $(MATH_LIBS)
+
+EXTRA_DIST = $(man_MANS) $(pdf_DATA) Makefile.old gvpr.vcproj
 
-DISTCLEANFILES = $(pdf_DATA) gdefs.h mkdefs
+DISTCLEANFILES = $(pdf_DATA)
index 13838999aad70468e951577959d9f1c453ad9c2a..e48a0a6d607ea5bfb1328d83ca184fc2a02cca62 100644 (file)
@@ -10,24 +10,22 @@ LOC_LIB=$(ROOT)/lib
 LOC_INCDIR=$(LOC_LIB)/include
 LOC_LIBDIR=$(LOC_LIB)/lib
 
-INCS = -I. -I$(ROOT) -I$(LOC_INCDIR) -I$(LOC_LIB)/cgraph -I$(LOC_LIB)/cdt
+INCS = -I. -I$(ROOT) -I$(LOC_INCDIR) -I$(LOC_LIB)/gvpr -I$(LOC_LIB)/cgraph -I$(LOC_LIB)/cdt
 
 DEFINES = -DHAVE_CONFIG_H -DUSE_CGRAPH
 
-OBJS = gvpr.o parse.o compile.o gprstate.o actions.o queue.o
+OBJS = gvprmain.o
 
-compile.o : gdefs.h
+LIBS = -L$(LOC_LIB)/gvpr -lgvpr \
+       -L$(LOC_LIB)/expr -lexpr \
+       -L$(LOC_LIB)/ast -last \
+       -L$(LOC_LIB)/sfio -lsfio \
+       -L$(LOC_LIB)/vmalloc -lvmalloc \
+       -L$(LOC_LIB)/ingraphs -lingraphs \
+       -L$(LOC_LIB)/cgraph -lcgraph \
+       -L$(LOC_LIB)/cdt -lcdt -lm
 
-gdefs.h : gprdata mkdefs
-       mkdefs gdefs.h < gprdata
-
-mkdefs : mkdefs.o
-       $(CC) $(LDFLAGS) mkdefs.o -o $@
-
-GLIBS = -L$(LOC_LIB)/cgraph -L$(LOC_LIB)/cdt -lcgraph -lcdt
-LIBS = -L$(LOC_LIBDIR) -lexpr -last -lvmalloc -lsfio -lingraphs $(GLIBS) -lm
-
-gvpr : $(OBJS) $(LOC_LIBDIR)/libexpr.a
+gvpr : $(OBJS)
        $(CSLD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
 
 $(OBJS) : gdefs.h
@@ -39,7 +37,7 @@ install : all
        $(INSTALL) gvpr.1 $(MANDIR)
 
 clean :
-       $(RM) core gdefs.h *.o 
+       $(RM) core *.o 
 
 distclean : clean
-       $(RM) mkdefs $(ALL)
+       $(RM) $(ALL)
diff --git a/cmd/gvpr/gvprmain.c b/cmd/gvpr/gvprmain.c
new file mode 100644 (file)
index 0000000..3c09f7a
--- /dev/null
@@ -0,0 +1,109 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+
+/*
+ * gvpr: graph pattern recognizer
+ *
+ * Written by Emden Gansner
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+#include "compat_unistd.h"
+#endif
+#include "gvpr.h"
+
+#ifdef DEBUG
+#include "sfio.h"
+static ssize_t outfn (void* sp, const char *buf, size_t nbyte, void* dp)
+{
+    write (1, "<stdout> ", 8);
+    return write (1, buf, nbyte);
+}
+
+static ssize_t errfn (void* sp, const char *buf, size_t nbyte, void* dp)
+{
+    write (2, "<stderr> ", 8);
+    return write (2, buf, nbyte);
+}
+
+static int iofread(void *chan, char *buf, int bufsize)
+{
+    return read(sffileno((Sfio_t *) chan), buf, bufsize);
+}
+
+static int ioputstr(void *chan, char *str)
+{
+    return sfputr((Sfio_t *) chan, str, -1);
+}
+
+static int ioflush(void *chan)
+{
+    return sfsync((Sfio_t *) chan);
+}
+
+static Agiodisc_t gprIoDisc = { iofread, ioputstr, ioflush };
+
+static Agdisc_t gprDisc = { &AgMemDisc, &AgIdDisc, &gprIoDisc };
+
+int
+main (int argc, char* argv[])
+{
+    Agraph_t* gs[2];
+    Agraph_t* g = agread (sfstdin, &gprDisc);
+    int rv, i;
+    gvpropts opts;
+
+    gs[0] = g;
+    gs[1] = 0;
+    opts.ingraphs = gs;
+    opts.out = outfn;
+    opts.err = errfn;
+    opts.flags = GV_USE_OUTGRAPH;
+    
+    rv = gvpr (argc, argv, &opts);
+
+    sfprintf (sfstderr, "rv %d\n", rv);
+    /* for (i = 0; i < opts.n_outgraphs; i++) */
+       /* agwrite (opts.outgraphs[i], sfstdout); */
+
+    rv = gvpr (argc, argv, &opts);
+
+    return rv;
+}
+
+#else
+int
+main (int argc, char* argv[])
+{
+    gvpropts opts;
+    opts.ingraphs = 0;
+    opts.out = 0;
+    opts.err = 0;
+    opts.flags = GV_USE_EXIT;
+    
+    return gvpr (argc, argv, &opts);
+}
+
+#endif
+
index 74d12288562a1c0f8ae30f15721dbfa1bb2be008..1901c66a9b355cac1f0a0f75d5e9a558c92bfd50 100644 (file)
@@ -3033,6 +3033,8 @@ AC_CONFIG_FILES(Makefile
        lib/sparse/Makefile
        lib/sfdpgen/Makefile
        lib/osage/Makefile
+       lib/gvpr/Makefile
+       lib/gvpr/libgvpr.pc
        lib/circogen/Makefile
        lib/twopigen/Makefile
        lib/patchwork/Makefile
index 92c981e7ab17dbfadd8b740242ac62c2316a877b..38591d58d3ace309d2c1003f322022a23e8dd71e 100644 (file)
@@ -4,6 +4,6 @@
 SUBDIRS = cdt graph cgraph gd pathplan sfio vmalloc ast \
        vpsc rbtree ortho sparse patchwork expr common \
        pack gvc xdot ingraphs topfish glcomp \
-       circogen dotgen fdpgen neatogen twopigen sfdpgen osage
+       circogen dotgen fdpgen neatogen twopigen sfdpgen osage gvpr
 
 EXTRA_DIST = Makefile.old gvc.vcproj gvc.def
diff --git a/lib/gvpr/Makefile.am b/lib/gvpr/Makefile.am
new file mode 100644 (file)
index 0000000..0dbb7e4
--- /dev/null
@@ -0,0 +1,50 @@
+# $Id$Revision: 
+## Process this file with automake to produce Makefile.in
+
+pkgconfigdir = $(libdir)/pkgconfig
+
+GVPR_VERSION="1:0:0"
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/lib/expr \
+       -I$(top_builddir)/lib/expr \
+       -I$(top_srcdir)/lib/vmalloc \
+       -I$(top_srcdir)/lib/sfio \
+       -I$(top_srcdir)/lib/ast \
+       -I$(top_srcdir)/lib/ingraphs \
+       -I$(top_srcdir)/lib/cgraph \
+       -I$(top_srcdir)/lib/cdt
+
+pkginclude_HEADERS = gvpr.h
+noinst_PROGRAMS = mkdefs
+noinst_HEADERS = actions.h compile.h gprstate.h parse.h queue.h
+noinst_LTLIBRARIES = libgvpr_C.la
+lib_LTLIBRARIES = libgvpr.la
+pkgconfig_DATA = libgvpr.pc
+
+libgvpr_C_la_SOURCES = actions.c compile.c gvpr.c gprstate.c parse.c queue.c
+$(libgvpr_C_la_OBJECTS): gdefs.h
+libgvpr_C_la_DEPENDENCIES = \
+    $(top_builddir)/lib/expr/libexpr_C.la \
+    $(top_builddir)/lib/ingraphs/libingraphs_C.la
+
+
+libgvpr_la_LDFLAGS = -version-info $(GVPR_VERSION) -no-undefined
+libgvpr_la_SOURCES = $(libgvpr_C_la_SOURCES)
+libgvpr_la_LIBADD = $(libgvpr_C_la_LIBADD) \
+       $(top_builddir)/lib/ingraphs/libingraphs_C.la \
+    $(top_builddir)/lib/expr/libexpr_C.la \
+    $(top_builddir)/lib/cdt/libcdt.la \
+    $(top_builddir)/lib/cgraph/libcgraph.la \
+    $(MATH_LIBS)
+libgvpr_la_DEPENDENCIES = $(libgvpr_C_la_DEPENDENCIES)
+
+mkdefs_SOURCES = mkdefs.c
+
+gdefs.h: $(top_srcdir)/lib/gvpr/gprdata mkdefs
+       ./mkdefs gdefs.h < $(top_srcdir)/lib/gvpr/gprdata
+
+EXTRA_DIST = $(man_MANS) $(pdf_DATA) lib Makefile.old gprdata mkdefs.c gdefs.h gvpr.vcproj
+
+DISTCLEANFILES = $(pdf_DATA) gdefs.h mkdefs
diff --git a/lib/gvpr/Makefile.old b/lib/gvpr/Makefile.old
new file mode 100644 (file)
index 0000000..33c5460
--- /dev/null
@@ -0,0 +1,50 @@
+#   gvpr library make file
+#   Written by Emden R. Gansner (23 June 2009)
+ALL = libgvpr.a
+all : $(ALL)
+ROOT=../..
+include $(ROOT)/Config.mk
+include $(ROOT)/makearch/$(ARCH)
+
+LOC_LIB=$(ROOT)/lib
+LOC_INCDIR=$(LOC_LIB)/include
+LOC_LIBDIR=$(LOC_LIB)/lib
+
+INCS = -I. -I$(ROOT) -I$(LOC_INCDIR) -I$(LOC_LIB)/cgraph -I$(LOC_LIB)/cdt \
+    -I$(LOC_LIB)/expr -I$(LOC_LIB)/ast -I$(LOC_LIB)/sfio -I$(LOC_LIB)/vmalloc -I$(LOC_LIB)/ingraphs
+
+DEFINES = -DHAVE_CONFIG_H -DUSE_CGRAPH
+
+OBJS = gvpr.o parse.o compile.o gprstate.o actions.o queue.o trie.o
+
+
+compile.o : gdefs.h
+
+gdefs.h : gprdata mkdefs
+       mkdefs gdefs.h < gprdata
+
+mkdefs : mkdefs.o
+       $(CC) $(LDFLAGS) mkdefs.o -o $@
+
+GLIBS = -L$(LOC_LIB)/cgraph -L$(LOC_LIB)/cdt -lcgraph -lcdt
+LIBS = -L$(LOC_LIBDIR) -lexpr -last -lvmalloc -lsfio -lingraphs $(GLIBS) -lm
+
+gvpr : $(OBJS) $(LOC_LIBDIR)/libexpr.a
+       $(CSLD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
+libgvpr.a: $(OBJS)
+       $(RM) libgvpr.a
+       $(AR) cr libgvpr.a $(OBJS)
+       $(RANLIB) libgvpr.a
+
+install: libgvpr.a
+       $(MKPATH) $(LIBDIR)
+       $(INSTALL) libpgvpr.a $(LIBDIR)
+
+
+$(OBJS) : gdefs.h
+
+clean :
+       $(RM) core gdefs.h *.o 
+
+distclean : clean
+       $(RM) mkdefs $(ALL)
similarity index 93%
rename from cmd/gvpr/actions.c
rename to lib/gvpr/actions.c
index a9b6ad85672b04ab648de74be0f11fcb4df32c45..2662a1dd3b472b2a5a36c9696ce2a4822cab64d0 100644 (file)
@@ -189,7 +189,7 @@ Agobj_t *copy(Agraph_t * g, Agobj_t * obj)
     char *name = agnameof(obj);
 
     if ((kind != AGRAPH) && !g) {
-       error(ERROR_FATAL, "NULL graph with non-graph object in copy()");
+       exerror("NULL graph with non-graph object in copy()");
        return 0;
     }
 
@@ -247,26 +247,32 @@ static Agraph_t *cloneSubg(Agraph_t * tgt, Agraph_t * g, Dt_t* emap)
        return 0;
     for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
        newt = agnode(tgt, agnameof(t), 0);
-       if (!newt)
-           error(ERROR_PANIC, "node %s not found in cloned graph %s",
+       if (!newt) {
+           exerror("node %s not found in cloned graph %s",
                  agnameof(t), agnameof(tgt));
-       agsubnode(ng, newt, 1);
+           return 0;
+       }
+       else
+           agsubnode(ng, newt, 1);
     }
     for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
        for (e = agfstout(g, t); e; e = agnxtout(g, e)) {
            newe = mapEdge (emap, e);
-           if (!newe)
-               error(ERROR_PANIC,
-                     "edge (%s,%s)[%s] not found in cloned graph %s",
+           if (!newe) {
+               exerror("edge (%s,%s)[%s] not found in cloned graph %s",
                      agnameof(agtail(e)), agnameof(aghead(e)),
                      agnameof(e), agnameof(tgt));
-           agsubedge(ng, newe, 1);
+               return 0;
+           }
+           else
+               agsubedge(ng, newe, 1);
        }
     }
     for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
        if (!cloneSubg(ng, sg, emap)) {
-           error(ERROR_FATAL, "error cloning subgraph %s from graph %s",
+           exerror("error cloning subgraph %s from graph %s",
                  agnameof(sg), agnameof(g));
+           return 0;
        }
     }
     return ng;
@@ -306,17 +312,17 @@ static void cloneGraph(Agraph_t * tgt, Agraph_t * src)
 
     for (t = agfstnode(src); t; t = agnxtnode(src, t)) {
        if (!copy(tgt, OBJ(t))) {
-           error(ERROR_FATAL, "error cloning node %s from graph %s",
+           exerror("error cloning node %s from graph %s",
                  agnameof(t), agnameof(src));
        }
     }
     for (t = agfstnode(src); t; t = agnxtnode(src, t)) {
        for (e = agfstout(src, t); e; e = agnxtout(src, e)) {
            if (!(ne = (Agedge_t*)copy(tgt, OBJ(e)))) {
-               error(ERROR_FATAL,
-                     "error cloning edge (%s,%s)[%s] from graph %s",
+               exerror("error cloning edge (%s,%s)[%s] from graph %s",
                      agnameof(agtail(e)), agnameof(aghead(e)),
                      agnameof(e), agnameof(src));
+               return;
            }
            ep->key = e;
            ep->val = ne;
@@ -325,7 +331,7 @@ static void cloneGraph(Agraph_t * tgt, Agraph_t * src)
     }
     for (sg = agfstsubg(src); sg; sg = agnxtsubg(sg)) {
        if (!cloneSubg(tgt, sg, emap)) {
-           error(ERROR_FATAL, "error cloning subgraph %s from graph %s",
+           exerror("error cloning subgraph %s from graph %s",
                  agnameof(sg), agnameof(src));
        }
     }
@@ -352,7 +358,7 @@ Agobj_t *clone(Agraph_t * g, Agobj_t * obj)
     char *name = agnameof(obj);
 
     if ((kind != AGRAPH) && !g) {
-       error(ERROR_FATAL, "NULL graph with non-graph object in clone()");
+       exerror("NULL graph with non-graph object in clone()");
        return 0;
     }
 
@@ -545,12 +551,12 @@ int writeFile(Agraph_t * g, char *f)
     Sfio_t *fp;
 
     if (!f) {
-       error(ERROR_FATAL, "NULL string passed to writeG");
+       exerror("NULL string passed to writeG");
        return 1;
     }
     fp = sfopen(0, f, "w");
     if (!fp) {
-       error(ERROR_FATAL, "Could not open %s for writing in writeG", f);
+       exerror("Could not open %s for writing in writeG", f);
        return 1;
     }
     rv = agwrite(g, fp);
@@ -568,12 +574,12 @@ Agraph_t *readFile(char *f)
     Sfio_t *fp;
 
     if (!f) {
-       error(ERROR_FATAL, "NULL string passed to readG");
+       exerror("NULL string passed to readG");
        return 0;
     }
     fp = sfopen(0, f, "r");
     if (!fp) {
-       error(ERROR_FATAL, "Could not open %s for reading in readG", f);
+       exerror("Could not open %s for reading in readG", f);
        return 0;
     }
     gp = readG(fp);
@@ -615,7 +621,7 @@ int openFile(Expr_t * ex, char *fname, char *mode)
        if (!ex->file[idx])
            break;
     if (idx == elementsof(ex->file)) {
-       error(ERROR_FATAL, "openF: no available descriptors");
+       exerror("openF: no available descriptors");
        return -1;
     }
     ex->file[idx] = sfopen(0, fname, mode);
@@ -630,11 +636,11 @@ int closeFile(Expr_t * ex, int fd)
     int rv;
 
     if ((0 <= fd) && (fd <= 2)) {
-       error(ERROR_FATAL, "closeF: cannot close standard stream %d", fd);
+       exerror("closeF: cannot close standard stream %d", fd);
        return -1;
     }
     if (!ex->file[fd]) {
-       error(ERROR_FATAL, "closeF: stream %d not open", fd);
+       exerror("closeF: stream %d not open", fd);
        return -1;
     }
     rv = sfclose(ex->file[fd]);
similarity index 100%
rename from cmd/gvpr/actions.h
rename to lib/gvpr/actions.h
similarity index 91%
rename from cmd/gvpr/compile.c
rename to lib/gvpr/compile.c
index ccdc5c21a3fe32bc54d8a0f85099d8805908328c..306d8b9ec90f307291e308acd691823f47a62d1c 100644 (file)
@@ -48,6 +48,9 @@
 
 #include <gdefs.h>
 
+#include "ctype.h"
+#include "trie.c"
+
 #define BITS_PER_BYTE 8
 #ifdef HAVE_INTPTR_T
 #define INT2PTR(t,v) ((t)(intptr_t)(v))
@@ -234,10 +237,9 @@ static Agobj_t *deref(Expr_t * pgm, Exnode_t * x, Exref_t * ref,
                    x->data.variable.dyna->data.variable.dyna->data.
                    constant.value.integer);
        if (!ptr) {
-           error(ERROR_FATAL, "null reference %s in expression %s.%s",
+           exerror("null reference %s in expression %s.%s",
                  ref->symbol->name, ref->symbol->name, deparse(pgm, x,
-                                                               state->
-                                                               tmp));
+                                                               state->tmp));
            return ptr;
        } else
            return deref(pgm, x, ref->next, (Agobj_t *) ptr, state);
@@ -260,36 +262,71 @@ static Agobj_t *deref(Expr_t * pgm, Exnode_t * x, Exref_t * ref,
            break;
        case M_head:
            if (!objp && !(objp = state->curobj)) {
-               error(ERROR_WARNING, "Current object $ not defined");
+               exerror("Current object $ not defined");
                return 0;
            }
            if (ISEDGE(objp))
                return deref(pgm, x, ref->next,
                             (Agobj_t *) AGHEAD((Agedge_t *) objp), state);
            else
-               error(ERROR_FATAL, "head of non-edge");
+               exerror("head of non-edge");
            break;
        case M_tail:
            if (!objp && !(objp = state->curobj)) {
-               error(ERROR_FATAL, "Current object $ not defined");
+               exerror("Current object $ not defined");
                return 0;
            }
            if (ISEDGE(objp))
                return deref(pgm, x, ref->next,
                             (Agobj_t *) AGTAIL((Agedge_t *) objp), state);
            else
-               error(ERROR_FATAL, "tail of non-edge %x", objp);
+               exerror("tail of non-edge %x", objp);
            break;
        default:
-           error(ERROR_WARNING, "%s : illegal reference",
+           exerror("%s : illegal reference",
                  ref->symbol->name);
-           return 0;
            break;
        }
     return 0;
 
 }
 
+/* assignable:
+ * Check that attribute is not a read-only, pseudo-attribute.
+ * Return 1 if okay; fatal otherwise.
+ */
+static int
+assignable (Agobj_t *objp, unsigned char* name)
+{
+    unsigned int ch;
+    int rv;
+    unsigned char* p = name;
+
+    TFA_Init();
+    while ((TFA_State >= 0) && (ch = *p)) {
+        TFA_Advance(ch & ~127 ? 127 : ch);
+        p++;
+    }
+    rv = TFA_Definition();
+    if (rv < 0) return 1;
+
+    switch (AGTYPE(objp)) {
+    case AGRAPH :
+       if (rv & Y(G))
+           exerror("Cannot assign to pseudo-graph attribute %s", name);
+       break;
+    case AGNODE :
+       if (rv & Y(V))
+           exerror("Cannot assign to pseudo-node attribute %s", name);
+       break;
+    default :  /* edge */
+       if (rv & Y(E))
+           exerror("Cannot assign to pseudo-edge attribute %s", name);
+       break;
+    }
+    return 1;
+}
+
 /* setattr:
  * Set object's attribute name to val.
  * Initialize attribute if necessary.
@@ -366,7 +403,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGNODE)
                v->integer = agdegree(agroot(objp), (Agnode_t *) objp, 1, 0);
            else {
-               error(ERROR_FATAL, "indegree of non-node");
+               exerror("indegree of non-node");
                return -1;
            }
            break;
@@ -374,7 +411,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGNODE)
                v->integer = agdegree(agroot(objp), (Agnode_t *) objp, 0, 1);
            else {
-               error(ERROR_FATAL, "outdegree of non-node");
+               exerror("outdegree of non-node");
                return -1;
            }
            break;
@@ -382,7 +419,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGNODE)
                v->integer = agdegree(agroot(objp), (Agnode_t *) objp, 1, 1);
            else {
-               error(ERROR_FATAL, "degree of non-node");
+               exerror("degree of non-node");
                return -1;
            }
            break;
@@ -390,7 +427,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGRAPH)
                v->integer = PTR2INT(agparent((Agraph_t *) objp));
            else {
-               error(ERROR_FATAL, "parent of non-graph");
+               exerror("parent of non-graph");
                return -1;
            }
            break;
@@ -401,7 +438,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGRAPH)
                v->integer = agnedges((Agraph_t *) objp);
            else {
-               error(ERROR_FATAL, "n_edges of non-graph");
+               exerror("n_edges of non-graph");
                return -1;
            }
            break;
@@ -409,7 +446,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGRAPH)
                v->integer = agnnodes((Agraph_t *) objp);
            else {
-               error(ERROR_FATAL, "n_nodes of non-graph");
+               exerror("n_nodes of non-graph");
                return -1;
            }
            break;
@@ -417,7 +454,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGRAPH)
                v->integer = agisdirected((Agraph_t *) objp);
            else {
-               error(ERROR_FATAL, "directed of non-graph");
+               exerror("directed of non-graph");
                return -1;
            }
            break;
@@ -425,7 +462,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
            if (AGTYPE(objp) == AGRAPH)
                v->integer = agisstrict((Agraph_t *) objp);
            else {
-               error(ERROR_FATAL, "strict of non-graph");
+               exerror("strict of non-graph");
                return -1;
            }
            break;
@@ -438,7 +475,7 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
        Agsym_t *gsym = agattrsym(objp, sym->name);
        if (!gsym) {
            gsym = agattr(agroot(agraphof(objp)), AGTYPE(objp), sym->name, "");
-           error(ERROR_WARNING, "Using value of uninitialized attribute \"%s\" of %s \"%s\"", sym->name, kindOf (objp), nameOf(pgm, objp));
+           error(ERROR_WARNING, "Using value of uninitialized %s attribute \"%s\" of \"%s\"", kindOf (objp), sym->name, nameOf(pgm, objp));
        }
        v->string = agxget(objp, gsym);
     }
@@ -452,7 +489,8 @@ static int lookup(Expr_t * pgm, Agobj_t * objp, Exid_t * sym, Extype_t * v,
 static char *getArg(int n, Gpr_t * state)
 {
     if (n >= state->argc) {
-       error(ERROR_FATAL, "program references ARGV[%d] - undefined", n);
+       exerror("program references ARGV[%d] - undefined", n);
+       return 0;
     }
     return (state->argv[n]);
 }
@@ -502,7 +540,8 @@ toKind (char* k, char* fn)
        kind = AGNODE;
        break;
     default :
-       error(ERROR_FATAL, "Unknown kind \"%s\" passed to %s()", k, fn);
+       exerror("Unknown kind \"%s\" passed to %s()", k, fn);
+       kind = 0;
        break;
     }
     return kind;
@@ -520,7 +559,8 @@ nxtAttr (Agraph_t *gp, char* k, char* name)
     if (name) {
        sym = agattr (gp, kind, name, 0);
        if (!sym) {
-           error(ERROR_FATAL, "Third argument \"%s\" in nxtAttr() must be the name of an existing attribute", name); 
+           exerror("Third argument \"%s\" in nxtAttr() must be the name of an existing attribute", name); 
+           return "";
        }
        
     }
@@ -549,7 +589,7 @@ getDfltAttr (Agraph_t *gp, char* k, char* name)
 /* getval:
  * Return value associated with gpr identifier.
  */
-Extype_t
+static Extype_t
 getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
        void *env, int elt, Exdisc_t * disc)
 {
@@ -749,7 +789,8 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
        case F_kindof:
            objp = INT2PTR(Agobj_t *, args[0].integer);
            if (!objp) {
-               error(ERROR_FATAL, "NULL object passed to kindOf()");
+               exerror("NULL object passed to kindOf()");
+               v.string = 0;
            } else switch (AGTYPE(objp)) {
                case AGRAPH :
                    v.string = "G";
@@ -1173,9 +1214,11 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
            objp = INT2PTR(Agobj_t *, args[0].integer);
            name = args[1].string;
            if (!objp) {
-               error(ERROR_FATAL, "NULL object passed to aget()/hasAttr()");
+               exerror("NULL object passed to aget()/hasAttr()");
+               v.integer = 0;
            } else if (!name) {
-               error(ERROR_FATAL, "NULL name passed to aget()/hasAttr()");
+               exerror("NULL name passed to aget()/hasAttr()");
+               v.integer = 0;
            }
            else {
                Agsym_t *gsym = agattrsym(objp, name);
@@ -1184,7 +1227,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
                else {
                    if (!gsym) {
                        gsym = agattr(agroot(agraphof(objp)), AGTYPE(objp), name, "");
-                       error(ERROR_WARNING, "Using value of uninitialized attribute \"%s\" of %s \"%s\" in aget()", name, kindOf (objp), nameOf(pgm, objp));
+                       error(ERROR_WARNING, "Using value of %s uninitialized attribute \"%s\" of \"%s\" in aget()", kindOf (objp), name, nameOf(pgm, objp));
                    }
                    v.string = agxget(objp, gsym);
                }
@@ -1242,13 +1285,15 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
            if (gp) {
                char* kind = args[1].string;
                if (!kind) {
-                   error(ERROR_FATAL,"NULL kind passed to fstAttr()");
+                   error(ERROR_ERROR,"NULL kind passed to fstAttr()");
+                   v.string = 0;
                }
                else {
                    v.string = nxtAttr (gp, kind, NULL);
                }
            } else {
-               error(ERROR_FATAL, "NULL graph passed to fstAttr()");
+               exerror("NULL graph passed to fstAttr()");
+               v.string = 0;
            }
            break;
        case F_nxtattr:
@@ -1259,10 +1304,12 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
                char* kind = args[1].string;
                char* name = args[2].string;
                if (!name) {
-                   error(ERROR_FATAL,"NULL name passed to %s", sym->name);
+                   exerror("NULL name passed to %s", sym->name);
+                   v.string = 0;
                }
                else if (!kind) {
-                   error(ERROR_FATAL,"NULL kind passed to %s", sym->name);
+                   exerror("NULL kind passed to %s", sym->name);
+                   v.string = 0;
                }
                else if (sym->index == F_isattr) {
                    v.integer = (agattr(gp, toKind (kind, sym->name), name, 0) != NULL);
@@ -1274,7 +1321,8 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
                    v.string = getDfltAttr(gp, kind, name);
                }
            } else {
-               error(ERROR_FATAL, "NULL graph passed to %s", sym->name);
+               exerror("NULL graph passed to %s", sym->name);
+               v.string = 0;
            }
            break;
        case F_canon:
@@ -1305,7 +1353,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
            v.integer = match(args[0].string, args[1].string);
            break;
        default:
-           error(ERROR_FATAL, "unknown function call: %s", sym->name);
+           exerror("unknown function call: %s", sym->name);
        }
        return v;
     } else if (elt == EX_ARRAY) {
@@ -1316,7 +1364,8 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
            v.string = getArg(args[0].integer, state);
            break;
        default:
-           error(ERROR_FATAL, "unknown array name: %s", sym->name);
+           exerror("unknown array name: %s", sym->name);
+           v.string = 0;
        }
        return v;
     }
@@ -1325,7 +1374,7 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
     if (ref) {
        objp = deref(pgm, node, ref, 0, state);
        if (!objp)
-           error(ERROR_FATAL, "null reference in expression %s",
+           exerror("null reference in expression %s",
                  deparse(pgm, node, state->tmp));
     } else if ((sym->lex == ID) && (sym->index <= LAST_V)) {
        switch (sym->index) {
@@ -1360,15 +1409,20 @@ getval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
        return v;
     } else {
        objp = state->curobj;
-       if (!objp)
-           error(ERROR_FATAL,
-                 "current object $ not defined as reference for %s",
+       if (!objp) {
+           exerror("current object $ not defined as reference for %s",
                  deparse(pgm, node, state->tmp));
+       }
     }
 
-    if (lookup(pgm, objp, sym, &v, state))
-       error(ERROR_FATAL, "in expression %s",
-             deparse(pgm, node, state->tmp));
+    if (objp) {
+       if (lookup(pgm, objp, sym, &v, state)) {
+           exerror("in expression %s", deparse(pgm, node, state->tmp));
+           v.integer = 0;
+       }
+    }
+    else
+       v.integer = 0;
 
     return v;
 }
@@ -1385,7 +1439,7 @@ static char *typeName(Expr_t * pg, int op)
  * Return -1 if not allowed.
  * Assume already type correct.
  */
-int
+static int
 setval(Expr_t * pgm, Exnode_t * x, Exid_t * sym, Exref_t * ref,
        void *env, int elt, Extype_t v, Exdisc_t * disc)
 {
@@ -1399,7 +1453,7 @@ setval(Expr_t * pgm, Exnode_t * x, Exid_t * sym, Exref_t * ref,
     if (ref) {
        objp = deref(pgm, x, ref, 0, state);
        if (!objp) {
-           error(ERROR_FATAL, "in expression %s.%s",
+           exerror("in expression %s.%s",
                  ref->symbol->name, deparse(pgm, x, state->tmp));
            return -1;
        }
@@ -1439,13 +1493,14 @@ setval(Expr_t * pgm, Exnode_t * x, Exid_t * sym, Exref_t * ref,
        return rv;
     } else {
        objp = state->curobj;
-       if (!objp)
-           error(ERROR_FATAL,
-                 "current object $ undefined in expression %s",
+       if (!objp) {
+           exerror("current object $ undefined in expression %s",
                  deparse(pgm, x, state->tmp));
+           return -1;
+       }
     }
-
     
+    assignable (objp, (unsigned char*)(sym->name));
     return setattr(objp, sym->name, v.string);
 }
 
@@ -1570,7 +1625,7 @@ static tctype typeChkExp(Exref_t * ref, Exid_t * sym)
  * The grammar has been  altered to disallow the first 3.
  * Type check expressions; return value unused.
  */
-Extype_t
+static Extype_t
 refval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
        char *str, int elt, Exdisc_t * disc)
 {
@@ -1624,24 +1679,16 @@ refval(Expr_t * pgm, Exnode_t * node, Exid_t * sym, Exref_t * ref,
            break;
        }
     } else {
-       if (!typeChkExp(ref, sym))
+       if (!typeChkExp(ref, sym)) {
+           Gpr_t *state = (Gpr_t *) (disc->user);
            exerror("type error using %s",
-                   deparse(pgm, node, sfstropen()));
+                   deparse(pgm, node, state->tmp));
+       }
        v = exzero(node->type);
     }
     return v;
 }
 
-#ifdef OLD
-static void cvtError(Exid_t * xref, char *msg)
-{
-    if (xref)
-       error(ERROR_FATAL, "%s: %s", xref->name, msg);
-    else
-       error(ERROR_FATAL, "%s", msg);
-}
-#endif
-
 /* binary:
  * Evaluate (l ex->op r) producing a value of type ex->type,
  * stored in l.
@@ -1802,9 +1849,9 @@ strToTvtype (char* s)
        } else if (!strcmp(sfx, "prepostrev")) {
            rt = TV_prepostrev;
        } else
-           error(ERROR_FATAL, "illegal string \"%s\" for type tvtype_t", s);
+           exerror("illegal string \"%s\" for type tvtype_t", s);
     } else
-       error(ERROR_FATAL, "illegal string \"%s\" for type tvtype_t", s);
+       exerror("illegal string \"%s\" for type tvtype_t", s);
     return rt;
 }
 
@@ -1869,22 +1916,27 @@ tvtypeToStr (int v)
  * Return -1 if conversion cannot be done, 0 otherwise.
  * If arg is > 0, conversion unnecessary; just report possibility.
  */
-int stringOf(Expr_t * prog, register Exnode_t * x, int arg)
+static int stringOf(Expr_t * prog, register Exnode_t * x, int arg)
 {
     Agobj_t *objp;
+    int rv = 0;
 
     if (arg)
        return 0;
 
     if (x->type == T_tvtyp) {
-       x->data.constant.value.string = 
-           tvtypeToStr (x->data.constant.value.integer);
+       if (!(x->data.constant.value.string = 
+           tvtypeToStr (x->data.constant.value.integer)))
+           rv = -1;
     } else {
        objp = INT2PTR(Agobj_t *, x->data.constant.value.integer);
-       if (!objp)
+       if (!objp) {
            exerror("cannot generate name for NULL %s",
                    typeName(prog, x->type));
-       x->data.constant.value.string = nameOf(prog, objp);
+           rv = -1;
+       }
+       else
+           x->data.constant.value.string = nameOf(prog, objp);
     }
     x->type = STRING;
     return 0;
@@ -1898,7 +1950,7 @@ int stringOf(Expr_t * prog, register Exnode_t * x, int arg)
  * Use #ifdef OLD to remove graph object conversion to strings,
  * as this seemed to dangerous.
  */
-int
+static int
 convert(Expr_t * prog, register Exnode_t * x, int type,
        register Exid_t * xref, int arg, Exdisc_t * disc)
 {
@@ -1967,7 +2019,7 @@ convert(Expr_t * prog, register Exnode_t * x, int type,
        else if (validTVT(x->data.constant.value.integer))
            ret = 0;
        else
-           error(ERROR_FATAL, "Integer value %d not legal for type tvtype_t",
+           exerror("Integer value %d not legal for type tvtype_t",
                x->data.constant.value.integer);
     }
     /* in case libexpr hands us the trivial case */
@@ -2029,26 +2081,34 @@ static Exdisc_t *initDisc(Gpr_t * state)
     Exdisc_t *dp;
 
     dp = newof(0, Exdisc_t, 1, 0);
-    if (!dp)
-       error(ERROR_FATAL,
+    if (!dp) {
+       error(ERROR_ERROR,
              "could not create libexp discipline: out of memory");
+       return 0;
+    }
 
     dp->version = EX_VERSION;
-    dp->flags = EX_CHARSTRING | EX_FATAL | EX_UNDECLARED;
+    dp->flags = EX_CHARSTRING | EX_UNDECLARED;
     dp->symbols = symbols;
     dp->convertf = convert;
     dp->stringof = stringOf;
     dp->binaryf = binary;
     dp->typename = typeName;
-    dp->errorf = (Exerror_f) errorf;
+    if (state->errf)
+       dp->errorf = state->errf;
+    else
+       dp->errorf = (Exerror_f) errorf;
     dp->keyf = keyval;
     dp->getf = getval;
     dp->reff = refval;
     dp->setf = setval;
     dp->matchf = matchval;
+    dp->exitf = state->exitf;
     dp->types = a2t;
     dp->user = state;
 
+    state->dp = dp;   /* dp is freed when state is freed */
+
     return dp;
 }
 
@@ -2059,9 +2119,10 @@ static Exdisc_t *initDisc(Gpr_t * state)
 static Exnode_t *compile(Expr_t * prog, char *src, char *input, int line,
                         char *lbl, char *sfx, int kind)
 {
-    Exnode_t *e;
+    Exnode_t *e = 0;
     Sfio_t *sf;
     Sfio_t *prefix;
+    int rv;
 
     /* create input stream */
     if (sfx) {
@@ -2082,13 +2143,13 @@ static Exnode_t *compile(Expr_t * prog, char *src, char *input, int line,
        line--;
     }
 
-    /* prog is set to exit on errors */
     if (!src)
        src = "<command line>";
-    excomp(prog, src, line, 0, sf);
+    rv = excomp(prog, src, line, 0, sf);
     sfclose(sf);
 
-    e = exexpr(prog, lbl, NiL, kind);
+    if (rv >= 0 && (getErrorErrors() == 0))
+       e = exexpr(prog, lbl, NiL, kind);
 
     return e;
 }
@@ -2101,12 +2162,7 @@ static void checkGuard(Exnode_t * gp, char *src, int line)
     gp = exnoncast(gp);
     if (gp && exisAssign(gp)) {
        if (src) {
-#ifdef GVDLL
            setErrorFileLine (src, line);
-#else
-           error_info.file = src;
-           error_info.line = line;
-#endif
        }
        error(ERROR_WARNING, "assignment used as bool in guard");
     }
@@ -2128,12 +2184,14 @@ static case_stmt *mkStmts(Expr_t * prog, char *src, case_info * sp,
            sfprintf(tmps, "%s_g%d", lbl, i);
            cs[i].guard = compile(prog, src, sp->guard, sp->gstart,
                                  sfstruse(tmps), 0, INTEGER);
+           if (getErrorErrors()) break;
            checkGuard(cs[i].guard, src, sp->gstart);
        }
        if (sp->action) {
            sfprintf(tmps, "%s_a%d", lbl, i);
            cs[i].action = compile(prog, src, sp->action, sp->astart,
                                   sfstruse(tmps), 0, INTEGER);
+           if (getErrorErrors()) break;
        }
        sp = sp->next;
     }
@@ -2161,7 +2219,6 @@ static char *doFlags(int flags, Sfio_t * s)
 comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
 {
     comp_prog *p;
-    Exdisc_t *dp;
     Sfio_t *tmps = sfstropen();
     char *endg_sfx = 0;
 
@@ -2169,9 +2226,11 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
     assert(BITS_PER_BYTE * sizeof(tctype) >= (1 << TBITS));
 
     p = newof(0, comp_prog, 1, 0);
-    if (!p)
-       error(ERROR_FATAL,
+    if (!p) {
+       error(ERROR_ERROR,
              "could not create compiled program: out of memory");
+       goto finish;
+    }
 
     if (flags) {
        endg_sfx = doFlags(flags, tmps);
@@ -2179,13 +2238,19 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
            endg_sfx = 0;
     }
 
-    dp = initDisc(state);
-    p->prog = exopen(dp);
+    if (!(initDisc(state)))
+       goto finish;
+    
+    exinit();
+    if (!(p->prog = exopen(state->dp)))
+       goto finish;
 
     codePhase = 0;
     if (inp->begin_stmt) {
        p->begin_stmt = compile(p->prog, inp->source, inp->begin_stmt,
                                inp->l_begin, 0, 0, VOID);
+       if (getErrorErrors())
+           goto finish;
     }
 
     codePhase = 1;
@@ -2194,6 +2259,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
        tchk[V_this][1] = Y(G);
        p->begg_stmt = compile(p->prog, inp->source, inp->begg_stmt,
                               inp->l_beging, "_begin_g", 0, VOID);
+       if (getErrorErrors())
+           goto finish;
     }
 
     codePhase = 2;
@@ -2203,6 +2270,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
        p->n_nstmts = inp->n_nstmts;
        p->node_stmts = mkStmts(p->prog, inp->source, inp->node_stmts,
                                inp->n_nstmts, "_nd");
+       if (getErrorErrors())
+           goto finish;
     }
 
     codePhase = 3;
@@ -2212,6 +2281,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
        p->n_estmts = inp->n_estmts;
        p->edge_stmts = mkStmts(p->prog, inp->source, inp->edge_stmts,
                                inp->n_estmts, "_eg");
+       if (getErrorErrors())
+           goto finish;
     }
 
     codePhase = 4;
@@ -2220,6 +2291,8 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
        tchk[V_this][1] = Y(G);
        p->endg_stmt = compile(p->prog, inp->source, inp->endg_stmt,
                               inp->l_endg, "_end_g", endg_sfx, VOID);
+       if (getErrorErrors())
+           goto finish;
     }
 
     codePhase = 5;
@@ -2227,16 +2300,32 @@ comp_prog *compileProg(parse_prog * inp, Gpr_t * state, int flags)
        symbols[0].type = T_obj;
        p->end_stmt = compile(p->prog, inp->source, inp->end_stmt,
                              inp->l_end, "_end_", 0, VOID);
+       if (getErrorErrors())
+           goto finish;
+    }
+    setErrorLine (0); /* execution errors have no line numbers */
+
+    finish:
+    if (getErrorErrors()) {
+       freeCompileProg (p);
+       p = 0;
     }
+
     sfclose(tmps);
-#ifdef GVDLL
-    setErrorLine (0);
-#else
-    error_info.line = 0;       /* execution errors have no line numbers */
-#endif
     return p;
 }
 
+void
+freeCompileProg (comp_prog *p)
+{
+    if (!p) return;
+
+    exclose (p->prog, 1);
+    free (p->node_stmts);
+    free (p->edge_stmts);
+    free (p);
+}
+
 /* walksGraph;
  * Returns true if program actually has node or edge statements.
  */
@@ -2312,6 +2401,10 @@ Agraph_t *openG(char *name, Agdesc_t desc)
 {
     Agraph_t *g;
 
+#ifdef GVDLL
+    gprDisc.mem = &AgMemDisc;
+    gprDisc.id = &AgIdDisc;
+#endif
     g = agopen(name, desc, &gprDisc);
     if (g)
        agbindrec(g, UDATA, sizeof(gdata), 0);
@@ -2366,3 +2459,4 @@ Agedge_t *openEdge(Agraph_t* g, Agnode_t * t, Agnode_t * h, char *key)
        agbindrec(ep, UDATA, sizeof(edata), 0);
     return ep;
 }
+
similarity index 96%
rename from cmd/gvpr/compile.h
rename to lib/gvpr/compile.h
index 7fa45f6bc507a254b58b5d125c08c7190d63babc..588d73ae02c455966f8b3b3b14b433f5da1bdb43 100644 (file)
@@ -62,6 +62,7 @@ extern "C" {
 
 #define SRCOUT    0x1
 #define INDUCE    0x2
+#define CLONE     0x4
 
     typedef struct {
        Expr_t *prog;
@@ -76,6 +77,7 @@ extern "C" {
     } comp_prog;
 
     extern comp_prog *compileProg(parse_prog *, Gpr_t *, int);
+    extern void freeCompileProg (comp_prog *p);
     extern int usesGraph(comp_prog *);
     extern int walksGraph(comp_prog *);
     extern Agraph_t *readG(Sfio_t * fp);
diff --git a/lib/gvpr/gdefs.h b/lib/gvpr/gdefs.h
new file mode 100644 (file)
index 0000000..03bc871
--- /dev/null
@@ -0,0 +1,304 @@
+#ifndef GDEFS_H
+#define GDEFS_H
+
+/* generated by mkdefs; do not edit */
+
+#define Y(i)    (1<<(i))
+
+#define V       0x4      /* NODE         */
+#define E       0x5      /* EDGE         */
+#define G       0x6      /* GRAPH        */
+#define O       0x7      /* OBJECT       */
+#define TV      0x8      /* TV_          */
+#define YALL    (Y(V)|Y(E)|Y(G))
+
+#define        V_this      1
+#define        V_thisg     2
+#define        V_targt     3
+#define        V_outgraph          4
+#define        V_tgtname           5
+#define        V_infname           6
+#define        V_travroot          7
+#define        V_travtype          8
+#define        V_ARGC      9
+#define        M_degree           10
+#define        M_head     11
+#define        M_tail     12
+#define        M_name     13
+#define        M_indegree         14
+#define        M_outdegree        15
+#define        M_root     16
+#define        M_parent           17
+#define        M_n_edges          18
+#define        M_n_nodes          19
+#define        M_directed         20
+#define        M_strict           21
+#define        T_node     22
+#define        T_edge     23
+#define        T_graph    24
+#define        T_obj      25
+#define        T_tvtyp    26
+#define        A_ARGV     27
+#define        F_graph    28
+#define        F_subg     29
+#define        F_issubg           30
+#define        F_fstsubg          31
+#define        F_nxtsubg          32
+#define        F_node     33
+#define        F_addnode          34
+#define        F_fstnode          35
+#define        F_nxtnode          36
+#define        F_nxtnodesg        37
+#define        F_isnode           38
+#define        F_issubnode        39
+#define        F_indegree         40
+#define        F_outdegree        41
+#define        F_degree           42
+#define        F_isin     43
+#define        F_edge     44
+#define        F_edgesg           45
+#define        F_addedge          46
+#define        F_fstout           47
+#define        F_nxtout           48
+#define        F_fstin    49
+#define        F_nxtin    50
+#define        F_fstedge          51
+#define        F_nxtedge          52
+#define        F_fstoutsg         53
+#define        F_nxtoutsg         54
+#define        F_fstinsg          55
+#define        F_nxtinsg          56
+#define        F_fstedgesg        57
+#define        F_nxtedgesg        58
+#define        F_compof           59
+#define        F_kindof           60
+#define        F_index    61
+#define        F_rindex           62
+#define        F_isedge           63
+#define        F_isedgesg         64
+#define        F_issubedge        65
+#define        F_length           66
+#define        F_match    67
+#define        F_write    68
+#define        F_writeg           69
+#define        F_readg    70
+#define        F_fwriteg          71
+#define        F_freadg           72
+#define        F_openf    73
+#define        F_closef           74
+#define        F_readl    75
+#define        F_induce           76
+#define        F_isdirect         77
+#define        F_isstrict         78
+#define        F_delete           79
+#define        F_clone    80
+#define        F_copy     81
+#define        F_copya    82
+#define        F_lock     83
+#define        F_nnodes           84
+#define        F_nedges           85
+#define        F_sqrt     86
+#define        F_cos      87
+#define        F_sin      88
+#define        F_atan2    89
+#define        F_exp      90
+#define        F_pow      91
+#define        F_log      92
+#define        F_min      93
+#define        F_max      94
+#define        F_sys      95
+#define        F_xof      96
+#define        F_yof      97
+#define        F_llof     98
+#define        F_urof     99
+#define        F_canon   100
+#define        F_get     101
+#define        F_set     102
+#define        F_dget    103
+#define        F_dset    104
+#define        F_hasattr         105
+#define        F_isattr          106
+#define        F_fstattr         107
+#define        F_nxtattr         108
+#define        C_flat    109
+#define        C_ne      110
+#define        C_en      111
+#define        C_bfs     112
+#define        C_dfs     113
+#define        C_fwd     114
+#define        C_rev     115
+#define        C_postdfs         116
+#define        C_postfwd         117
+#define        C_postrev         118
+#define        C_prepostdfs      119
+#define        C_prepostfwd      120
+#define        C_prepostrev      121
+#define        C_null    122
+
+#define LAST_V 9
+#define LAST_M 21
+#define MINNAME 1
+#define MAXNAME 122
+
+static Exid_t symbols[] = {
+       EX_ID ( "$", ID, V_this, T_obj, 0),
+       EX_ID ( "$G", ID, V_thisg, T_graph, 0),
+       EX_ID ( "$T", ID, V_targt, T_graph, 0),
+       EX_ID ( "$O", ID, V_outgraph, T_graph, 0),
+       EX_ID ( "$tgtname", ID, V_tgtname, STRING, 0),
+       EX_ID ( "$F", ID, V_infname, STRING, 0),
+       EX_ID ( "$tvroot", ID, V_travroot, T_node, 0),
+       EX_ID ( "$tvtype", ID, V_travtype, T_tvtyp, 0),
+       EX_ID ( "ARGC", ID, V_ARGC, INTEGER, 0),
+       EX_ID ( "degree", ID, M_degree, INTEGER, 0),
+       EX_ID ( "head", ID, M_head, T_node, 0),
+       EX_ID ( "tail", ID, M_tail, T_node, 0),
+       EX_ID ( "name", ID, M_name, STRING, 0),
+       EX_ID ( "indegree", ID, M_indegree, INTEGER, 0),
+       EX_ID ( "outdegree", ID, M_outdegree, INTEGER, 0),
+       EX_ID ( "root", ID, M_root, T_graph, 0),
+       EX_ID ( "parent", ID, M_parent, T_graph, 0),
+       EX_ID ( "n_edges", ID, M_n_edges, INTEGER, 0),
+       EX_ID ( "n_nodes", ID, M_n_nodes, INTEGER, 0),
+       EX_ID ( "directed", ID, M_directed, INTEGER, 0),
+       EX_ID ( "strict", ID, M_strict, INTEGER, 0),
+       EX_ID ( "node_t", DECLARE, T_node, T_node, 0),
+       EX_ID ( "edge_t", DECLARE, T_edge, T_edge, 0),
+       EX_ID ( "graph_t", DECLARE, T_graph, T_graph, 0),
+       EX_ID ( "obj_t", DECLARE, T_obj, T_obj, 0),
+       EX_ID ( "tvtype_t", DECLARE, T_tvtyp, T_tvtyp, 0),
+       EX_ID ( "ARGV", ARRAY, A_ARGV, S|A(1,I), 0),
+       EX_ID ( "graph", FUNCTION, F_graph, G|A(1,S)|A(2,S), 0),
+       EX_ID ( "subg", FUNCTION, F_subg, G|A(1,G)|A(2,S), 0),
+       EX_ID ( "isSubg", FUNCTION, F_issubg, G|A(1,G)|A(2,S), 0),
+       EX_ID ( "fstsubg", FUNCTION, F_fstsubg, G|A(1,G), 0),
+       EX_ID ( "nxtsubg", FUNCTION, F_nxtsubg, G|A(1,G), 0),
+       EX_ID ( "node", FUNCTION, F_node, V|A(1,G)|A(2,S), 0),
+       EX_ID ( "subnode", FUNCTION, F_addnode, V|A(1,G)|A(2,V), 0),
+       EX_ID ( "fstnode", FUNCTION, F_fstnode, V|A(1,G), 0),
+       EX_ID ( "nxtnode", FUNCTION, F_nxtnode, V|A(1,V), 0),
+       EX_ID ( "nxtnode_sg", FUNCTION, F_nxtnodesg, V|A(1,G)|A(2,V), 0),
+       EX_ID ( "isNode", FUNCTION, F_isnode, V|A(1,G)|A(2,S), 0),
+       EX_ID ( "isSubnode", FUNCTION, F_issubnode, I|A(1,G)|A(2,V), 0),
+       EX_ID ( "indegreeOf", FUNCTION, F_indegree, I|A(1,G)|A(2,V), 0),
+       EX_ID ( "outdegreeOf", FUNCTION, F_outdegree, I|A(1,G)|A(2,V), 0),
+       EX_ID ( "degreeOf", FUNCTION, F_degree, I|A(1,G)|A(2,V), 0),
+       EX_ID ( "isIn", FUNCTION, F_isin, I|A(1,G)|A(2,O), 0),
+       EX_ID ( "edge", FUNCTION, F_edge, E|A(1,V)|A(2,V)|A(3,S), 0),
+       EX_ID ( "edge_sg", FUNCTION, F_edgesg, E|A(1,G)|A(2,V)|A(3,V)|A(4,S), 0),
+       EX_ID ( "subedge", FUNCTION, F_addedge, E|A(1,G)|A(2,E), 0),
+       EX_ID ( "fstout", FUNCTION, F_fstout, E|A(1,V), 0),
+       EX_ID ( "nxtout", FUNCTION, F_nxtout, E|A(1,E), 0),
+       EX_ID ( "fstin", FUNCTION, F_fstin, E|A(1,V), 0),
+       EX_ID ( "nxtin", FUNCTION, F_nxtin, E|A(1,E), 0),
+       EX_ID ( "fstedge", FUNCTION, F_fstedge, E|A(1,V), 0),
+       EX_ID ( "nxtedge", FUNCTION, F_nxtedge, E|A(1,E)|A(2,V), 0),
+       EX_ID ( "fstout_sg", FUNCTION, F_fstoutsg, E|A(1,G)|A(2,V), 0),
+       EX_ID ( "nxtout_sg", FUNCTION, F_nxtoutsg, E|A(1,G)|A(2,E), 0),
+       EX_ID ( "fstin_sg", FUNCTION, F_fstinsg, E|A(1,G)|A(2,V), 0),
+       EX_ID ( "nxtin_sg", FUNCTION, F_nxtinsg, E|A(1,G)|A(2,E), 0),
+       EX_ID ( "fstedge_sg", FUNCTION, F_fstedgesg, E|A(1,G)|A(2,V), 0),
+       EX_ID ( "nxtedge_sg", FUNCTION, F_nxtedgesg, E|A(1,G)|A(2,E)|A(3,V), 0),
+       EX_ID ( "compOf", FUNCTION, F_compof, G|A(1,G)|A(2,V), 0),
+       EX_ID ( "kindOf", FUNCTION, F_kindof, S|A(1,O), 0),
+       EX_ID ( "index", FUNCTION, F_index, I|A(1,S)|A(2,S), 0),
+       EX_ID ( "rindex", FUNCTION, F_rindex, I|A(1,S)|A(2,S), 0),
+       EX_ID ( "isEdge", FUNCTION, F_isedge, E|A(1,V)|A(2,V)|A(3,S), 0),
+       EX_ID ( "isEdge_sg", FUNCTION, F_isedgesg, E|A(1,G)|A(2,V)|A(3,V)|A(4,S), 0),
+       EX_ID ( "isSubedge", FUNCTION, F_issubedge, I|A(1,G)|A(2,E), 0),
+       EX_ID ( "length", FUNCTION, F_length, I|A(1,S), 0),
+       EX_ID ( "match", FUNCTION, F_match, I|A(1,S)|A(2,S), 0),
+       EX_ID ( "write", FUNCTION, F_write, I|A(1,G), 0),
+       EX_ID ( "writeG", FUNCTION, F_writeg, I|A(1,G)|A(2,S), 0),
+       EX_ID ( "readG", FUNCTION, F_readg, G|A(1,S), 0),
+       EX_ID ( "fwriteG", FUNCTION, F_fwriteg, I|A(1,G)|A(2,I), 0),
+       EX_ID ( "freadG", FUNCTION, F_freadg, G|A(1,I), 0),
+       EX_ID ( "openF", FUNCTION, F_openf, I|A(1,S)|A(2,S), 0),
+       EX_ID ( "closeF", FUNCTION, F_closef, I|A(1,I), 0),
+       EX_ID ( "readL", FUNCTION, F_readl, S|A(1,I), 0),
+       EX_ID ( "induce", FUNCTION, F_induce, I|A(1,G), 0),
+       EX_ID ( "isDirect", FUNCTION, F_isdirect, I|A(1,G), 0),
+       EX_ID ( "isStrict", FUNCTION, F_isstrict, I|A(1,G), 0),
+       EX_ID ( "delete", FUNCTION, F_delete, I|A(1,G)|A(2,O), 0),
+       EX_ID ( "clone", FUNCTION, F_clone, O|A(1,G)|A(2,O), 0),
+       EX_ID ( "copy", FUNCTION, F_copy, O|A(1,G)|A(2,O), 0),
+       EX_ID ( "copyA", FUNCTION, F_copya, I|A(1,O)|A(2,O), 0),
+       EX_ID ( "lock", FUNCTION, F_lock, I|A(1,G)|A(2,I), 0),
+       EX_ID ( "nNodes", FUNCTION, F_nnodes, I|A(1,G), 0),
+       EX_ID ( "nEdges", FUNCTION, F_nedges, I|A(1,G), 0),
+       EX_ID ( "sqrt", FUNCTION, F_sqrt, F|A(1,F), 0),
+       EX_ID ( "cos", FUNCTION, F_cos, F|A(1,F), 0),
+       EX_ID ( "sin", FUNCTION, F_sin, F|A(1,F), 0),
+       EX_ID ( "atan2", FUNCTION, F_atan2, F|A(1,F)|A(2,F), 0),
+       EX_ID ( "exp", FUNCTION, F_exp, F|A(1,F), 0),
+       EX_ID ( "pow", FUNCTION, F_pow, F|A(1,F)|A(2,F), 0),
+       EX_ID ( "log", FUNCTION, F_log, F|A(1,F), 0),
+       EX_ID ( "MIN", FUNCTION, F_min, F|A(1,F)|A(2,F), 0),
+       EX_ID ( "MAX", FUNCTION, F_max, F|A(1,F)|A(2,F), 0),
+       EX_ID ( "system", FUNCTION, F_sys, I|A(1,S), 0),
+       EX_ID ( "xOf", FUNCTION, F_xof, S|A(1,S), 0),
+       EX_ID ( "yOf", FUNCTION, F_yof, S|A(1,S), 0),
+       EX_ID ( "llOf", FUNCTION, F_llof, S|A(1,S), 0),
+       EX_ID ( "urOf", FUNCTION, F_urof, S|A(1,S), 0),
+       EX_ID ( "canon", FUNCTION, F_canon, S|A(1,S), 0),
+       EX_ID ( "aget", FUNCTION, F_get, S|A(1,O)|A(2,S), 0),
+       EX_ID ( "aset", FUNCTION, F_set, I|A(1,O)|A(2,S)|A(3,S), 0),
+       EX_ID ( "getDflt", FUNCTION, F_dget, S|A(1,G)|A(2,S)|A(3,S), 0),
+       EX_ID ( "setDflt", FUNCTION, F_dset, I|A(1,G)|A(2,S)|A(3,S)|A(4,S), 0),
+       EX_ID ( "hasAttr", FUNCTION, F_hasattr, I|A(1,O)|A(2,S), 0),
+       EX_ID ( "isAttr", FUNCTION, F_isattr, I|A(1,G)|A(2,S)|A(3,S), 0),
+       EX_ID ( "fstAttr", FUNCTION, F_fstattr, S|A(1,G)|A(2,S), 0),
+       EX_ID ( "nxtAttr", FUNCTION, F_nxtattr, S|A(1,G)|A(2,S)|A(3,S), 0),
+       EX_ID ( "TV_flat", CONSTANT, C_flat, T_tvtyp, 0),
+       EX_ID ( "TV_ne", CONSTANT, C_ne, T_tvtyp, 0),
+       EX_ID ( "TV_en", CONSTANT, C_en, T_tvtyp, 0),
+       EX_ID ( "TV_bfs", CONSTANT, C_bfs, T_tvtyp, 0),
+       EX_ID ( "TV_dfs", CONSTANT, C_dfs, T_tvtyp, 0),
+       EX_ID ( "TV_fwd", CONSTANT, C_fwd, T_tvtyp, 0),
+       EX_ID ( "TV_rev", CONSTANT, C_rev, T_tvtyp, 0),
+       EX_ID ( "TV_postdfs", CONSTANT, C_postdfs, T_tvtyp, 0),
+       EX_ID ( "TV_postfwd", CONSTANT, C_postfwd, T_tvtyp, 0),
+       EX_ID ( "TV_postrev", CONSTANT, C_postrev, T_tvtyp, 0),
+       EX_ID ( "TV_prepostdfs", CONSTANT, C_prepostdfs, T_tvtyp, 0),
+       EX_ID ( "TV_prepostfwd", CONSTANT, C_prepostfwd, T_tvtyp, 0),
+       EX_ID ( "TV_prepostrev", CONSTANT, C_prepostrev, T_tvtyp, 0),
+       EX_ID ( "NULL", CONSTANT, C_null, T_obj, 0),
+       EX_ID ( {0}, 0, 0, 0, 0)
+};
+
+static char* typenames[] = {
+       "node_t",
+       "edge_t",
+       "graph_t",
+       "obj_t",
+       "tvtype_t",
+};
+
+typedef unsigned short tctype;
+
+static tctype tchk[][2] = {
+       { 0, 0 },
+       { 0, YALL },
+       { 0, Y(G) },
+       { 0, Y(G) },
+       { 0, Y(G) },
+       { 0, Y(S) },
+       { 0, Y(S) },
+       { 0, Y(V) },
+       { 0, Y(TV) },
+       { 0, Y(I) },
+       { Y(V), Y(I) },
+       { Y(E), Y(V) },
+       { Y(E), Y(V) },
+       { YALL, Y(S) },
+       { Y(V), Y(I) },
+       { Y(V), Y(I) },
+       { YALL, Y(G) },
+       { Y(G), Y(G) },
+       { Y(G), Y(I) },
+       { Y(G), Y(I) },
+       { Y(G), Y(I) },
+       { Y(G), Y(I) },
+};
+
+#endif
similarity index 100%
rename from cmd/gvpr/gprdata
rename to lib/gvpr/gprdata
similarity index 71%
rename from cmd/gvpr/gprstate.c
rename to lib/gvpr/gprstate.c
index b5878e4c1a30b7ee27a2fe2f07230f958454da54..ad237bff92b62c0463c5be33d8d5f2d13cfd5b91 100644 (file)
@@ -34,29 +34,46 @@ int validTVT(int c)
     return ((TV_flat <= c) && (c <= TV_prepostrev));
 }
 
-void initGPRState(Gpr_t * state, Vmalloc_t * vm, gpr_info * info)
+void initGPRState(Gpr_t * state, Vmalloc_t * vm)
 {
     state->tgtname = vmstrdup(vm, "gvpr_result");
-    state->tvt = TV_flat;
-    state->tvroot = 0;
-    state->outFile = info->outFile;
-    state->argc = info->argc;
-    state->argv = info->argv;
 }
 
-Gpr_t *openGPRState()
+Gpr_t *openGPRState(gpr_info* info)
 {
     Gpr_t *state;
 
-    if (!(state = newof(0, Gpr_t, 1, 0)))
-       error(ERROR_FATAL, "Could not create gvpr state: out of memory");
+    if (!(state = newof(0, Gpr_t, 1, 0))) {
+       error(ERROR_ERROR, "Could not create gvpr state: out of memory");
+       return state;
+    }
+
+    if (!(state->tmp = sfstropen())) {
+       error(ERROR_ERROR, "Could not create state tmpfile");
+       free (state);
+       return 0;
+    }
 
-    if (!(state->tmp = sfstropen()))
-       error(ERROR_FATAL, "Could not create state");
+    state->tvt = TV_flat;
+    state->tvroot = 0;
+    state->outFile = info->outFile;
+    state->argc = info->argc;
+    state->argv = info->argv;
+    state->errf = info->errf;
+    state->flags = info->flags;
 
     return state;
 }
 
+void closeGPRState(Gpr_t* state)
+{
+    if (!state) return;
+    if (state->tmp)
+       sfclose (state->tmp);
+    free (state->dp);
+    free (state);
+}
+
 #ifdef WIN32_DLL
 int pathisrelative (char* path)
 {
similarity index 86%
rename from cmd/gvpr/gprstate.h
rename to lib/gvpr/gprstate.h
index 01f88fb3ef0294919d2a74e2d65d37b7bf36ac9b..e1433351108c75cb09b1a73675a0588cf227d83a 100644 (file)
@@ -25,6 +25,7 @@ extern "C" {
 #include "cgraph.h"
 #include "ast.h"
 #include "vmalloc.h"
+#include "expr.h"
 
     typedef enum { TV_flat, TV_ne, TV_en, 
                    TV_bfs, 
@@ -39,6 +40,9 @@ extern "C" {
        Agraph_t *outgraph;
        Agobj_t *curobj;
        Sfio_t *tmp;
+       Exdisc_t *dp;
+       Exerror_f errf;
+       Exexit_f exitf;
        char *tgtname;
        char *infname;
        Sfio_t *outFile;
@@ -47,16 +51,21 @@ extern "C" {
        int name_used;
        int argc;
        char **argv;
+       int flags;
     } Gpr_t;
 
     typedef struct {
        Sfio_t *outFile;
        int argc;
        char **argv;
+       Exerror_f errf;
+       Exexit_f exitf;
+       int flags;
     } gpr_info;
 
-    extern Gpr_t *openGPRState(void);
-    extern void initGPRState(Gpr_t *, Vmalloc_t *, gpr_info *);
+    extern Gpr_t *openGPRState(gpr_info*);
+    extern void closeGPRState(Gpr_t* state);
+    extern void initGPRState(Gpr_t *, Vmalloc_t *);
     extern int validTVT(int);
 
 #ifdef WIN32_DLL
similarity index 56%
rename from cmd/gvpr/gvpr.c
rename to lib/gvpr/gvpr.c
index c026b862bcfcc058548de02c5bc62e59eb0666bf..280a93931ba40e15ba8dd6a57c8bc859cac07fda 100644 (file)
 #include "ingraphs.h"
 #include "compile.h"
 #include "queue.h"
+#include "gvpr.h"
+#include "actions.h"
 #include "sfstr.h"
 #include <error.h>
 #include <string.h>
 #include <ctype.h>
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#else
-#include "compat_getopt.h"
-#endif
-
-char *Info[] = {
-    "gvpr",                    /* Program */
-    VERSION,                   /* Version */
-    BUILDDATE                  /* Build Date */
-};
+#include <setjmp.h>
 
 #define DFLT_GPRPATH    "."
 
+#define GV_USE_JUMP 4
+
+static char *Info[] = {
+    "gvpr",                     /* Program */
+    VERSION,                    /* Version */
+    BUILDDATE                   /* Build Date */
+};
+
 static const char *usage =
-    ": gvpr [-o <ofile>] [-a <args>] ([-f <prog>] | 'prog') [files]\n\
+    " [-o <ofile>] [-a <args>] ([-f <prog>] | 'prog') [files]\n\
    -c         - use source graph for output\n\
    -f <pfile> - find program in file <pfile>\n\
    -i         - create node induced subgraph\n\
@@ -66,15 +66,16 @@ static const char *usage =
    -?         - print usage info\n\
 If no files are specified, stdin is used\n";
 
-struct {
-    char *cmdName;
+typedef struct {
+    char *cmdName;              /* command name */
     Sfio_t *outFile;           /* output stream; stdout default */
-    char *program;
+    char *program;              /* program source */
     int useFile;               /* true if program comes from a file */
     int compflags;
     char **inFiles;
     int argc;
     char **argv;
+    int state;                  /* > 0 : continue; <= 0 finish */
 } options;
 
 static Sfio_t *openOut(char *name)
@@ -83,7 +84,7 @@ static Sfio_t *openOut(char *name)
 
     outs = sfopen(0, name, "w");
     if (outs == 0) {
-       error(ERROR_FATAL, "could not open %s for writing", name);
+       error(ERROR_ERROR, "could not open %s for writing", name);
     }
     return outs;
 }
@@ -99,40 +100,41 @@ static Sfio_t *openOut(char *name)
  * NB. There must be white space between tokens. Otherwise, they
  * are concatenated.
  */
-static char*
-gettok (char** sp)
+static char *gettok(char **sp)
 {
-    char* s = *sp;
-    char* ws = s;
-    char* rs = s;
-    char  c;
-    char  q = '\0';  /* if non-0, in quote mode with quote char q */
-
-    while (isspace(*rs)) rs++;
-    if ((c = *rs) == '\0') return NULL;
+    char *s = *sp;
+    char *ws = s;
+    char *rs = s;
+    char c;
+    char q = '\0';             /* if non-0, in quote mode with quote char q */
+
+    while (isspace(*rs))
+       rs++;
+    if ((c = *rs) == '\0')
+       return NULL;
     while ((c = *rs)) {
-        if (q && (q == c)) {  /* end quote */
+       if (q && (q == c)) {    /* end quote */
            q = '\0';
-       }
-       else if (!q && ((c == '"') || (c == '\''))) { 
+       } else if (!q && ((c == '"') || (c == '\''))) {
            q = c;
-       }
-        else if (c == '\\') {
+       } else if (c == '\\') {
            rs++;
            c = *rs;
-           if (c) *ws++ = c;
+           if (c)
+               *ws++ = c;
            else {
-               error(ERROR_WARNING, 
-                  "backslash in argument followed by no character - ignored");
+               error(ERROR_WARNING,
+                     "backslash in argument followed by no character - ignored");
                rs--;
            }
-       } 
-       else if (q || !isspace(c))
+       } else if (q || !isspace(c))
            *ws++ = c;
-       else break;
-        rs++;
+       else
+           break;
+       rs++;
     }
-    if (*rs) rs++;
+    if (*rs)
+       rs++;
     else if (q)
        error(ERROR_WARNING, "no closing quote for argument %s", s);
     *sp = rs;
@@ -170,7 +172,7 @@ static int parseArgs(char *s, int argc, char ***argv)
        argc = oldcnt + cnt;
        av = oldof(*argv, char *, argc, 0);
        for (i = 0; i < cnt; i++)
-           av[oldcnt+i] = strdup(args[i]);
+           av[oldcnt + i] = strdup(args[i]);
        *argv = av;
     }
     return argc;
@@ -189,6 +191,7 @@ static int parseArgs(char *s, int argc, char ***argv)
  * Translate -f arg parameter into a pathname.
  * If arg contains '/', return arg.
  * Else search directories in GPRPATH for arg.
+ * Return NULL on error.
  */
 static char *resolve(char *arg)
 {
@@ -200,18 +203,20 @@ static char *resolve(char *arg)
     size_t sz;
 
 #ifdef WIN32_DLL
-    if (!pathisrelative (arg))
+    if (!pathisrelative(arg))
 #else
     if (strchr(arg, '/'))
 #endif
-       return arg;
+       return strdup(arg);
 
     path = getenv("GPRPATH");
     if (!path)
        path = DFLT_GPRPATH;
 
-    if (!(fp = sfstropen()))
-       error(ERROR_FATAL, "Could not open buffer");
+    if (!(fp = sfstropen())) {
+       error(ERROR_ERROR, "Could not open buffer");
+       return 0;
+    }
 
     while (*path && !fname) {
        if (*path == LISTSEP) { /* skip colons */
@@ -237,102 +242,181 @@ static char *resolve(char *arg)
     }
 
     if (!fname)
-       error(ERROR_FATAL, "Could not find file \"%s\" in GPRPATH", arg);
+       error(ERROR_ERROR, "Could not find file \"%s\" in GPRPATH", arg);
 
     sfclose(fp);
     return fname;
 }
 
-/* scanArgs:
- * Parse command line options.
+static char*
+getOptarg (int c, char** argp, int* argip, int argc, char** argv)
+{
+    char* rv; 
+    char* arg = *argp;
+    int argi = *argip;
+
+    if (*arg) {
+       rv = arg;
+       while (*arg) arg++; 
+       *argp = arg;
+    }
+    else if (argi < argc) {
+       rv = argv[argi++];
+       *argip = argi;
+    } 
+    else {
+       rv = NULL;
+       error(ERROR_WARNING, "missing argument for option -%c", c);
+    }
+    return rv;
+}
+
+/* doFlags:
+ * Process a command-line argument starting with a '-'.
+ * argi is the index of the next available item in argv[].
+ * argc has its usual meaning.
+ *
+ * return > 0 given next argi value
+ *        = 0 for exit with 0
+ *        < 0 for error
  */
-static void scanArgs(int argc, char **argv)
+static int
+doFlags(char* arg, int argi, int argc, char** argv, options* opts)
 {
     int c;
-    char *outname = 0;
-
-    options.cmdName = argv[0];
-    options.outFile = 0;
-    options.useFile = 0;
-    options.argv = 0;
-    options.argc = 0;
-#ifdef GVDLL
-    setErrorId (options.cmdName);
-#else
-    error_info.id = options.cmdName;
-#endif
 
-    while ((c = getopt(argc, argv, ":q?Vcia:f:o:")) != -1) {
+    while ((c = *arg++)) {
        switch (c) {
        case 'c':
-           options.compflags |= SRCOUT;
+           opts->compflags |= SRCOUT;
+           break;
+       case 'C':
+           opts->compflags |= (SRCOUT|CLONE);
            break;
        case 'f':
-           options.useFile = 1;
-           options.program = resolve(optarg);
+           if ((optarg = getOptarg(c, &arg, &argi, argc, argv)) && (opts->program = resolve(optarg))) {
+               opts->useFile = 1;
+           }
+           else return -1;
            break;
        case 'i':
-           options.compflags |= INDUCE;
+           opts->compflags |= INDUCE;
            break;
        case 'a':
-           options.argc = parseArgs(optarg, options.argc, &options.argv);
+           if ((optarg = getOptarg(c, &arg, &argi, argc, argv))) {
+               opts->argc = parseArgs(optarg, opts->argc, &(opts->argv));
+           }
+           else return -1;
            break;
        case 'o':
-           outname = optarg;
+           if (!(optarg = getOptarg(c, &arg, &argi, argc, argv)) && !(opts->outFile = openOut(optarg)))
+               return -1;
            break;
        case 'q':
-           setTraceLevel (ERROR_ERROR);
+           setTraceLevel (ERROR_ERROR);  /* Don't emit warning messages */
            break;
        case 'V':
-           fprintf(stderr, "%s version %s (%s)\n",
+           sfprintf(sfstderr, "%s version %s (%s)\n",
                    Info[0], Info[1], Info[2]);
-           exit(0);
+           return 0;
            break;
        case '?':
-           if (optopt == '?') {
-               error(ERROR_USAGE, "%s", usage);
-               exit(0);
-           } else {
-               error(ERROR_ERROR, "option -%c unrecognized", optopt);
-           }
+           error(ERROR_USAGE|ERROR_WARNING, "%s", usage);
+           return 0;
            break;
-       case ':':
-           error(ERROR_ERROR, "missing argument for option -%c", optopt);
+       default :
+           error(ERROR_WARNING, "option -%c unrecognized", c);
            break;
        }
     }
-    argv += optind;
-    argc -= optind;
+    return argi;
+}
+
+static void
+freeOpts (options* opts)
+{
+    int i;
+    if (!opts) return;
+    if (opts->outFile != sfstdout)
+       sfclose (opts->outFile);
+    free (opts->inFiles);
+    if (opts->useFile)
+       free (opts->program);
+    if (opts->argc) {
+       for (i = 0; i < opts->argc; i++)
+           free (opts->argv[i]);
+       free (opts->argv);
+    }
+    free (opts);
+}
+
+/* scanArgs:
+ * Parse command line options.
+ */
+static options* scanArgs(int argc, char **argv, gvpropts* uopts)
+{
+    int i, nfiles;
+    char** input_filenames;
+    char* arg;
+    options* opts = newof(0,options,1,0);
+
+    opts->cmdName = argv[0];
+    opts->state = 1;
+    setErrorId (opts->cmdName);
+
+    /* estimate number of file names */
+    nfiles = 0;
+    for (i = 1; i < argc; i++)
+       if (argv[i] && argv[i][0] != '-')
+           nfiles++;
+    input_filenames = newof(0,char*,nfiles + 1,0);
+
+    /* loop over arguments */
+    nfiles = 0;
+    for (i = 1; i < argc; ) {
+       arg = argv[i++];
+       if (*arg == '-') {
+           i = doFlags (arg+1, i, argc, argv, opts);
+           if (i <= 0) {
+               opts->state = i;
+               goto opts_done;
+           }
+       } else if (arg)
+           input_filenames[nfiles++] = arg;
+    }
 
     /* Handle additional semantics */
-    if (options.useFile == 0) {
-       if (argc == 0) {
-           error(ERROR_ERROR, "No program supplied via argument or -f option");
-#ifdef GVDLL
-           setErrorErrors (1);
-#else
-           error_info.errors = 1;
-#endif
+    if (opts->useFile == 0) {
+       if (nfiles == 0) {
+           error(ERROR_ERROR,
+                 "No program supplied via argument or -f option");
+           opts->state = -1;
        } else {
-           options.program = *argv++;
-           argc--;
+           opts->program = input_filenames[0];
+           for (i = 1; i <= nfiles; i++)
+               input_filenames[i-1] = input_filenames[i];
+           nfiles--;
        }
     }
-    if (argc == 0)
-       options.inFiles = 0;
-    else
-       options.inFiles = argv;
-    if (outname)
-       options.outFile = openOut(outname);
+    if (nfiles == 0) {
+       opts->inFiles = 0;
+       free (input_filenames);
+       input_filenames = 0;
+    }
     else
-       options.outFile = sfstdout;
+       opts->inFiles = input_filenames;
 
-#ifdef GVDLL
-    if (getErrorErrors ())
-#else
-    if (error_info.errors)
-#endif
-       error(ERROR_USAGE | 4, "%s", usage);
+    if (!(opts->outFile))
+       opts->outFile = sfstdout;
+
+  opts_done:
+    if (opts->state <= 0) {
+       if (opts->state < 0)
+           error(ERROR_USAGE|ERROR_ERROR, "%s", usage);
+       free (input_filenames);
+    }
+
+    return opts;
 }
 
 static void evalEdge(Gpr_t * state, comp_prog * xprog, Agedge_t * e)
@@ -404,8 +488,8 @@ static Agnode_t *nextNode(Gpr_t * state, nodestream * nodes)
 #define PUSH(x)  (((x)->iu.integer)|=2)
 #define POP(x)  (((x)->iu.integer)&=(~2))
 
-typedef Agedge_t *(*fstedgefn_t) (Agraph_t*, Agnode_t *);
-typedef Agedge_t *(*nxttedgefn_t) (Agraph_t*, Agedge_t *, Agnode_t *);
+typedef Agedge_t *(*fstedgefn_t) (Agraph_t *, Agnode_t *);
+typedef Agedge_t *(*nxttedgefn_t) (Agraph_t *, Agedge_t *, Agnode_t *);
 
 #define PRE_VISIT 1
 #define POST_VISIT 2
@@ -417,9 +501,9 @@ typedef struct {
     unsigned char visit;
 } trav_fns;
 
-static trav_fns DFSfns = { agfstedge, agnxtedge, 1, 0};
-static trav_fns FWDfns = { agfstout, (nxttedgefn_t) agnxtout, 0, 0};
-static trav_fns REVfns = { agfstin, (nxttedgefn_t) agnxtin, 0, 0};
+static trav_fns DFSfns = { agfstedge, agnxtedge, 1, 0 };
+static trav_fns FWDfns = { agfstout, (nxttedgefn_t) agnxtout, 0, 0 };
+static trav_fns REVfns = { agfstin, (nxttedgefn_t) agnxtin, 0, 0 };
 
 static void travBFS(Gpr_t * state, comp_prog * xprog)
 {
@@ -428,7 +512,7 @@ static void travBFS(Gpr_t * state, comp_prog * xprog)
     ndata *nd;
     Agnode_t *n;
     Agedge_t *cure;
-    Agraph_tg = state->curgraph;
+    Agraph_t *g = state->curgraph;
 
     q = mkQueue();
     nodes.oldroot = 0;
@@ -438,15 +522,17 @@ static void travBFS(Gpr_t * state, comp_prog * xprog)
        if (MARKED(nd))
            continue;
        PUSH(nd);
-       push (q,n);
+       push(q, n);
        while ((n = pull(q))) {
            nd = nData(n);
            MARK(nd);
-           POP(nd);
+           POP(nd);
            evalNode(state, xprog, n);
-           for (cure = agfstedge(g, n); cure; cure = agnxtedge(g, cure, n)) {
+           for (cure = agfstedge(g, n); cure;
+                cure = agnxtedge(g, cure, n)) {
                nd = nData(cure->node);
-               if (MARKED(nd)) continue;
+               if (MARKED(nd))
+                   continue;
                evalEdge(state, xprog, cure);
                if (!ONSTACK(nd)) {
                    push(q, cure->node);
@@ -455,7 +541,7 @@ static void travBFS(Gpr_t * state, comp_prog * xprog)
            }
        }
     }
-    freeQ (q);
+    freeQ(q);
 }
 
 static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns)
@@ -493,18 +579,18 @@ static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns)
            else
                cure = fns->fstedge(state->curgraph, curn);
            if (cure) {
-               if (entry == agopp(cure))  /* skip edge used to get here */
+               if (entry == agopp(cure))       /* skip edge used to get here */
                    continue;
                nd = nData(cure->node);
                if (MARKED(nd)) {
-                    /* For undirected DFS, visit an edge only if its head
-                     * is on the stack, to avoid visiting it twice.
-                     * This is no problem in directed DFS.
-                     */
+                   /* For undirected DFS, visit an edge only if its head
+                    * is on the stack, to avoid visiting it twice.
+                    * This is no problem in directed DFS.
+                    */
                    if (fns->undirected) {
-                       if (ONSTACK(nd)) evalEdge(state, xprog, cure);
-                   }
-                   else
+                       if (ONSTACK(nd))
+                           evalEdge(state, xprog, cure);
+                   else
                        evalEdge(state, xprog, cure);
                } else {
                    evalEdge(state, xprog, cure);
@@ -531,13 +617,13 @@ static void travDFS(Gpr_t * state, comp_prog * xprog, trav_fns * fns)
            }
        }
     }
-    freeQ (stk);
+    freeQ(stk);
 }
 
 static void travNodes(Gpr_t * state, comp_prog * xprog)
 {
     Agnode_t *n;
-    Agraph_tg = state->curgraph;
+    Agraph_t *g = state->curgraph;
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
        evalNode(state, xprog, n);
     }
@@ -547,7 +633,7 @@ static void travEdges(Gpr_t * state, comp_prog * xprog)
 {
     Agnode_t *n;
     Agedge_t *e;
-    Agraph_tg = state->curgraph;
+    Agraph_t *g = state->curgraph;
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
        for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
            evalEdge(state, xprog, e);
@@ -559,7 +645,7 @@ static void travFlat(Gpr_t * state, comp_prog * xprog)
 {
     Agnode_t *n;
     Agedge_t *e;
-    Agraph_tg = state->curgraph;
+    Agraph_t *g = state->curgraph;
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
        evalNode(state, xprog, n);
        if (xprog->n_estmts > 0) {
@@ -640,6 +726,23 @@ static void traverse(Gpr_t * state, comp_prog * xprog)
     }
 }
 
+/* addOutputGraph:
+ * Append output graph to option struct.
+ * We know uopts and state->outgraph are non-NULL.
+ */
+static void
+addOutputGraph (Gpr_t* state, gvpropts* uopts)
+{
+    Agraph_t* g = state->outgraph;
+
+    if ((agroot(g) == state->curgraph) && !uopts->ingraphs)
+       g = (Agraph_t*)clone (0, (Agobj_t *)g);
+
+    uopts->n_outgraphs++;
+    uopts->outgraphs = oldof(uopts->outgraphs,Agraph_t*,uopts->n_outgraphs,0);
+    uopts->outgraphs[uopts->n_outgraphs-1] = g;
+}
+
 static void chkClose(Agraph_t * g)
 {
     gdata *data;
@@ -666,32 +769,131 @@ static int ing_close(void *fp)
     return sfclose((Sfio_t *) fp);
 }
 
-#ifdef GVDLL
 static ingdisc ingDisc = { ing_open, ing_read, ing_close, 0 };
-#else
-static ingdisc ingDisc = { ing_open, ing_read, ing_close, &_Sfstdin };
-#endif
 
-int main(int argc, char *argv[])
+static void
+setDisc (Sfio_t* sp, Sfdisc_t* dp, gvprwr fn)
 {
-    parse_prog *prog;
+    dp->readf = 0;
+    dp->writef = (Sfwrite_f)fn;
+    dp->seekf = 0;
+    dp->exceptf = 0;
+    dp->disc = 0;
+    dp = sfdisc (sp, dp);
+}
+
+static jmp_buf jbuf;
+
+/* gvexitf:
+ * Only used if GV_USE_EXIT not set during exeval.
+ * This implies setjmp/longjmp set up.
+ */
+static void 
+gvexitf (Expr_t *handle, Exdisc_t *discipline, int v)
+{
+    longjmp (jbuf, v);
+}
+
+static int 
+gverrorf (Expr_t *handle, Exdisc_t *discipline, int level, ...)
+{
+    va_list ap;
+
+    va_start(ap, level);
+    errorv((discipline
+           && handle) ? *((char **) handle) : (char *) handle, level, ap);
+    va_end(ap);
+
+    if (level >= ERROR_ERROR) {
+       Gpr_t *state = (Gpr_t*)(discipline->user);
+       if (state->flags & GV_USE_EXIT)
+            exit(1);
+       else if (state->flags & GV_USE_JUMP)
+           longjmp (jbuf, 1);
+    }
+
+    return 0;
+}
+
+/* gvpr:
+ * main loop for gvpr.
+ * Return 0 on success; non-zero on error.
+ *
+ * FIX:
+ *  - close non-source/non-output graphs
+ */
+int gvpr (int argc, char *argv[], gvpropts * uopts)
+{
+    Sfdisc_t errdisc;
+    Sfdisc_t outdisc;
+    parse_prog *prog = 0;
     ingraph_state *ing;
-    comp_prog *xprog;
-    Gpr_t *state;
+    comp_prog *xprog = 0;
+    Gpr_t *state = 0;
     gpr_info info;
+    int rv = 0;
+    options* opts = 0;
+    int incoreGraphs;
+
+    setErrorErrors (0);
+    ingDisc.dflt = sfstdin;
+    if (uopts) {
+       if (uopts->out) setDisc (sfstdout, &outdisc, uopts->out);
+       if (uopts->err) setDisc (sfstderr, &errdisc, uopts->err);
+    }
 
-#ifdef GVDLL
-    ingDisc.dflt = &_Sfstdin;
-#endif
-    scanArgs(argc, argv);
+    opts = scanArgs(argc, argv, uopts);
+    if (opts->state <= 0) {
+       rv = opts->state;
+       goto finish;
+    }
+
+    prog = parseProg(opts->program, opts->useFile);
+    if (!prog) {
+       rv = 1;
+       goto finish;
+    }
+    info.outFile = opts->outFile;
+    info.argc = opts->argc;
+    info.argv = opts->argv;
+    info.errf = (Exerror_f)gverrorf;
+    if (uopts) 
+       info.flags = uopts->flags; 
+    else
+       info.flags = 0;
+    if ((uopts->flags & GV_USE_EXIT))
+       info.exitf = 0;
+    else
+       info.exitf = gvexitf;
+    state = openGPRState(&info);
+    if (!state) {
+       rv = 1;
+       goto finish;
+    }
+    xprog = compileProg(prog, state, opts->compflags);
+    if (!xprog) {
+       rv = 1;
+       goto finish;
+    }
+
+    initGPRState(state, xprog->prog->vm);
+    
+    if ((uopts->flags & GV_USE_OUTGRAPH)) {
+       uopts->outgraphs = 0;
+       uopts->n_outgraphs = 0;
+    }
 
-    prog = parseProg(options.program, options.useFile);
-    state = openGPRState();
-    xprog = compileProg(prog, state, options.compflags);
-    info.outFile = options.outFile;
-    info.argc = options.argc;
-    info.argv = options.argv;
-    initGPRState(state, xprog->prog->vm, &info);
+    if (!(uopts->flags & GV_USE_EXIT)) {
+       state->flags |= GV_USE_JUMP;
+       if ((rv = setjmp (jbuf))) {
+           goto finish;
+       }
+    }
+
+    if (uopts && uopts->ingraphs)
+       incoreGraphs = 1;
+    else
+       incoreGraphs = 0;
 
     /* do begin */
     if (xprog->begin_stmt)
@@ -699,10 +901,17 @@ int main(int argc, char *argv[])
 
     /* if program is not null */
     if (usesGraph(xprog)) {
-       ing = newIng(0, options.inFiles, &ingDisc);
+       if (uopts && uopts->ingraphs)
+           ing = newIngGraphs(0, uopts->ingraphs, &ingDisc);
+       else
+           ing = newIng(0, opts->inFiles, &ingDisc);
+       
        while ((state->curgraph = nextGraph(ing))) {
            state->infname = fileName(ing);
+
            /* begin graph */
+           if (incoreGraphs && (opts->compflags & CLONE))
+               state->curgraph = clone (0, (Agobj_t*)(state->curgraph));
            state->curobj = (Agobj_t *) state->curgraph;
            state->tvroot = 0;
            if (xprog->begg_stmt)
@@ -723,24 +932,43 @@ int main(int argc, char *argv[])
                agdelete(state->curgraph, state->target);
 
            /* output graph, if necessary
-             * For this, the outgraph must be defined, and either
-             * be non-empty or the -c option was used.
-             */
-           if (state->outgraph && 
-               (agnnodes(state->outgraph) || (options.compflags & SRCOUT)))
-                   agwrite(state->outgraph, options.outFile);
-
-           chkClose(state->curgraph);
+            * For this, the outgraph must be defined, and either
+            * be non-empty or the -c option was used.
+            */
+           if (state->outgraph && (agnnodes(state->outgraph)
+                                   || (opts->compflags & SRCOUT))) {
+               if (uopts && (uopts->flags & GV_USE_OUTGRAPH))
+                   addOutputGraph (state, uopts);
+               else
+                   agwrite(state->outgraph, opts->outFile);
+           }
+
+           if (!incoreGraphs)
+               chkClose(state->curgraph);
            state->target = 0;
            state->outgraph = 0;
        }
     }
 
-    /* do end */
+       /* do end */
     state->curgraph = 0;
     state->curobj = 0;
     if (xprog->end_stmt)
        exeval(xprog->prog, xprog->end_stmt, state);
 
-    exit(0);
+  finish:
+    /* free all allocated resources */
+    freeParseProg (prog);
+    freeCompileProg (xprog);
+    closeGPRState(state);
+    closeIngraph (ing);
+    freeOpts (opts);
+
+    if (uopts) {
+       if (uopts->out) sfdisc (sfstdout, 0);
+       if (uopts->err) sfdisc (sfstderr, 0);
+    }
+
+    return rv;
 }
+
diff --git a/lib/gvpr/gvpr.h b/lib/gvpr/gvpr.h
new file mode 100644 (file)
index 0000000..925daf6
--- /dev/null
@@ -0,0 +1,48 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GVPR_H
+#define GVPR_H
+
+#include "cgraph.h"
+
+  /* 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
+
+typedef ssize_t (*gvprwr) (void*, const char *buf, size_t nbyte, void*);
+
+typedef struct {
+    Agraph_t** ingraphs;      /* NULL-terminated array of input graphs */
+    int n_outgraphs;          /* if GV_USE_OUTGRAPH set, output graphs */
+    Agraph_t** outgraphs;
+    gvprwr out;               /* write function for stdout */
+    gvprwr err;               /* write function for stderr */
+    int flags;
+} gvpropts;
+
+    extern int gvpr (int argc, char *argv[], gvpropts* opts);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib/gvpr/libgvpr.pc.in b/lib/gvpr/libgvpr.pc.in
new file mode 100644 (file)
index 0000000..7bdfe0a
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/@PACKAGE@
+
+Name: libgvpr
+Description: The GVPR library
+Version: @VERSION@
+Libs: -L${libdir} -lgvpr -lcgraph -lcdt
+Cflags: -I${includedir}
+
similarity index 100%
rename from cmd/gvpr/mkdefs.c
rename to lib/gvpr/mkdefs.c
similarity index 87%
rename from cmd/gvpr/parse.c
rename to lib/gvpr/parse.c
index 2ae2af6be77eeb0d59104876f40c19805cb7b677..5628a0176b3235c3454f1a580daed0d2a559f408 100644 (file)
@@ -209,10 +209,12 @@ static case_t parseKind(Sfio_t * str)
     c = skipWS(str);
     if (c < 0)
        return Eof;
-    if (!isalpha(c))
-       error(ERROR_FATAL,
+    if (!isalpha(c)) {
+       error(ERROR_ERROR,
              "expected keyword BEGIN/END/N/E...; found '%c', line %d", c,
              lineno);
+       return Error;
+    }
 
     kwLine = lineno;
     parseID(str, c, buf, BSIZE);
@@ -237,7 +239,7 @@ static case_t parseKind(Sfio_t * str)
        break;
     }
     if (cs == Error)
-       error(ERROR_FATAL, "unexpected keyword \"%s\", line %d", buf,
+       error(ERROR_ERROR, "unexpected keyword \"%s\", line %d", buf,
              kwLine);
     return cs;
 }
@@ -247,7 +249,7 @@ static case_t parseKind(Sfio_t * str)
  * up to and including a terminating character ec
  * that is not escaped with a back quote.
  */
-static void endString(Sfio_t * ins, Sfio_t * outs, char ec)
+static int endString(Sfio_t * ins, Sfio_t * outs, char ec)
 {
     int sline = lineno;
     int c;
@@ -257,13 +259,16 @@ static void endString(Sfio_t * ins, Sfio_t * outs, char ec)
            sfputc(outs, c);
            c = sfgetc(ins);
        }
-       if (c < 0)
-           error(ERROR_FATAL, "unclosed string, start line %d", sline);
+       if (c < 0) {
+           error(ERROR_ERROR, "unclosed string, start line %d", sline);
+           return c;
+       }
        if (c == '\n')
            lineno++;
        sfputc(outs, (char) c);
     }
     sfputc(outs, c);
+    return 0;
 }
 
 /* endBracket:
@@ -290,7 +295,7 @@ static int endBracket(Sfio_t * ins, Sfio_t * outs, char bc, char ec)
                sfputc(outs, (char) c);
        } else if ((c == '\'') || (c == '"')) {
            sfputc(outs, (char) c);
-           endString(ins, outs, c);
+           if (endString(ins, outs, c)) return -1;
        } else
            sfputc(outs, (char) c);
     }
@@ -314,11 +319,15 @@ static char *parseBracket(Sfio_t * str, Sfio_t * buf, int bc, int ec)
     }
     startLine = lineno;
     c = endBracket(str, buf, bc, ec);
-    if (c < 0)
-       error(ERROR_FATAL,
+    if (c < 0) {
+       if (!getErrorErrors())
+           error(ERROR_ERROR,
              "unclosed bracket %c%c expression, start line %d", bc, ec,
              startLine);
-    return strdup(sfstruse(buf));
+       return 0;
+    }
+    else
+       return strdup(sfstruse(buf));
 }
 
 /* parseAction:
@@ -352,6 +361,7 @@ parseCase(Sfio_t * str, char **guard, int *gline, char **action,
          int *aline)
 {
     case_t kind;
+
     Sfio_t *buf = sfstropen();
 
     kind = parseKind(str);
@@ -362,13 +372,19 @@ parseCase(Sfio_t * str, char **guard, int *gline, char **action,
     case EndG:
        *action = parseAction(str, buf);
        *aline = startLine;
+       if (getErrorErrors ())
+           kind = Error;
        break;
     case Edge:
     case Node:
        *guard = parseGuard(str, buf);
        *gline = startLine;
-       *action = parseAction(str, buf);
-       *aline = startLine;
+       if (!getErrorErrors ()) {
+           *action = parseAction(str, buf);
+           *aline = startLine;
+       }
+       if (getErrorErrors ())
+           kind = Error;
        break;
     case Eof:
     case Error:                /* to silence warnings */
@@ -421,7 +437,7 @@ bindAction(case_t cs, char *action, int aline, char **ap, int *lp)
        error(ERROR_WARNING, "%s with no action, line %d - ignored",
              caseStr(cs), kwLine);
     else if (*ap)
-       error(ERROR_FATAL, "additional %s section, line %d", caseStr(cs),
+       error(ERROR_ERROR, "additional %s section, line %d", caseStr(cs),
              kwLine);
     else {
        *ap = action;
@@ -431,7 +447,6 @@ bindAction(case_t cs, char *action, int aline, char **ap, int *lp)
 
 /* parseProg:
  * Parses input into gpr sections.
- * Only returns if successful.
  */
 parse_prog *parseProg(char *input, int isFile)
 {
@@ -451,7 +466,8 @@ parse_prog *parseProg(char *input, int isFile)
 
     prog = newof(0, parse_prog, 1, 0);
     if (!prog) {
-       error(ERROR_FATAL, "parseProg: out of memory");
+       error(ERROR_ERROR, "parseProg: out of memory");
+       return 0;
     }
 
     if (isFile) {
@@ -465,9 +481,11 @@ parse_prog *parseProg(char *input, int isFile)
     str = sfopen(0, input, mode);
     if (!str) {
        if (isFile)
-           error(ERROR_FATAL, "could not open %s for reading", input);
+           error(ERROR_ERROR, "could not open %s for reading", input);
        else
-           error(ERROR_FATAL, "parseProg : unable to create sfio stream");
+           error(ERROR_ERROR, "parseProg : unable to create sfio stream");
+       free (prog);
+       return 0;
     }
 
     more = 1;
@@ -503,6 +521,7 @@ parse_prog *parseProg(char *input, int isFile)
                edgelist = edgel;
            break;
        case Error:             /* to silence warnings */
+           more = 0;
            break;
        }
     }
@@ -514,5 +533,37 @@ parse_prog *parseProg(char *input, int isFile)
 
     sfclose(str);
 
+    if (getErrorErrors ()) {
+       freeParseProg (prog);
+       prog = 0;
+    }
+
     return prog;
 }
+
+static void
+freeCaseList (case_info* ip)
+{
+    case_info* nxt;
+    while (ip) {
+       nxt = ip->next;
+       free (ip->guard);
+       free (ip->action);
+       free (ip);
+       ip = nxt;
+    }
+}
+
+void 
+freeParseProg (parse_prog * prog)
+{
+    if (!prog) return;
+    free (prog->begin_stmt);
+    free (prog->begg_stmt);
+    freeCaseList (prog->node_stmts);
+    freeCaseList (prog->edge_stmts);
+    free (prog->endg_stmt);
+    free (prog->end_stmt);
+    free (prog);
+}
+
similarity index 96%
rename from cmd/gvpr/parse.h
rename to lib/gvpr/parse.h
index 7e84435fe03e6ad4716a25a407a73d5272af7180..da348726ddf76c76b9d8344111cd583330fd2d23 100644 (file)
@@ -47,6 +47,7 @@ extern "C" {
 
 
     extern parse_prog *parseProg(char *, int);
+    extern void freeParseProg (parse_prog *);
 
 #endif
 
similarity index 100%
rename from cmd/gvpr/queue.c
rename to lib/gvpr/queue.c
similarity index 100%
rename from cmd/gvpr/queue.h
rename to lib/gvpr/queue.h
diff --git a/lib/gvpr/trie.c b/lib/gvpr/trie.c
new file mode 100644 (file)
index 0000000..aff27b2
--- /dev/null
@@ -0,0 +1,136 @@
+#define UNDERLINE
+
+#include "trieFA.h"
+
+TrieState           TrieStateTbl[70] = {
+    { -1, 0, 0x3b8620 },
+    { -1, 9, 0x440 },
+    { -1, 11, 0x100 },
+    { -1, 12, 0x80000 },
+    { -1, 13, 0x40 },
+    { -1, 14, 0x40 },
+    { Y(V), 15, 0x0 },
+    { -1, 15, 0x80000 },
+    { -1, 16, 0x40 },
+    { -1, 17, 0x10 },
+    { -1, 18, 0x200000 },
+    { -1, 19, 0x40 },
+    { -1, 20, 0x20 },
+    { Y(G), 21, 0x0 },
+    { -1, 21, 0x40 },
+    { -1, 22, 0x4 },
+    { -1, 23, 0x20 },
+    { Y(E), 24, 0x0 },
+    { -1, 24, 0x8000 },
+    { -1, 25, 0x20 },
+    { -1, 26, 0x40 },
+    { -1, 27, 0x100 },
+    { -1, 28, 0x80000 },
+    { -1, 29, 0x40 },
+    { -1, 30, 0x40 },
+    { Y(V), 31, 0x0 },
+    { -1, 31, 0x5 },
+    { -1, 33, 0x8040 },
+    { -1, 35, 0x20 },
+    { -1, 36, 0x100 },
+    { -1, 37, 0x40 },
+    { -1, 38, 0x100000 },
+    { Y(G), 39, 0x0 },
+    { -1, 39, 0x10000 },
+    { -1, 40, 0x20 },
+    { -1, 41, 0x40 },
+    { -1, 42, 0x100000 },
+    { Y(G), 43, 0x0 },
+    { -1, 43, 0x4000 },
+    { -1, 44, 0x40 },
+    { YALL, 45, 0x0 },
+    { -1, 45, 0x400000 },
+    { -1, 46, 0x200000 },
+    { -1, 47, 0x20 },
+    { -1, 48, 0x40 },
+    { -1, 49, 0x100 },
+    { -1, 50, 0x80000 },
+    { -1, 51, 0x40 },
+    { -1, 52, 0x40 },
+    { Y(V), 53, 0x0 },
+    { -1, 53, 0x4 },
+    { -1, 54, 0x80000 },
+    { -1, 55, 0x40 },
+    { -1, 56, 0x8000 },
+    { -1, 57, 0x200000 },
+    { Y(G), 58, 0x0 },
+    { -1, 58, 0x10000 },
+    { -1, 59, 0x10000 },
+    { -1, 60, 0x200000 },
+    { YALL, 61, 0x0 },
+    { -1, 61, 0x200000 },
+    { -1, 62, 0x80000 },
+    { -1, 63, 0x400 },
+    { -1, 64, 0x10 },
+    { -1, 65, 0x200000 },
+    { Y(G), 66, 0x0 },
+    { -1, 66, 0x4 },
+    { -1, 67, 0x400 },
+    { -1, 68, 0x2000 },
+    { Y(E), 69, 0x0 },
+};
+TrieTrans           TrieTransTbl[69] = {
+    /* State   0 */  { 'd',   1 }, { 'h',  14 }, { 'i',  18 }, { 'n',  26 }, { 'o',  41 }, { 'p',  50 }, { 'r',  56 }, { 's',  60 }, { 't',  66 },
+    /* State   1 */  { 'e',   2 }, { 'i',   7 },
+    /* State   2 */  { 'g',   3 },
+    /* State   3 */  { 'r',   4 },
+    /* State   4 */  { 'e',   5 },
+    /* State   5 */  { 'e',   6 },
+    /* State   7 */  { 'r',   8 },
+    /* State   8 */  { 'e',   9 },
+    /* State   9 */  { 'c',  10 },
+    /* State  10 */  { 't',  11 },
+    /* State  11 */  { 'e',  12 },
+    /* State  12 */  { 'd',  13 },
+    /* State  14 */  { 'e',  15 },
+    /* State  15 */  { 'a',  16 },
+    /* State  16 */  { 'd',  17 },
+    /* State  18 */  { 'n',  19 },
+    /* State  19 */  { 'd',  20 },
+    /* State  20 */  { 'e',  21 },
+    /* State  21 */  { 'g',  22 },
+    /* State  22 */  { 'r',  23 },
+    /* State  23 */  { 'e',  24 },
+    /* State  24 */  { 'e',  25 },
+    /* State  26 */  { '_',  27 }, { 'a',  38 },
+    /* State  27 */  { 'e',  28 }, { 'n',  33 },
+    /* State  28 */  { 'd',  29 },
+    /* State  29 */  { 'g',  30 },
+    /* State  30 */  { 'e',  31 },
+    /* State  31 */  { 's',  32 },
+    /* State  33 */  { 'o',  34 },
+    /* State  34 */  { 'd',  35 },
+    /* State  35 */  { 'e',  36 },
+    /* State  36 */  { 's',  37 },
+    /* State  38 */  { 'm',  39 },
+    /* State  39 */  { 'e',  40 },
+    /* State  41 */  { 'u',  42 },
+    /* State  42 */  { 't',  43 },
+    /* State  43 */  { 'd',  44 },
+    /* State  44 */  { 'e',  45 },
+    /* State  45 */  { 'g',  46 },
+    /* State  46 */  { 'r',  47 },
+    /* State  47 */  { 'e',  48 },
+    /* State  48 */  { 'e',  49 },
+    /* State  50 */  { 'a',  51 },
+    /* State  51 */  { 'r',  52 },
+    /* State  52 */  { 'e',  53 },
+    /* State  53 */  { 'n',  54 },
+    /* State  54 */  { 't',  55 },
+    /* State  56 */  { 'o',  57 },
+    /* State  57 */  { 'o',  58 },
+    /* State  58 */  { 't',  59 },
+    /* State  60 */  { 't',  61 },
+    /* State  61 */  { 'r',  62 },
+    /* State  62 */  { 'i',  63 },
+    /* State  63 */  { 'c',  64 },
+    /* State  64 */  { 't',  65 },
+    /* State  66 */  { 'a',  67 },
+    /* State  67 */  { 'i',  68 },
+    /* State  68 */  { 'l',  69 },
+};
diff --git a/lib/gvpr/trieFA.h b/lib/gvpr/trieFA.h
new file mode 100644 (file)
index 0000000..6369e4a
--- /dev/null
@@ -0,0 +1,87 @@
+/* File - trieFA.h
+ *
+ *    This file contains code to be included in the scanner file using a
+ * generated trie-based FA.
+ */
+
+typedef struct {                               /* An entry in the FA state table                       */
+       short                   def;            /*      If this state is an accepting state then*/
+                                                               /*      this is the definition, otherwise -1.   */
+       short                   trans_base;     /* The base index into the transition table.*/
+       long                    mask;           /* The transition mask.                                         */
+}TrieState ;
+
+typedef struct {                               /* An entry in the FA transition table.         */
+       short                   c;                              /* The transition character (lowercase).*/
+       short                   next_state;             /* The next state.                                              */
+}TrieTrans ;
+
+#ifdef UNDERLINE
+static long CharMask[28] = {
+       0x0000001,      0x0000000,      0x0000004,      0x0000008,      
+       0x0000010,      0x0000020,      0x0000040,      0x0000080,
+       0x0000100,      0x0000200,      0x0000400,      0x0000800,
+       0x0001000,      0x0002000,      0x0004000,      0x0008000,
+       0x0010000,      0x0020000,      0x0040000,      0x0080000,
+       0x0100000,      0x0200000,      0x0400000,      0x0800000,
+       0x1000000,      0x2000000,  0x4000000,  0x8000000,
+};
+
+#define IN_MASK_RANGE(C)       (islower(C) || ((C) == '_'))
+#define MASK_INDEX(C)  ((C) - '_')
+
+#else
+static long CharMask[26] = {
+       0x0000001,      0x0000002,      0x0000004,      0x0000008,      
+       0x0000010,      0x0000020,      0x0000040,      0x0000080,
+       0x0000100,      0x0000200,      0x0000400,      0x0000800,
+       0x0001000,      0x0002000,      0x0004000,      0x0008000,
+       0x0010000,      0x0020000,      0x0040000,      0x0080000,
+       0x0100000,      0x0200000,      0x0400000,      0x0800000,
+       0x1000000,      0x2000000                                               
+};
+
+#define IN_MASK_RANGE(C)       islower(C)
+#define MASK_INDEX(C)          ((C) - 'a')
+
+#endif
+
+static short           TFA_State;
+
+/* TFA_Init:
+ *
+ *    Initialize the trie FA.
+ */
+#define TFA_Init() TFA_State = 0
+
+/* TFA_Advance:
+ *
+ *    Advance to the next state (or -1) on the lowercase letter c. 
+ */
+#define TFA_Advance(C) {                                                                                                                       \
+       char            c = C;                                                                                                                          \
+       if (TFA_State >= 0) {                                                                                                                   \
+               if (isupper(c))                                                                                                                         \
+                       c = tolower(c);                                                                                                                 \
+               else if (! IN_MASK_RANGE(c)) {                                                                                          \
+                       TFA_State = -1;                                                                                                                 \
+                       goto TFA_done;                                                                                                                  \
+               }                                                                                                                                                       \
+               if (TrieStateTbl[TFA_State].mask & CharMask[MASK_INDEX(c)]) {                           \
+                       short           i = TrieStateTbl[TFA_State].trans_base;                                         \
+                       while (TrieTransTbl[i].c != c)                                                                                  \
+                               i++;                                                                                                                            \
+                       TFA_State = TrieTransTbl[i].next_state;                                                                 \
+               }                                                                                                                                                       \
+               else                                                                                                                                            \
+                       TFA_State = -1;                                                                                                                 \
+       }                                                                                                                                                               \
+  TFA_done:;                                                                                                                                           \
+} /* end of TFA_Advance. */
+
+/* TFA_Definition:
+ *
+ *    Return the definition (if any) associated with the current state.
+ */
+#define TFA_Definition() \
+       ((TFA_State < 0) ? -1 : TrieStateTbl[TFA_State].def)