Happy new year.
[idzebra-moved-to-github.git] / index / recctrl.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2011 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20
21 #include <stdio.h>
22 #include <assert.h>
23 #include <string.h>
24 #if HAVE_DLFCN_H
25 #include <dlfcn.h>
26 #endif
27
28 #include <direntz.h>
29 #include <idzebra/util.h>
30 #include <idzebra/recctrl.h>
31
32 struct recTypeClass {
33     RecType recType;
34     struct recTypeClass *next;
35     void *module_handle;
36 };
37
38 struct recTypeInstance {
39     RecType recType;
40     struct recTypeInstance *next;
41     int init_flag;
42     void *clientData;
43 };
44
45 struct recTypes {
46     data1_handle dh;
47     struct recTypeInstance *entries;
48 };
49
50 static void recTypeClass_add (struct recTypeClass **rts, RecType *rt,
51                               NMEM nmem, void *module_handle);
52
53
54 RecTypeClass recTypeClass_create (Res res, NMEM nmem)
55 {
56     struct recTypeClass *rts = 0;
57
58 #ifdef IDZEBRA_STATIC_GRS_SGML
59     if (1)
60     {
61         extern RecType idzebra_filter_grs_sgml[];
62         recTypeClass_add (&rts, idzebra_filter_grs_sgml, nmem, 0);
63     }
64 #endif
65
66 #ifdef IDZEBRA_STATIC_TEXT
67     if (1)
68     {
69         extern RecType idzebra_filter_text[];
70         recTypeClass_add (&rts, idzebra_filter_text, nmem, 0);
71     }
72 #endif
73
74 #ifdef IDZEBRA_STATIC_GRS_XML
75 #if HAVE_EXPAT_H
76     if (1)
77     {
78         extern RecType idzebra_filter_grs_xml[];
79         recTypeClass_add (&rts, idzebra_filter_grs_xml, nmem, 0);
80     }
81 #endif
82 #endif
83
84 #ifdef IDZEBRA_STATIC_GRS_REGX
85     if (1)
86     {
87         extern RecType idzebra_filter_grs_regx[];
88         recTypeClass_add (&rts, idzebra_filter_grs_regx, nmem, 0);
89     }
90 #endif
91
92 #ifdef IDZEBRA_STATIC_GRS_MARC
93     if (1)
94     {
95         extern RecType idzebra_filter_grs_marc[];
96         recTypeClass_add (&rts, idzebra_filter_grs_marc, nmem, 0);
97     }
98 #endif
99
100 #ifdef IDZEBRA_STATIC_SAFARI
101     if (1)
102     {
103         extern RecType idzebra_filter_safari[];
104         recTypeClass_add (&rts, idzebra_filter_safari, nmem, 0);
105     }
106 #endif
107
108 #ifdef IDZEBRA_STATIC_ALVIS
109     if (1)
110     {
111         extern RecType idzebra_filter_alvis[];
112         recTypeClass_add (&rts, idzebra_filter_alvis, nmem, 0);
113     }
114 #endif
115
116 #ifdef IDZEBRA_STATIC_DOM
117     if (1)
118     {
119         extern RecType idzebra_filter_dom[];
120         recTypeClass_add (&rts, idzebra_filter_dom, nmem, 0);
121     }
122 #endif
123
124     return rts;
125 }
126
127 static void load_from_dir(RecTypeClass *rts, NMEM nmem, const char *dirname)
128 {
129 #if HAVE_DLFCN_H
130     DIR *dir = opendir(dirname);
131     if (dir)
132     {
133         struct dirent *de;
134         
135         while ((de = readdir(dir)))
136         {
137             size_t dlen = strlen(de->d_name);
138             if (dlen >= 5 &&
139                 !memcmp(de->d_name, "mod-", 4) &&
140                 !strcmp(de->d_name + dlen - 3, ".so"))
141             {
142                 void *mod_p, *fl;
143                 char fname[FILENAME_MAX*2+1];
144                 sprintf(fname, "%.*s/%.*s",
145                         FILENAME_MAX, dirname,
146                         FILENAME_MAX, de->d_name);
147                 mod_p = dlopen(fname, RTLD_NOW|RTLD_GLOBAL);
148                 if (mod_p && (fl = dlsym(mod_p, "idzebra_filter")))
149                 {
150                     yaz_log(YLOG_LOG, "Loaded filter module %s", fname);
151                     recTypeClass_add(rts, fl, nmem, mod_p);
152                 }
153                 else if (mod_p)
154                 {
155                     const char *err = dlerror();
156                     yaz_log(YLOG_WARN, "dlsym failed %s %s",
157                             fname, err ? err : "none");
158                     dlclose(mod_p);
159                 }
160                 else
161                 {
162                     const char *err = dlerror();
163                     yaz_log(YLOG_WARN, "dlopen failed %s %s",
164                             fname, err ? err : "none");
165                     
166                 }
167             }
168         }
169         closedir(dir);
170     }
171 #endif
172 }
173
174 void recTypeClass_load_modules(RecTypeClass *rts, NMEM nmem,
175                                const char *module_path)
176 {
177     while (module_path)
178     {
179         const char *comp_ptr;
180         char comp[FILENAME_MAX+1];
181         size_t len;
182         
183         len = yaz_filepath_comp(&module_path, &comp_ptr);
184         if (!len || len >= FILENAME_MAX)
185             break;
186         
187         memcpy(comp, comp_ptr, len);
188         comp[len] = '\0';
189
190         load_from_dir(rts, nmem, comp);
191     }
192 }
193
194 static void recTypeClass_add(struct recTypeClass **rts, RecType *rt,
195                              NMEM nmem, void *module_handle)
196 {
197     while (*rt)
198     {
199         struct recTypeClass *r = (struct recTypeClass *)
200             nmem_malloc (nmem, sizeof(*r));
201         
202         r->next = *rts;
203         *rts = r;
204
205         r->module_handle = module_handle;
206         module_handle = 0; /* so that we only store module_handle once */
207         r->recType = *rt;
208
209         rt++;
210     }
211 }
212
213 void recTypeClass_info(RecTypeClass rtc, void *cd,
214                        void (*cb)(void *cd, const char *s))
215 {
216     for (; rtc; rtc = rtc->next)
217         (*cb)(cd, rtc->recType->name);
218 }
219
220 void recTypeClass_destroy(RecTypeClass rtc)
221 {
222     for (; rtc; rtc = rtc->next)
223     {
224 #if HAVE_DLFCN_H
225         if (rtc->module_handle)
226             dlclose(rtc->module_handle);
227 #endif
228     }
229 }
230
231 RecTypes recTypes_init(RecTypeClass rtc, data1_handle dh)
232 {
233     RecTypes rts = (RecTypes) nmem_malloc(data1_nmem_get(dh), sizeof(*rts));
234
235     struct recTypeInstance **rti = &rts->entries;
236     
237     rts->dh = dh;
238
239     for (; rtc; rtc = rtc->next)
240     {
241         *rti = nmem_malloc(data1_nmem_get(dh), sizeof(**rti));
242         (*rti)->recType = rtc->recType;
243         (*rti)->init_flag = 0;
244         rti = &(*rti)->next;
245     }
246     *rti = 0;
247     return rts;
248 }
249
250 void recTypes_destroy (RecTypes rts)
251 {
252     struct recTypeInstance *rti;
253
254     for (rti = rts->entries; rti; rti = rti->next)
255     {
256         if (rti->init_flag)
257             (*(rti->recType)->destroy)(rti->clientData);
258     }
259 }
260
261 RecType recType_byName (RecTypes rts, Res res, const char *name,
262                         void **clientDataP)
263 {
264     struct recTypeInstance *rti;
265
266     for (rti = rts->entries; rti; rti = rti->next)
267     {
268         size_t slen = strlen(rti->recType->name);
269         if (!strncmp (rti->recType->name, name, slen)
270             && (name[slen] == '\0' || name[slen] == '.'))
271         {
272             if (!rti->init_flag)
273             {
274                 rti->init_flag = 1;
275                 rti->clientData =
276                     (*(rti->recType)->init)(res, rti->recType);
277             }
278             *clientDataP = rti->clientData;
279             if (name[slen])
280                 slen++;  /* skip . */
281
282             if (rti->recType->config)
283             {
284                 if ((*(rti->recType)->config)
285                     (rti->clientData, res, name+slen) != ZEBRA_OK)
286                     return 0;
287             }
288             return rti->recType;
289         }
290     }
291     return 0;
292 }
293
294 /*
295  * Local variables:
296  * c-basic-offset: 4
297  * c-file-style: "Stroustrup"
298  * indent-tabs-mode: nil
299  * End:
300  * vim: shiftwidth=4 tabstop=8 expandtab
301  */
302