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