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