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