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