2 gw-res.c: Implementation of resource management.
7 Revision 1.1 1995/02/09 17:27:11 adam
11 Initial: Dec 8, 94 (Adam Dickmeiss)
12 Last update: Dec 19, 94 (Adam Dickmeiss)
27 #include <sys/types.h>
34 symtab_open: Create empty symbol table.
35 symbol table handle is returned.
38 static struct res_symtab *symtab_open (void)
40 struct res_symtab *symtab;
42 symtab = malloc (sizeof(*symtab));
50 symtab_close: Delete symbol table.
52 static void symtab_close (struct res_symtab *symtab)
54 struct res_sym_entry *entry, *entry1;
56 for (entry = symtab->next; entry; entry = entry1)
65 symtab_override: Add symbol to table. 'rl' holds symbol
66 table entry info. If the symbol is already present it
67 will override old info.
69 static int symtab_override (struct res_symtab *symtab,
70 struct res_line_info *rl)
72 struct res_sym_entry *entry;
74 for (entry = symtab->next; entry; entry=entry->next)
75 if (!strcmp (entry->info->name, rl->name))
80 entry = malloc (sizeof(*entry));
83 entry->next = symtab->next;
90 symtab_lookup: Symbol table lookup. If successful info is returned;
91 otherwise NULL is returned.
93 static struct res_line_info *symtab_lookup (struct res_symtab *symtab,
96 struct res_sym_entry *entry;
98 for (entry = symtab->next; entry; entry=entry->next)
99 if (!strcmp (entry->info->name, name))
105 lock_file: File locking using fcntl.
108 static void lock_file (int fd, int type)
112 area.l_whence = SEEK_SET;
115 fcntl (fd, F_SETLKW, &area);
120 gw_res_init: A resource handle is returned by this function
121 describing empty resources.
123 GwRes gw_res_init (void)
127 if (!(p = malloc (sizeof(*p))))
130 p->symtab = symtab_open ();
140 gw_res_close: The resources described by 'id' are freed.
141 No further references to 'id' are allowed.
143 void gw_res_close (GwRes id)
145 struct res_line_info *rl, *rl1;
146 struct res_file_info *rf, *rf1;
150 symtab_close (id->symtab);
151 for (rf = id->files; rf; rf = rf1)
153 for (rl = rf->lines; rl; rl = rl1)
168 add_name: add a node with line information.
170 static struct res_line_info *add_name (enum res_kind kind,
171 const char *name, const char *value)
173 struct res_line_info *rl;
175 if (!(rl = malloc (sizeof(*rl))))
181 rl->name = gw_strdup (name);
192 rl->value = gw_strdup (value);
206 gw_res_merge: The resources described by 'id' are merged by the contents
207 of 'filename'. If a resource is duplicated (in both resources 'id'
208 and the file) the resource is set to the value specified in 'filename'.
209 This function returns 0 on success; -1 on failure ('filename'
212 int gw_res_merge (GwRes id, const char *filename)
217 struct res_file_info *ri;
218 struct res_line_info **rlp, *rl;
219 struct res_line_info *rl_last = NULL;
224 gw_log (GW_LOG_DEBUG, "res", "gw_res_merge");
225 gw_log (GW_LOG_DEBUG, "res", "checking %s", filename);
226 if (!(inf = fopen (filename, "r")))
229 flock (fileno(inf), LOCK_SH);
231 lock_file (fileno (inf), F_RDLCK);
233 if (!(ri = malloc (sizeof (*ri))))
238 if (!(ri->fname = gw_strdup (filename)))
244 gw_log (GW_LOG_DEBUG, "res", "reading %s", filename);
245 ri->next = id->files;
249 while (fgets (buffer, sizeof(buffer)-1, inf))
252 while ((cp = strchr (buffer, '\n')))
256 rl = add_name (comment, NULL, buffer);
265 else if (*buffer == '\0' || *buffer == ' ' || *buffer == '\t')
268 while (buffer[i] == ' ' || buffer[i] == '\t')
270 if (buffer[i] == '\0')
272 rl = add_name (blank, NULL, NULL);
282 { /* continuation line */
283 int j = strlen (buffer)-1;
284 /* strip trailing blanks */
285 while (buffer[j] == '\t' || buffer[j] == ' ')
290 if (strlen(value)+strlen(buffer+i) >= sizeof(value)-2)
292 gw_log (GW_LOG_WARN, "res", "Resource `%s' is "
293 " truncated", rl_last->name);
297 /* effectively add one blank, then buffer */
299 strcat (value, buffer+i);
303 gw_log (GW_LOG_WARN, "res", "Resource file has bad "
304 "continuation line");
308 { /* resource line */
312 rl_last->value = gw_strdup (value);
315 while (buffer[i] && buffer[i] != ':')
317 if (buffer[i] == ':')
319 int j = strlen(buffer)-1;
320 buffer[i++] = '\0'; /* terminate name */
321 while (buffer[i] == ' ' || buffer[i] == '\t')
322 i++; /* skip blanks before */
323 while (buffer[j] == '\t' || buffer[j] == ' ')
324 --j; /* skip blanks after */
325 buffer[j+1] = '\0'; /* terminate value */
326 strcpy (value, buffer+i);
327 rl_last = add_name (resource, buffer, NULL);
333 rlp = &rl_last->next;
339 rl_last->value = gw_strdup (value);
341 flock (fileno (inf), LOCK_UN);
343 lock_file (fileno (inf), F_UNLCK);
346 gw_log (GW_LOG_DEBUG, "res", "close of %s", filename);
347 for (rl = ri->lines; rl; rl = rl->next)
352 gw_log (GW_LOG_DEBUG, "res", "%s", rl->value);
355 gw_log (GW_LOG_DEBUG, "res", "%s: %s", rl->name, rl->value);
356 if (symtab_override (id->symtab, rl) < 0)
360 gw_log (GW_LOG_DEBUG, "res", "");
366 gw_log (GW_LOG_DEBUG, "res", "gw_res_merge returned %d", err);
371 gw_res_get: The resource with name 'name' is checked in the resources
372 represented by 'id'. If the resource is present a pointer to the
373 value (null-terminated string) is returned. If the value is not
374 present the value of 'def' is returned.
376 const char *gw_res_get (GwRes id, const char *name, const char *def)
378 struct res_line_info *rl;
381 rl = symtab_lookup (id->symtab, name);
388 gw_res_put: Change a resource - modify if it exists - add if not
389 already there. The resource will have impact on the file name
390 'fname'. Use gw_res_commit (see below) to actually write to the
393 int gw_res_put (GwRes id, const char *name, const char *value,
396 struct res_file_info *ri;
397 struct res_line_info **rlp;
401 for (ri = id->files; ri; ri = ri->next)
402 if (!strcmp (ri->fname, fname))
406 if (!(ri = malloc (sizeof (*ri))))
408 if (!(ri->fname = gw_strdup (fname)))
413 ri->next = id->files;
417 for (rlp = &ri->lines; *rlp; rlp = &(*rlp)->next)
418 if (!strcmp ((*rlp)->name, name))
422 char *new_val = gw_strdup (value);
425 free ((*rlp)->value);
426 (*rlp)->value = new_val;
430 *rlp = add_name (resource, name, value);
434 if (symtab_override (id->symtab, *rlp) < 0)
441 gw_res_commit: Write the resource file 'fname'. If resources
442 are modified/added then these will be written now.
444 int gw_res_commit (GwRes id, const char *fname)
446 struct res_file_info *ri;
447 struct res_line_info *rl;
454 for (ri = id->files; ri; ri = ri->next)
455 if (!strcmp (ri->fname, fname))
459 if (!(out = fopen (fname, "w")))
462 flock (fileno (out), LOCK_EX);
464 lock_file (fileno (out), F_WRLCK);
466 for (rl = ri->lines; rl; rl = rl->next)
470 fputs (rl->value, out);
475 fprintf (out, "%s: ", rl->name);
476 pos = strlen(rl->name)+2;
481 if (strlen(rl->value+i) <= left)
485 if (rl->value[i+left] == ' ')
493 for (j = 0; j<left; j++)
494 fputc (rl->value[i+j], out);
499 fprintf (out, "\n ");
502 fprintf (out, "%s\n", rl->value+i);
509 flock (fileno (out), LOCK_UN);
511 lock_file (fileno (out), F_UNLCK);
518 gw_res_trav: Traverse resources associated with file 'fname'. For
519 each resource the handler 'tf' is invoked with name and value.
521 int gw_res_trav (GwRes id, const char *fname, void (*tf)(const char *name,
529 struct res_file_info *ri;
530 struct res_line_info *rl;
532 for (ri = id->files; ri; ri = ri->next)
533 if (!strcmp (ri->fname, fname))
537 for (rl = ri->lines; rl; rl = rl->next)
538 if (rl->kind == resource)
539 (*tf) (rl->name, rl->value);
543 struct res_sym_entry *entry;
545 for (entry = id->symtab->next; entry; entry=entry->next)
546 (*tf) (entry->info->name, entry->info->value);