Revise resource API to take default/override resources.
[idzebra-moved-to-github.git] / util / res.c
1 /* $Id: res.c,v 1.34 2004-01-22 11:27:22 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #ifdef WIN32
29 #include <io.h>
30 #else
31 #include <unistd.h>
32 #endif
33
34 #include <zebrautl.h>
35 #include <yaz/yaz-util.h>
36
37 struct res_entry {
38     char *name;
39     char *value;
40     struct res_entry *next;
41 };
42
43 struct res_struct {
44     struct res_entry *first, *last;
45     char *name;
46     int  init;
47     Res def_res;
48     Res over_res;
49 };
50
51 static struct res_entry *add_entry (Res r)
52 {
53     struct res_entry *resp;
54
55     if (!r->first)
56         resp = r->last = r->first =
57             (struct res_entry *) xmalloc (sizeof(*resp));
58     else
59     {
60         resp = (struct res_entry *) xmalloc (sizeof(*resp));
61         r->last->next = resp;
62         r->last = resp;
63     }
64     resp->next = NULL;
65     return resp;
66 }
67
68 static void reread (Res r)
69 {
70     struct res_entry *resp;
71     char *line;
72     char *val_buf;
73     int val_size, val_max = 256;
74     char fr_buf[1024];
75     FILE *fr;
76
77     assert (r);
78     r->init = 1;
79
80     val_buf = (char*) xmalloc (val_max);
81
82     if (!r->name)
83         return; 
84
85     fr = fopen (r->name, "r");
86     if (!fr)
87     {
88         logf (LOG_WARN|LOG_ERRNO, "Cannot open `%s'", r->name);
89         return ;
90     }
91     while (1)
92     {
93         line = fgets (fr_buf, sizeof(fr_buf)-1, fr);
94         if (!line)
95             break;
96         if (*line == '#')
97         {
98             int no = 0;
99
100             while (fr_buf[no] && fr_buf[no] != '\n')
101                 no++;
102             fr_buf[no] = '\0';
103
104             resp = add_entry (r);
105             resp->name = (char*) xmalloc (no+1);
106             resp->value = NULL;
107             strcpy (resp->name, fr_buf);
108         }
109         else
110         {
111             int no = 0;
112             while (1)
113             {
114                 if (fr_buf[no] == 0 || fr_buf[no] == '\n' )
115                 {
116                     no = 0;
117                     break;
118                 }
119                 if (strchr (": \t", fr_buf[no]))
120                     break;
121                 no++;
122             }
123             if (!no)
124                 continue;
125             fr_buf[no++] = '\0';
126             resp = add_entry (r);
127             resp->name = (char*) xmalloc (no);
128             strcpy (resp->name, fr_buf);
129             
130             while (strchr (" \t", fr_buf[no]))
131                 no++;
132             val_size = 0;
133             while (1)
134             {
135                 if (fr_buf[no] == '\0' || strchr("\n\r\f", fr_buf[no]))
136                 {
137                     while (val_size > 0 &&
138                               (val_buf[val_size-1] == ' ' ||
139                                val_buf[val_size-1] == '\t'))
140                         val_size--;
141                     val_buf[val_size++] = '\0';
142                     resp->value = (char*) xmalloc (val_size);
143                     strcpy (resp->value, val_buf);
144                     logf (LOG_DEBUG, "(name=%s,value=%s)",
145                          resp->name, resp->value);
146                     break;
147                 }
148                 else if (fr_buf[no] == '\\' && strchr ("\n\r\f", fr_buf[no+1]))
149                 {
150                     line = fgets (fr_buf, sizeof(fr_buf)-1, fr);
151                     if (!line)
152                     {
153                         resp->value = (char*) xmalloc (val_size);
154                         strcpy (resp->value, val_buf);
155                         break;
156                     }
157                     no = 0;
158                 }
159                 else
160                 {
161                     val_buf[val_size++] = fr_buf[no++];
162                     if (val_size+1 >= val_max)
163                     {
164                         char *nb;
165
166                         nb = (char*) xmalloc (val_max+=1024);
167                         memcpy (nb, val_buf, val_size);
168                         xfree (val_buf);
169                         val_buf = nb;
170                     }
171                 }
172             }
173         }
174     }                
175     xfree (val_buf);
176     fclose (fr);
177 }
178
179 Res res_open (const char *name, Res def_res, Res over_res)
180 {
181     Res r;
182
183     if (name)
184     {
185 #ifdef WIN32
186         if (access (name, 4))
187 #else
188         if (access (name, R_OK))
189 #endif
190         {
191             logf (LOG_WARN|LOG_ERRNO, "Cannot open `%s'", name);
192             return 0;
193         }
194     }
195     r = (Res) xmalloc (sizeof(*r));
196     r->init = 0;
197     r->first = r->last = NULL;
198     if (name)
199         r->name = xstrdup (name);
200     else
201         r->name=0;
202     r->def_res = def_res;
203     r->over_res = over_res;
204     return r;
205 }
206
207 void res_close (Res r)
208 {
209     if (!r)
210         return;
211     if (r->init)
212     {
213         struct res_entry *re, *re1;
214         for (re = r->first; re; re=re1)
215         {
216             if (re->name)
217                 xfree (re->name);
218             if (re->value)
219                 xfree (re->value);
220             re1 = re->next;
221             xfree (re);
222         }
223     }
224     xfree (r->name);
225     xfree (r);
226 }
227
228 const char *res_get_prefix (Res r, const char *name, const char *prefix,
229                             const char *def)
230 {
231     const char *v = 0;;
232     if (prefix)
233     {
234         char rname[128];
235         
236         if (strlen(name) + strlen(prefix) >= (sizeof(rname)-2))
237             return 0;
238         strcpy(rname, prefix);
239         strcat(rname, ".");
240         strcat(rname, name);
241         v = res_get(r, rname);
242     }
243     if (!v)
244         v = res_get(r, name);
245     if (!v)
246         v = def;
247     return v;
248 }
249
250 const char *res_get (Res r, const char *name)
251 {
252     struct res_entry *re;
253     const char *v;
254
255     if (!r)
256         return 0;
257     
258     v = res_get(r->over_res, name);
259     if (v)
260         return v;
261
262     if (!r->init)
263         reread (r);
264     for (re = r->first; re; re=re->next)
265         if (re->value && !yaz_matchstr (re->name, name))
266             return re->value;
267
268     return res_get (r->def_res, name);
269 }
270
271 const char *res_get_def (Res r, const char *name, const char *def)
272 {
273     const char *t;
274
275     if (!(t = res_get (r, name)))
276     {
277         logf (LOG_DEBUG, "CAUTION: Using default resource %s:%s", name, def);
278         return def;
279     }
280     else
281         return t;
282 }
283
284 int res_get_match (Res r, const char *name, const char *value, const char *s)
285 {
286     const char *cn = res_get (r, name);
287
288     if (!cn)
289         cn = s;
290     if (cn && !yaz_matchstr (cn, value))
291         return 1;
292     return 0;
293 }
294
295 void res_set (Res r, const char *name, const char *value)
296 {
297     struct res_entry *re;
298     assert (r);
299     if (!r->init)
300         reread (r);
301
302     for (re = r->first; re; re=re->next)
303         if (re->value && !yaz_matchstr (re->name, name))
304         {
305             xfree (re->value);
306             re->value = xstrdup (value);
307             return;
308         }
309     re = add_entry (r);
310     re->name = xstrdup (name);
311     re->value = xstrdup (value);
312 }
313
314 int res_trav (Res r, const char *prefix, void *p,
315               void (*f)(void *p, const char *name, const char *value))
316 {
317     struct res_entry *re;
318     int l = 0;
319     int no = 0;
320     
321     if (!r)
322         return 0;
323     if (prefix)
324         l = strlen(prefix);
325     if (!r->init)
326         reread (r);
327     for (re = r->first; re; re=re->next)
328         if (re->value)
329             if (l==0 || !memcmp (re->name, prefix, l))
330             {
331                 (*f)(p, re->name, re->value);
332                 no++;
333             }
334     if (!no)
335         return res_trav (r->def_res, prefix, p, f);
336     return no;
337 }
338
339
340 int res_write (Res r)
341 {
342     struct res_entry *re;
343     FILE *fr;
344
345     assert (r);
346     if (!r->init)
347         reread (r);
348     if (!r->name)
349         return 0; /* ok, this was not from a file */
350     fr = fopen (r->name, "w");
351     if (!fr)
352     {
353         logf (LOG_FATAL|LOG_ERRNO, "Cannot create `%s'", r->name);
354         exit (1);
355     }
356
357     for (re = r->first; re; re=re->next)
358     {
359         int no = 0;
360         int lefts = strlen(re->name)+2;
361
362         if (!re->value)
363             fprintf (fr, "%s\n", re->name);
364         else
365         {
366             fprintf (fr, "%s: ", re->name);
367             while (lefts + strlen(re->value+no) > 78)
368             {
369                 int i = 20;
370                 int ind = no+ 78-lefts;
371                 while (--i >= 0)
372                 {
373                     if (re->value[ind] == ' ')
374                         break;
375                     --ind;
376                 }
377                 if (i<0)
378                     ind = no + 78 - lefts;
379                 for (i = no; i != ind; i++)
380                     putc (re->value[i], fr);
381                 fprintf (fr, "\\\n");
382                 no=ind;
383                 lefts = 0;
384             }
385             fprintf (fr, "%s\n", re->value+no);
386         }
387     }
388     fclose (fr);
389     return 0;
390 }
391
392
393