DSREP adaptor: list

The DSREP_list adaptor is, of course, the adaptor which basically makes the entire DSREP adaptor class obsolete by providing a repository-manager based replacement. The repmgr was built entirely to supersede dsrep, pdrep, and taskindex, so ... here we go.
#include <stdio.h>
#include <stdarg.h>
#include "repmgr.h"
The adaptor_info structure is used to pass adaptor info (duh) back to the config module when it's building an adaptor instance. Here's what it contains:
static char *names[] = 

XML * DSREP_list_init (WFTK_ADAPTOR * ad, va_list args);
XML * DSREP_list_free (WFTK_ADAPTOR * ad, va_list args);
XML * DSREP_list_info (WFTK_ADAPTOR * ad, va_list args);
XML * DSREP_list_new (WFTK_ADAPTOR * ad, va_list args);
XML * DSREP_list_load (WFTK_ADAPTOR * ad, va_list args);
XML * DSREP_list_save (WFTK_ADAPTOR * ad, va_list args);
XML * DSREP_list_delete (WFTK_ADAPTOR * ad, va_list args);
XML * DSREP_list_archive (WFTK_ADAPTOR * ad, va_list args);

static WFTK_API_FUNC vtab[] = 

static struct wftk_adaptor_info _DSREP_list_info =
Cool. So here's the incredibly complex function which returns a pointer to that:
struct wftk_adaptor_info * DSREP_list_get_info ()
   return & _DSREP_list_info;
Initialization of the adaptor is pretty straightforward, and really it's the most complicated part of the thing, since the rest just basically wraps the repmgr API.
XML * DSREP_list_init (WFTK_ADAPTOR * ad, va_list args) {
   const char * parms;
   XML * mark;

   parms = xml_attrval (ad->parms, "parm");
   if (!*parms) parms = "";

   if (*parms) {
      mark = repos_defn (ad->session, parms);
      if (!mark) xml_setf (ad->parms, "error", "List '%s' is not defined in the repository.", parms);
      xml_setf (ad->parms, "spec", "list:%s", parms);
      xml_set (ad->parms, "list", parms);
      return NULL;

   mark = xml_search (ad->session, "list", "dsrep-default", "yes");
   if (!mark) mark = xml_search (ad->session, "list", NULL, NULL);
   if (!mark) {
      xml_setf (ad->parms, "error", "No lists defined in repository.");
   } else {
      xml_set (ad->parms, "list", xml_attrval (mark, "id"));
      xml_setf (ad->parms, "spec", "list:%s", xml_attrval (mark, "id"));

   return (XML *) 0;
And like most adaptors, this one has nothing to free when deallocated.
XML * DSREP_list_free (WFTK_ADAPTOR * ad, va_list args) { return (XML *) 0; }
Next up is the info call, which builds and returns a little XML telling the caller about the adaptor. If the adaptor itself is NULL, then it just returns info about the installed adaptor handler; otherwise it's free to elaborate on the adaptor instance.
XML * DSREP_list_info (WFTK_ADAPTOR * ad, va_list args) {
   XML * info;

   info = xml_create ("info");
   xml_set (info, "type", "dsrep");
   xml_set (info, "name", "list");
   xml_set (info, "ver", "1.0.0");
   xml_set (info, "compiled", __DATE__ " " __TIME__);
   xml_set (info, "author", "Michael Roberts");
   xml_set (info, "contact", "wftk@vivtek.com");
   xml_set (info, "extra_functions", "0");

   return (info);

Creation of a new datasheet is the addition of an entry in the named list. Mostly I think this won't be called; instead, a new entry will be created with repos_add and workflow will be invoked from there as a state transition or an on-add setting. But for the case when we actually use wftk_process_new on a list, we need to call repos_add ourselves. This is where it happens.

I'm not sure that the ID request can always be handled. It might be better always to expect the repository to create a unique ID. Dunno yet.
XML * DSREP_list_new  (WFTK_ADAPTOR * ad, va_list args)
   char * id = (char *) 0;
   XML * ret = xml_create ("record");

   if (args) id = va_arg (args, char *);
   if (id) xml_set (ret, "id", id);

   repos_add (ad->session, xml_attrval (ad->parms, "list"), ret);

   return ret;
Loading a datasheet is just retrieval of the appropriate object. The repmgr takes care of all the hard work, and in fact, the rest of this adaptor is just wrapper for the repmgr API.
XML * DSREP_list_load (WFTK_ADAPTOR * ad, va_list args) {
   char *id = (char *) 0;

   if (args) id = va_arg (args, char *);
   if (!id) {
      xml_set (ad->parms, "error", "No ID given.");
      return (XML *) 0;

   return (repos_get (ad->session, xml_attrval (ad->parms, "list"), id));
Saving is repos_mod, yadda yadda.
XML * DSREP_list_save (WFTK_ADAPTOR * ad, va_list args) {
   XML * ds = NULL;

   if (args) ds = va_arg (args, XML *);
   if (!ds) {
      xml_set (ad->parms, "error", "No datasheet given.");
      return (XML *) 0;

   repos_mod (ad->session, xml_attrval (ad->parms, "list"), ds, NULL);

   return ds;
And deletion. I can't believe I waited a year to write this stupid adaptor. I blame George Bush.
XML * DSREP_list_delete (WFTK_ADAPTOR * ad, va_list args) {
   char * id = (char *) 0;

   if (args) id = va_arg (args, char *);
   if (!id) {
      xml_set (ad->parms, "error", "No ID given.");
      return (XML *) 0;

   repos_del (ad->session, xml_attrval (ad->parms, "list"), id);
   return (XML *) 0;
The archival functionality is pretty well covered in the repository manager by treating it as a state transition into an archive-to "state sink" which automatically moves the object into a different list. Since I never really implemented the wftk_process_archive API call, though, it doesn't make a lot of since to do anything in the adaptor. Consider it a fossil.
XML * DSREP_list_archive (WFTK_ADAPTOR * ad, va_list args) { return (XML *) NULL; }

This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2003, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. This presentation was prepared with LPML. Try literate programming. You'll like it.