IDZEBRA  2.2.7
res.c
Go to the documentation of this file.
1 /* This file is part of the Zebra server.
2  Copyright (C) Index Data
3 
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8 
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 
18 */
19 
20 #if HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #ifdef WIN32
28 #include <io.h>
29 #endif
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 
34 #include <yaz/tokenizer.h>
35 #include <yaz/yaz-util.h>
36 #include <idzebra/res.h>
37 
38 #define YLOG_RES 0
39 
40 struct res_entry {
41  char *name;
42  char *value;
43  struct res_entry *next;
44 };
45 
46 struct res_struct {
47  int ref_count;
48  struct res_entry *first, *last;
51 };
52 
53 static Res res_incref(Res r)
54 {
55  if (r)
56  r->ref_count++;
57  return r;
58 }
59 
60 static struct res_entry *add_entry(Res r)
61 {
62  struct res_entry *resp;
63 
64  if (!r->first)
65  resp = r->last = r->first =
66  (struct res_entry *) xmalloc(sizeof(*resp));
67  else
68  {
69  resp = (struct res_entry *) xmalloc(sizeof(*resp));
70  r->last->next = resp;
71  r->last = resp;
72  }
73  resp->next = NULL;
74  return resp;
75 }
76 
77 static char *xstrdup_env(const char *src)
78 {
79  int i = 0;
80  int j = 0;
81  char *dst;
82  int env_strlen = 0;
83 
84  while (src[i])
85  {
86  if (src[i] == '$' && src[i+1] == '{')
87  {
88  char envname[128];
89  char *env_val;
90  int k = 0;
91  i = i + 2;
92  while (k < 127 && src[i] && !strchr(":}\n\r\f", src[i]))
93  envname[k++] = src[i++];
94  envname[k] = '\0';
95 
96  env_val = getenv(envname);
97  if (env_val)
98  env_strlen += 1 + strlen(env_val);
99  else
100  env_strlen++;
101  while (src[i] && !strchr("}\n\r\f", src[i]))
102  i++;
103  if (src[i] == '}')
104  i++;
105  }
106  else
107  i++;
108  }
109  dst = xmalloc(1 + env_strlen + i);
110  i = 0;
111  while (src[i])
112  {
113  if (src[i] == '$' && src[i+1] == '{')
114  {
115  char envname[128];
116  char *env_val;
117  int k = 0;
118  i = i + 2;
119  while(k < 127 && src[i] && !strchr(":}\n\r\f", src[i]))
120  envname[k++] = src[i++];
121  envname[k] = '\0';
122  env_val = getenv(envname);
123  if (env_val)
124  {
125  strcpy(dst+j, env_val);
126  j += strlen(env_val);
127  }
128  else if (src[i] == ':' && src[i+1] == '-')
129  {
130  i = i + 2;
131  while (src[i] && !strchr("}\n\r\f", src[i]))
132  dst[j++] = src[i++];
133  }
134  while (src[i] && !strchr("}\n\r\f", src[i]))
135  i++;
136  if (src[i] == '}')
137  i++;
138  }
139  else
140  dst[j++] = src[i++];
141  }
142  dst[j] = '\0';
143  return dst;
144 }
145 
146 ZEBRA_RES res_read_file(Res r, const char *fname)
147 {
148  FILE *fr;
149  int errors = 0;
150 
151  assert(r);
152 
153  fr = fopen(fname, "r");
154  if (!fr)
155  {
156  yaz_log(YLOG_WARN|YLOG_ERRNO, "Cannot open `%s'", fname);
157  errors++;
158  }
159  else
160  {
161  char fr_buf[1024];
162  char *line;
163  int lineno = 1;
164  WRBUF wrbuf_val = wrbuf_alloc();
165  yaz_tok_cfg_t yt = yaz_tok_cfg_create();
166 
167  while ((line = fgets(fr_buf, sizeof(fr_buf)-1, fr)))
168  {
169  yaz_tok_parse_t tp = yaz_tok_parse_buf(yt, line);
170  int t = yaz_tok_move(tp);
171 
172  if (t == YAZ_TOK_STRING)
173  {
174  size_t sz;
175  struct res_entry *resp;
176  const char *cp = yaz_tok_parse_string(tp);
177  const char *cp1 = strchr(cp, ':');
178 
179  if (!cp1)
180  {
181  yaz_log(YLOG_FATAL, "%s:%d missing colon after '%s'",
182  fname, lineno, cp);
183  errors++;
184  break;
185  }
186  resp = add_entry(r);
187  sz = cp1 - cp;
188  resp->name = xmalloc(sz + 1);
189  memcpy(resp->name, cp, sz);
190  resp->name[sz] = '\0';
191 
192  wrbuf_rewind(wrbuf_val);
193 
194  if (cp1[1])
195  {
196  /* name:value */
197  wrbuf_puts(wrbuf_val, cp1+1);
198  }
199  else
200  {
201  /* name: value */
202  t = yaz_tok_move(tp);
203 
204  if (t != YAZ_TOK_STRING)
205  {
206  resp->value = xstrdup("");
207  yaz_log(YLOG_FATAL, "%s:%d missing value after '%s'",
208  fname, lineno, resp->name);
209  errors++;
210  break;
211  }
212  wrbuf_puts(wrbuf_val, yaz_tok_parse_string(tp));
213  }
214  while ((t=yaz_tok_move(tp)) == YAZ_TOK_STRING)
215  {
216  wrbuf_putc(wrbuf_val, ' ');
217  wrbuf_puts(wrbuf_val, yaz_tok_parse_string(tp));
218  }
219  resp->value = xstrdup_env(wrbuf_cstr(wrbuf_val));
220  /* printf("name=%s value=%s\n", resp->name, resp->value); */
221  }
222  lineno++;
223  yaz_tok_parse_destroy(tp);
224  }
225  fclose(fr);
226  yaz_tok_cfg_destroy(yt);
227  wrbuf_destroy(wrbuf_val);
228  }
229  if (errors)
230  return ZEBRA_FAIL;
231  return ZEBRA_OK;
232 }
233 
234 Res res_open(Res def_res, Res over_res)
235 {
236  Res r;
237  r = (Res) xmalloc(sizeof(*r));
238 
239  r->ref_count = 1;
240  r->first = r->last = NULL;
241  r->def_res = res_incref(def_res);
242  r->over_res = res_incref(over_res);
243  return r;
244 }
245 
246 void res_clear(Res r)
247 {
248  struct res_entry *re, *re1;
249  for (re = r->first; re; re=re1)
250  {
251  if (re->name)
252  xfree(re->name);
253  if (re->value)
254  xfree(re->value);
255  re1 = re->next;
256  xfree(re);
257  }
258  r->first = r->last = NULL;
259 }
260 
261 void res_close(Res r)
262 {
263  if (r && --(r->ref_count) == 0)
264  {
265  res_clear(r);
266  res_close(r->def_res);
267  res_close(r->over_res);
268  xfree(r);
269  }
270 }
271 
272 const char *res_get_prefix(Res r, const char *name, const char *prefix,
273  const char *def)
274 {
275  const char *v = 0;;
276  if (prefix)
277  {
278  char rname[128];
279 
280  if (strlen(name) + strlen(prefix) >= (sizeof(rname)-2))
281  return 0;
282  strcpy(rname, prefix);
283  strcat(rname, ".");
284  strcat(rname, name);
285  v = res_get(r, rname);
286  }
287  if (!v)
288  v = res_get(r, name);
289  if (!v)
290  v = def;
291  return v;
292 }
293 
294 const char *res_get(Res r, const char *name)
295 {
296  struct res_entry *re;
297  const char *v;
298 
299  if (!r)
300  return 0;
301 
302  v = res_get(r->over_res, name);
303  if (v)
304  return v;
305 
306  for (re = r->first; re; re=re->next)
307  if (re->value && !yaz_matchstr(re->name, name))
308  return re->value;
309 
310  return res_get(r->def_res, name);
311 }
312 
313 const char *res_get_def(Res r, const char *name, const char *def)
314 {
315  const char *t;
316 
317  if (!(t = res_get(r, name)))
318  {
319  if (def)
320  yaz_log(YLOG_DEBUG, "Using default resource %s:%s", name, def);
321  return def;
322  }
323  else
324  return t;
325 }
326 
327 int res_get_match(Res r, const char *name, const char *value, const char *s)
328 {
329  const char *cn = res_get(r, name);
330 
331  if (!cn)
332  cn = s;
333  if (cn && !yaz_matchstr(cn, value))
334  return 1;
335  return 0;
336 }
337 
338 void res_set(Res r, const char *name, const char *value)
339 {
340  struct res_entry *re;
341  assert(r);
342 
343  if (!value)
344  return;
345  for (re = r->first; re; re=re->next)
346  if (re->value && !yaz_matchstr(re->name, name))
347  {
348  xfree(re->value);
349  re->value = xstrdup_env(value);
350  return;
351  }
352  re = add_entry(r);
353  re->name = xstrdup(name);
354  re->value = xstrdup_env(value);
355 }
356 
357 int res_trav(Res r, const char *prefix, void *p,
358  void (*f)(void *p, const char *name, const char *value))
359 {
360  struct res_entry *re;
361  int l = 0;
362  int no = 0;
363 
364  if (!r)
365  return 0;
366  no = res_trav(r->over_res, prefix, p, f);
367  if (no)
368  return no;
369  if (prefix)
370  l = strlen(prefix);
371  for (re = r->first; re; re=re->next)
372  if (re->value)
373  if (l==0 || !memcmp(re->name, prefix, l))
374  {
375  (*f)(p, re->name, re->value);
376  no++;
377  }
378  if (!no)
379  return res_trav(r->def_res, prefix, p, f);
380  return no;
381 }
382 
383 
384 ZEBRA_RES res_write_file(Res r, const char *fname)
385 {
386  struct res_entry *re;
387  FILE *fr;
388 
389  assert(r);
390  fr = fopen(fname, "w");
391  if (!fr)
392  {
393  yaz_log(YLOG_FATAL|YLOG_ERRNO, "Cannot create `%s'", fname);
394  return ZEBRA_FAIL;
395  }
396 
397  for (re = r->first; re; re=re->next)
398  {
399  int no = 0;
400  int lefts = strlen(re->name)+2;
401 
402  if (!re->value)
403  fprintf(fr, "%s\n", re->name);
404  else
405  {
406  fprintf(fr, "%s: ", re->name);
407  while (lefts + strlen(re->value+no) > 78)
408  {
409  int i = 20;
410  int ind = no+ 78-lefts;
411  while (--i >= 0)
412  {
413  if (re->value[ind] == ' ')
414  break;
415  --ind;
416  }
417  if (i<0)
418  ind = no + 78 - lefts;
419  for (i = no; i != ind; i++)
420  putc(re->value[i], fr);
421  fprintf(fr, "\\\n");
422  no=ind;
423  lefts = 0;
424  }
425  fprintf(fr, "%s\n", re->value+no);
426  }
427  }
428  fclose(fr);
429  return ZEBRA_OK;
430 }
431 
432 ZEBRA_RES res_get_int(Res r, const char *name, int *val)
433 {
434  const char *cp = res_get(r, name);
435  if (cp)
436  {
437  if (sscanf(cp, "%d", val) == 1)
438  return ZEBRA_OK;
439  yaz_log(YLOG_WARN, "Expected integer for resource %s", name);
440  }
441  return ZEBRA_FAIL;
442 }
443 
444 
445 void res_add(Res r, const char *name, const char *value)
446 {
447  struct res_entry *re;
448  assert(r);
449  assert(name);
450  assert(value);
451  yaz_log(YLOG_RES, "res_add res=%p, name=%s, value=%s", r, name, value);
452  re = add_entry(r);
453  re->name = xstrdup(name);
454  re->value = xstrdup_env(value);
455 }
456 
457 void res_dump(Res r, int level)
458 {
459  struct res_entry *re;
460 
461  if (!r)
462  return;
463 
464  for (re = r->first; re; re=re->next) {
465  printf("%*s - %s:='%s'\n",level * 4,"",re->name,re->value);
466  }
467 
468  if (r->def_res) {
469  printf("%*s DEF ",level * 4,"");
470  res_dump(r->def_res, level + 1);
471  }
472 
473  if (r->over_res) {
474  printf("%*s OVER ",level * 4,"");
475  res_dump(r->over_res, level + 1);
476  }
477 }
478 
479 int res_check(Res r_i, Res r_v)
480 {
481  struct res_entry *e_i;
482  int errors = 0;
483 
484  for (e_i = r_i->first; e_i; e_i = e_i->next)
485  {
486  struct res_entry *e_v;
487  for (e_v = r_v->first; e_v; e_v = e_v->next)
488  {
489  int prefix_allowed = 0;
490  int suffix_allowed = 0;
491  const char *name = e_i->name;
492  size_t name_len = strlen(e_i->name);
493  char namez[32];
494  const char *first_dot = 0;
495  const char *second_dot = 0;
496 
497  if (strchr(e_v->value, 'p'))
498  prefix_allowed = 1;
499  if (strchr(e_v->value, 's'))
500  suffix_allowed = 1;
501 
502  first_dot = strchr(name, '.');
503  if (prefix_allowed && first_dot)
504  {
505  name = first_dot+1;
506  name_len = strlen(name);
507  }
508  second_dot = strchr(name, '.');
509  if (suffix_allowed && second_dot)
510  {
511  name_len = second_dot - name;
512  }
513  if (name_len < sizeof(namez)-1)
514  {
515  memcpy(namez, name, name_len);
516  namez[name_len] = '\0';
517  if (!yaz_matchstr(namez, e_v->name))
518  break;
519  }
520  /* for case 'a.b' we have to check 'a' as well */
521  if (prefix_allowed && suffix_allowed && first_dot && !second_dot)
522  {
523  name = e_i->name;
524  name_len = first_dot - name;
525  if (name_len < sizeof(namez)-1)
526  {
527  memcpy(namez, name, name_len);
528  namez[name_len] = '\0';
529  if (!yaz_matchstr(namez, e_v->name))
530  break;
531  }
532  }
533  }
534  if (!e_v)
535  {
536  yaz_log(YLOG_WARN, "The following setting is unrecognized: %s",
537  e_i->name);
538  errors++;
539  }
540  }
541  return errors;
542 }
543 
544 /*
545  * Local variables:
546  * c-basic-offset: 4
547  * c-file-style: "Stroustrup"
548  * indent-tabs-mode: nil
549  * End:
550  * vim: shiftwidth=4 tabstop=8 expandtab
551  */
552 
#define YLOG_RES
Definition: res.c:38
void res_set(Res r, const char *name, const char *value)
Definition: res.c:338
void res_dump(Res r, int level)
Definition: res.c:457
static char * xstrdup_env(const char *src)
Definition: res.c:77
void res_close(Res r)
Definition: res.c:261
static Res res_incref(Res r)
Definition: res.c:53
ZEBRA_RES res_read_file(Res r, const char *fname)
Definition: res.c:146
void res_add(Res r, const char *name, const char *value)
Definition: res.c:445
int res_get_match(Res r, const char *name, const char *value, const char *s)
Definition: res.c:327
const char * res_get_prefix(Res r, const char *name, const char *prefix, const char *def)
Definition: res.c:272
int res_check(Res r_i, Res r_v)
Definition: res.c:479
ZEBRA_RES res_write_file(Res r, const char *fname)
Definition: res.c:384
void res_clear(Res r)
Definition: res.c:246
const char * res_get(Res r, const char *name)
Definition: res.c:294
Res res_open(Res def_res, Res over_res)
Definition: res.c:234
static struct res_entry * add_entry(Res r)
Definition: res.c:60
const char * res_get_def(Res r, const char *name, const char *def)
Definition: res.c:313
ZEBRA_RES res_get_int(Res r, const char *name, int *val)
Definition: res.c:432
int res_trav(Res r, const char *prefix, void *p, void(*f)(void *p, const char *name, const char *value))
Definition: res.c:357
struct res_struct * Res
Definition: res.h:27
Definition: res.c:40
char * name
Definition: res.c:41
struct res_entry * next
Definition: res.c:43
char * value
Definition: res.c:42
Definition: res.c:46
struct res_entry * first
Definition: res.c:48
int ref_count
Definition: res.c:47
struct res_entry * last
Definition: res.c:48
Res def_res
Definition: res.c:49
Res over_res
Definition: res.c:50
#define ZEBRA_FAIL
Definition: util.h:81
#define ZEBRA_OK
Definition: util.h:82
short ZEBRA_RES
Common return type for Zebra API.
Definition: util.h:80