d3307e75eef7a263cc4164c5ced2f77566567c47
[idzebra-moved-to-github.git] / util / res.c
1 /*
2  * Copyright (C) 1994-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: res.c,v $
7  * Revision 1.28  2000-12-01 17:59:08  adam
8  * Fixed bug regarding online updates on WIN32.
9  * When zebra.cfg is not available the server will not abort.
10  *
11  * Revision 1.27  1999/11/30 13:48:04  adam
12  * Improved installation. Updated for inclusion of YAZ header files.
13  *
14  * Revision 1.26  1999/10/07 09:48:36  adam
15  * Allow res_get / res_get_def with NULL res.
16  *
17  * Revision 1.25  1999/05/26 07:49:14  adam
18  * C++ compilation.
19  *
20  * Revision 1.24  1999/02/02 14:51:42  adam
21  * Updated WIN32 code specific sections. Changed header.
22  *
23  * Revision 1.23  1998/10/28 15:18:55  adam
24  * Fix for DOS-formatted configuration files.
25  *
26  * Revision 1.22  1998/01/12 15:04:32  adam
27  * Removed exit - call.
28  *
29  * Revision 1.21  1997/11/18 10:04:03  adam
30  * Function res_trav returns number of 'hits'.
31  *
32  * Revision 1.20  1997/10/31 12:39:15  adam
33  * Resouce name can be terminated with either white-space or colon.
34  *
35  * Revision 1.19  1997/10/27 14:27:59  adam
36  * Fixed memory leak.
37  *
38  * Revision 1.18  1997/09/17 12:19:24  adam
39  * Zebra version corresponds to YAZ version 1.4.
40  * Changed Zebra server so that it doesn't depend on global common_resource.
41  *
42  * Revision 1.17  1997/09/09 13:38:19  adam
43  * Partial port to WIN95/NT.
44  *
45  * Revision 1.16  1996/10/29 13:47:49  adam
46  * Implemented res_get_match. Updated to use zebrautl instead of alexpath.
47  *
48  * Revision 1.15  1996/05/22 08:23:43  adam
49  * Bug fix: trailing blanks in resource values where not removed.
50  *
51  * Revision 1.14  1996/04/26 11:51:20  adam
52  * Resource names are matched by the yaz_matchstr routine instead of strcmp.
53  *
54  * Revision 1.13  1995/09/04  12:34:05  adam
55  * Various cleanup. YAZ util used instead.
56  *
57  * Revision 1.12  1995/01/24  16:40:32  adam
58  * Bug fix.
59  *
60  * Revision 1.11  1994/10/05  16:54:52  adam
61  * Minor changes.
62  *
63  * Revision 1.10  1994/10/05  10:47:31  adam
64  * Small bug fix.
65  *
66  * Revision 1.9  1994/09/16  14:41:12  quinn
67  * Added log warning to res_get_def
68  *
69  * Revision 1.8  1994/09/16  14:37:12  quinn
70  * added res_get_def
71  *
72  * Revision 1.7  1994/09/06  13:01:03  quinn
73  * Removed const from declaration of res_get
74  *
75  * Revision 1.6  1994/09/01  17:45:14  adam
76  * Work on resource manager.
77  *
78  * Revision 1.5  1994/08/18  11:02:28  adam
79  * Implementation of res_write.
80  *
81  * Revision 1.4  1994/08/18  10:02:01  adam
82  * Module alexpath moved from res.c to alexpath.c. Minor changes in res-test.c
83  *
84  * Revision 1.3  1994/08/18  09:43:51  adam
85  * Development of resource manager. Only missing is res_write.
86  *
87  * Revision 1.2  1994/08/18  08:23:26  adam
88  * Res.c now use handles. xmalloc defines xstrdup.
89  *
90  * Revision 1.1  1994/08/17  15:34:23  adam
91  * Initial version of resource manager.
92  *
93  */
94 #include <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #include <assert.h>
98 #ifdef WIN32
99 #include <io.h>
100 #else
101 #include <unistd.h>
102 #endif
103
104 #include <zebrautl.h>
105 #include <yaz/yaz-util.h>
106
107 static struct res_entry *add_entry (Res r)
108 {
109     struct res_entry *resp;
110
111     if (!r->first)
112         resp = r->last = r->first =
113             (struct res_entry *) xmalloc (sizeof(*resp));
114     else
115     {
116         resp = (struct res_entry *) xmalloc (sizeof(*resp));
117         r->last->next = resp;
118         r->last = resp;
119     }
120     resp->next = NULL;
121     return resp;
122 }
123
124 static void reread (Res r)
125 {
126     struct res_entry *resp;
127     char *line;
128     char *val_buf;
129     int val_size, val_max = 256;
130     char fr_buf[1024];
131     FILE *fr;
132
133     assert (r);
134     r->init = 1;
135
136     val_buf = (char*) xmalloc (val_max);
137
138     fr = fopen (r->name, "r");
139     if (!fr)
140     {
141         logf (LOG_WARN|LOG_ERRNO, "Cannot open %s", r->name);
142         return ;
143     }
144     while (1)
145     {
146         line = fgets (fr_buf, sizeof(fr_buf)-1, fr);
147         if (!line)
148             break;
149         if (*line == '#')
150         {
151             int no = 0;
152
153             while (fr_buf[no] && fr_buf[no] != '\n')
154                 no++;
155             fr_buf[no] = '\0';
156
157             resp = add_entry (r);
158             resp->name = (char*) xmalloc (no+1);
159             resp->value = NULL;
160             strcpy (resp->name, fr_buf);
161         }
162         else
163         {
164             int no = 0;
165             while (1)
166             {
167                 if (fr_buf[no] == 0 || fr_buf[no] == '\n' )
168                 {
169                     no = 0;
170                     break;
171                 }
172                 if (strchr (": \t", fr_buf[no]))
173                     break;
174                 no++;
175             }
176             if (!no)
177                 continue;
178             fr_buf[no++] = '\0';
179             resp = add_entry (r);
180             resp->name = (char*) xmalloc (no);
181             strcpy (resp->name, fr_buf);
182             
183             while (strchr (" \t", fr_buf[no]))
184                 no++;
185             val_size = 0;
186             while (1)
187             {
188                 if (fr_buf[no] == '\0' || strchr("\n\r\f", fr_buf[no]))
189                 {
190                     while (val_size > 0 &&
191                               (val_buf[val_size-1] == ' ' ||
192                                val_buf[val_size-1] == '\t'))
193                         val_size--;
194                     val_buf[val_size++] = '\0';
195                     resp->value = (char*) xmalloc (val_size);
196                     strcpy (resp->value, val_buf);
197                     logf (LOG_DEBUG, "(name=%s,value=%s)",
198                          resp->name, resp->value);
199                     break;
200                 }
201                 else if (fr_buf[no] == '\\' && strchr ("\n\r\f", fr_buf[no+1]))
202                 {
203                     line = fgets (fr_buf, sizeof(fr_buf)-1, fr);
204                     if (!line)
205                     {
206                         resp->value = (char*) xmalloc (val_size);
207                         strcpy (resp->value, val_buf);
208                         break;
209                     }
210                     no = 0;
211                 }
212                 else
213                 {
214                     val_buf[val_size++] = fr_buf[no++];
215                     if (val_size+1 >= val_max)
216                     {
217                         char *nb;
218
219                         nb = (char*) xmalloc (val_max+=1024);
220                         memcpy (nb, val_buf, val_size);
221                         xfree (val_buf);
222                         val_buf = nb;
223                     }
224                 }
225             }
226         }
227     }                
228     xfree (val_buf);
229     fclose (fr);
230 }
231
232 Res res_open (const char *name)
233 {
234     Res r;
235 #ifdef WIN32
236     if (access (name, 4))
237 #else
238     if (access (name, R_OK))
239 #endif
240     {
241         logf (LOG_LOG|LOG_ERRNO, "Cannot access resource file `%s'", name);
242         return NULL;
243     }
244     r = (Res) xmalloc (sizeof(*r));
245     r->init = 0;
246     r->first = r->last = NULL;
247     r->name = xstrdup (name);
248     return r;
249 }
250
251 void res_close (Res r)
252 {
253     if (!r)
254         return;
255     if (r->init)
256     {
257         struct res_entry *re, *re1;
258         for (re = r->first; re; re=re1)
259         {
260             if (re->name)
261                 xfree (re->name);
262             if (re->value)
263                 xfree (re->value);
264             re1 = re->next;
265             xfree (re);
266         }
267     }
268     xfree (r->name);
269     xfree (r);
270 }
271
272 char *res_get (Res r, const char *name)
273 {
274     struct res_entry *re;
275
276     if (!r)
277         return NULL;
278     if (!r->init)
279         reread (r);
280     for (re = r->first; re; re=re->next)
281         if (re->value && !yaz_matchstr (re->name, name))
282             return re->value;
283     return NULL;
284 }
285
286 char *res_get_def (Res r, const char *name, char *def)
287 {
288     char *t;
289
290     if (!(t = res_get (r, name)))
291     {
292         logf (LOG_DEBUG, "CAUTION: Using default resource %s:%s", name, def);
293         return def;
294     }
295     else
296         return t;
297 }
298
299 int res_get_match (Res r, const char *name, const char *value, const char *s)
300 {
301     const char *cn = res_get (r, name);
302
303     if (!cn)
304         cn = s;
305     if (cn && !yaz_matchstr (cn, value))
306         return 1;
307     return 0;
308 }
309
310 void res_put (Res r, const char *name, const char *value)
311 {
312     struct res_entry *re;
313     assert (r);
314     if (!r->init)
315         reread (r);
316
317     for (re = r->first; re; re=re->next)
318         if (re->value && !yaz_matchstr (re->name, name))
319         {
320             xfree (re->value);
321             re->value = xstrdup (value);
322             return;
323         }
324     re = add_entry (r);
325     re->name = xstrdup (name);
326     re->value = xstrdup (value);
327 }
328
329 int res_trav (Res r, const char *prefix, void *p,
330               void (*f)(void *p, const char *name, const char *value))
331 {
332     struct res_entry *re;
333     int l = 0;
334     int no = 0;
335     
336     if (!r)
337         return 0;
338     if (prefix)
339         l = strlen(prefix);
340     if (!r->init)
341         reread (r);
342     for (re = r->first; re; re=re->next)
343         if (re->value)
344             if (l==0 || !memcmp (re->name, prefix, l))
345             {
346                 (*f)(p, re->name, re->value);
347                 no++;
348             }
349     return no;
350 }
351
352
353 int res_write (Res r)
354 {
355     struct res_entry *re;
356     FILE *fr;
357
358     assert (r);
359     if (!r->init)
360         reread (r);
361     fr = fopen (r->name, "w");
362     if (!fr)
363     {
364         logf (LOG_FATAL|LOG_ERRNO, "Cannot create %s", r->name);
365         exit (1);
366     }
367
368     for (re = r->first; re; re=re->next)
369     {
370         int no = 0;
371         int lefts = strlen(re->name)+2;
372
373         if (!re->value)
374             fprintf (fr, "%s\n", re->name);
375         else
376         {
377             fprintf (fr, "%s: ", re->name);
378             while (lefts + strlen(re->value+no) > 78)
379             {
380                 int i = 20;
381                 int ind = no+ 78-lefts;
382                 while (--i >= 0)
383                 {
384                     if (re->value[ind] == ' ')
385                         break;
386                     --ind;
387                 }
388                 if (i<0)
389                     ind = no + 78 - lefts;
390                 for (i = no; i != ind; i++)
391                     putc (re->value[i], fr);
392                 fprintf (fr, "\\\n");
393                 no=ind;
394                 lefts = 0;
395             }
396             fprintf (fr, "%s\n", re->value+no);
397         }
398     }
399     fclose (fr);
400     return 0;
401 }
402
403
404