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