struct loaded_library { int adaptor_class; char adaptor[32]; /* Note the limit on adaptor name. Since typical names are "localxml" or "oracle" this limit should be quite sufficient. */ char filename[256]; /* Here we'll build the path to the DLL. */ #ifdef WINDOWS HINSTANCE inst; /* This is how we'll do it under Win32. Under Unix, I still have to learn how... */ #endif struct wftk_adaptor_info * ai; struct loaded_library * next; }; struct loaded_library * loaded_libraries = NULL; |
void wftk_config_cleanup () { struct loaded_library * ll; while (loaded_libraries) { ll = loaded_libraries; loaded_libraries = ll->next; #ifdef WINDOWS FreeLibrary (ll->inst); #endif free (ll); } } |
static void wftk_config_adaptor_log (XML * session, WFTK_ADAPTOR * ad, int level, const char * message) { #ifndef WFTK_WITH_REPMGR if (level < 3) { wftk_config_debug_message ('A', "[%d]%s (%d): %s", ad->num, xml_attrval (ad->parms, "spec"), level, message); } #else repos_log (session, level, 0, NULL, "adaptor", "class %d %s: %s", ad->num, xml_attrval (ad->parms, "spec"), message); #endif } |
wftk_config_get_adaptor
function.
Note a couple of things about this function. First, if the adaptor descriptor is a null pointer,
that means that the config module should use the system default, and that default must be statically
linked at the moment. (Later I'll work out how to signify a default DLL in the config structure.)
To make the declarations of statically linked adaptors come out right, we need to declare a few functions
for each right here. So to configure this config module with a new statically linked adaptor, all you
need to do is to declare the functions here, and then add the adaptor into the switch
statement
below, and of course link the adaptor to the core engine at link time.
And now the function itself.
static WFTK_ADAPTOR * wftk_config_get_adaptor (XML * session, int adaptor_class, const char * adaptor_descriptor, int name_length) { char namebuf[64]; struct loaded_library * library; WFTK_ADAPTOR_INFO_FN * func; struct wftk_adaptor_info * ai = NULL; char * dll_start = ""; WFTK_ADAPTOR * ret; WFTK_SESSION * sess = wftk_session_init (session); #ifdef WFTK_WITH_REPMGR repos_log (session, 6, 0, NULL, "adaptor", "Loading adaptor class %d, descriptor %s, name length %d", adaptor_class, adaptor_descriptor, name_length); #endif if (sess->static_module_lookup) ai = (sess->static_module_lookup) (adaptor_class, name_length, adaptor_descriptor); if (!ai && name_length) { /* The adaptor isn't statically linked, anyway. Let's try finding it dynamically, if it's named. */ switch (adaptor_class) { case DSREP: dll_start = "DSREP_"; break; case DATASTORE: dll_start = "DATASTORE_"; break; case DATATYPE: dll_start = "DATATYPE_"; break; case PDREP: dll_start = "PDREP_"; break; case USER: dll_start = "USER_"; break; case LIST: dll_start = "LIST_"; break; case PERMS: dll_start = "PERMS_"; break; case TASKINDEX: dll_start = "TASKINDEX_"; if (!name_length) { /* The default not being a static link, we have to check the config for an explicit name. */ adaptor_descriptor = (char *) wftk_config_get_value (session, "taskindex.default"); if (strchr (adaptor_descriptor, ':')) name_length = strchr (adaptor_descriptor, ':') - adaptor_descriptor; else name_length = strlen (adaptor_descriptor); } break; case NOTIFY: dll_start = "NOTIFY_"; if (!name_length) { adaptor_descriptor = (char *) wftk_config_get_value (session, "notify.default"); if (strchr (adaptor_descriptor, ':')) name_length = strchr (adaptor_descriptor, ':') - adaptor_descriptor; else name_length = strlen (adaptor_descriptor); } break; case ACTION: dll_start = "ACTION_"; break; case DEBUG_MSG: dll_start = "DEBUG_MSG_"; break; default: return (WFTK_ADAPTOR *) 0; } /* Is this DLL already loaded? Check the loaded list. */ library = loaded_libraries; strncpy (namebuf, adaptor_descriptor, name_length); while (library) { if (adaptor_class == library->adaptor_class && !strcmp (namebuf, library->adaptor)) { ai = library->ai; break; } library = library->next; } #ifdef WINDOWS if (!ai) { /* Look for a properly named DLL. When I figure out dynaloading under Unix this will expand. */ library = (struct loaded_library *) malloc (sizeof (struct loaded_library)); library->adaptor_class = adaptor_class; strcpy (library->adaptor, namebuf); strcpy (namebuf, dll_start); strncat (namebuf, adaptor_descriptor, name_length); strcat (namebuf, ".dll"); library->inst = LoadLibrary (namebuf); if (!library->inst) { #ifndef WFTK_WITH_REPMGR wftk_config_debug_message ('A', "Failed to load library %s (%d).\n", namebuf, GetLastError()); #else repos_log (session, 1, 0, NULL, "adaptor", "Failed to load library %s (%d).", namebuf, GetLastError()); #endif free (library); return NULL; } strcpy (namebuf, dll_start); strncat (namebuf, adaptor_descriptor, name_length); strcat (namebuf, "_get_info"); func = (WFTK_ADAPTOR_INFO_FN *) GetProcAddress (library->inst, namebuf); if (!func) { #ifndef WFTK_WITH_REPMGR wftk_config_debug_message ('A', "Adaptor doesn't export %s.\n", namebuf); #else repos_log (session, 1, 0, NULL, "adaptor", "Adaptor doesn't export %s.", namebuf); #endif free (library); return NULL; } ai = (*func) (); } #endif } if (!ai) return (WFTK_ADAPTOR *) 0; /* No luck. */ ret = (WFTK_ADAPTOR *) malloc (sizeof (struct wftk_adaptor) + ai->nfuncs * sizeof (void *)); if (!ret) return (WFTK_ADAPTOR *) 0; ret->num = adaptor_class; ret->parms = (void *) 0; /* This will be filled in by the caller. */ ret->nfuncs = ai->nfuncs; ret->names = ai->names; ret->vtab = ai->vtab; ret->session = session; ret->log = (WFTK_ADAPTOR_LOG_FN) wftk_config_adaptor_log; return (ret); } |
static WFTK_ADAPTORLIST * wftk_config_get_adaptorlist (XML * session, int adaptor_class) { const char * spec = ""; int adaptors = 0; int i; const char * mark; char * mark2; char * adaptorbuffer; WFTK_ADAPTOR * ad_repmgr = NULL; /* Just to be sure. */ WFTK_ADAPTORLIST * list; switch (adaptor_class) { case TASKINDEX: spec = wftk_config_get_value (session, "taskindex.always"); ad_repmgr = wftk_get_adaptor (session, TASKINDEX, "list:"); break; case NOTIFY: spec = wftk_config_get_value (session, "notify.always"); break; default: return (WFTK_ADAPTORLIST *) 0; } if (!*spec && !ad_repmgr) return (WFTK_ADAPTORLIST *) 0; /* First pass: count semicolons, so we know how large a list structure to allocate. */ mark = spec; adaptorbuffer = (char *) malloc (strlen (spec) + 1); do { mark = strchr (mark, ';'); if (!mark) break; adaptors++; mark++; } while (mark); if (ad_repmgr) adaptors++; list = (WFTK_ADAPTORLIST *) malloc (sizeof (WFTK_ADAPTOR_LIST) + adaptors * sizeof (WFTK_ADAPTOR *)); list->count = adaptors; if (ad_repmgr) list->ads[0] = ad_repmgr; for (i=ad_repmgr ? 1 : 0, mark = spec; i < adaptors; i++) { strcpy (adaptorbuffer, mark); mark = strchr(mark, ';'); if (mark) { mark++; while (*mark == ' ') mark++; } mark2 = strchr (adaptorbuffer, ';'); if (mark2) *mark2 = '\0'; list->ads[i] = wftk_get_adaptor (session, adaptor_class, adaptorbuffer); } free ((void *) adaptorbuffer); return (list); } |
switch
we need a bunch of string comparisons. Sorry. The smarter
config module will presumably just pass this off to some API (the canonical one being the Windows Registry, of course.)
This function itself uses the definitions in the localdefs.h file. That seems weird -- why not just include the values
right here? -- but it's more natural to look for config values in a .h file than in a .c file, so I think that makes more
sense for the time being. At any rate, with any luck that's going to be superseded relatively quickly anyway. Right?
And wow -- I superseded it before I even finished the release. It was just too stupid. The compiled values will still
be there as fallbacks in case you want to run sans config.xml, but we'll go ahead and read config.xml.
static XML * config_find_option (XML * xml, const char * name) { int len; XML * x; char * mark = strchr (name, '.'); if (mark) len = mark - name; else len = strlen (name); x = xml_firstelem (xml); while (x) { if (!strncmp (xml_attrval (x, "name"), name, len) || !strncmp (xml_attrval (x, "id"), name, len) || !strncmp ("?", name, len)) { if (mark) { return (config_find_option (x, mark + 1)); } return (x); } x = xml_nextelem (x); } return NULL; } static XML * config_get_option (XML * session, const char * valuename) { WFTK_SESSION * sess = wftk_session_init(session); if (sess) { if (sess->config) { return (config_find_option (sess->config, valuename)); } } return NULL; } WFTK_EXPORT const char * wftk_config_get_value (XML * session, const char * valuename) { XML * mark = config_get_option (session, valuename); if (mark) return (xml_attrval (mark, "value")); /*if (!strcmp (valuename, "pdrep.localxml.directory")) return PROCDEF_DIRECTORY; if (!strcmp (valuename, "dsrep.localxml.directory")) return DATASHEET_DIRECTORY; if (!strcmp (valuename, "user.localxml.directory")) return USER_DIRECTORY; if (!strcmp (valuename, "group.localxml.directory")) return GROUP_DIRECTORY; if (!strcmp (valuename, "taskindex.odbc.?.conn")) return ODBC_CONNECTION;*/ return ""; } |
WFTK_EXPORT void wftk_config_debug_message (char type, const char * message, ...) { va_list arglist; va_start (arglist, message); printf ("DEBUG %c:", type); vprintf (message, arglist); printf ("\n"); va_end (arglist); } |
This code and documentation are released under the terms of the GNU license. They are additionally copyright (c) 2002, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. |