API to the resource system, passing memMax through it.
[idzebra-moved-to-github.git] / util / res.c
1 /* $Id: res.c,v 1.33 2002-10-22 09:37:56 heikki Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #ifdef WIN32
29 #include <io.h>
30 #else
31 #include <unistd.h>
32 #endif
33
34 #include <zebrautl.h>
35 #include <yaz/yaz-util.h>
36
37 struct res_entry {
38     char *name;
39     char *value;
40     struct res_entry *next;
41 };
42
43 struct res_struct {
44     struct res_entry *first, *last;
45     char *name;
46     int  init;
47     Res def_res;
48 };
49
50 static struct res_entry *add_entry (Res r)
51 {
52     struct res_entry *resp;
53
54     if (!r->first)
55         resp = r->last = r->first =
56             (struct res_entry *) xmalloc (sizeof(*resp));
57     else
58     {
59         resp = (struct res_entry *) xmalloc (sizeof(*resp));
60         r->last->next = resp;
61         r->last = resp;
62     }
63     resp->next = NULL;
64     return resp;
65 }
66
67 static void reread (Res r)
68 {
69     struct res_entry *resp;
70     char *line;
71     char *val_buf;
72     int val_size, val_max = 256;
73     char fr_buf[1024];
74     FILE *fr;
75
76     assert (r);
77     r->init = 1;
78
79     val_buf = (char*) xmalloc (val_max);
80
81     if (!r->name)
82         return; 
83
84     fr = fopen (r->name, "r");
85     if (!fr)
86     {
87         logf (LOG_WARN|LOG_ERRNO, "Cannot open `%s'", r->name);
88         return ;
89     }
90     while (1)
91     {
92         line = fgets (fr_buf, sizeof(fr_buf)-1, fr);
93         if (!line)
94             break;
95         if (*line == '#')
96         {
97             int no = 0;
98
99             while (fr_buf[no] && fr_buf[no] != '\n')
100                 no++;
101             fr_buf[no] = '\0';
102
103             resp = add_entry (r);
104             resp->name = (char*) xmalloc (no+1);
105             resp->value = NULL;
106             strcpy (resp->name, fr_buf);
107         }
108         else
109         {
110             int no = 0;
111             while (1)
112             {
113                 if (fr_buf[no] == 0 || fr_buf[no] == '\n' )
114                 {
115                     no = 0;
116                     break;
117                 }
118                 if (strchr (": \t", fr_buf[no]))
119                     break;
120                 no++;
121             }
122             if (!no)
123                 continue;
124             fr_buf[no++] = '\0';
125             resp = add_entry (r);
126             resp->name = (char*) xmalloc (no);
127             strcpy (resp->name, fr_buf);
128             
129             while (strchr (" \t", fr_buf[no]))
130                 no++;
131             val_size = 0;
132             while (1)
133             {
134                 if (fr_buf[no] == '\0' || strchr("\n\r\f", fr_buf[no]))
135                 {
136                     while (val_size > 0 &&
137                               (val_buf[val_size-1] == ' ' ||
138                                val_buf[val_size-1] == '\t'))
139                         val_size--;
140                     val_buf[val_size++] = '\0';
141                     resp->value = (char*) xmalloc (val_size);
142                     strcpy (resp->value, val_buf);
143                     logf (LOG_DEBUG, "(name=%s,value=%s)",
144                          resp->name, resp->value);
145                     break;
146                 }
147                 else if (fr_buf[no] == '\\' && strchr ("\n\r\f", fr_buf[no+1]))
148                 {
149                     line = fgets (fr_buf, sizeof(fr_buf)-1, fr);
150                     if (!line)
151                     {
152                         resp->value = (char*) xmalloc (val_size);
153                         strcpy (resp->value, val_buf);
154                         break;
155                     }
156                     no = 0;
157                 }
158                 else
159                 {
160                     val_buf[val_size++] = fr_buf[no++];
161                     if (val_size+1 >= val_max)
162                     {
163                         char *nb;
164
165                         nb = (char*) xmalloc (val_max+=1024);
166                         memcpy (nb, val_buf, val_size);
167                         xfree (val_buf);
168                         val_buf = nb;
169                     }
170                 }
171             }
172         }
173     }                
174     xfree (val_buf);
175     fclose (fr);
176 }
177
178 Res res_open (const char *name, Res def_res)
179 {
180     Res r;
181
182     if (name)
183     {
184 #ifdef WIN32
185         if (access (name, 4))
186 #else
187         if (access (name, R_OK))
188 #endif
189         {
190             logf (LOG_WARN|LOG_ERRNO, "Cannot open `%s'", name);
191             return 0;
192         }
193     }
194     r = (Res) xmalloc (sizeof(*r));
195     r->init = 0;
196     r->first = r->last = NULL;
197     if (name)
198         r->name = xstrdup (name);
199     else
200         r->name=0;
201     r->def_res = def_res;
202     return r;
203 }
204
205 void res_close (Res r)
206 {
207     if (!r)
208         return;
209     if (r->init)
210     {
211         struct res_entry *re, *re1;
212         for (re = r->first; re; re=re1)
213         {
214             if (re->name)
215                 xfree (re->name);
216             if (re->value)
217                 xfree (re->value);
218             re1 = re->next;
219             xfree (re);
220         }
221     }
222     xfree (r->name);
223     xfree (r);
224 }
225
226 char *res_get (Res r, const char *name)
227 {
228     struct res_entry *re;
229
230     if (!r)
231         return 0;
232     if (!r->init)
233         reread (r);
234     for (re = r->first; re; re=re->next)
235         if (re->value && !yaz_matchstr (re->name, name))
236             return re->value;
237
238     return res_get (r->def_res, name);
239 }
240
241 char *res_get_def (Res r, const char *name, char *def)
242 {
243     char *t;
244
245     if (!(t = res_get (r, name)))
246     {
247         logf (LOG_DEBUG, "CAUTION: Using default resource %s:%s", name, def);
248         return def;
249     }
250     else
251         return t;
252 }
253
254 int res_get_match (Res r, const char *name, const char *value, const char *s)
255 {
256     const char *cn = res_get (r, name);
257
258     if (!cn)
259         cn = s;
260     if (cn && !yaz_matchstr (cn, value))
261         return 1;
262     return 0;
263 }
264
265 void res_put (Res r, const char *name, const char *value)
266 {
267     struct res_entry *re;
268     assert (r);
269     if (!r->init)
270         reread (r);
271
272     for (re = r->first; re; re=re->next)
273         if (re->value && !yaz_matchstr (re->name, name))
274         {
275             xfree (re->value);
276             re->value = xstrdup (value);
277             return;
278         }
279     re = add_entry (r);
280     re->name = xstrdup (name);
281     re->value = xstrdup (value);
282 }
283
284 int res_trav (Res r, const char *prefix, void *p,
285               void (*f)(void *p, const char *name, const char *value))
286 {
287     struct res_entry *re;
288     int l = 0;
289     int no = 0;
290     
291     if (!r)
292         return 0;
293     if (prefix)
294         l = strlen(prefix);
295     if (!r->init)
296         reread (r);
297     for (re = r->first; re; re=re->next)
298         if (re->value)
299             if (l==0 || !memcmp (re->name, prefix, l))
300             {
301                 (*f)(p, re->name, re->value);
302                 no++;
303             }
304     if (!no)
305         return res_trav (r->def_res, prefix, p, f);
306     return no;
307 }
308
309
310 int res_write (Res r)
311 {
312     struct res_entry *re;
313     FILE *fr;
314
315     assert (r);
316     if (!r->init)
317         reread (r);
318     if (!r->name)
319         return 0; /* ok, this was not from a file */
320     fr = fopen (r->name, "w");
321     if (!fr)
322     {
323         logf (LOG_FATAL|LOG_ERRNO, "Cannot create `%s'", r->name);
324         exit (1);
325     }
326
327     for (re = r->first; re; re=re->next)
328     {
329         int no = 0;
330         int lefts = strlen(re->name)+2;
331
332         if (!re->value)
333             fprintf (fr, "%s\n", re->name);
334         else
335         {
336             fprintf (fr, "%s: ", re->name);
337             while (lefts + strlen(re->value+no) > 78)
338             {
339                 int i = 20;
340                 int ind = no+ 78-lefts;
341                 while (--i >= 0)
342                 {
343                     if (re->value[ind] == ' ')
344                         break;
345                     --ind;
346                 }
347                 if (i<0)
348                     ind = no + 78 - lefts;
349                 for (i = no; i != ind; i++)
350                     putc (re->value[i], fr);
351                 fprintf (fr, "\\\n");
352                 no=ind;
353                 lefts = 0;
354             }
355             fprintf (fr, "%s\n", re->value+no);
356         }
357     }
358     fclose (fr);
359     return 0;
360 }
361
362
363