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