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