2 * Implementation of resource management.
4 * Europagate, 1994-1995.
7 * Revision 1.5 1995/02/23 08:32:22 adam
10 * Revision 1.3 1995/02/21 14:00:11 adam
13 * Revision 1.2 1995/02/16 13:21:30 adam
14 * A few logging messages added.
16 * Revision 1.1.1.1 1995/02/09 17:27:12 adam
17 * Initial version of email gateway under CVS control.
19 * Initial: Dec 8, 94 (Adam Dickmeiss)
33 #include <sys/types.h>
40 symtab_open: Create empty symbol table.
41 symbol table handle is returned.
44 static struct res_symtab *symtab_open (void)
46 struct res_symtab *symtab;
48 symtab = malloc (sizeof(*symtab));
56 symtab_close: Delete symbol table.
58 static void symtab_close (struct res_symtab *symtab)
60 struct res_sym_entry *entry, *entry1;
62 for (entry = symtab->next; entry; entry = entry1)
71 symtab_override: Add symbol to table. 'rl' holds symbol
72 table entry info. If the symbol is already present it
73 will override old info.
75 static int symtab_override (struct res_symtab *symtab,
76 struct res_line_info *rl)
78 struct res_sym_entry *entry;
80 for (entry = symtab->next; entry; entry=entry->next)
81 if (!strcmp (entry->info->name, rl->name))
86 entry = malloc (sizeof(*entry));
89 entry->next = symtab->next;
96 symtab_lookup: Symbol table lookup. If successful info is returned;
97 otherwise NULL is returned.
99 static struct res_line_info *symtab_lookup (struct res_symtab *symtab,
102 struct res_sym_entry *entry;
104 for (entry = symtab->next; entry; entry=entry->next)
105 if (!strcmp (entry->info->name, name))
111 lock_file: File locking using fcntl.
114 static void lock_file (int fd, int type)
118 area.l_whence = SEEK_SET;
121 fcntl (fd, F_SETLKW, &area);
126 gw_res_init: A resource handle is returned by this function
127 describing empty resources.
129 GwRes gw_res_init (void)
133 if (!(p = malloc (sizeof(*p))))
136 p->symtab = symtab_open ();
146 gw_res_close: The resources described by 'id' are freed.
147 No further references to 'id' are allowed.
149 void gw_res_close (GwRes id)
151 struct res_line_info *rl, *rl1;
152 struct res_file_info *rf, *rf1;
156 symtab_close (id->symtab);
157 for (rf = id->files; rf; rf = rf1)
159 for (rl = rf->lines; rl; rl = rl1)
174 add_name: add a node with line information.
176 static struct res_line_info *add_name (enum res_kind kind,
177 const char *name, const char *value)
179 struct res_line_info *rl;
181 if (!(rl = malloc (sizeof(*rl))))
187 rl->name = gw_strdup (name);
198 rl->value = gw_strdup (value);
212 gw_res_merge: The resources described by 'id' are merged by the contents
213 of 'filename'. If a resource is duplicated (in both resources 'id'
214 and the file) the resource is set to the value specified in 'filename'.
215 This function returns 0 on success; -1 on failure ('filename'
218 int gw_res_merge (GwRes id, const char *filename)
223 struct res_file_info *ri;
224 struct res_line_info **rlp, *rl;
225 struct res_line_info *rl_last = NULL;
230 gw_log (GW_LOG_DEBUG, "res", "gw_res_merge");
231 gw_log (GW_LOG_DEBUG, "res", "checking %s", filename);
232 if (!(inf = fopen (filename, "r")))
235 flock (fileno(inf), LOCK_SH);
237 lock_file (fileno (inf), F_RDLCK);
239 if (!(ri = malloc (sizeof (*ri))))
244 if (!(ri->fname = gw_strdup (filename)))
250 gw_log (GW_LOG_DEBUG, "res", "reading %s", filename);
251 ri->next = id->files;
255 while (fgets (buffer, sizeof(buffer)-1, inf))
258 while ((cp = strchr (buffer, '\n')))
262 rl = add_name (comment, NULL, buffer);
271 else if (*buffer == '\0' || *buffer == ' ' || *buffer == '\t')
274 while (buffer[i] == ' ' || buffer[i] == '\t')
276 if (buffer[i] == '\0')
278 rl = add_name (blank, NULL, NULL);
288 { /* continuation line */
289 int j = strlen (buffer)-1;
290 /* strip trailing blanks */
291 while (buffer[j] == '\t' || buffer[j] == ' ')
296 if (strlen(value)+strlen(buffer+i) >= sizeof(value)-2)
298 gw_log (GW_LOG_WARN, "res", "Resource `%s' is "
299 " truncated", rl_last->name);
303 /* effectively add one blank, then buffer */
305 strcat (value, buffer+i);
309 gw_log (GW_LOG_WARN, "res", "Resource file has bad "
310 "continuation line");
314 { /* resource line */
318 rl_last->value = gw_strdup (value);
321 while (buffer[i] && buffer[i] != ':')
323 if (buffer[i] == ':')
325 int j = strlen(buffer)-1;
326 buffer[i++] = '\0'; /* terminate name */
327 while (buffer[i] == ' ' || buffer[i] == '\t')
328 i++; /* skip blanks before */
329 while (buffer[j] == '\t' || buffer[j] == ' ')
330 --j; /* skip blanks after */
331 buffer[j+1] = '\0'; /* terminate value */
332 strcpy (value, buffer+i);
333 rl_last = add_name (resource, buffer, NULL);
339 rlp = &rl_last->next;
345 rl_last->value = gw_strdup (value);
347 flock (fileno (inf), LOCK_UN);
349 lock_file (fileno (inf), F_UNLCK);
352 gw_log (GW_LOG_DEBUG, "res", "close of %s", filename);
353 for (rl = ri->lines; rl; rl = rl->next)
358 gw_log (GW_LOG_DEBUG, "res", "%s", rl->value);
361 gw_log (GW_LOG_DEBUG, "res", "%s: %s", rl->name, rl->value);
362 if (symtab_override (id->symtab, rl) < 0)
366 gw_log (GW_LOG_DEBUG, "res", "");
372 gw_log (GW_LOG_DEBUG, "res", "gw_res_merge returned %d", err);
377 gw_res_get: The resource with name 'name' is checked in the resources
378 represented by 'id'. If the resource is present a pointer to the
379 value (null-terminated string) is returned. If the value is not
380 present the value of 'def' is returned.
382 const char *gw_res_get (GwRes id, const char *name, const char *def)
384 struct res_line_info *rl;
387 rl = symtab_lookup (id->symtab, name);
394 gw_res_put: Change a resource - modify if it exists - add if not
395 already there. The resource will have impact on the file name
396 'fname'. Use gw_res_commit (see below) to actually write to the
399 int gw_res_put (GwRes id, const char *name, const char *value,
402 struct res_file_info *ri;
403 struct res_line_info **rlp;
407 for (ri = id->files; ri; ri = ri->next)
408 if (!strcmp (ri->fname, fname))
412 if (!(ri = malloc (sizeof (*ri))))
414 if (!(ri->fname = gw_strdup (fname)))
419 ri->next = id->files;
423 for (rlp = &ri->lines; *rlp; rlp = &(*rlp)->next)
424 if (!strcmp ((*rlp)->name, name))
428 char *new_val = gw_strdup (value);
431 free ((*rlp)->value);
432 (*rlp)->value = new_val;
436 *rlp = add_name (resource, name, value);
440 if (symtab_override (id->symtab, *rlp) < 0)
447 gw_res_commit: Write the resource file 'fname'. If resources
448 are modified/added then these will be written now.
450 int gw_res_commit (GwRes id, const char *fname)
452 struct res_file_info *ri;
453 struct res_line_info *rl;
460 for (ri = id->files; ri; ri = ri->next)
461 if (!strcmp (ri->fname, fname))
465 if (!(out = fopen (fname, "w")))
468 flock (fileno (out), LOCK_EX);
470 lock_file (fileno (out), F_WRLCK);
472 for (rl = ri->lines; rl; rl = rl->next)
476 fputs (rl->value, out);
481 fprintf (out, "%s: ", rl->name);
482 pos = strlen(rl->name)+2;
487 if ((int) strlen(rl->value+i) <= left)
491 if (rl->value[i+left] == ' ')
499 for (j = 0; j<left; j++)
500 fputc (rl->value[i+j], out);
505 fprintf (out, "\n ");
508 fprintf (out, "%s\n", rl->value+i);
515 flock (fileno (out), LOCK_UN);
517 lock_file (fileno (out), F_UNLCK);
524 gw_res_trav: Traverse resources associated with file 'fname'. For
525 each resource the handler 'tf' is invoked with name and value.
527 int gw_res_trav (GwRes id, const char *fname, void (*tf)(const char *name,
535 struct res_file_info *ri;
536 struct res_line_info *rl;
538 for (ri = id->files; ri; ri = ri->next)
539 if (!strcmp (ri->fname, fname))
543 for (rl = ri->lines; rl; rl = rl->next)
544 if (rl->kind == resource)
545 (*tf) (rl->name, rl->value);
549 struct res_sym_entry *entry;
551 for (entry = id->symtab->next; entry; entry=entry->next)
552 (*tf) (entry->info->name, entry->info->value);