Add gvPluginList to gvc API - user can query available plugins;
authorerg <devnull@localhost>
Sat, 26 Feb 2011 19:56:38 +0000 (19:56 +0000)
committererg <devnull@localhost>
Sat, 26 Feb 2011 19:56:38 +0000 (19:56 +0000)
removed use of ad hoc extensible string from gvplugin and replaced
with agxbuf.

lib/gvc/gvc.3
lib/gvc/gvc.h
lib/gvc/gvplugin.c

index f35385f0d14f888ecf87562d0edbd863981d6503..dcb8667a1dbaebabd93f55285a6f5bfabf576e13 100644 (file)
@@ -48,6 +48,10 @@ extern int gvFreeLayout(GVC_t *gvc, graph_t *g);
 /* Clean up graphviz context */
 extern int gvFreeContext(GVC_t *gvc);
 
+/* Inquire about available plugins */
+/* See comment in gvc.h            */
+extern char** gvPluginList(GVC_t *gvc, char* kind, int* cnt, char*);
+
 \fP
 .fi
 .SH DESCRIPTION
index a76f9e820a69870b53c61f419b302d636cba9add..d3b0edc896839b3c766a6d28e6e602b13468559d 100644 (file)
@@ -94,10 +94,18 @@ extern int gvFreeLayout(GVC_t *gvc, graph_t *g);
 extern void gvFinalize(GVC_t *gvc);
 extern int gvFreeContext(GVC_t *gvc);
 
-
-
-
-
+/* Return list of plugins of type kind.
+ * kind would normally be "render" "layout" "textlayout" "device" "loadimage"
+ * The size of the list is stored in sz.
+ * The caller is responsible for freeing the storage. This involves
+ * freeing each item, then the list.
+ * Returns NULL on error, or if there are no plugins.
+ * In the former case, sz is unchanged; in the latter, sz = 0.
+ *
+ * At present, the str argument is unused, but may be used to modify
+ * the search as in gvplugin_list above.
+ */
+extern char** gvPluginList (GVC_t *gvc, char* kind, int* sz, char*);
 
 /** Add a library from your user application
  * @param gvc Graphviz context to add library to
index becde761f80c5abfa38e57890a9a94920f2c553f..3336201e1161988502f9a257d1530e573a33d986 100644 (file)
@@ -20,6 +20,7 @@
 #include       <ltdl.h>
 #endif
 
+#include       <agxbuf.h>
 #include        "memory.h"
 #include        "types.h"
 #include        "gvplugin.h"
@@ -345,41 +346,27 @@ gvplugin_available_t *gvplugin_load(GVC_t * gvc, api_t api, const char *str)
     return rv;
 }
 
-/* string buffer management
-       - FIXME - must have 20 solutions for this same thing */
-static char *append_buf(char sep, const char *str, boolean new)
-{
-    static char *buf;
-    static int bufsz, pos;
-    int len;
-    char *p;
-
-    if (new)
-       pos = 0;
-    len = strlen(str) + 1;
-    if (bufsz < (pos + len + 1)) {
-       bufsz += 4 * len;
-       buf = grealloc(buf, bufsz);
-    }
-    p = buf + pos;
-    *p++ = sep;
-    strcpy(p, str);
-    pos += len;
-    return buf;
-}
-
-/* assemble a string list of available plugins */
+/* assemble a string list of available plugins 
+ * non-re-entrant as character store is shared
+ */
 char *gvplugin_list(GVC_t * gvc, api_t api, const char *str)
 {
+    static int first = 1;
     gvplugin_available_t **pnext, **plugin;
-    char *buf = NULL;
+    char *bp;
     char *s, *p, *q, *typestr_last;
     boolean new = TRUE;
+    static agxbuf xb;
 
     /* check for valid apis[] index */
     if (api < 0)
        return NULL;
 
+    if (first) {
+       agxbinit(&xb, 0, 0);
+       first = 0;
+    }
+
     /* does str have a :path modifier? */
 #ifdef WIN32
     s = _strdup(str);
@@ -402,8 +389,8 @@ char *gvplugin_list(GVC_t * gvc, api_t api, const char *str)
            /* list only the matching type, or all types if s is an empty string */
            if (!s[0] || strcasecmp(s, q) == 0) {
                /* list each member of the matching type as "type:path" */
-               append_buf(' ', (*pnext)->typestr, new);
-               buf = append_buf(':', (*pnext)->package->name, FALSE);
+               agxbputc(&xb,' '); agxbput(&xb, (*pnext)->typestr);
+               agxbputc(&xb,':'); agxbput(&xb, (*pnext)->package->name);
                new = FALSE;
            }
            free(q);
@@ -420,7 +407,7 @@ char *gvplugin_list(GVC_t * gvc, api_t api, const char *str)
                *p++ = '\0';
            if (!typestr_last || strcasecmp(typestr_last, q) != 0) {
                /* list it as "type"  i.e. w/o ":path" */
-               buf = append_buf(' ', q, new);
+               agxbputc(&xb,' '); agxbput(&xb, q);
                new = FALSE;
            }
            if(!typestr_last)
@@ -430,9 +417,59 @@ char *gvplugin_list(GVC_t * gvc, api_t api, const char *str)
        if(!typestr_last)
            free(typestr_last);
     }
-    if (!buf)
-       buf = "";
-    return buf;
+    if (new)
+       bp = "";
+    else
+       bp = agxbuse(&xb);
+    return bp;
+}
+
+/* gvPluginList:
+ * Return list of plugins of type kind.
+ * The size of the list is stored in sz.
+ * The caller is responsible for freeing the storage. This involves
+ * freeing each item, then the list.
+ * Returns NULL on error, or if there are no plugins.
+ * In the former case, sz is unchanged; in the latter, sz = 0.
+ *
+ * At present, the str argument is unused, but may be used to modify
+ * the search as in gvplugin_list above.
+ */
+char **gvPluginList(GVC_t * gvc, char* kind, int* sz, const char *str)
+{
+    int api;
+    gvplugin_available_t **pnext, **plugin;
+    int cnt = 0;    
+    char** list = NULL;
+    char *p, *q, *typestr_last;
+
+    if (!kind) return NULL;
+    for (api = 0; api < ARRAY_SIZE(api_names); api++) {
+       if (!strcasecmp(kind,api_names[api]))
+           break;
+    }
+    if (api == ARRAY_SIZE(api_names)) {
+        agerr(AGERR, "unrecognized api name \"%s\"\n", kind);
+       return NULL;
+    }
+
+    /* point to the beginning of the linked list of plugins for this api */
+    plugin = &(gvc->apis[api]);
+    typestr_last = NULL;
+    for (pnext = plugin; *pnext; pnext = &((*pnext)->next)) {
+           /* list only one instance of type */
+       q = strdup((*pnext)->typestr);
+       if ((p = strchr(q, ':')))
+           *p++ = '\0';
+       if (!typestr_last || strcasecmp(typestr_last, q) != 0) {
+           list = RALLOC(cnt+1,list,char*);
+           list[cnt++] = q;
+       }
+       typestr_last = q;
+    }
+
+    *sz = cnt;
+    return list;
 }
 
 void gvplugin_write_status(GVC_t * gvc)