1 /* $Id: database.c,v 1.7 2007-04-08 20:52:09 quinn Exp $ */
3 #include <libxml/parser.h>
4 #include <libxml/tree.h>
5 #include <libxslt/xslt.h>
6 #include <libxslt/transform.h>
7 #include <libxslt/xsltutils.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
21 #include <netinet/in.h>
23 static struct host *hosts = 0; // The hosts we know about
24 static struct database *databases = 0; // The databases we know about
27 static xmlDoc *get_explain_xml(const char *id)
33 if (!config || !config->targetprofiles)
35 yaz_log(YLOG_WARN, "Config must be loaded and specify targetprofiles");
38 if (config->targetprofiles->type != Targetprofiles_local)
40 yaz_log(YLOG_FATAL, "Only supports local type");
43 dir = config->targetprofiles->src;
45 sprintf(path, "%s/%s", dir, ide);
47 return xmlParseFile(path);
52 // Create a new host structure for hostport
53 static struct host *create_host(const char *hostport)
55 struct addrinfo *addrinfo, hints;
59 unsigned char addrbuf[4];
62 host = xmalloc(sizeof(struct host));
63 host->hostport = xstrdup(hostport);
64 host->connections = 0;
66 if ((port = strchr(hostport, ':')))
72 hints.ai_family = PF_INET;
73 hints.ai_socktype = SOCK_STREAM;
74 hints.ai_protocol = IPPROTO_TCP;
77 hints.ai_canonname = 0;
79 // This is not robust code. It assumes that getaddrinfo always
80 // returns AF_INET address.
81 if ((res = getaddrinfo(hostport, port, &hints, &addrinfo)))
83 yaz_log(YLOG_WARN, "Failed to resolve %s: %s", hostport, gai_strerror(res));
84 xfree(host->hostport);
88 assert(addrinfo->ai_family == PF_INET);
89 memcpy(addrbuf, &((struct sockaddr_in*)addrinfo->ai_addr)->sin_addr.s_addr, 4);
90 sprintf(ipport, "%u.%u.%u.%u:%s",
91 addrbuf[0], addrbuf[1], addrbuf[2], addrbuf[3], port);
92 host->ipport = xstrdup(ipport);
93 freeaddrinfo(addrinfo);
99 static struct host *find_host(const char *hostport)
102 for (p = hosts; p; p = p->next)
103 if (!strcmp(p->hostport, hostport))
105 return create_host(hostport);
108 static struct database *load_database(const char *id)
110 xmlDoc *doc = get_explain_xml(id);
111 struct zr_explain *explain = 0;
118 nmem = nmem_create();
121 explain = zr_read_xml(nmem, xmlDocGetRootElement(doc));
125 if (strlen(id) > 255)
127 strcpy(hostport, id);
128 if ((dbname = strchr(hostport, '/')))
132 if (!(host = find_host(hostport)))
134 db = nmem_malloc(nmem, sizeof(*db));
135 memset(db, 0, sizeof(*db));
137 db->url = nmem_strdup(nmem, id);
139 db->databases = xmalloc(2 * sizeof(char *));
140 db->databases[0] = nmem_strdup(nmem, dbname);
141 db->databases[1] = 0;
143 db->explain = explain;
145 db->next = databases;
154 // Return a database structure by ID. Load and add to list if necessary
155 // new==1 just means we know it's not in the list
156 struct database *find_database(const char *id, int new)
161 for (p = databases; p; p = p->next)
162 if (!strcmp(p->url, id))
165 return load_database(id);
168 static int match_zurl(const char *zurl, const char *pattern)
170 if (!strcmp(pattern, "*"))
172 else if (!strncmp(pattern, "*/", 2))
174 char *db = strchr(zurl, '/');
177 if (!strcmp(pattern + 2, db))
182 else if (!strcmp(pattern, zurl))
188 // This will be generalized at some point
189 static int match_criterion(struct database *db, struct database_criterion *c)
191 if (!strcmp(c->name, "id"))
193 struct database_criterion_value *v;
194 for (v = c->values; v; v = v->next)
195 if (match_zurl(db->url, v->value))
203 int database_match_criteria(struct database *db, struct database_criterion *cl)
205 for (; cl; cl = cl->next)
206 if (!match_criterion(db, cl))
208 if (cl) // one of the criteria failed to match -- skip this db
214 // Cycles through databases, calling a handler function on the ones for
215 // which all criteria matched.
216 int grep_databases(void *context, struct database_criterion *cl,
217 void (*fun)(void *context, struct database *db))
222 for (p = databases; p; p = p->next)
224 if (database_match_criteria(p, cl))
233 // Initialize CCL map for a target
234 // Note: This approach ignores user-specific CCL maps, for which I
235 // don't presently see any application.
236 static void prepare_cclmap(void *ignore, struct database *db)
242 db->ccl_map = ccl_qual_mk();
243 for (s = db->settings[PZ_CCLMAP]; s; s = s->next)
246 char *p = strchr(s->name + 3, ':');
249 yaz_log(YLOG_FATAL, "Malformed cclmap name: %s", s->name);
253 ccl_qual_fitem(db->ccl_map, s->value, p);
257 // Initialize YAZ Map structures for MARC-based targets
258 static void prepare_yazmarc(void *ignore, struct database *db)
264 for (s = db->settings[PZ_NATIVESYNTAX]; s; s = s->next)
265 if (!*s->user && !strcmp(s->value, "iso2709"))
267 char *encoding = "marc-8s";
270 db->yaz_marc = yaz_marc_create();
271 yaz_marc_subfield_str(db->yaz_marc, "\t");
272 // See if a native encoding is specified
273 for (s = db->settings[PZ_ENCODING]; s; s = s->next)
279 if (!(cm = yaz_iconv_open("utf-8", encoding)))
281 yaz_log(YLOG_FATAL, "Unable to map from %s to UTF-8", encoding);
284 yaz_marc_iconv(db->yaz_marc, cm);
289 // Prepare XSLT stylesheets for record normalization
290 static void prepare_map(void *ignore, struct database *db)
296 for (s = db->settings[PZ_XSLT]; s; s = s->next)
300 struct database_retrievalmap **m = &db->map;
303 nmem_strsplit(nmem, ",", s->value, &stylesheets, &num);
304 for (i = 0; i < num; i++)
306 (*m) = nmem_malloc(nmem, sizeof(**m));
308 if (!((*m)->stylesheet = conf_load_stylesheet(stylesheets[i])))
310 yaz_log(YLOG_FATAL, "Unable to load stylesheet: %s",
319 yaz_log(YLOG_WARN, "No Normalization stylesheet for target %s", db->url);
322 // Read settings for each database, and prepare support data structures
323 void prepare_databases(void)
325 grep_databases(0, 0, prepare_cclmap);
326 grep_databases(0, 0, prepare_yazmarc);
327 grep_databases(0, 0, prepare_map);
330 // This function will most likely vanish when a proper target profile mechanism is
332 void load_simpletargets(const char *fn)
334 FILE *f = fopen(fn, "r");
339 yaz_log(YLOG_WARN|YLOG_ERRNO, "open %s", fn);
343 while (fgets(line, 255, f))
349 if (strncmp(line, "target ", 7))
351 line[strlen(line) - 1] = '\0';
353 if ((name = strchr(line, ';')))
358 if (!(db = find_database(url, 0)))
359 yaz_log(YLOG_WARN, "Unable to load database %s", url);
361 db->name = nmem_strdup(nmem, name);
370 * indent-tabs-mode: nil
372 * vim: shiftwidth=4 tabstop=8 expandtab