2 gw-res.c: Implementation of resource management.
7 Revision 1.2 1995/02/16 13:21:30 adam
8 A few logging messages added.
10 * Revision 1.1.1.1 1995/02/09 17:27:12 adam
11 * Initial version of email gateway under CVS control.
14 Initial: Dec 8, 94 (Adam Dickmeiss)
15 Last update: Dec 19, 94 (Adam Dickmeiss)
30 #include <sys/types.h>
37 symtab_open: Create empty symbol table.
38 symbol table handle is returned.
41 static struct res_symtab *symtab_open (void)
43 struct res_symtab *symtab;
45 symtab = malloc (sizeof(*symtab));
53 symtab_close: Delete symbol table.
55 static void symtab_close (struct res_symtab *symtab)
57 struct res_sym_entry *entry, *entry1;
59 for (entry = symtab->next; entry; entry = entry1)
68 symtab_override: Add symbol to table. 'rl' holds symbol
69 table entry info. If the symbol is already present it
70 will override old info.
72 static int symtab_override (struct res_symtab *symtab,
73 struct res_line_info *rl)
75 struct res_sym_entry *entry;
77 for (entry = symtab->next; entry; entry=entry->next)
78 if (!strcmp (entry->info->name, rl->name))
83 entry = malloc (sizeof(*entry));
86 entry->next = symtab->next;
93 symtab_lookup: Symbol table lookup. If successful info is returned;
94 otherwise NULL is returned.
96 static struct res_line_info *symtab_lookup (struct res_symtab *symtab,
99 struct res_sym_entry *entry;
101 for (entry = symtab->next; entry; entry=entry->next)
102 if (!strcmp (entry->info->name, name))
108 lock_file: File locking using fcntl.
111 static void lock_file (int fd, int type)
115 area.l_whence = SEEK_SET;
118 fcntl (fd, F_SETLKW, &area);
123 gw_res_init: A resource handle is returned by this function
124 describing empty resources.
126 GwRes gw_res_init (void)
130 if (!(p = malloc (sizeof(*p))))
133 p->symtab = symtab_open ();
143 gw_res_close: The resources described by 'id' are freed.
144 No further references to 'id' are allowed.
146 void gw_res_close (GwRes id)
148 struct res_line_info *rl, *rl1;
149 struct res_file_info *rf, *rf1;
153 symtab_close (id->symtab);
154 for (rf = id->files; rf; rf = rf1)
156 for (rl = rf->lines; rl; rl = rl1)
171 add_name: add a node with line information.
173 static struct res_line_info *add_name (enum res_kind kind,
174 const char *name, const char *value)
176 struct res_line_info *rl;
178 if (!(rl = malloc (sizeof(*rl))))
184 rl->name = gw_strdup (name);
195 rl->value = gw_strdup (value);
209 gw_res_merge: The resources described by 'id' are merged by the contents
210 of 'filename'. If a resource is duplicated (in both resources 'id'
211 and the file) the resource is set to the value specified in 'filename'.
212 This function returns 0 on success; -1 on failure ('filename'
215 int gw_res_merge (GwRes id, const char *filename)
220 struct res_file_info *ri;
221 struct res_line_info **rlp, *rl;
222 struct res_line_info *rl_last = NULL;
227 gw_log (GW_LOG_DEBUG, "res", "gw_res_merge");
228 gw_log (GW_LOG_DEBUG, "res", "checking %s", filename);
229 if (!(inf = fopen (filename, "r")))
232 flock (fileno(inf), LOCK_SH);
234 lock_file (fileno (inf), F_RDLCK);
236 if (!(ri = malloc (sizeof (*ri))))
241 if (!(ri->fname = gw_strdup (filename)))
247 gw_log (GW_LOG_DEBUG, "res", "reading %s", filename);
248 ri->next = id->files;
252 while (fgets (buffer, sizeof(buffer)-1, inf))
255 while ((cp = strchr (buffer, '\n')))
259 rl = add_name (comment, NULL, buffer);
268 else if (*buffer == '\0' || *buffer == ' ' || *buffer == '\t')
271 while (buffer[i] == ' ' || buffer[i] == '\t')
273 if (buffer[i] == '\0')
275 rl = add_name (blank, NULL, NULL);
285 { /* continuation line */
286 int j = strlen (buffer)-1;
287 /* strip trailing blanks */
288 while (buffer[j] == '\t' || buffer[j] == ' ')
293 if (strlen(value)+strlen(buffer+i) >= sizeof(value)-2)
295 gw_log (GW_LOG_WARN, "res", "Resource `%s' is "
296 " truncated", rl_last->name);
300 /* effectively add one blank, then buffer */
302 strcat (value, buffer+i);
306 gw_log (GW_LOG_WARN, "res", "Resource file has bad "
307 "continuation line");
311 { /* resource line */
315 rl_last->value = gw_strdup (value);
318 while (buffer[i] && buffer[i] != ':')
320 if (buffer[i] == ':')
322 int j = strlen(buffer)-1;
323 buffer[i++] = '\0'; /* terminate name */
324 while (buffer[i] == ' ' || buffer[i] == '\t')
325 i++; /* skip blanks before */
326 while (buffer[j] == '\t' || buffer[j] == ' ')
327 --j; /* skip blanks after */
328 buffer[j+1] = '\0'; /* terminate value */
329 strcpy (value, buffer+i);
330 rl_last = add_name (resource, buffer, NULL);
336 rlp = &rl_last->next;
342 rl_last->value = gw_strdup (value);
344 flock (fileno (inf), LOCK_UN);
346 lock_file (fileno (inf), F_UNLCK);
349 gw_log (GW_LOG_DEBUG, "res", "close of %s", filename);
350 for (rl = ri->lines; rl; rl = rl->next)
355 gw_log (GW_LOG_DEBUG, "res", "%s", rl->value);
358 gw_log (GW_LOG_DEBUG, "res", "%s: %s", rl->name, rl->value);
359 if (symtab_override (id->symtab, rl) < 0)
363 gw_log (GW_LOG_DEBUG, "res", "");
369 gw_log (GW_LOG_DEBUG, "res", "gw_res_merge returned %d", err);
374 gw_res_get: The resource with name 'name' is checked in the resources
375 represented by 'id'. If the resource is present a pointer to the
376 value (null-terminated string) is returned. If the value is not
377 present the value of 'def' is returned.
379 const char *gw_res_get (GwRes id, const char *name, const char *def)
381 struct res_line_info *rl;
384 rl = symtab_lookup (id->symtab, name);
391 gw_res_put: Change a resource - modify if it exists - add if not
392 already there. The resource will have impact on the file name
393 'fname'. Use gw_res_commit (see below) to actually write to the
396 int gw_res_put (GwRes id, const char *name, const char *value,
399 struct res_file_info *ri;
400 struct res_line_info **rlp;
404 for (ri = id->files; ri; ri = ri->next)
405 if (!strcmp (ri->fname, fname))
409 if (!(ri = malloc (sizeof (*ri))))
411 if (!(ri->fname = gw_strdup (fname)))
416 ri->next = id->files;
420 for (rlp = &ri->lines; *rlp; rlp = &(*rlp)->next)
421 if (!strcmp ((*rlp)->name, name))
425 char *new_val = gw_strdup (value);
428 free ((*rlp)->value);
429 (*rlp)->value = new_val;
433 *rlp = add_name (resource, name, value);
437 if (symtab_override (id->symtab, *rlp) < 0)
444 gw_res_commit: Write the resource file 'fname'. If resources
445 are modified/added then these will be written now.
447 int gw_res_commit (GwRes id, const char *fname)
449 struct res_file_info *ri;
450 struct res_line_info *rl;
457 for (ri = id->files; ri; ri = ri->next)
458 if (!strcmp (ri->fname, fname))
462 if (!(out = fopen (fname, "w")))
465 flock (fileno (out), LOCK_EX);
467 lock_file (fileno (out), F_WRLCK);
469 for (rl = ri->lines; rl; rl = rl->next)
473 fputs (rl->value, out);
478 fprintf (out, "%s: ", rl->name);
479 pos = strlen(rl->name)+2;
484 if (strlen(rl->value+i) <= left)
488 if (rl->value[i+left] == ' ')
496 for (j = 0; j<left; j++)
497 fputc (rl->value[i+j], out);
502 fprintf (out, "\n ");
505 fprintf (out, "%s\n", rl->value+i);
512 flock (fileno (out), LOCK_UN);
514 lock_file (fileno (out), F_UNLCK);
521 gw_res_trav: Traverse resources associated with file 'fname'. For
522 each resource the handler 'tf' is invoked with name and value.
524 int gw_res_trav (GwRes id, const char *fname, void (*tf)(const char *name,
532 struct res_file_info *ri;
533 struct res_line_info *rl;
535 for (ri = id->files; ri; ri = ri->next)
536 if (!strcmp (ri->fname, fname))
540 for (rl = ri->lines; rl; rl = rl->next)
541 if (rl->kind == resource)
542 (*tf) (rl->name, rl->value);
546 struct res_sym_entry *entry;
548 for (entry = id->symtab->next; entry; entry=entry->next)
549 (*tf) (entry->info->name, entry->info->value);