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