webperimental: killstack decides stack protects.
[freeciv.git] / utility / registry_ini.c
blobc183d9ce15541e78148db7173d7b7d5c14f1c560
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 /**************************************************************************
15 the idea with this file is to create something similar to the ms-windows
16 .ini files functions.
17 however the interface is nice. ie:
18 secfile_lookup_str(file, "player%d.unit%d.name", plrno, unitno);
19 ***************************************************************************/
21 /**************************************************************************
22 Description of the file format:
23 (This is based on a format by the original authors, with
24 various incremental extensions. --dwp)
26 - Whitespace lines are ignored, as are lines where the first
27 non-whitespace character is ';' (comment lines).
28 Optionally '#' can also be used for comments.
30 - A line of the form:
31 *include "filename"
32 includes the named file at that point. (The '*' must be the
33 first character on the line.) The file is found by looking in
34 FREECIV_DATA_PATH. Non-infinite recursive includes are allowed.
36 - A line with "[name]" labels the start of a section with
37 that name; one of these must be the first non-comment line in
38 the file. Any spaces within the brackets are included in the
39 name, but this feature (?) should probably not be used...
41 - Within a section, lines have one of the following forms:
42 subname = "stringvalue"
43 subname = -digits
44 subname = digits
45 subname = TRUE
46 sunname = FALSE
47 for a value with given name and string, negative integer, and
48 positive integer values, respectively. These entries are
49 referenced in the following functions as "sectionname.subname".
50 The section name should not contain any dots ('.'); the subname
51 can, but they have no particular significance. There can be
52 optional whitespace before and/or after the equals sign.
53 You can put a newline after (but not before) the equals sign.
55 Backslash is an escape character in strings (double-quoted strings
56 only, not names); recognised escapes are \n, \\, and \".
57 (Any other \<char> is just treated as <char>.)
59 - Gettext markings: You can surround strings like so:
60 foo = _("stringvalue")
61 The registry just ignores these extra markings, but this is
62 useful for marking strings for translations via gettext tools.
64 - Multiline strings: Strings can have embeded newlines, eg:
65 foo = _("
66 This is a string
67 over multiple lines
69 This is equivalent to:
70 foo = _("\nThis is a string\nover multiple lines\n")
71 Note that if you missplace the trailing doublequote you can
72 easily end up with strange errors reading the file...
74 - Strings read from a file: A file can be read as a string value:
75 foo = *filename.txt*
77 - Vector format: An entry can have multiple values separated
78 by commas, eg:
79 foo = 10, 11, "x"
80 These are accessed by names "foo", "foo,1" and "foo,2"
81 (with section prefix as above). So the above is equivalent to:
82 foo = 10
83 foo,1 = 11
84 foo,2 = "x"
85 As in the example, in principle you can mix integers and strings,
86 but the calling program will probably require elements to be the
87 same type. Note that the first element of a vector is not "foo,0",
88 in order that the name of the first element is the same whether or
89 not there are subsequent elements. However as a convenience, if
90 you try to lookup "foo,0" then you get back "foo". (So you should
91 never have "foo,0" as a real name in the datafile.)
93 - Tabular format: The lines:
94 foo = { "bar", "baz", "bax"
95 "wow", 10, -5
96 "cool", "str"
97 "hmm", 314, 99, 33, 11
99 are equivalent to the following:
100 foo0.bar = "wow"
101 foo0.baz = 10
102 foo0.bax = -5
103 foo1.bar = "cool"
104 foo1.baz = "str"
105 foo2.bar = "hmm"
106 foo2.baz = 314
107 foo2.bax = 99
108 foo2.bax,1 = 33
109 foo2.bax,2 = 11
110 The first line specifies the base name and the column names, and the
111 subsequent lines have data. Again it is possible to mix string and
112 integer values in a column, and have either more or less values
113 in a row than there are column headings, but the code which uses
114 this information (via the registry) may set more stringent conditions.
115 If a row has more entries than column headings, the last column is
116 treated as a vector (as above). You can optionally put a newline
117 after '=' and/or after '{'.
119 The equivalence above between the new and old formats is fairly
120 direct: internally, data is converted to the old format.
121 In principle it could be a good idea to represent the data
122 as a table (2-d array) internally, but the current method
123 seems sufficient and relatively simple...
125 There is a limited ability to save data in tabular:
126 So long as the section_file is constructed in an expected way,
127 tabular data (with no missing or extra values) can be saved
128 in tabular form. (See section_file_save().)
130 - Multiline vectors: if the last non-comment non-whitespace
131 character in a line is a comma, the line is considered to
132 continue on to the next line. Eg:
133 foo = 10,
136 This is equivalent to the original "vector format" example above.
137 Such multi-lines can occur for column headings, vectors, or
138 table rows, again with some potential for strange errors...
140 ***************************************************************************/
142 /**************************************************************************
143 Hashing registry lookups: (by dwp)
144 - Have a hash table direct to entries, bypassing sections division.
145 - For convenience, store the key (the full section+entry name)
146 in the hash table (some memory overhead).
147 - The number of entries is fixed when the hash table is built.
148 - Now uses hash.c
149 **************************************************************************/
151 #ifdef HAVE_CONFIG_H
152 #include <fc_config.h>
153 #endif
155 #include <stdarg.h>
156 #include <stdlib.h>
157 #include <string.h>
159 /* utility */
160 #include "astring.h"
161 #include "bugs.h"
162 #include "deprecations.h"
163 #include "fcintl.h"
164 #include "inputfile.h"
165 #include "ioz.h"
166 #include "log.h"
167 #include "mem.h"
168 #include "registry.h"
169 #include "section_file.h"
170 #include "shared.h"
171 #include "support.h"
173 #include "registry_ini.h"
175 #define MAX_LEN_SECPATH 1024
177 /* Set to FALSE for old-style savefiles. */
178 #define SAVE_TABLES TRUE
180 #define SPECVEC_TAG astring
181 #include "specvec.h"
183 static inline bool entry_used(const struct entry *pentry);
184 static inline void entry_use(struct entry *pentry);
186 static void entry_to_file(const struct entry *pentry, fz_FILE *fs);
187 static void entry_from_inf_token(struct section *psection, const char *name,
188 const char *tok, struct inputfile *file);
190 /* An 'entry' is a string, integer, boolean or string vector;
191 * See enum entry_type in registry.h.
193 struct entry {
194 struct section *psection; /* Parent section. */
195 char *name; /* Name, not including section prefix. */
196 enum entry_type type; /* The type of the entry. */
197 int used; /* Number of times entry looked up. */
198 char *comment; /* Comment, may be NULL. */
200 union {
201 /* ENTRY_BOOL */
202 struct {
203 bool value;
204 } boolean;
205 /* ENTRY_INT */
206 struct {
207 int value;
208 } integer;
209 /* ENTRY_FLOAT */
210 struct {
211 float value;
212 } floating;
213 /* ENTRY_STR */
214 struct {
215 char *value; /* Malloced string. */
216 bool escaped; /* " or $. Usually TRUE */
217 bool raw; /* Do not add anything. */
218 bool gt_marking; /* Save with gettext marking. */
219 } string;
223 static struct entry *section_entry_filereference_new(struct section *psection,
224 const char *name, const char *value);
226 /***************************************************************************
227 Simplification of fileinfoname().
228 ***************************************************************************/
229 static const char *datafilename(const char *filename)
231 return fileinfoname(get_data_dirs(), filename);
234 /**************************************************************************
235 Ensure name is correct to use it as section or entry name.
236 **************************************************************************/
237 static bool is_secfile_entry_name_valid(const char *name)
239 static const char *const allowed = "_.,-[]";
241 while ('\0' != *name) {
242 if (!fc_isalnum(*name) && NULL == strchr(allowed, *name)) {
243 return FALSE;
245 name++;
247 return TRUE;
250 /**************************************************************************
251 Insert an entry into the hash table. Returns TRUE on success.
252 **************************************************************************/
253 static bool secfile_hash_insert(struct section_file *secfile,
254 struct entry *pentry)
256 char buf[256];
257 struct entry *hentry;
259 if (NULL == secfile->hash.entries) {
260 /* Consider as success if this secfile doesn't have built the entries
261 * hash table. */
262 return TRUE;
265 entry_path(pentry, buf, sizeof(buf));
266 if (entry_hash_replace_full(secfile->hash.entries, buf, pentry,
267 NULL, &hentry)) {
268 entry_use(hentry);
269 if (!secfile->allow_duplicates) {
270 SECFILE_LOG(secfile, entry_section(hentry),
271 "Tried to insert same value twice: %s", buf);
272 return FALSE;
276 return TRUE;
279 /**************************************************************************
280 Delete an entry from the hash table. Returns TRUE on success.
281 **************************************************************************/
282 static bool secfile_hash_delete(struct section_file *secfile,
283 struct entry *pentry)
285 char buf[256];
287 if (NULL == secfile->hash.entries) {
288 /* Consider as success if this secfile doesn't have built the entries
289 * hash table. */
290 return TRUE;
293 entry_path(pentry, buf, sizeof(buf));
294 return entry_hash_remove(secfile->hash.entries, buf);
297 /**************************************************************************
298 Base function to load a section file. Note it closes the inputfile.
299 **************************************************************************/
300 static struct section_file *secfile_from_input_file(struct inputfile *inf,
301 const char *filename,
302 const char *section,
303 bool allow_duplicates)
305 struct section_file *secfile;
306 struct section *psection = NULL;
307 struct section *single_section = NULL;
308 bool table_state = FALSE; /* TRUE when within tabular format. */
309 int table_lineno = 0; /* Row number in tabular, 0 top data row. */
310 const char *tok;
311 int i;
312 struct astring base_name = ASTRING_INIT; /* for table or single entry */
313 struct astring field_name = ASTRING_INIT;
314 struct astring_vector columns; /* astrings for column headings */
315 bool found_my_section = FALSE;
316 bool error = FALSE;
318 if (!inf) {
319 return NULL;
322 /* Assign the real value later, to speed up the creation of new entries. */
323 secfile = secfile_new(TRUE);
324 if (filename) {
325 secfile->name = fc_strdup(filename);
326 } else {
327 secfile->name = NULL;
330 astring_vector_init(&columns);
332 if (filename) {
333 log_verbose("Reading registry from \"%s\"", filename);
334 } else {
335 log_verbose("Reading registry");
338 while (!inf_at_eof(inf)) {
339 if (inf_token(inf, INF_TOK_EOL)) {
340 continue;
342 if (inf_at_eof(inf)) {
343 /* may only realise at eof after trying to read eol above */
344 break;
346 tok = inf_token(inf, INF_TOK_SECTION_NAME);
347 if (tok) {
348 if (found_my_section) {
349 /* This shortcut will stop any further loading after the requested
350 * section has been loaded (i.e., at the start of a new section).
351 * This is needed to make the behavior useful, since the whole
352 * purpose is to short-cut further loading of the file. However
353 * normally a section may be split up, and that will no longer
354 * work here because it will be short-cut. */
355 SECFILE_LOG(secfile, psection, "%s",
356 inf_log_str(inf, "Found requested section; finishing"));
357 goto END;
359 if (table_state) {
360 SECFILE_LOG(secfile, psection, "%s",
361 inf_log_str(inf, "New section during table"));
362 error = TRUE;
363 goto END;
365 /* Check if we already have a section with this name.
366 (Could ignore this and have a duplicate sections internally,
367 but then secfile_get_secnames_prefix would return duplicates.)
368 Duplicate section in input are likely to be useful for includes.
370 psection = secfile_section_by_name(secfile, tok);
371 if (!psection) {
372 if (!section || strcmp(tok, section) == 0) {
373 psection = secfile_section_new(secfile, tok);
374 if (section) {
375 single_section = psection;
376 found_my_section = TRUE;
380 if (!inf_token(inf, INF_TOK_EOL)) {
381 SECFILE_LOG(secfile, psection, "%s",
382 inf_log_str(inf, "Expected end of line"));
383 error = TRUE;
384 goto END;
386 continue;
388 if (inf_token(inf, INF_TOK_TABLE_END)) {
389 if (!table_state) {
390 SECFILE_LOG(secfile, psection, "%s",
391 inf_log_str(inf, "Misplaced \"}\""));
392 error = TRUE;
393 goto END;
395 if (!inf_token(inf, INF_TOK_EOL)) {
396 SECFILE_LOG(secfile, psection, "%s",
397 inf_log_str(inf, "Expected end of line"));
398 error = TRUE;
399 goto END;
401 table_state = FALSE;
402 continue;
404 if (table_state) {
405 i = -1;
406 do {
407 int num_columns = astring_vector_size(&columns);
409 i++;
410 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
411 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
412 SECFILE_LOG(secfile, psection, "%s",
413 inf_log_str(inf, "Expected value"));
414 error = TRUE;
415 goto END;
418 if (i < num_columns) {
419 astr_set(&field_name, "%s%d.%s", astr_str(&base_name),
420 table_lineno, astr_str(&columns.p[i]));
421 } else {
422 astr_set(&field_name, "%s%d.%s,%d", astr_str(&base_name),
423 table_lineno, astr_str(&columns.p[num_columns - 1]),
424 (int) (i - num_columns + 1));
426 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
427 } while (inf_token(inf, INF_TOK_COMMA));
429 if (!inf_token(inf, INF_TOK_EOL)) {
430 SECFILE_LOG(secfile, psection, "%s",
431 inf_log_str(inf, "Expected end of line"));
432 error = TRUE;
433 goto END;
435 table_lineno++;
436 continue;
439 if (!(tok = inf_token(inf, INF_TOK_ENTRY_NAME))) {
440 SECFILE_LOG(secfile, psection, "%s",
441 inf_log_str(inf, "Expected entry name"));
442 error = TRUE;
443 goto END;
446 /* need to store tok before next calls: */
447 astr_set(&base_name, "%s", tok);
449 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
451 if (inf_token(inf, INF_TOK_TABLE_START)) {
452 i = -1;
453 do {
454 i++;
455 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
456 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
457 SECFILE_LOG(secfile, psection, "%s",
458 inf_log_str(inf, "Expected value"));
459 error = TRUE;
460 goto END;
462 if (tok[0] != '\"') {
463 SECFILE_LOG(secfile, psection, "%s",
464 inf_log_str(inf, "Table column header non-string"));
465 error = TRUE;
466 goto END;
468 { /* expand columns: */
469 int j, n_prev;
470 n_prev = astring_vector_size(&columns);
471 for (j = i + 1; j < n_prev; j++) {
472 astr_free(&columns.p[j]);
474 astring_vector_reserve(&columns, i + 1);
475 for (j = n_prev; j < i + 1; j++) {
476 astr_init(&columns.p[j]);
479 astr_set(&columns.p[i], "%s", tok + 1);
481 } while (inf_token(inf, INF_TOK_COMMA));
483 if (!inf_token(inf, INF_TOK_EOL)) {
484 SECFILE_LOG(secfile, psection, "%s",
485 inf_log_str(inf, "Expected end of line"));
486 error = TRUE;
487 goto END;
489 table_state = TRUE;
490 table_lineno = 0;
491 continue;
493 /* ordinary value: */
494 i = -1;
495 do {
496 i++;
497 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
498 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
499 SECFILE_LOG(secfile, psection, "%s",
500 inf_log_str(inf, "Expected value"));
501 error = TRUE;
502 goto END;
504 if (i == 0) {
505 entry_from_inf_token(psection, astr_str(&base_name), tok, inf);
506 } else {
507 astr_set(&field_name, "%s,%d", astr_str(&base_name), i);
508 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
510 } while (inf_token(inf, INF_TOK_COMMA));
511 if (!inf_token(inf, INF_TOK_EOL)) {
512 SECFILE_LOG(secfile, psection, "%s",
513 inf_log_str(inf, "Expected end of line"));
514 error = TRUE;
515 goto END;
519 if (table_state) {
520 SECFILE_LOG(secfile, psection,
521 "Finished registry before end of table");
522 error = TRUE;
525 END:
526 inf_close(inf);
527 astr_free(&base_name);
528 astr_free(&field_name);
529 for (i = 0; i < astring_vector_size(&columns); i++) {
530 astr_free(&columns.p[i]);
532 astring_vector_free(&columns);
534 if (section != NULL) {
535 if (!found_my_section) {
536 secfile_destroy(secfile);
537 return NULL;
540 /* Build the entry hash table with single section information */
541 secfile->allow_duplicates = allow_duplicates;
542 entry_list_iterate(section_entries(single_section), pentry) {
543 if (!secfile_hash_insert(secfile, pentry)) {
544 secfile_destroy(secfile);
545 return NULL;
547 } entry_list_iterate_end;
549 return secfile;
552 if (!error) {
553 /* Build the entry hash table. */
554 secfile->allow_duplicates = allow_duplicates;
555 secfile->hash.entries = entry_hash_new_nentries(secfile->num_entries);
557 section_list_iterate(secfile->sections, hashing_section) {
558 entry_list_iterate(section_entries(hashing_section), pentry) {
559 if (!secfile_hash_insert(secfile, pentry)) {
560 error = TRUE;
561 break;
563 } entry_list_iterate_end;
564 if (error) {
565 break;
567 } section_list_iterate_end;
569 if (error) {
570 secfile_destroy(secfile);
571 return NULL;
572 } else {
573 return secfile;
577 /**************************************************************************
578 Create a section file from a file, read only one particular section.
579 Returns NULL on error.
580 **************************************************************************/
581 struct section_file *secfile_load_section(const char *filename,
582 const char *section,
583 bool allow_duplicates)
585 char real_filename[1024];
587 interpret_tilde(real_filename, sizeof(real_filename), filename);
588 return secfile_from_input_file(inf_from_file(real_filename, datafilename),
589 filename, section, allow_duplicates);
592 /**************************************************************************
593 Create a section file from a stream. Returns NULL on error.
594 **************************************************************************/
595 struct section_file *secfile_from_stream(fz_FILE *stream,
596 bool allow_duplicates)
598 return secfile_from_input_file(inf_from_stream(stream, datafilename),
599 NULL, NULL, allow_duplicates);
602 /**************************************************************************
603 Returns TRUE iff the character is legal in a table entry name.
604 **************************************************************************/
605 static bool is_legal_table_entry_name(char c, bool num)
607 return (num ? fc_isalnum(c) : fc_isalpha(c)) || c == '_';
610 /**************************************************************************
611 Save the previously filled in section_file to disk.
613 There is now limited ability to save in the new tabular format
614 (to give smaller savefiles).
615 The start of a table is detected by an entry with name of the form:
616 (alphabetical_component)(zero)(period)(alphanumeric_component)
617 Eg: u0.id, or c0.id, in the freeciv savefile.
618 The alphabetical component is taken as the "name" of the table,
619 and the component after the period as the first column name.
620 This should be followed by the other column values for u0,
621 and then subsequent u1, u2, etc, in strict order with no omissions,
622 and with all of the columns for all uN in the same order as for u0.
624 If compression_level is non-zero, then compress using zlib. (Should
625 only supply non-zero compression_level if already know that FREECIV_HAVE_LIBZ.)
626 Below simply specifies FZ_ZLIB method, since fz_fromFile() automatically
627 changes to FZ_PLAIN method when level == 0.
628 **************************************************************************/
629 bool secfile_save(const struct section_file *secfile, const char *filename,
630 int compression_level, enum fz_method compression_method)
632 char real_filename[1024];
633 char pentry_name[128];
634 const char *col_entry_name;
635 fz_FILE *fs;
636 const struct entry_list_link *ent_iter, *save_iter, *col_iter;
637 struct entry *pentry, *col_pentry;
638 int i;
640 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
642 if (NULL == filename) {
643 filename = secfile->name;
646 interpret_tilde(real_filename, sizeof(real_filename), filename);
647 fs = fz_from_file(real_filename, "w",
648 compression_method, compression_level);
650 if (!fs) {
651 SECFILE_LOG(secfile, NULL, _("Could not open %s for writing"), real_filename);
653 return FALSE;
656 section_list_iterate(secfile->sections, psection) {
657 if (psection->special == EST_INCLUDE) {
658 for (ent_iter = entry_list_head(section_entries(psection));
659 ent_iter && (pentry = entry_list_link_data(ent_iter));
660 ent_iter = entry_list_link_next(ent_iter)) {
662 fc_assert(!strcmp(entry_name(pentry), "file"));
664 fz_fprintf(fs, "*include ");
665 entry_to_file(pentry, fs);
666 fz_fprintf(fs, "\n");
668 } else if (psection->special == EST_COMMENT) {
669 for (ent_iter = entry_list_head(section_entries(psection));
670 ent_iter && (pentry = entry_list_link_data(ent_iter));
671 ent_iter = entry_list_link_next(ent_iter)) {
673 fc_assert(!strcmp(entry_name(pentry), "comment"));
675 entry_to_file(pentry, fs);
676 fz_fprintf(fs, "\n");
678 } else {
679 fz_fprintf(fs, "\n[%s]\n", section_name(psection));
681 /* Following doesn't use entry_list_iterate() because we want to do
682 * tricky things with the iterators...
684 for (ent_iter = entry_list_head(section_entries(psection));
685 ent_iter && (pentry = entry_list_link_data(ent_iter));
686 ent_iter = entry_list_link_next(ent_iter)) {
687 const char *comment;
689 /* Tables: break out of this loop if this is a non-table
690 * entry (pentry and ent_iter unchanged) or after table (pentry
691 * and ent_iter suitably updated, pentry possibly NULL).
692 * After each table, loop again in case the next entry
693 * is another table.
695 for (;;) {
696 char *c, *first, base[64];
697 int offset, irow, icol, ncol;
699 /* Example: for first table name of "xyz0.blah":
700 * first points to the original string pentry->name
701 * base contains "xyz";
702 * offset = 5 (so first+offset gives "blah")
703 * note strlen(base) = offset - 2
706 if (!SAVE_TABLES) {
707 break;
710 sz_strlcpy(pentry_name, entry_name(pentry));
711 c = first = pentry_name;
712 if (*c == '\0' || !is_legal_table_entry_name(*c, FALSE)) {
713 break;
715 for (; *c != '\0' && is_legal_table_entry_name(*c, FALSE); c++) {
716 /* nothing */
718 if (0 != strncmp(c, "0.", 2)) {
719 break;
721 c += 2;
722 if (*c == '\0' || !is_legal_table_entry_name(*c, TRUE)) {
723 break;
726 offset = c - first;
727 first[offset - 2] = '\0';
728 sz_strlcpy(base, first);
729 first[offset - 2] = '0';
730 fz_fprintf(fs, "%s={", base);
732 /* Save an iterator at this first entry, which we can later use
733 * to repeatedly iterate over column names:
735 save_iter = ent_iter;
737 /* write the column names, and calculate ncol: */
738 ncol = 0;
739 col_iter = save_iter;
740 for (; (col_pentry = entry_list_link_data(col_iter));
741 col_iter = entry_list_link_next(col_iter)) {
742 col_entry_name = entry_name(col_pentry);
743 if (strncmp(col_entry_name, first, offset) != 0) {
744 break;
746 fz_fprintf(fs, "%s\"%s\"", (ncol == 0 ? "" : ","),
747 col_entry_name + offset);
748 ncol++;
750 fz_fprintf(fs, "\n");
752 /* Iterate over rows and columns, incrementing ent_iter as we go,
753 * and writing values to the table. Have a separate iterator
754 * to the column names to check they all match.
756 irow = icol = 0;
757 col_iter = save_iter;
758 for (;;) {
759 char expect[128]; /* pentry->name we're expecting */
761 pentry = entry_list_link_data(ent_iter);
762 col_pentry = entry_list_link_data(col_iter);
764 fc_snprintf(expect, sizeof(expect), "%s%d.%s",
765 base, irow, entry_name(col_pentry) + offset);
767 /* break out of tabular if doesn't match: */
768 if ((!pentry) || (strcmp(entry_name(pentry), expect) != 0)) {
769 if (icol != 0) {
770 /* If the second or later row of a table is missing some
771 * entries that the first row had, we drop out of the tabular
772 * format. This is inefficient so we print a warning message;
773 * the calling code probably needs to be fixed so that it can
774 * use the more efficient tabular format.
776 * FIXME: If the first row is missing some entries that the
777 * second or later row has, then we'll drop out of tabular
778 * format without an error message. */
779 bugreport_request("In file %s, there is no entry in the registry for\n"
780 "%s.%s (or the entries are out of order). This means\n"
781 "a less efficient non-tabular format will be used.\n"
782 "To avoid this make sure all rows of a table are\n"
783 "filled out with an entry for every column.",
784 real_filename, section_name(psection), expect);
785 fz_fprintf(fs, "\n");
787 fz_fprintf(fs, "}\n");
788 break;
791 if (icol > 0) {
792 fz_fprintf(fs, ",");
794 entry_to_file(pentry, fs);
796 ent_iter = entry_list_link_next(ent_iter);
797 col_iter = entry_list_link_next(col_iter);
799 icol++;
800 if (icol == ncol) {
801 fz_fprintf(fs, "\n");
802 irow++;
803 icol = 0;
804 col_iter = save_iter;
807 if (!pentry) {
808 break;
811 if (!pentry) {
812 break;
815 /* Classic entry. */
816 col_entry_name = entry_name(pentry);
817 fz_fprintf(fs, "%s=", col_entry_name);
818 entry_to_file(pentry, fs);
820 /* Check for vector. */
821 for (i = 1;; i++) {
822 col_iter = entry_list_link_next(ent_iter);
823 col_pentry = entry_list_link_data(col_iter);
824 if (NULL == col_pentry) {
825 break;
827 fc_snprintf(pentry_name, sizeof(pentry_name),
828 "%s,%d", col_entry_name, i);
829 if (0 != strcmp(pentry_name, entry_name(col_pentry))) {
830 break;
832 fz_fprintf(fs, ",");
833 entry_to_file(col_pentry, fs);
834 ent_iter = col_iter;
837 comment = entry_comment(pentry);
838 if (comment) {
839 fz_fprintf(fs, "#%s\n", comment);
840 } else {
841 fz_fprintf(fs, "\n");
845 } section_list_iterate_end;
847 if (0 != fz_ferror(fs)) {
848 SECFILE_LOG(secfile, NULL, "Error before closing %s: %s",
849 real_filename, fz_strerror(fs));
850 fz_fclose(fs);
851 return FALSE;
853 if (0 != fz_fclose(fs)) {
854 SECFILE_LOG(secfile, NULL, "Error closing %s", real_filename);
855 return FALSE;
858 return TRUE;
861 /**************************************************************************
862 Print log messages for any entries in the file which have
863 not been looked up -- ie, unused or unrecognised entries.
864 To mark an entry as used without actually doing anything with it,
865 you could do something like:
866 section_file_lookup(&file, "foo.bar"); / * unused * /
867 **************************************************************************/
868 void secfile_check_unused(const struct section_file *secfile)
870 bool any = FALSE;
872 section_list_iterate(secfile_sections(secfile), psection) {
873 entry_list_iterate(section_entries(psection), pentry) {
874 if (!entry_used(pentry)) {
875 if (!any && secfile->name) {
876 log_verbose("Unused entries in file %s:", secfile->name);
877 any = TRUE;
879 if (are_deprecation_warnings_enabled()) {
880 log_deprecation_always("%s: unused entry: %s.%s",
881 secfile->name != NULL ? secfile->name : "nameless",
882 section_name(psection), entry_name(pentry));
883 } else {
884 #ifdef FREECIV_TESTMATIC
885 log_testmatic("%s: unused entry: %s.%s",
886 secfile->name != NULL ? secfile->name : "nameless",
887 section_name(psection), entry_name(pentry));
888 #else /* FREECIV_TESTMATIC */
889 log_verbose(" unused entry: %s.%s",
890 section_name(psection), entry_name(pentry));
891 #endif /* FREECIV_TESTMATIC */
894 } entry_list_iterate_end;
895 } section_list_iterate_end;
898 /**************************************************************************
899 Return the filename the section file was loaded as, or "(anonymous)"
900 if this sectionfile was created rather than loaded from file.
901 The memory is managed internally, and should not be altered,
902 nor used after secfile_destroy() called for the section file.
903 **************************************************************************/
904 const char *secfile_name(const struct section_file *secfile)
906 if (NULL == secfile) {
907 return "NULL";
908 } else if (secfile->name) {
909 return secfile->name;
910 } else {
911 return "(anonymous)";
915 /**************************************************************************
916 Seperates the section and entry names. Create the section if missing.
917 **************************************************************************/
918 static struct section *secfile_insert_base(struct section_file *secfile,
919 const char *path,
920 const char **pent_name)
922 char fullpath[MAX_LEN_SECPATH];
923 char *ent_name;
924 struct section *psection;
926 sz_strlcpy(fullpath, path);
928 ent_name = strchr(fullpath, '.');
929 if (!ent_name) {
930 SECFILE_LOG(secfile, NULL,
931 "Section and entry names must be separated by a dot.");
932 return NULL;
935 /* Separates section and entry names. */
936 *ent_name = '\0';
937 *pent_name = path + (ent_name - fullpath) + 1;
938 psection = secfile_section_by_name(secfile, fullpath);
939 if (psection) {
940 return psection;
941 } else {
942 return secfile_section_new(secfile, fullpath);
946 /**************************************************************************
947 Insert a boolean entry.
948 **************************************************************************/
949 struct entry *secfile_insert_bool_full(struct section_file *secfile,
950 bool value, const char *comment,
951 bool allow_replace,
952 const char *path, ...)
954 char fullpath[MAX_LEN_SECPATH];
955 const char *ent_name;
956 struct section *psection;
957 struct entry *pentry = NULL;
958 va_list args;
960 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
962 va_start(args, path);
963 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
964 va_end(args);
966 psection = secfile_insert_base(secfile, fullpath, &ent_name);
967 if (!psection) {
968 return NULL;
971 if (allow_replace) {
972 pentry = section_entry_by_name(psection, ent_name);
973 if (NULL != pentry) {
974 if (ENTRY_BOOL == entry_type(pentry)) {
975 if (!entry_bool_set(pentry, value)) {
976 return NULL;
978 } else {
979 entry_destroy(pentry);
980 pentry = NULL;
985 if (NULL == pentry) {
986 pentry = section_entry_bool_new(psection, ent_name, value);
989 if (NULL != pentry && NULL != comment) {
990 entry_set_comment(pentry, comment);
993 return pentry;
996 /**************************************************************************
997 Insert 'dim' boolean entries at 'path,0', 'path,1' etc. Returns
998 the number of entries inserted or replaced.
999 **************************************************************************/
1000 size_t secfile_insert_bool_vec_full(struct section_file *secfile,
1001 const bool *values, size_t dim,
1002 const char *comment, bool allow_replace,
1003 const char *path, ...)
1005 char fullpath[MAX_LEN_SECPATH];
1006 size_t i, ret = 0;
1007 va_list args;
1009 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1011 va_start(args, path);
1012 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1013 va_end(args);
1015 /* NB: 'path,0' is actually 'path'. See comment in the head
1016 * of the file. */
1017 if (dim > 0
1018 && NULL != secfile_insert_bool_full(secfile, values[0], comment,
1019 allow_replace, "%s", fullpath)) {
1020 ret++;
1022 for (i = 1; i < dim; i++) {
1023 if (NULL != secfile_insert_bool_full(secfile, values[i], comment,
1024 allow_replace, "%s,%d",
1025 fullpath, (int) i)) {
1026 ret++;
1030 return ret;
1033 /**************************************************************************
1034 Insert a integer entry.
1035 **************************************************************************/
1036 struct entry *secfile_insert_int_full(struct section_file *secfile,
1037 int value, const char *comment,
1038 bool allow_replace,
1039 const char *path, ...)
1041 char fullpath[MAX_LEN_SECPATH];
1042 const char *ent_name;
1043 struct section *psection;
1044 struct entry *pentry = NULL;
1045 va_list args;
1047 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1049 va_start(args, path);
1050 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1051 va_end(args);
1053 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1054 if (!psection) {
1055 return NULL;
1058 if (allow_replace) {
1059 pentry = section_entry_by_name(psection, ent_name);
1060 if (NULL != pentry) {
1061 if (ENTRY_INT == entry_type(pentry)) {
1062 if (!entry_int_set(pentry, value)) {
1063 return NULL;
1065 } else {
1066 entry_destroy(pentry);
1067 pentry = NULL;
1072 if (NULL == pentry) {
1073 pentry = section_entry_int_new(psection, ent_name, value);
1076 if (NULL != pentry && NULL != comment) {
1077 entry_set_comment(pentry, comment);
1080 return pentry;
1083 /**************************************************************************
1084 Insert 'dim' integer entries at 'path,0', 'path,1' etc. Returns
1085 the number of entries inserted or replaced.
1086 **************************************************************************/
1087 size_t secfile_insert_int_vec_full(struct section_file *secfile,
1088 const int *values, size_t dim,
1089 const char *comment, bool allow_replace,
1090 const char *path, ...)
1092 char fullpath[MAX_LEN_SECPATH];
1093 size_t i, ret = 0;
1094 va_list args;
1096 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1098 va_start(args, path);
1099 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1100 va_end(args);
1102 /* NB: 'path,0' is actually 'path'. See comment in the head
1103 * of the file. */
1104 if (dim > 0
1105 && NULL != secfile_insert_int_full(secfile, values[0], comment,
1106 allow_replace, "%s", fullpath)) {
1107 ret++;
1109 for (i = 1; i < dim; i++) {
1110 if (NULL != secfile_insert_int_full(secfile, values[i], comment,
1111 allow_replace, "%s,%d",
1112 fullpath, (int) i)) {
1113 ret++;
1117 return ret;
1120 /**************************************************************************
1121 Insert a floating entry.
1122 **************************************************************************/
1123 struct entry *secfile_insert_float_full(struct section_file *secfile,
1124 float value, const char *comment,
1125 bool allow_replace,
1126 const char *path, ...)
1128 char fullpath[MAX_LEN_SECPATH];
1129 const char *ent_name;
1130 struct section *psection;
1131 struct entry *pentry = NULL;
1132 va_list args;
1134 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1136 va_start(args, path);
1137 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1138 va_end(args);
1140 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1141 if (!psection) {
1142 return NULL;
1145 if (allow_replace) {
1146 pentry = section_entry_by_name(psection, ent_name);
1147 if (NULL != pentry) {
1148 if (ENTRY_FLOAT == entry_type(pentry)) {
1149 if (!entry_float_set(pentry, value)) {
1150 return NULL;
1152 } else {
1153 entry_destroy(pentry);
1154 pentry = NULL;
1159 if (NULL == pentry) {
1160 pentry = section_entry_float_new(psection, ent_name, value);
1163 if (NULL != pentry && NULL != comment) {
1164 entry_set_comment(pentry, comment);
1167 return pentry;
1170 /**************************************************************************
1171 Insert a include entry.
1172 **************************************************************************/
1173 struct section *secfile_insert_include(struct section_file *secfile,
1174 const char *filename)
1176 struct section *psection;
1177 char buffer[200];
1179 fc_snprintf(buffer, sizeof(buffer), "include_%u", secfile->num_includes++);
1181 fc_assert_ret_val(secfile_section_by_name(secfile, buffer) == NULL, NULL);
1183 /* Create include section. */
1184 psection = secfile_section_new(secfile, buffer);
1185 psection->special = EST_INCLUDE;
1187 /* Then add string entry "file" to it. */
1188 secfile_insert_str_full(secfile, filename, NULL, FALSE, FALSE,
1189 EST_INCLUDE, "%s.file", buffer);
1191 return psection;
1194 /**************************************************************************
1195 Insert a long comment entry.
1196 **************************************************************************/
1197 struct section *secfile_insert_long_comment(struct section_file *secfile,
1198 const char *comment)
1200 struct section *psection;
1201 char buffer[200];
1203 fc_snprintf(buffer, sizeof(buffer), "long_comment_%u", secfile->num_long_comments++);
1205 fc_assert_ret_val(secfile_section_by_name(secfile, buffer) == NULL, NULL);
1207 /* Create long comment section. */
1208 psection = secfile_section_new(secfile, buffer);
1209 psection->special = EST_COMMENT;
1211 /* Then add string entry "comment" to it. */
1212 secfile_insert_str_full(secfile, comment, NULL, FALSE, TRUE,
1213 EST_COMMENT, "%s.comment", buffer);
1215 return psection;
1218 /**************************************************************************
1219 Insert a string entry.
1220 **************************************************************************/
1221 struct entry *secfile_insert_str_full(struct section_file *secfile,
1222 const char *str,
1223 const char *comment,
1224 bool allow_replace,
1225 bool no_escape,
1226 enum entry_special_type stype,
1227 const char *path, ...)
1229 char fullpath[MAX_LEN_SECPATH];
1230 const char *ent_name;
1231 struct section *psection;
1232 struct entry *pentry = NULL;
1233 va_list args;
1235 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1237 va_start(args, path);
1238 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1239 va_end(args);
1241 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1242 if (!psection) {
1243 return NULL;
1246 if (psection->special != stype) {
1247 log_error("Tried to insert wrong type of entry to section");
1248 return NULL;
1251 if (allow_replace) {
1252 pentry = section_entry_by_name(psection, ent_name);
1253 if (NULL != pentry) {
1254 if (ENTRY_STR == entry_type(pentry)) {
1255 if (!entry_str_set(pentry, str)) {
1256 return NULL;
1258 } else {
1259 entry_destroy(pentry);
1260 pentry = NULL;
1265 if (NULL == pentry) {
1266 pentry = section_entry_str_new(psection, ent_name, str, !no_escape);
1269 if (NULL != pentry && NULL != comment) {
1270 entry_set_comment(pentry, comment);
1273 if (stype == EST_COMMENT) {
1274 pentry->string.raw = TRUE;
1277 return pentry;
1280 /**************************************************************************
1281 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1282 the number of entries inserted or replaced.
1283 **************************************************************************/
1284 size_t secfile_insert_str_vec_full(struct section_file *secfile,
1285 const char *const *strings, size_t dim,
1286 const char *comment, bool allow_replace,
1287 bool no_escape, const char *path, ...)
1289 char fullpath[MAX_LEN_SECPATH];
1290 size_t i, ret = 0;
1291 va_list args;
1293 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1295 va_start(args, path);
1296 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1297 va_end(args);
1299 /* NB: 'path,0' is actually 'path'. See comment in the head
1300 * of the file. */
1301 if (dim > 0
1302 && NULL != secfile_insert_str_full(secfile, strings[0], comment,
1303 allow_replace, no_escape, FALSE,
1304 "%s", fullpath)) {
1305 ret++;
1307 for (i = 1; i < dim; i++) {
1308 if (NULL != secfile_insert_str_full(secfile, strings[i], comment,
1309 allow_replace, no_escape, FALSE,
1310 "%s,%d", fullpath, (int) i)) {
1311 ret++;
1315 return ret;
1318 /****************************************************************************
1319 Insert a read-from-a-file string entry
1320 ****************************************************************************/
1321 struct entry *secfile_insert_filereference(struct section_file *secfile,
1322 char *filename, char *path, ...)
1324 char fullpath[MAX_LEN_SECPATH];
1325 const char *ent_name;
1326 struct section *psection;
1327 struct entry *pentry = NULL;
1328 va_list args;
1330 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1332 va_start(args, path);
1333 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1334 va_end(args);
1336 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1337 if (!psection) {
1338 return NULL;
1341 if (psection->special != EST_NORMAL) {
1342 log_error("Tried to insert normal entry to different kind of section");
1343 return NULL;
1346 if (NULL == pentry) {
1347 pentry = section_entry_filereference_new(psection, ent_name, filename);
1350 return pentry;
1353 /****************************************************************************
1354 Insert a enumerator entry.
1355 ****************************************************************************/
1356 struct entry *secfile_insert_plain_enum_full(struct section_file *secfile,
1357 int enumerator,
1358 secfile_enum_name_fn_t name_fn,
1359 const char *comment,
1360 bool allow_replace,
1361 const char *path, ...)
1363 char fullpath[MAX_LEN_SECPATH];
1364 const char *str;
1365 const char *ent_name;
1366 struct section *psection;
1367 struct entry *pentry = NULL;
1368 va_list args;
1370 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1371 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1372 str = name_fn(enumerator);
1373 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != str, NULL);
1375 va_start(args, path);
1376 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1377 va_end(args);
1379 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1380 if (!psection) {
1381 return NULL;
1384 if (allow_replace) {
1385 pentry = section_entry_by_name(psection, ent_name);
1386 if (NULL != pentry) {
1387 if (ENTRY_STR == entry_type(pentry)) {
1388 if (!entry_str_set(pentry, str)) {
1389 return NULL;
1391 } else {
1392 entry_destroy(pentry);
1393 pentry = NULL;
1398 if (NULL == pentry) {
1399 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1402 if (NULL != pentry && NULL != comment) {
1403 entry_set_comment(pentry, comment);
1406 return pentry;
1409 /****************************************************************************
1410 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1411 the number of entries inserted or replaced.
1412 ****************************************************************************/
1413 size_t secfile_insert_plain_enum_vec_full(struct section_file *secfile,
1414 const int *enumurators, size_t dim,
1415 secfile_enum_name_fn_t name_fn,
1416 const char *comment,
1417 bool allow_replace,
1418 const char *path, ...)
1420 char fullpath[MAX_LEN_SECPATH];
1421 size_t i, ret = 0;
1422 va_list args;
1424 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1425 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1427 va_start(args, path);
1428 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1429 va_end(args);
1431 /* NB: 'path,0' is actually 'path'. See comment in the head
1432 * of the file. */
1433 if (dim > 0
1434 && NULL != secfile_insert_plain_enum_full(secfile, enumurators[0],
1435 name_fn, comment,
1436 allow_replace, "%s",
1437 fullpath)) {
1438 ret++;
1440 for (i = 1; i < dim; i++) {
1441 if (NULL != secfile_insert_plain_enum_full(secfile, enumurators[i],
1442 name_fn, comment,
1443 allow_replace, "%s,%d",
1444 fullpath, (int) i)) {
1445 ret++;
1449 return ret;
1452 /****************************************************************************
1453 Insert a bitwise value entry.
1454 ****************************************************************************/
1455 struct entry *secfile_insert_bitwise_enum_full(struct section_file *secfile,
1456 int bitwise_val,
1457 secfile_enum_name_fn_t
1458 name_fn,
1459 secfile_enum_iter_fn_t
1460 begin_fn,
1461 secfile_enum_iter_fn_t
1462 end_fn,
1463 secfile_enum_next_fn_t
1464 next_fn,
1465 const char *comment,
1466 bool allow_replace,
1467 const char *path, ...)
1469 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1470 const char *ent_name;
1471 struct section *psection;
1472 struct entry *pentry = NULL;
1473 va_list args;
1474 int i;
1476 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1477 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1478 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, NULL);
1479 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, NULL);
1480 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, NULL);
1482 /* Compute a string containing all the values separated by '|'. */
1483 str[0] = '\0'; /* Insert at least an empty string. */
1484 if (0 != bitwise_val) {
1485 for (i = begin_fn(); i != end_fn(); i = next_fn(i)) {
1486 if (i & bitwise_val) {
1487 if ('\0' == str[0]) {
1488 sz_strlcpy(str, name_fn(i));
1489 } else {
1490 cat_snprintf(str, sizeof(str), "|%s", name_fn(i));
1496 va_start(args, path);
1497 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1498 va_end(args);
1500 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1501 if (!psection) {
1502 return NULL;
1505 if (allow_replace) {
1506 pentry = section_entry_by_name(psection, ent_name);
1507 if (NULL != pentry) {
1508 if (ENTRY_STR == entry_type(pentry)) {
1509 if (!entry_str_set(pentry, str)) {
1510 return NULL;
1512 } else {
1513 entry_destroy(pentry);
1514 pentry = NULL;
1519 if (NULL == pentry) {
1520 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1523 if (NULL != pentry && NULL != comment) {
1524 entry_set_comment(pentry, comment);
1527 return pentry;
1530 /****************************************************************************
1531 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1532 the number of entries inserted or replaced.
1533 ****************************************************************************/
1534 size_t secfile_insert_bitwise_enum_vec_full(struct section_file *secfile,
1535 const int *bitwise_vals,
1536 size_t dim,
1537 secfile_enum_name_fn_t name_fn,
1538 secfile_enum_iter_fn_t begin_fn,
1539 secfile_enum_iter_fn_t end_fn,
1540 secfile_enum_next_fn_t next_fn,
1541 const char *comment,
1542 bool allow_replace,
1543 const char *path, ...)
1545 char fullpath[MAX_LEN_SECPATH];
1546 size_t i, ret = 0;
1547 va_list args;
1549 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1550 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1551 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, 0);
1552 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, 0);
1553 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, 0);
1555 va_start(args, path);
1556 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1557 va_end(args);
1559 /* NB: 'path,0' is actually 'path'. See comment in the head
1560 * of the file. */
1561 if (dim > 0
1562 && NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[0],
1563 name_fn, begin_fn, end_fn,
1564 next_fn, comment,
1565 allow_replace, "%s",
1566 fullpath)) {
1567 ret++;
1569 for (i = 1; i < dim; i++) {
1570 if (NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[i],
1571 name_fn, begin_fn, end_fn,
1572 next_fn, comment,
1573 allow_replace, "%s,%d",
1574 fullpath, (int) i)) {
1575 ret++;
1579 return ret;
1582 /****************************************************************************
1583 Insert an enumerator value entry that we only have a name accessor
1584 function.
1585 ****************************************************************************/
1586 struct entry *secfile_insert_enum_data_full(struct section_file *secfile,
1587 int value, bool bitwise,
1588 secfile_enum_name_data_fn_t name_fn,
1589 secfile_data_t data,
1590 const char *comment,
1591 bool allow_replace,
1592 const char *path, ...)
1594 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1595 const char *ent_name, *val_name;
1596 struct section *psection;
1597 struct entry *pentry = NULL;
1598 va_list args;
1599 int i;
1601 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1602 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1604 if (bitwise) {
1605 /* Compute a string containing all the values separated by '|'. */
1606 str[0] = '\0'; /* Insert at least an empty string. */
1607 if (0 != value) {
1608 for (i = 0; (val_name = name_fn(data, i)); i++) {
1609 if ((1 << i) & value) {
1610 if ('\0' == str[0]) {
1611 sz_strlcpy(str, val_name);
1612 } else {
1613 cat_snprintf(str, sizeof(str), "|%s", val_name);
1618 } else {
1619 if (!(val_name = name_fn(data, value))) {
1620 SECFILE_LOG(secfile, NULL, "Value %d not supported.", value);
1621 return NULL;
1623 sz_strlcpy(str, val_name);
1626 va_start(args, path);
1627 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1628 va_end(args);
1630 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1631 if (!psection) {
1632 return NULL;
1635 if (allow_replace) {
1636 pentry = section_entry_by_name(psection, ent_name);
1637 if (NULL != pentry) {
1638 if (ENTRY_STR == entry_type(pentry)) {
1639 if (!entry_str_set(pentry, str)) {
1640 return NULL;
1642 } else {
1643 entry_destroy(pentry);
1644 pentry = NULL;
1649 if (NULL == pentry) {
1650 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1653 if (NULL != pentry && NULL != comment) {
1654 entry_set_comment(pentry, comment);
1657 return pentry;
1660 /****************************************************************************
1661 Insert 'dim' entries at 'path,0', 'path,1' etc. Returns the number of
1662 entries inserted or replaced.
1663 ****************************************************************************/
1664 size_t secfile_insert_enum_vec_data_full(struct section_file *secfile,
1665 const int *values, size_t dim,
1666 bool bitwise,
1667 secfile_enum_name_data_fn_t name_fn,
1668 secfile_data_t data,
1669 const char *comment,
1670 bool allow_replace,
1671 const char *path, ...)
1673 char fullpath[MAX_LEN_SECPATH];
1674 size_t i, ret = 0;
1675 va_list args;
1677 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1678 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1680 va_start(args, path);
1681 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1682 va_end(args);
1684 /* NB: 'path,0' is actually 'path'. See comment in the head
1685 * of the file. */
1686 if (dim > 0
1687 && NULL != secfile_insert_enum_data_full(secfile, values[0], bitwise,
1688 name_fn, data, comment,
1689 allow_replace, "%s",
1690 fullpath)) {
1691 ret++;
1693 for (i = 1; i < dim; i++) {
1694 if (NULL != secfile_insert_enum_data_full(secfile, values[i], bitwise,
1695 name_fn, data, comment,
1696 allow_replace, "%s,%d",
1697 fullpath, (int) i)) {
1698 ret++;
1702 return ret;
1705 /****************************************************************************
1706 Returns the entry by the name or NULL if not matched.
1707 ****************************************************************************/
1708 struct entry *secfile_entry_by_path(const struct section_file *secfile,
1709 const char *path)
1711 char fullpath[MAX_LEN_SECPATH];
1712 char *ent_name;
1713 size_t len;
1714 struct section *psection;
1716 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1718 sz_strlcpy(fullpath, path);
1720 /* treat "sec.foo,0" as "sec.foo": */
1721 len = strlen(fullpath);
1722 if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1723 fullpath[len - 2] = '\0';
1726 if (NULL != secfile->hash.entries) {
1727 struct entry *pentry;
1729 if (entry_hash_lookup(secfile->hash.entries, fullpath, &pentry)) {
1730 entry_use(pentry);
1732 return pentry;
1735 /* I dont like strtok.
1736 * - Me neither! */
1737 ent_name = strchr(fullpath, '.');
1738 if (!ent_name) {
1739 return NULL;
1742 /* Separates section and entry names. */
1743 *ent_name++ = '\0';
1744 psection = secfile_section_by_name(secfile, fullpath);
1745 if (psection) {
1746 return section_entry_by_name(psection, ent_name);
1747 } else {
1748 return NULL;
1752 /**************************************************************************
1753 Delete an entry.
1754 **************************************************************************/
1755 bool secfile_entry_delete(struct section_file *secfile,
1756 const char *path, ...)
1758 char fullpath[MAX_LEN_SECPATH];
1759 va_list args;
1760 struct entry *pentry;
1762 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1764 va_start(args, path);
1765 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1766 va_end(args);
1768 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1769 SECFILE_LOG(secfile, NULL, "Path %s does not exists.", fullpath);
1770 return FALSE;
1773 entry_destroy(pentry);
1775 return TRUE;
1778 /**************************************************************************
1779 Returns the entry at "fullpath" or NULL if not matched.
1780 **************************************************************************/
1781 struct entry *secfile_entry_lookup(const struct section_file *secfile,
1782 const char *path, ...)
1784 char fullpath[MAX_LEN_SECPATH];
1785 va_list args;
1787 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1789 va_start(args, path);
1790 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1791 va_end(args);
1793 return secfile_entry_by_path(secfile, fullpath);
1796 /**************************************************************************
1797 Lookup a boolean value in the secfile. Returns TRUE on success.
1798 **************************************************************************/
1799 bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1800 const char *path, ...)
1802 char fullpath[MAX_LEN_SECPATH];
1803 const struct entry *pentry;
1804 va_list args;
1806 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1808 va_start(args, path);
1809 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1810 va_end(args);
1812 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1813 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1814 return FALSE;
1817 return entry_bool_get(pentry, bval);
1820 /**************************************************************************
1821 Lookup a boolean value in the secfile. On failure, use the default
1822 value.
1823 **************************************************************************/
1824 bool secfile_lookup_bool_default(const struct section_file *secfile,
1825 bool def, const char *path, ...)
1827 char fullpath[MAX_LEN_SECPATH];
1828 const struct entry *pentry;
1829 bool bval;
1830 va_list args;
1832 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1834 va_start(args, path);
1835 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1836 va_end(args);
1838 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1839 return def;
1842 if (entry_bool_get(pentry, &bval)) {
1843 return bval;
1846 return def;
1849 /**************************************************************************
1850 Lookup a boolean vector in the secfile. Returns NULL on error. This
1851 vector is not owned by the registry module, and should be free by the
1852 user.
1853 **************************************************************************/
1854 bool *secfile_lookup_bool_vec(const struct section_file *secfile,
1855 size_t *dim, const char *path, ...)
1857 char fullpath[MAX_LEN_SECPATH];
1858 size_t i = 0;
1859 bool *vec;
1860 va_list args;
1862 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1863 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
1865 va_start(args, path);
1866 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1867 va_end(args);
1869 /* Check size. */
1870 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1871 i++;
1873 *dim = i;
1875 if (0 == i) {
1876 /* Doesn't exist. */
1877 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1878 return NULL;
1881 vec = fc_malloc(i * sizeof(bool));
1882 for (i = 0; i < *dim; i++) {
1883 if (!secfile_lookup_bool(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1884 SECFILE_LOG(secfile, NULL,
1885 "An error occurred when looking up to \"%s,%d\" entry.",
1886 fullpath, (int) i);
1887 free(vec);
1888 *dim = 0;
1889 return NULL;
1893 return vec;
1896 /**************************************************************************
1897 Lookup a integer value in the secfile. Returns TRUE on success.
1898 **************************************************************************/
1899 bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1900 const char *path, ...)
1902 char fullpath[MAX_LEN_SECPATH];
1903 const struct entry *pentry;
1904 va_list args;
1906 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1908 va_start(args, path);
1909 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1910 va_end(args);
1912 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1913 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1914 return FALSE;
1917 return entry_int_get(pentry, ival);
1920 /**************************************************************************
1921 Lookup a integer value in the secfile. On failure, use the default
1922 value.
1923 **************************************************************************/
1924 int secfile_lookup_int_default(const struct section_file *secfile, int def,
1925 const char *path, ...)
1927 char fullpath[MAX_LEN_SECPATH];
1928 const struct entry *pentry;
1929 int ival;
1930 va_list args;
1932 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1934 va_start(args, path);
1935 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1936 va_end(args);
1938 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1939 return def;
1942 if (entry_int_get(pentry, &ival)) {
1943 return ival;
1946 return def;
1949 /**************************************************************************
1950 Lookup a integer value in the secfile. The value will be arranged to
1951 match the interval [minval, maxval]. On failure, use the default
1952 value.
1953 **************************************************************************/
1954 int secfile_lookup_int_def_min_max(const struct section_file *secfile,
1955 int defval, int minval, int maxval,
1956 const char *path, ...)
1958 char fullpath[MAX_LEN_SECPATH];
1959 const struct entry *pentry;
1960 int value;
1961 va_list args;
1963 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
1965 va_start(args, path);
1966 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1967 va_end(args);
1969 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1970 return defval;
1973 if (!entry_int_get(pentry, &value)) {
1974 return defval;
1977 if (value < minval) {
1978 SECFILE_LOG(secfile, entry_section(pentry),
1979 "\"%s\" should be in the interval [%d, %d] but is %d;"
1980 "using the minimal value.",
1981 fullpath, minval, maxval, value);
1982 value = minval;
1985 if (value > maxval) {
1986 SECFILE_LOG(secfile, entry_section(pentry),
1987 "\"%s\" should be in the interval [%d, %d] but is %d;"
1988 "using the maximal value.",
1989 fullpath, minval, maxval, value);
1990 value = maxval;
1993 return value;
1996 /**************************************************************************
1997 Lookup a integer vector in the secfile. Returns NULL on error. This
1998 vector is not owned by the registry module, and should be free by the
1999 user.
2000 **************************************************************************/
2001 int *secfile_lookup_int_vec(const struct section_file *secfile,
2002 size_t *dim, const char *path, ...)
2004 char fullpath[MAX_LEN_SECPATH];
2005 size_t i = 0;
2006 int *vec;
2007 va_list args;
2009 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2010 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2012 va_start(args, path);
2013 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2014 va_end(args);
2016 /* Check size. */
2017 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2018 i++;
2020 *dim = i;
2022 if (0 == i) {
2023 /* Doesn't exist. */
2024 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2025 return NULL;
2028 vec = fc_malloc(i * sizeof(int));
2029 for (i = 0; i < *dim; i++) {
2030 if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
2031 SECFILE_LOG(secfile, NULL,
2032 "An error occurred when looking up to \"%s,%d\" entry.",
2033 fullpath, (int) i);
2034 free(vec);
2035 *dim = 0;
2036 return NULL;
2040 return vec;
2043 /**************************************************************************
2044 Lookup a floating point value in the secfile. Returns TRUE on success.
2045 **************************************************************************/
2046 bool secfile_lookup_float(const struct section_file *secfile, float *fval,
2047 const char *path, ...)
2049 char fullpath[MAX_LEN_SECPATH];
2050 const struct entry *pentry;
2051 va_list args;
2053 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2055 va_start(args, path);
2056 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2057 va_end(args);
2059 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2060 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2061 return FALSE;
2064 return entry_float_get(pentry, fval);
2067 /**************************************************************************
2068 Lookup a floating point value in the secfile. On failure, use the default
2069 value.
2070 **************************************************************************/
2071 float secfile_lookup_float_default(const struct section_file *secfile,
2072 float def, const char *path, ...)
2074 char fullpath[MAX_LEN_SECPATH];
2075 const struct entry *pentry;
2076 float fval;
2077 va_list args;
2079 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2081 va_start(args, path);
2082 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2083 va_end(args);
2085 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2086 return def;
2089 if (entry_float_get(pentry, &fval)) {
2090 return fval;
2093 return def;
2096 /**************************************************************************
2097 Lookup a string value in the secfile. Returns NULL on error.
2098 **************************************************************************/
2099 const char *secfile_lookup_str(const struct section_file *secfile,
2100 const char *path, ...)
2102 char fullpath[MAX_LEN_SECPATH];
2103 const struct entry *pentry;
2104 const char *str;
2105 va_list args;
2107 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2109 va_start(args, path);
2110 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2111 va_end(args);
2113 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2114 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2115 return NULL;
2118 if (entry_str_get(pentry, &str)) {
2119 return str;
2122 return NULL;
2125 /**************************************************************************
2126 Lookup a string value in the secfile. On failure, use the default
2127 value.
2128 **************************************************************************/
2129 const char *secfile_lookup_str_default(const struct section_file *secfile,
2130 const char *def,
2131 const char *path, ...)
2133 char fullpath[MAX_LEN_SECPATH];
2134 const struct entry *pentry;
2135 const char *str;
2136 va_list args;
2138 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2140 va_start(args, path);
2141 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2142 va_end(args);
2144 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2145 return def;
2148 if (entry_str_get(pentry, &str)) {
2149 return str;
2152 return def;
2155 /**************************************************************************
2156 Lookup a string vector in the secfile. Returns NULL on error. This
2157 vector is not owned by the registry module, and should be free by the
2158 user, but the string pointers stored inside the vector shouldn't be
2159 free.
2160 **************************************************************************/
2161 const char **secfile_lookup_str_vec(const struct section_file *secfile,
2162 size_t *dim, const char *path, ...)
2164 char fullpath[MAX_LEN_SECPATH];
2165 size_t i = 0;
2166 const char **vec;
2167 va_list args;
2169 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2170 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2172 va_start(args, path);
2173 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2174 va_end(args);
2176 /* Check size. */
2177 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2178 i++;
2180 *dim = i;
2182 if (0 == i) {
2183 /* Doesn't exist. */
2184 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2185 return NULL;
2188 vec = fc_malloc(i * sizeof(const char *));
2189 for (i = 0; i < *dim; i++) {
2190 if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d",
2191 fullpath, (int) i))) {
2192 SECFILE_LOG(secfile, NULL,
2193 "An error occurred when looking up to \"%s,%d\" entry.",
2194 fullpath, (int) i);
2195 free(vec);
2196 *dim = 0;
2197 return NULL;
2201 return vec;
2204 /****************************************************************************
2205 Lookup an enumerator value in the secfile. Returns FALSE on error.
2206 ****************************************************************************/
2207 bool secfile_lookup_plain_enum_full(const struct section_file *secfile,
2208 int *penumerator,
2209 secfile_enum_is_valid_fn_t is_valid_fn,
2210 secfile_enum_by_name_fn_t by_name_fn,
2211 const char *path, ...)
2213 char fullpath[MAX_LEN_SECPATH];
2214 const struct entry *pentry;
2215 const char *str;
2216 va_list args;
2218 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2219 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2220 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2221 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2223 va_start(args, path);
2224 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2225 va_end(args);
2227 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2228 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2229 return FALSE;
2232 if (!entry_str_get(pentry, &str)) {
2233 return FALSE;
2236 *penumerator = by_name_fn(str, strcmp);
2237 if (is_valid_fn(*penumerator)) {
2238 return TRUE;
2241 SECFILE_LOG(secfile, entry_section(pentry),
2242 "Entry \"%s\": no match for \"%s\".",
2243 entry_name(pentry), str);
2244 return FALSE;
2247 /****************************************************************************
2248 Lookup an enumerator value in the secfile. Returns 'defval' on error.
2249 ****************************************************************************/
2250 int secfile_lookup_plain_enum_default_full(const struct section_file
2251 *secfile, int defval,
2252 secfile_enum_is_valid_fn_t
2253 is_valid_fn,
2254 secfile_enum_by_name_fn_t
2255 by_name_fn,
2256 const char *path, ...)
2258 char fullpath[MAX_LEN_SECPATH];
2259 const struct entry *pentry;
2260 const char *str;
2261 int val;
2262 va_list args;
2264 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2265 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2266 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2268 va_start(args, path);
2269 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2270 va_end(args);
2272 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2273 return defval;
2276 if (!entry_str_get(pentry, &str)) {
2277 return defval;
2280 val = by_name_fn(str, strcmp);
2281 if (is_valid_fn(val)) {
2282 return val;
2283 } else {
2284 return defval;
2288 /**************************************************************************
2289 Lookup a enumerator vector in the secfile. Returns NULL on error. This
2290 vector is not owned by the registry module, and should be free by the
2291 user.
2292 **************************************************************************/
2293 int *secfile_lookup_plain_enum_vec_full(const struct section_file *secfile,
2294 size_t *dim,
2295 secfile_enum_is_valid_fn_t
2296 is_valid_fn,
2297 secfile_enum_by_name_fn_t
2298 by_name_fn,
2299 const char *path, ...)
2301 char fullpath[MAX_LEN_SECPATH];
2302 size_t i = 0;
2303 int *vec;
2304 va_list args;
2306 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2307 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2308 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2309 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2311 va_start(args, path);
2312 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2313 va_end(args);
2315 /* Check size. */
2316 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2317 i++;
2319 *dim = i;
2321 if (0 == i) {
2322 /* Doesn't exist. */
2323 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2324 return NULL;
2327 vec = fc_malloc(i * sizeof(int));
2328 for (i = 0; i < *dim; i++) {
2329 if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2330 by_name_fn, "%s,%d",
2331 fullpath, (int) i)) {
2332 SECFILE_LOG(secfile, NULL,
2333 "An error occurred when looking up to \"%s,%d\" entry.",
2334 fullpath, (int) i);
2335 free(vec);
2336 *dim = 0;
2337 return NULL;
2341 return vec;
2344 /****************************************************************************
2345 Lookup a bitwise enumerator value in the secfile. Returns FALSE on error.
2346 ****************************************************************************/
2347 bool secfile_lookup_bitwise_enum_full(const struct section_file *secfile,
2348 int *penumerator,
2349 secfile_enum_is_valid_fn_t is_valid_fn,
2350 secfile_enum_by_name_fn_t by_name_fn,
2351 const char *path, ...)
2353 char fullpath[MAX_LEN_SECPATH];
2354 const struct entry *pentry;
2355 const char *str, *p;
2356 char val_name[MAX_LEN_SECPATH];
2357 int val;
2358 va_list args;
2360 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2361 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2362 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2363 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2365 va_start(args, path);
2366 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2367 va_end(args);
2369 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2370 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2371 return FALSE;
2374 if (!entry_str_get(pentry, &str)) {
2375 return FALSE;
2378 *penumerator = 0;
2379 if ('\0' == str[0]) {
2380 /* Empty string = no value. */
2381 return TRUE;
2384 /* Value names are separated by '|'. */
2385 do {
2386 p = strchr(str, '|');
2387 if (NULL != p) {
2388 p++;
2389 fc_strlcpy(val_name, str, p - str);
2390 } else {
2391 /* Last segment, full copy. */
2392 sz_strlcpy(val_name, str);
2394 remove_leading_trailing_spaces(val_name);
2395 val = by_name_fn(val_name, strcmp);
2396 if (!is_valid_fn(val)) {
2397 SECFILE_LOG(secfile, entry_section(pentry),
2398 "Entry \"%s\": no match for \"%s\".",
2399 entry_name(pentry), val_name);
2400 return FALSE;
2402 *penumerator |= val;
2403 str = p;
2404 } while (NULL != p);
2406 return TRUE;
2409 /****************************************************************************
2410 Lookup an enumerator value in the secfile. Returns 'defval' on error.
2411 ****************************************************************************/
2412 int secfile_lookup_bitwise_enum_default_full(const struct section_file
2413 *secfile, int defval,
2414 secfile_enum_is_valid_fn_t
2415 is_valid_fn,
2416 secfile_enum_by_name_fn_t
2417 by_name_fn,
2418 const char *path, ...)
2420 char fullpath[MAX_LEN_SECPATH];
2421 const struct entry *pentry;
2422 const char *str, *p;
2423 char val_name[MAX_LEN_SECPATH];
2424 int val, full_val;
2425 va_list args;
2427 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2428 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2429 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2431 va_start(args, path);
2432 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2433 va_end(args);
2435 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2436 return defval;
2439 if (!entry_str_get(pentry, &str)) {
2440 return defval;
2443 if ('\0' == str[0]) {
2444 /* Empty string = no value. */
2445 return 0;
2448 /* Value names are separated by '|'. */
2449 full_val = 0;
2450 do {
2451 p = strchr(str, '|');
2452 if (NULL != p) {
2453 p++;
2454 fc_strlcpy(val_name, str, p - str);
2455 } else {
2456 /* Last segment, full copy. */
2457 sz_strlcpy(val_name, str);
2459 remove_leading_trailing_spaces(val_name);
2460 val = by_name_fn(val_name, strcmp);
2461 if (!is_valid_fn(val)) {
2462 return defval;
2464 full_val |= val;
2465 str = p;
2466 } while (NULL != p);
2468 return full_val;
2471 /**************************************************************************
2472 Lookup a enumerator vector in the secfile. Returns NULL on error. This
2473 vector is not owned by the registry module, and should be free by the
2474 user.
2475 **************************************************************************/
2476 int *secfile_lookup_bitwise_enum_vec_full(const struct section_file *secfile,
2477 size_t *dim,
2478 secfile_enum_is_valid_fn_t
2479 is_valid_fn,
2480 secfile_enum_by_name_fn_t
2481 by_name_fn,
2482 const char *path, ...)
2484 char fullpath[MAX_LEN_SECPATH];
2485 size_t i = 0;
2486 int *vec;
2487 va_list args;
2489 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2490 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2491 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2492 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2494 va_start(args, path);
2495 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2496 va_end(args);
2498 /* Check size. */
2499 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2500 i++;
2502 *dim = i;
2504 if (0 == i) {
2505 /* Doesn't exist. */
2506 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2507 return NULL;
2510 vec = fc_malloc(i * sizeof(int));
2511 for (i = 0; i < *dim; i++) {
2512 if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2513 by_name_fn, "%s,%d",
2514 fullpath, (int) i)) {
2515 SECFILE_LOG(secfile, NULL,
2516 "An error occurred when looking up to \"%s,%d\" entry.",
2517 fullpath, (int) i);
2518 free(vec);
2519 *dim = 0;
2521 return NULL;
2525 return vec;
2528 /****************************************************************************
2529 Lookup a value saved as string in the secfile. Returns FALSE on error.
2530 ****************************************************************************/
2531 bool secfile_lookup_enum_data(const struct section_file *secfile,
2532 int *pvalue, bool bitwise,
2533 secfile_enum_name_data_fn_t name_fn,
2534 secfile_data_t data, const char *path, ...)
2536 char fullpath[MAX_LEN_SECPATH];
2537 const struct entry *pentry;
2538 const char *str, *p, *name;
2539 char val_name[MAX_LEN_SECPATH];
2540 int val;
2541 va_list args;
2543 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2544 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != pvalue, FALSE);
2545 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, FALSE);
2547 va_start(args, path);
2548 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2549 va_end(args);
2551 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2552 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2553 return FALSE;
2556 if (!entry_str_get(pentry, &str)) {
2557 return FALSE;
2560 if (bitwise) {
2561 *pvalue = 0;
2562 if ('\0' == str[0]) {
2563 /* Empty string = no value. */
2564 return TRUE;
2567 /* Value names are separated by '|'. */
2568 do {
2569 p = strchr(str, '|');
2570 if (NULL != p) {
2571 p++;
2572 fc_strlcpy(val_name, str, p - str);
2573 } else {
2574 /* Last segment, full copy. */
2575 sz_strlcpy(val_name, str);
2577 remove_leading_trailing_spaces(val_name);
2578 for (val = 0; (name = name_fn(data, val)); val++) {
2579 if (0 == fc_strcasecmp(name, val_name)) {
2580 break;
2583 if (NULL == name) {
2584 SECFILE_LOG(secfile, entry_section(pentry),
2585 "Entry \"%s\": no match for \"%s\".",
2586 entry_name(pentry), val_name);
2587 return FALSE;
2589 *pvalue |= 1 << val;
2590 str = p;
2591 } while (NULL != p);
2592 } else {
2593 for (val = 0; (name = name_fn(data, val)); val++) {
2594 if (0 == fc_strcasecmp(name, str)) {
2595 *pvalue = val;
2596 break;
2599 if (NULL == name) {
2600 SECFILE_LOG(secfile, entry_section(pentry),
2601 "Entry \"%s\": no match for \"%s\".",
2602 entry_name(pentry), str);
2603 return FALSE;
2607 return TRUE;
2610 /****************************************************************************
2611 Lookup a value saved as string in the secfile. Returns 'defval' on error.
2612 ****************************************************************************/
2613 int secfile_lookup_enum_default_data(const struct section_file *secfile,
2614 int defval, bool bitwise,
2615 secfile_enum_name_data_fn_t name_fn,
2616 secfile_data_t data,
2617 const char *path, ...)
2619 char fullpath[MAX_LEN_SECPATH];
2620 const struct entry *pentry;
2621 const char *str, *p, *name;
2622 char val_name[MAX_LEN_SECPATH];
2623 int value, val;
2624 va_list args;
2626 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2627 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, defval);
2629 va_start(args, path);
2630 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2631 va_end(args);
2633 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2634 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2635 return defval;
2638 if (!entry_str_get(pentry, &str)) {
2639 return defval;
2642 value = 0;
2643 if (bitwise) {
2644 if ('\0' == str[0]) {
2645 /* Empty string = no value. */
2646 return value;
2649 /* Value names are separated by '|'. */
2650 do {
2651 p = strchr(str, '|');
2652 if (NULL != p) {
2653 p++;
2654 fc_strlcpy(val_name, str, p - str);
2655 } else {
2656 /* Last segment, full copy. */
2657 sz_strlcpy(val_name, str);
2659 remove_leading_trailing_spaces(val_name);
2660 for (val = 0; (name = name_fn(data, val)); val++) {
2661 if (0 == strcmp(name, val_name)) {
2662 break;
2665 if (NULL == name) {
2666 SECFILE_LOG(secfile, entry_section(pentry),
2667 "Entry \"%s\": no match for \"%s\".",
2668 entry_name(pentry), val_name);
2669 return defval;
2671 value |= 1 << val;
2672 str = p;
2673 } while (NULL != p);
2674 } else {
2675 for (val = 0; (name = name_fn(data, val)); val++) {
2676 if (0 == strcmp(name, str)) {
2677 value = val;
2678 break;
2681 if (NULL == name) {
2682 SECFILE_LOG(secfile, entry_section(pentry),
2683 "Entry \"%s\": no match for \"%s\".",
2684 entry_name(pentry), str);
2685 return defval;
2689 return value;
2692 /****************************************************************************
2693 Lookup a vector in the secfile. Returns NULL on error. This vector
2694 is not owned by the registry module, and should be free by the user.
2695 ****************************************************************************/
2696 int *secfile_lookup_enum_vec_data(const struct section_file *secfile,
2697 size_t *dim, bool bitwise,
2698 secfile_enum_name_data_fn_t name_fn,
2699 secfile_data_t data, const char *path, ...)
2701 char fullpath[MAX_LEN_SECPATH];
2702 size_t i = 0;
2703 int *vec;
2704 va_list args;
2706 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2707 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2708 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
2710 va_start(args, path);
2711 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2712 va_end(args);
2714 /* Check size. */
2715 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2716 i++;
2718 *dim = i;
2720 if (0 == i) {
2721 /* Doesn't exist. */
2722 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2723 return NULL;
2726 vec = fc_malloc(i * sizeof(int));
2727 for (i = 0; i < *dim; i++) {
2728 if (!secfile_lookup_enum_data(secfile, vec + i, bitwise, name_fn, data,
2729 "%s,%d", fullpath, (int) i)) {
2730 SECFILE_LOG(secfile, NULL,
2731 "An error occurred when looking up to \"%s,%d\" entry.",
2732 fullpath, (int) i);
2733 free(vec);
2734 *dim = 0;
2735 return NULL;
2739 return vec;
2742 /****************************************************************************
2743 Returns the first section matching the name.
2744 ****************************************************************************/
2745 struct section *secfile_section_by_name(const struct section_file *secfile,
2746 const char *name)
2748 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2750 section_list_iterate(secfile->sections, psection) {
2751 if (0 == strcmp(section_name(psection), name)) {
2752 return psection;
2754 } section_list_iterate_end;
2756 return NULL;
2759 /**************************************************************************
2760 Find a section by path.
2761 **************************************************************************/
2762 struct section *secfile_section_lookup(const struct section_file *secfile,
2763 const char *path, ...)
2765 char fullpath[MAX_LEN_SECPATH];
2766 va_list args;
2768 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2770 va_start(args, path);
2771 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2772 va_end(args);
2774 return secfile_section_by_name(secfile, fullpath);
2777 /**************************************************************************
2778 Returns the list of sections. This list is owned by the registry module
2779 and shouldn't be modified and destroyed.
2780 **************************************************************************/
2781 const struct section_list *
2782 secfile_sections(const struct section_file *secfile)
2784 return (NULL != secfile ? secfile->sections : NULL);
2787 /**************************************************************************
2788 Returns the list of sections which match the name prefix. Returns NULL
2789 if no section was found. This list is not owned by the registry module
2790 and the user must destroy it when he finished to work with it.
2791 **************************************************************************/
2792 struct section_list *
2793 secfile_sections_by_name_prefix(const struct section_file *secfile,
2794 const char *prefix)
2796 struct section_list *matches = NULL;
2797 size_t len;
2799 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2800 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, NULL);
2802 len = strlen(prefix);
2803 if (0 == len) {
2804 return NULL;
2807 section_list_iterate(secfile->sections, psection) {
2808 if (0 == strncmp(section_name(psection), prefix, len)) {
2809 if (NULL == matches) {
2810 matches = section_list_new();
2812 section_list_append(matches, psection);
2814 } section_list_iterate_end;
2816 return matches;
2819 /**************************************************************************
2820 Create a new section in the secfile.
2821 **************************************************************************/
2822 struct section *secfile_section_new(struct section_file *secfile,
2823 const char *name)
2825 struct section *psection;
2827 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2829 if (NULL == name || '\0' == name[0]) {
2830 SECFILE_LOG(secfile, NULL, "Cannot create a section without name.");
2831 return NULL;
2834 if (!is_secfile_entry_name_valid(name)) {
2835 SECFILE_LOG(secfile, NULL, "\"%s\" is not a valid section name.",
2836 name);
2837 return NULL;
2840 if (NULL != secfile_section_by_name(secfile, name)) {
2841 /* We cannot duplicate sections in any case! Not even if one is
2842 * include -section and the other not. */
2843 SECFILE_LOG(secfile, NULL, "Section \"%s\" already exists.", name);
2844 return NULL;
2847 psection = fc_malloc(sizeof(struct section));
2848 psection->special = EST_NORMAL;
2849 psection->name = fc_strdup(name);
2850 psection->entries = entry_list_new_full(entry_destroy);
2852 /* Append to secfile. */
2853 psection->secfile = secfile;
2854 section_list_append(secfile->sections, psection);
2856 if (NULL != secfile->hash.sections) {
2857 section_hash_insert(secfile->hash.sections, psection->name, psection);
2860 return psection;
2863 /**************************************************************************
2864 Remove this section from the secfile.
2865 **************************************************************************/
2866 void section_destroy(struct section *psection)
2868 struct section_file *secfile;
2870 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2872 section_clear_all(psection);
2874 if ((secfile = psection->secfile)) {
2875 /* Detach from secfile. */
2876 if (section_list_remove(secfile->sections, psection)) {
2877 /* This has called section_destroy() already then. */
2878 return;
2880 if (NULL != secfile->hash.sections) {
2881 section_hash_remove(secfile->hash.sections, psection->name);
2885 entry_list_destroy(psection->entries);
2886 free(psection->name);
2887 free(psection);
2890 /**************************************************************************
2891 Remove all entries.
2892 **************************************************************************/
2893 void section_clear_all(struct section *psection)
2895 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2897 /* This include the removing of the hash datas. */
2898 entry_list_clear(psection->entries);
2900 if (0 < entry_list_size(psection->entries)) {
2901 SECFILE_LOG(psection->secfile, psection,
2902 "After clearing all, %d entries are still remaining.",
2903 entry_list_size(psection->entries));
2907 /**************************************************************************
2908 Change the section name. Returns TRUE on success.
2909 **************************************************************************/
2910 bool section_set_name(struct section *psection, const char *name)
2912 struct section_file *secfile;
2913 struct section *pother;
2915 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, FALSE);
2916 secfile = psection->secfile;
2917 SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, NULL != secfile, FALSE);
2919 if (NULL == name || '\0' == name[0]) {
2920 SECFILE_LOG(secfile, psection, "No new name for section \"%s\".",
2921 psection->name);
2922 return FALSE;
2925 if (!is_secfile_entry_name_valid(name)) {
2926 SECFILE_LOG(secfile, psection,
2927 "\"%s\" is not a valid section name for section \"%s\".",
2928 name, psection->name);
2929 return FALSE;
2932 if ((pother = secfile_section_by_name(secfile, name))
2933 && pother != psection) {
2934 /* We cannot duplicate sections in any case! */
2935 SECFILE_LOG(secfile, psection, "Section \"%s\" already exists.", name);
2936 return FALSE;
2939 /* Remove old references in the hash tables. */
2940 if (NULL != secfile->hash.sections) {
2941 section_hash_remove(secfile->hash.sections, psection->name);
2943 if (NULL != secfile->hash.entries) {
2944 entry_list_iterate(psection->entries, pentry) {
2945 secfile_hash_delete(secfile, pentry);
2946 } entry_list_iterate_end;
2949 /* Really rename. */
2950 free(psection->name);
2951 psection->name = fc_strdup(name);
2953 /* Reinsert new references into the hash tables. */
2954 if (NULL != secfile->hash.sections) {
2955 section_hash_insert(secfile->hash.sections, psection->name, psection);
2957 if (NULL != secfile->hash.entries) {
2958 entry_list_iterate(psection->entries, pentry) {
2959 secfile_hash_insert(secfile, pentry);
2960 } entry_list_iterate_end;
2963 return TRUE;
2966 /**************************************************************************
2967 Returns a list containing all the entries. This list is owned by the
2968 secfile, so don't modify or destroy it.
2969 **************************************************************************/
2970 const struct entry_list *section_entries(const struct section *psection)
2972 return (NULL != psection ? psection->entries : NULL);
2975 /**************************************************************************
2976 Returns the the first entry matching the name.
2977 **************************************************************************/
2978 struct entry *section_entry_by_name(const struct section *psection,
2979 const char *name)
2981 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2983 entry_list_iterate(psection->entries, pentry) {
2984 if (0 == strcmp(entry_name(pentry), name)) {
2985 entry_use(pentry);
2986 return pentry;
2988 } entry_list_iterate_end;
2990 return NULL;
2993 /**************************************************************************
2994 Returns the entry matching the path.
2995 **************************************************************************/
2996 struct entry *section_entry_lookup(const struct section *psection,
2997 const char *path, ...)
2999 char fullpath[MAX_LEN_SECPATH];
3000 struct entry *pentry;
3001 va_list args;
3003 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
3005 va_start(args, path);
3006 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
3007 va_end(args);
3009 if ((pentry = section_entry_by_name(psection, fullpath))) {
3010 return pentry;
3013 /* Try with full path. */
3014 if ((pentry = secfile_entry_by_path(psection->secfile, fullpath))
3015 && psection == entry_section(pentry)) {
3016 /* Unsure this is really owned by this section. */
3017 return pentry;
3020 return NULL;
3023 /**************************************************************************
3024 Returns a new entry.
3025 **************************************************************************/
3026 static struct entry *entry_new(struct section *psection, const char *name)
3028 struct section_file *secfile;
3029 struct entry *pentry;
3031 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
3033 secfile = psection->secfile;
3034 if (NULL == name || '\0' == name[0]) {
3035 SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
3036 return NULL;
3039 if (!is_secfile_entry_name_valid(name)) {
3040 SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
3041 name);
3042 return NULL;
3045 if (!secfile->allow_duplicates
3046 && NULL != section_entry_by_name(psection, name)) {
3047 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3048 return NULL;
3051 pentry = fc_malloc(sizeof(struct entry));
3052 pentry->name = fc_strdup(name);
3053 pentry->type = -1; /* Invalid case. */
3054 pentry->used = 0;
3055 pentry->comment = NULL;
3057 /* Append to section. */
3058 pentry->psection = psection;
3059 entry_list_append(psection->entries, pentry);
3061 /* Notify secfile. */
3062 secfile->num_entries++;
3063 secfile_hash_insert(secfile, pentry);
3065 return pentry;
3068 /**************************************************************************
3069 Returns a new entry of type ENTRY_INT.
3070 **************************************************************************/
3071 struct entry *section_entry_int_new(struct section *psection,
3072 const char *name, int value)
3074 struct entry *pentry = entry_new(psection, name);
3076 if (NULL != pentry) {
3077 pentry->type = ENTRY_INT;
3078 pentry->integer.value = value;
3081 return pentry;
3084 /**************************************************************************
3085 Returns a new entry of type ENTRY_BOOL.
3086 **************************************************************************/
3087 struct entry *section_entry_bool_new(struct section *psection,
3088 const char *name, bool value)
3090 struct entry *pentry = entry_new(psection, name);
3092 if (NULL != pentry) {
3093 pentry->type = ENTRY_BOOL;
3094 pentry->boolean.value = value;
3097 return pentry;
3100 /**************************************************************************
3101 Returns a new entry of type ENTRY_FLOAT.
3102 **************************************************************************/
3103 struct entry *section_entry_float_new(struct section *psection,
3104 const char *name, float value)
3106 struct entry *pentry = entry_new(psection, name);
3108 if (NULL != pentry) {
3109 pentry->type = ENTRY_FLOAT;
3110 pentry->floating.value = value;
3113 return pentry;
3116 /**************************************************************************
3117 Returns a new entry of type ENTRY_STR.
3118 **************************************************************************/
3119 struct entry *section_entry_str_new(struct section *psection,
3120 const char *name, const char *value,
3121 bool escaped)
3123 struct entry *pentry = entry_new(psection, name);
3125 if (NULL != pentry) {
3126 pentry->type = ENTRY_STR;
3127 pentry->string.value = fc_strdup(NULL != value ? value : "");
3128 pentry->string.escaped = escaped;
3129 pentry->string.raw = FALSE;
3130 pentry->string.gt_marking = FALSE;
3133 return pentry;
3136 /**************************************************************************
3137 Returns a new entry of type ENTRY_FILEREFERENCE.
3138 **************************************************************************/
3139 static struct entry *section_entry_filereference_new(struct section *psection,
3140 const char *name, const char *value)
3142 struct entry *pentry = entry_new(psection, name);
3144 if (NULL != pentry) {
3145 pentry->type = ENTRY_FILEREFERENCE;
3146 pentry->string.value = fc_strdup(NULL != value ? value : "");
3149 return pentry;
3152 /**************************************************************************
3153 Entry structure destructor.
3154 **************************************************************************/
3155 void entry_destroy(struct entry *pentry)
3157 struct section_file *secfile;
3158 struct section *psection;
3160 if (NULL == pentry) {
3161 return;
3164 if ((psection = pentry->psection)) {
3165 /* Detach from section. */
3166 if (entry_list_remove(psection->entries, pentry)) {
3167 /* This has called entry_destroy() already then. */
3168 return;
3170 if ((secfile = psection->secfile)) {
3171 /* Detach from secfile. */
3172 secfile->num_entries--;
3173 secfile_hash_delete(secfile, pentry);
3177 /* Specific type free. */
3178 switch (pentry->type) {
3179 case ENTRY_BOOL:
3180 case ENTRY_INT:
3181 case ENTRY_FLOAT:
3182 break;
3184 case ENTRY_STR:
3185 case ENTRY_FILEREFERENCE:
3186 free(pentry->string.value);
3187 break;
3190 /* Common free. */
3191 free(pentry->name);
3192 if (NULL != pentry->comment) {
3193 free(pentry->comment);
3195 free(pentry);
3198 /**************************************************************************
3199 Returns the parent section of this entry.
3200 **************************************************************************/
3201 struct section *entry_section(const struct entry *pentry)
3203 return (NULL != pentry ? pentry->psection : NULL);
3206 /**************************************************************************
3207 Returns the type of this entry or -1 or error.
3208 **************************************************************************/
3209 enum entry_type entry_type(const struct entry *pentry)
3211 return (NULL != pentry ? pentry->type : -1);
3214 /**************************************************************************
3215 Build the entry path. Returns like snprintf().
3216 **************************************************************************/
3217 int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3219 return fc_snprintf(buf, buf_len, "%s.%s",
3220 section_name(entry_section(pentry)),
3221 entry_name(pentry));
3224 /**************************************************************************
3225 Returns the name of this entry.
3226 **************************************************************************/
3227 const char *entry_name(const struct entry *pentry)
3229 return (NULL != pentry ? pentry->name : NULL);
3232 /**************************************************************************
3233 Sets the name of the entry. Returns TRUE on success.
3234 **************************************************************************/
3235 bool entry_set_name(struct entry *pentry, const char *name)
3237 struct section *psection;
3238 struct section_file *secfile;
3240 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3241 psection = pentry->psection;
3242 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != psection, FALSE);
3243 secfile = psection->secfile;
3244 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != secfile, FALSE);
3246 if (NULL == name || '\0' == name[0]) {
3247 SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3248 pentry->name);
3249 return FALSE;
3252 if (!is_secfile_entry_name_valid(name)) {
3253 SECFILE_LOG(secfile, psection,
3254 "\"%s\" is not a valid entry name for entry \"%s\".",
3255 name, pentry->name);
3256 return FALSE;
3259 if (!secfile->allow_duplicates) {
3260 struct entry *pother = section_entry_by_name(psection, name);
3262 if (NULL != pother && pother != pentry) {
3263 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3264 return FALSE;
3268 /* Remove from hash table the old path. */
3269 secfile_hash_delete(secfile, pentry);
3271 /* Really rename the entry. */
3272 free(pentry->name);
3273 pentry->name = fc_strdup(name);
3275 /* Insert into hash table the new path. */
3276 secfile_hash_insert(secfile, pentry);
3277 return TRUE;
3280 /**************************************************************************
3281 Returns the comment associated to this entry.
3282 **************************************************************************/
3283 const char *entry_comment(const struct entry *pentry)
3285 return (NULL != pentry ? pentry->comment : NULL);
3288 /**************************************************************************
3289 Sets a comment for the entry. Pass NULL to remove the current one.
3290 **************************************************************************/
3291 void entry_set_comment(struct entry *pentry, const char *comment)
3293 if (NULL == pentry) {
3294 return;
3297 if (NULL != pentry->comment) {
3298 free(pentry->comment);
3301 pentry->comment = (NULL != comment ? fc_strdup(comment) : NULL);
3304 /**************************************************************************
3305 Returns TRUE if this entry has been used.
3306 **************************************************************************/
3307 static inline bool entry_used(const struct entry *pentry)
3309 return (0 < pentry->used);
3312 /**************************************************************************
3313 Increase the used count.
3314 **************************************************************************/
3315 static inline void entry_use(struct entry *pentry)
3317 pentry->used++;
3320 /**************************************************************************
3321 Gets an boolean value. Returns TRUE on success.
3322 On old saved files, 0 and 1 can also be considered as bool.
3323 **************************************************************************/
3324 bool entry_bool_get(const struct entry *pentry, bool *value)
3326 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3328 if (ENTRY_INT == pentry->type
3329 && (pentry->integer.value == 0
3330 || pentry->integer.value == 1)
3331 && NULL != pentry->psection
3332 && NULL != pentry->psection->secfile
3333 && pentry->psection->secfile->allow_digital_boolean) {
3334 *value = (0 != pentry->integer.value);
3335 return TRUE;
3338 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3339 ENTRY_BOOL == pentry->type, FALSE);
3341 if (NULL != value) {
3342 *value = pentry->boolean.value;
3344 return TRUE;
3347 /**************************************************************************
3348 Sets an boolean value. Returns TRUE on success.
3349 **************************************************************************/
3350 bool entry_bool_set(struct entry *pentry, bool value)
3352 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3353 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3354 ENTRY_BOOL == pentry->type, FALSE);
3356 pentry->boolean.value = value;
3357 return TRUE;
3360 /**************************************************************************
3361 Gets an floating value. Returns TRUE on success.
3362 **************************************************************************/
3363 bool entry_float_get(const struct entry *pentry, float *value)
3365 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3366 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3367 ENTRY_FLOAT == pentry->type, FALSE);
3369 if (NULL != value) {
3370 *value = pentry->floating.value;
3373 return TRUE;
3376 /**************************************************************************
3377 Sets an floating value. Returns TRUE on success.
3378 **************************************************************************/
3379 bool entry_float_set(struct entry *pentry, float value)
3381 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3382 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3383 ENTRY_FLOAT == pentry->type, FALSE);
3385 pentry->floating.value = value;
3387 return TRUE;
3390 /**************************************************************************
3391 Gets an integer value. Returns TRUE on success.
3392 **************************************************************************/
3393 bool entry_int_get(const struct entry *pentry, int *value)
3395 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3396 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3397 ENTRY_INT == pentry->type, FALSE);
3399 if (NULL != value) {
3400 *value = pentry->integer.value;
3402 return TRUE;
3405 /**************************************************************************
3406 Sets an integer value. Returns TRUE on success.
3407 **************************************************************************/
3408 bool entry_int_set(struct entry *pentry, int value)
3410 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3411 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3412 ENTRY_INT == pentry->type, FALSE);
3414 pentry->integer.value = value;
3415 return TRUE;
3418 /**************************************************************************
3419 Gets an string value. Returns TRUE on success.
3420 **************************************************************************/
3421 bool entry_str_get(const struct entry *pentry, const char **value)
3423 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3424 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3425 ENTRY_STR == pentry->type, FALSE);
3427 if (NULL != value) {
3428 *value = pentry->string.value;
3430 return TRUE;
3433 /**************************************************************************
3434 Sets an string value. Returns TRUE on success.
3435 **************************************************************************/
3436 bool entry_str_set(struct entry *pentry, const char *value)
3438 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3439 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3440 ENTRY_STR == pentry->type, FALSE);
3442 free(pentry->string.value);
3443 pentry->string.value = fc_strdup(NULL != value ? value : "");
3444 return TRUE;
3447 /**************************************************************************
3448 Returns if the string would be escaped.
3449 **************************************************************************/
3450 bool entry_str_escaped(const struct entry *pentry)
3452 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3453 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3454 ENTRY_STR == pentry->type, FALSE);
3456 return pentry->string.escaped;
3459 /**************************************************************************
3460 Sets if the string would be escaped. Returns TRUE on success.
3461 **************************************************************************/
3462 bool entry_str_set_escaped(struct entry *pentry, bool escaped)
3464 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3465 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3466 ENTRY_STR == pentry->type, FALSE);
3468 pentry->string.escaped = escaped;
3469 return TRUE;
3472 /**************************************************************************
3473 Sets if the string should get gettext marking. Returns TRUE on success.
3474 **************************************************************************/
3475 bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
3477 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3478 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3479 ENTRY_STR == pentry->type, FALSE);
3481 pentry->string.gt_marking = gt_marking;
3483 return TRUE;
3486 /**************************************************************************
3487 Push an entry into a file stream.
3488 **************************************************************************/
3489 static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
3491 static char buf[8192];
3492 char *dot = NULL;
3493 int i;
3495 switch (pentry->type) {
3496 case ENTRY_BOOL:
3497 fz_fprintf(fs, "%s", pentry->boolean.value ? "TRUE" : "FALSE");
3498 break;
3499 case ENTRY_INT:
3500 fz_fprintf(fs, "%d", pentry->integer.value);
3501 break;
3502 case ENTRY_FLOAT:
3503 snprintf(buf, sizeof(buf), "%f", pentry->floating.value);
3504 for (i = 0; buf[i] != '\0' ; i++) {
3505 if (buf[i] == '.') {
3506 dot = &(buf[i]);
3507 break;
3510 if (dot == NULL) {
3511 /* There's no '.' so it would seem like a integer value when loaded.
3512 * Force it not to look like an integer by adding ".0" */
3513 fz_fprintf(fs, "%s.0", buf);
3514 } else {
3515 fz_fprintf(fs, "%s", buf);
3517 break;
3518 case ENTRY_STR:
3519 if (pentry->string.escaped) {
3520 make_escapes(pentry->string.value, buf, sizeof(buf));
3521 if (pentry->string.gt_marking) {
3522 fz_fprintf(fs, "_(\"%s\")", buf);
3523 } else {
3524 fz_fprintf(fs, "\"%s\"", buf);
3526 } else if (pentry->string.raw) {
3527 fz_fprintf(fs, "%s", pentry->string.value);
3528 } else {
3529 fz_fprintf(fs, "$%s$", pentry->string.value);
3531 break;
3532 case ENTRY_FILEREFERENCE:
3533 fz_fprintf(fs, "*%s*", pentry->string.value);
3534 break;
3538 /**************************************************************************
3539 Creates a new entry from the token.
3540 **************************************************************************/
3541 static void entry_from_inf_token(struct section *psection, const char *name,
3542 const char *tok, struct inputfile *inf)
3544 if (!entry_from_token(psection, name, tok)) {
3545 log_error("%s", inf_log_str(inf, "Entry value not recognized: %s", tok));