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