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