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