2 * Implementation of resource management.
4 * Europagate, 1994-1995.
7 * Revision 1.6 1995/04/19 12:12:07 adam
8 * Resource system uses only one log debug level.
10 * Revision 1.5 1995/02/23 08:32:22 adam
13 * Revision 1.3 1995/02/21 14:00:11 adam
16 * Revision 1.2 1995/02/16 13:21:30 adam
17 * A few logging messages added.
19 * Revision 1.1.1.1 1995/02/09 17:27:12 adam
20 * Initial version of email gateway under CVS control.
22 * Initial: Dec 8, 94 (Adam Dickmeiss)
36 #include <sys/types.h>
43 symtab_open: Create empty symbol table.
44 symbol table handle is returned.
47 static struct res_symtab *symtab_open (void)
49 struct res_symtab *symtab;
51 symtab = malloc (sizeof(*symtab));
59 symtab_close: Delete symbol table.
61 static void symtab_close (struct res_symtab *symtab)
63 struct res_sym_entry *entry, *entry1;
65 for (entry = symtab->next; entry; entry = entry1)
74 symtab_override: Add symbol to table. 'rl' holds symbol
75 table entry info. If the symbol is already present it
76 will override old info.
78 static int symtab_override (struct res_symtab *symtab,
79 struct res_line_info *rl)
81 struct res_sym_entry *entry;
83 for (entry = symtab->next; entry; entry=entry->next)
84 if (!strcmp (entry->info->name, rl->name))
89 entry = malloc (sizeof(*entry));
92 entry->next = symtab->next;
99 symtab_lookup: Symbol table lookup. If successful info is returned;
100 otherwise NULL is returned.
102 static struct res_line_info *symtab_lookup (struct res_symtab *symtab,
105 struct res_sym_entry *entry;
107 for (entry = symtab->next; entry; entry=entry->next)
108 if (!strcmp (entry->info->name, name))
114 lock_file: File locking using fcntl.
117 static void lock_file (int fd, int type)
121 area.l_whence = SEEK_SET;
124 fcntl (fd, F_SETLKW, &area);
129 gw_res_init: A resource handle is returned by this function
130 describing empty resources.
132 GwRes gw_res_init (void)
136 if (!(p = malloc (sizeof(*p))))
139 p->symtab = symtab_open ();
149 gw_res_close: The resources described by 'id' are freed.
150 No further references to 'id' are allowed.
152 void gw_res_close (GwRes id)
154 struct res_line_info *rl, *rl1;
155 struct res_file_info *rf, *rf1;
159 symtab_close (id->symtab);
160 for (rf = id->files; rf; rf = rf1)
162 for (rl = rf->lines; rl; rl = rl1)
177 add_name: add a node with line information.
179 static struct res_line_info *add_name (enum res_kind kind,
180 const char *name, const char *value)
182 struct res_line_info *rl;
184 if (!(rl = malloc (sizeof(*rl))))
190 rl->name = gw_strdup (name);
201 rl->value = gw_strdup (value);
215 gw_res_merge: The resources described by 'id' are merged by the contents
216 of 'filename'. If a resource is duplicated (in both resources 'id'
217 and the file) the resource is set to the value specified in 'filename'.
218 This function returns 0 on success; -1 on failure ('filename'
221 int gw_res_merge (GwRes id, const char *filename)
226 struct res_file_info *ri;
227 struct res_line_info **rlp, *rl;
228 struct res_line_info *rl_last = NULL;
233 gw_log (RES_DEBUG, "res", "gw_res_merge");
234 gw_log (RES_DEBUG, "res", "checking %s", filename);
235 if (!(inf = fopen (filename, "r")))
238 flock (fileno(inf), LOCK_SH);
240 lock_file (fileno (inf), F_RDLCK);
242 if (!(ri = malloc (sizeof (*ri))))
247 if (!(ri->fname = gw_strdup (filename)))
253 gw_log (RES_DEBUG, "res", "reading %s", filename);
254 ri->next = id->files;
258 while (fgets (buffer, sizeof(buffer)-1, inf))
261 while ((cp = strchr (buffer, '\n')))
265 rl = add_name (comment, NULL, buffer);
274 else if (*buffer == '\0' || *buffer == ' ' || *buffer == '\t')
277 while (buffer[i] == ' ' || buffer[i] == '\t')
279 if (buffer[i] == '\0')
281 rl = add_name (blank, NULL, NULL);
291 { /* continuation line */
292 int j = strlen (buffer)-1;
293 /* strip trailing blanks */
294 while (buffer[j] == '\t' || buffer[j] == ' ')
299 if (strlen(value)+strlen(buffer+i) >= sizeof(value)-2)
301 gw_log (GW_LOG_WARN, "res", "Resource `%s' is "
302 " truncated", rl_last->name);
306 /* effectively add one blank, then buffer */
308 strcat (value, buffer+i);
312 gw_log (GW_LOG_WARN, "res", "Resource file has bad "
313 "continuation line");
317 { /* resource line */
321 rl_last->value = gw_strdup (value);
324 while (buffer[i] && buffer[i] != ':')
326 if (buffer[i] == ':')
328 int j = strlen(buffer)-1;
329 buffer[i++] = '\0'; /* terminate name */
330 while (buffer[i] == ' ' || buffer[i] == '\t')
331 i++; /* skip blanks before */
332 while (buffer[j] == '\t' || buffer[j] == ' ')
333 --j; /* skip blanks after */
334 buffer[j+1] = '\0'; /* terminate value */
335 strcpy (value, buffer+i);
336 rl_last = add_name (resource, buffer, NULL);
342 rlp = &rl_last->next;
348 rl_last->value = gw_strdup (value);
350 flock (fileno (inf), LOCK_UN);
352 lock_file (fileno (inf), F_UNLCK);
355 gw_log (RES_DEBUG, "res", "close of %s", filename);
356 for (rl = ri->lines; rl; rl = rl->next)
361 gw_log (RES_DEBUG, "res", "%s", rl->value);
364 gw_log (RES_DEBUG, "res", "%s: %s", rl->name, rl->value);
365 if (symtab_override (id->symtab, rl) < 0)
369 gw_log (RES_DEBUG, "res", "");
375 gw_log (RES_DEBUG, "res", "gw_res_merge returned %d", err);
380 gw_res_get: The resource with name 'name' is checked in the resources
381 represented by 'id'. If the resource is present a pointer to the
382 value (null-terminated string) is returned. If the value is not
383 present the value of 'def' is returned.
385 const char *gw_res_get (GwRes id, const char *name, const char *def)
387 struct res_line_info *rl;
390 rl = symtab_lookup (id->symtab, name);
397 gw_res_put: Change a resource - modify if it exists - add if not
398 already there. The resource will have impact on the file name
399 'fname'. Use gw_res_commit (see below) to actually write to the
402 int gw_res_put (GwRes id, const char *name, const char *value,
405 struct res_file_info *ri;
406 struct res_line_info **rlp;
410 for (ri = id->files; ri; ri = ri->next)
411 if (!strcmp (ri->fname, fname))
415 if (!(ri = malloc (sizeof (*ri))))
417 if (!(ri->fname = gw_strdup (fname)))
422 ri->next = id->files;
426 for (rlp = &ri->lines; *rlp; rlp = &(*rlp)->next)
427 if (!strcmp ((*rlp)->name, name))
431 char *new_val = gw_strdup (value);
434 free ((*rlp)->value);
435 (*rlp)->value = new_val;
439 *rlp = add_name (resource, name, value);
443 if (symtab_override (id->symtab, *rlp) < 0)
450 gw_res_commit: Write the resource file 'fname'. If resources
451 are modified/added then these will be written now.
453 int gw_res_commit (GwRes id, const char *fname)
455 struct res_file_info *ri;
456 struct res_line_info *rl;
463 for (ri = id->files; ri; ri = ri->next)
464 if (!strcmp (ri->fname, fname))
468 if (!(out = fopen (fname, "w")))
471 flock (fileno (out), LOCK_EX);
473 lock_file (fileno (out), F_WRLCK);
475 for (rl = ri->lines; rl; rl = rl->next)
479 fputs (rl->value, out);
484 fprintf (out, "%s: ", rl->name);
485 pos = strlen(rl->name)+2;
490 if ((int) strlen(rl->value+i) <= left)
494 if (rl->value[i+left] == ' ')
502 for (j = 0; j<left; j++)
503 fputc (rl->value[i+j], out);
508 fprintf (out, "\n ");
511 fprintf (out, "%s\n", rl->value+i);
518 flock (fileno (out), LOCK_UN);
520 lock_file (fileno (out), F_UNLCK);
527 gw_res_trav: Traverse resources associated with file 'fname'. For
528 each resource the handler 'tf' is invoked with name and value.
530 int gw_res_trav (GwRes id, const char *fname, void (*tf)(const char *name,
538 struct res_file_info *ri;
539 struct res_line_info *rl;
541 for (ri = id->files; ri; ri = ri->next)
542 if (!strcmp (ri->fname, fname))
546 for (rl = ri->lines; rl; rl = rl->next)
547 if (rl->kind == resource)
548 (*tf) (rl->name, rl->value);
552 struct res_sym_entry *entry;
554 for (entry = id->symtab->next; entry; entry=entry->next)
555 (*tf) (entry->info->name, entry->info->value);