Removed silencing of gtk warning logs from gtk3.22-client.
[freeciv.git] / utility / registry_ini.c
blob1ee923b9382f1d7dddf267bdf8bfe295d5839e70
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 "deprecations.h"
162 #include "fcintl.h"
163 #include "inputfile.h"
164 #include "ioz.h"
165 #include "log.h"
166 #include "mem.h"
167 #include "registry.h"
168 #include "section_file.h"
169 #include "shared.h"
170 #include "support.h"
172 #include "registry_ini.h"
174 #define MAX_LEN_SECPATH 1024
176 /* Set to FALSE for old-style savefiles. */
177 #define SAVE_TABLES TRUE
179 #define SPECVEC_TAG astring
180 #include "specvec.h"
182 static inline bool entry_used(const struct entry *pentry);
183 static inline void entry_use(struct entry *pentry);
185 static void entry_to_file(const struct entry *pentry, fz_FILE *fs);
186 static void entry_from_inf_token(struct section *psection, const char *name,
187 const char *tok, struct inputfile *file);
189 static struct entry *section_entry_filereference_new(struct section *psection,
190 const char *name, const char *value);
192 /***************************************************************************
193 Simplification of fileinfoname().
194 ***************************************************************************/
195 static const char *datafilename(const char *filename)
197 return fileinfoname(get_data_dirs(), filename);
200 /**************************************************************************
201 Ensure name is correct to use it as section or entry name.
202 **************************************************************************/
203 static bool is_secfile_entry_name_valid(const char *name)
205 static const char *const allowed = "_.,-[]";
207 while ('\0' != *name) {
208 if (!fc_isalnum(*name) && NULL == strchr(allowed, *name)) {
209 return FALSE;
211 name++;
213 return TRUE;
216 /**************************************************************************
217 Insert an entry into the hash table. Returns TRUE on success.
218 **************************************************************************/
219 static bool secfile_hash_insert(struct section_file *secfile,
220 struct entry *pentry)
222 char buf[256];
223 struct entry *hentry;
225 if (NULL == secfile->hash.entries) {
226 /* Consider as success if this secfile doesn't have built the entries
227 * hash table. */
228 return TRUE;
231 entry_path(pentry, buf, sizeof(buf));
232 if (entry_hash_replace_full(secfile->hash.entries, buf, pentry,
233 NULL, &hentry)) {
234 entry_use(hentry);
235 if (!secfile->allow_duplicates) {
236 SECFILE_LOG(secfile, entry_section(hentry),
237 "Tried to insert same value twice: %s", buf);
238 return FALSE;
242 return TRUE;
245 /**************************************************************************
246 Delete an entry from the hash table. Returns TRUE on success.
247 **************************************************************************/
248 static bool secfile_hash_delete(struct section_file *secfile,
249 struct entry *pentry)
251 char buf[256];
253 if (NULL == secfile->hash.entries) {
254 /* Consider as success if this secfile doesn't have built the entries
255 * hash table. */
256 return TRUE;
259 entry_path(pentry, buf, sizeof(buf));
260 return entry_hash_remove(secfile->hash.entries, buf);
263 /**************************************************************************
264 Base function to load a section file. Note it closes the inputfile.
265 **************************************************************************/
266 static struct section_file *secfile_from_input_file(struct inputfile *inf,
267 const char *filename,
268 const char *section,
269 bool allow_duplicates)
271 struct section_file *secfile;
272 struct section *psection = NULL;
273 struct section *single_section = NULL;
274 bool table_state = FALSE; /* TRUE when within tabular format. */
275 int table_lineno = 0; /* Row number in tabular, 0 top data row. */
276 const char *tok;
277 int i;
278 struct astring base_name = ASTRING_INIT; /* for table or single entry */
279 struct astring field_name = ASTRING_INIT;
280 struct astring_vector columns; /* astrings for column headings */
281 bool found_my_section = FALSE;
282 bool error = FALSE;
284 if (!inf) {
285 return NULL;
288 /* Assign the real value later, to speed up the creation of new entries. */
289 secfile = secfile_new(TRUE);
290 if (filename) {
291 secfile->name = fc_strdup(filename);
292 } else {
293 secfile->name = NULL;
296 astring_vector_init(&columns);
298 if (filename) {
299 log_verbose("Reading registry from \"%s\"", filename);
300 } else {
301 log_verbose("Reading registry");
304 while (!inf_at_eof(inf)) {
305 if (inf_token(inf, INF_TOK_EOL)) {
306 continue;
308 if (inf_at_eof(inf)) {
309 /* may only realise at eof after trying to read eol above */
310 break;
312 tok = inf_token(inf, INF_TOK_SECTION_NAME);
313 if (tok) {
314 if (found_my_section) {
315 /* This shortcut will stop any further loading after the requested
316 * section has been loaded (i.e., at the start of a new section).
317 * This is needed to make the behavior useful, since the whole
318 * purpose is to short-cut further loading of the file. However
319 * normally a section may be split up, and that will no longer
320 * work here because it will be short-cut. */
321 SECFILE_LOG(secfile, psection, "%s",
322 inf_log_str(inf, "Found requested section; finishing"));
323 goto END;
325 if (table_state) {
326 SECFILE_LOG(secfile, psection, "%s",
327 inf_log_str(inf, "New section during table"));
328 error = TRUE;
329 goto END;
331 /* Check if we already have a section with this name.
332 (Could ignore this and have a duplicate sections internally,
333 but then secfile_get_secnames_prefix would return duplicates.)
334 Duplicate section in input are likely to be useful for includes.
336 psection = secfile_section_by_name(secfile, tok);
337 if (!psection) {
338 if (!section || strcmp(tok, section) == 0) {
339 psection = secfile_section_new(secfile, tok);
340 if (section) {
341 single_section = psection;
342 found_my_section = TRUE;
346 if (!inf_token(inf, INF_TOK_EOL)) {
347 SECFILE_LOG(secfile, psection, "%s",
348 inf_log_str(inf, "Expected end of line"));
349 error = TRUE;
350 goto END;
352 continue;
354 if (inf_token(inf, INF_TOK_TABLE_END)) {
355 if (!table_state) {
356 SECFILE_LOG(secfile, psection, "%s",
357 inf_log_str(inf, "Misplaced \"}\""));
358 error = TRUE;
359 goto END;
361 if (!inf_token(inf, INF_TOK_EOL)) {
362 SECFILE_LOG(secfile, psection, "%s",
363 inf_log_str(inf, "Expected end of line"));
364 error = TRUE;
365 goto END;
367 table_state = FALSE;
368 continue;
370 if (table_state) {
371 i = -1;
372 do {
373 int num_columns = astring_vector_size(&columns);
375 i++;
376 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
377 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
378 SECFILE_LOG(secfile, psection, "%s",
379 inf_log_str(inf, "Expected value"));
380 error = TRUE;
381 goto END;
384 if (i < num_columns) {
385 astr_set(&field_name, "%s%d.%s", astr_str(&base_name),
386 table_lineno, astr_str(&columns.p[i]));
387 } else {
388 astr_set(&field_name, "%s%d.%s,%d", astr_str(&base_name),
389 table_lineno, astr_str(&columns.p[num_columns - 1]),
390 (int) (i - num_columns + 1));
392 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
393 } while (inf_token(inf, INF_TOK_COMMA));
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_lineno++;
402 continue;
405 if (!(tok = inf_token(inf, INF_TOK_ENTRY_NAME))) {
406 SECFILE_LOG(secfile, psection, "%s",
407 inf_log_str(inf, "Expected entry name"));
408 error = TRUE;
409 goto END;
412 /* need to store tok before next calls: */
413 astr_set(&base_name, "%s", tok);
415 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
417 if (inf_token(inf, INF_TOK_TABLE_START)) {
418 i = -1;
419 do {
420 i++;
421 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
422 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
423 SECFILE_LOG(secfile, psection, "%s",
424 inf_log_str(inf, "Expected value"));
425 error = TRUE;
426 goto END;
428 if (tok[0] != '\"') {
429 SECFILE_LOG(secfile, psection, "%s",
430 inf_log_str(inf, "Table column header non-string"));
431 error = TRUE;
432 goto END;
434 { /* expand columns: */
435 int j, n_prev;
436 n_prev = astring_vector_size(&columns);
437 for (j = i + 1; j < n_prev; j++) {
438 astr_free(&columns.p[j]);
440 astring_vector_reserve(&columns, i + 1);
441 for (j = n_prev; j < i + 1; j++) {
442 astr_init(&columns.p[j]);
445 astr_set(&columns.p[i], "%s", tok + 1);
447 } while (inf_token(inf, INF_TOK_COMMA));
449 if (!inf_token(inf, INF_TOK_EOL)) {
450 SECFILE_LOG(secfile, psection, "%s",
451 inf_log_str(inf, "Expected end of line"));
452 error = TRUE;
453 goto END;
455 table_state = TRUE;
456 table_lineno = 0;
457 continue;
459 /* ordinary value: */
460 i = -1;
461 do {
462 i++;
463 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
464 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
465 SECFILE_LOG(secfile, psection, "%s",
466 inf_log_str(inf, "Expected value"));
467 error = TRUE;
468 goto END;
470 if (i == 0) {
471 entry_from_inf_token(psection, astr_str(&base_name), tok, inf);
472 } else {
473 astr_set(&field_name, "%s,%d", astr_str(&base_name), i);
474 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
476 } while (inf_token(inf, INF_TOK_COMMA));
477 if (!inf_token(inf, INF_TOK_EOL)) {
478 SECFILE_LOG(secfile, psection, "%s",
479 inf_log_str(inf, "Expected end of line"));
480 error = TRUE;
481 goto END;
485 if (table_state) {
486 SECFILE_LOG(secfile, psection,
487 "Finished registry before end of table");
488 error = TRUE;
491 END:
492 inf_close(inf);
493 astr_free(&base_name);
494 astr_free(&field_name);
495 for (i = 0; i < astring_vector_size(&columns); i++) {
496 astr_free(&columns.p[i]);
498 astring_vector_free(&columns);
500 if (section != NULL) {
501 if (!found_my_section) {
502 secfile_destroy(secfile);
503 return NULL;
506 /* Build the entry hash table with single section information */
507 secfile->allow_duplicates = allow_duplicates;
508 entry_list_iterate(section_entries(single_section), pentry) {
509 if (!secfile_hash_insert(secfile, pentry)) {
510 secfile_destroy(secfile);
511 return NULL;
513 } entry_list_iterate_end;
515 return secfile;
518 if (!error) {
519 /* Build the entry hash table. */
520 secfile->allow_duplicates = allow_duplicates;
521 secfile->hash.entries = entry_hash_new_nentries(secfile->num_entries);
523 section_list_iterate(secfile->sections, hashing_section) {
524 entry_list_iterate(section_entries(hashing_section), pentry) {
525 if (!secfile_hash_insert(secfile, pentry)) {
526 error = TRUE;
527 break;
529 } entry_list_iterate_end;
530 if (error) {
531 break;
533 } section_list_iterate_end;
535 if (error) {
536 secfile_destroy(secfile);
537 return NULL;
538 } else {
539 return secfile;
543 /**************************************************************************
544 Create a section file from a file, read only one particular section.
545 Returns NULL on error.
546 **************************************************************************/
547 struct section_file *secfile_load_section(const char *filename,
548 const char *section,
549 bool allow_duplicates)
551 char real_filename[1024];
553 interpret_tilde(real_filename, sizeof(real_filename), filename);
554 return secfile_from_input_file(inf_from_file(real_filename, datafilename),
555 filename, section, allow_duplicates);
558 /**************************************************************************
559 Create a section file from a stream. Returns NULL on error.
560 **************************************************************************/
561 struct section_file *secfile_from_stream(fz_FILE *stream,
562 bool allow_duplicates)
564 return secfile_from_input_file(inf_from_stream(stream, datafilename),
565 NULL, NULL, allow_duplicates);
568 /**************************************************************************
569 Returns TRUE iff the character is legal in a table entry name.
570 **************************************************************************/
571 static bool is_legal_table_entry_name(char c, bool num)
573 return (num ? fc_isalnum(c) : fc_isalpha(c)) || c == '_';
576 /**************************************************************************
577 Save the previously filled in section_file to disk.
579 There is now limited ability to save in the new tabular format
580 (to give smaller savefiles).
581 The start of a table is detected by an entry with name of the form:
582 (alphabetical_component)(zero)(period)(alphanumeric_component)
583 Eg: u0.id, or c0.id, in the freeciv savefile.
584 The alphabetical component is taken as the "name" of the table,
585 and the component after the period as the first column name.
586 This should be followed by the other column values for u0,
587 and then subsequent u1, u2, etc, in strict order with no omissions,
588 and with all of the columns for all uN in the same order as for u0.
590 If compression_level is non-zero, then compress using zlib. (Should
591 only supply non-zero compression_level if already know that FREECIV_HAVE_LIBZ.)
592 Below simply specifies FZ_ZLIB method, since fz_fromFile() automatically
593 changes to FZ_PLAIN method when level == 0.
594 **************************************************************************/
595 bool secfile_save(const struct section_file *secfile, const char *filename,
596 int compression_level, enum fz_method compression_method)
598 char real_filename[1024];
599 char pentry_name[128];
600 const char *col_entry_name;
601 fz_FILE *fs;
602 const struct entry_list_link *ent_iter, *save_iter, *col_iter;
603 struct entry *pentry, *col_pentry;
604 int i;
606 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
608 if (NULL == filename) {
609 filename = secfile->name;
612 interpret_tilde(real_filename, sizeof(real_filename), filename);
613 fs = fz_from_file(real_filename, "w",
614 compression_method, compression_level);
616 if (!fs) {
617 return FALSE;
620 section_list_iterate(secfile->sections, psection) {
621 if (psection->include) {
622 for (ent_iter = entry_list_head(section_entries(psection));
623 ent_iter && (pentry = entry_list_link_data(ent_iter));
624 ent_iter = entry_list_link_next(ent_iter)) {
626 fc_assert(!strcmp(entry_name(pentry), "file"));
628 fz_fprintf(fs, "*include ");
629 entry_to_file(pentry, fs);
630 fz_fprintf(fs, "\n");
632 } else {
633 fz_fprintf(fs, "\n[%s]\n", section_name(psection));
635 /* Following doesn't use entry_list_iterate() because we want to do
636 * tricky things with the iterators...
638 for (ent_iter = entry_list_head(section_entries(psection));
639 ent_iter && (pentry = entry_list_link_data(ent_iter));
640 ent_iter = entry_list_link_next(ent_iter)) {
641 const char *comment;
643 /* Tables: break out of this loop if this is a non-table
644 * entry (pentry and ent_iter unchanged) or after table (pentry
645 * and ent_iter suitably updated, pentry possibly NULL).
646 * After each table, loop again in case the next entry
647 * is another table.
649 for (;;) {
650 char *c, *first, base[64];
651 int offset, irow, icol, ncol;
653 /* Example: for first table name of "xyz0.blah":
654 * first points to the original string pentry->name
655 * base contains "xyz";
656 * offset = 5 (so first+offset gives "blah")
657 * note strlen(base) = offset - 2
660 if (!SAVE_TABLES) {
661 break;
664 sz_strlcpy(pentry_name, entry_name(pentry));
665 c = first = pentry_name;
666 if (*c == '\0' || !is_legal_table_entry_name(*c, FALSE)) {
667 break;
669 for (; *c != '\0' && is_legal_table_entry_name(*c, FALSE); c++) {
670 /* nothing */
672 if (0 != strncmp(c, "0.", 2)) {
673 break;
675 c += 2;
676 if (*c == '\0' || !is_legal_table_entry_name(*c, TRUE)) {
677 break;
680 offset = c - first;
681 first[offset - 2] = '\0';
682 sz_strlcpy(base, first);
683 first[offset - 2] = '0';
684 fz_fprintf(fs, "%s={", base);
686 /* Save an iterator at this first entry, which we can later use
687 * to repeatedly iterate over column names:
689 save_iter = ent_iter;
691 /* write the column names, and calculate ncol: */
692 ncol = 0;
693 col_iter = save_iter;
694 for(; (col_pentry = entry_list_link_data(col_iter));
695 col_iter = entry_list_link_next(col_iter)) {
696 col_entry_name = entry_name(col_pentry);
697 if (strncmp(col_entry_name, first, offset) != 0) {
698 break;
700 fz_fprintf(fs, "%s\"%s\"", (ncol == 0 ? "" : ","),
701 col_entry_name + offset);
702 ncol++;
704 fz_fprintf(fs, "\n");
706 /* Iterate over rows and columns, incrementing ent_iter as we go,
707 * and writing values to the table. Have a separate iterator
708 * to the column names to check they all match.
710 irow = icol = 0;
711 col_iter = save_iter;
712 for (;;) {
713 char expect[128]; /* pentry->name we're expecting */
715 pentry = entry_list_link_data(ent_iter);
716 col_pentry = entry_list_link_data(col_iter);
718 fc_snprintf(expect, sizeof(expect), "%s%d.%s",
719 base, irow, entry_name(col_pentry) + offset);
721 /* break out of tabular if doesn't match: */
722 if ((!pentry) || (strcmp(entry_name(pentry), expect) != 0)) {
723 if (icol != 0) {
724 /* If the second or later row of a table is missing some
725 * entries that the first row had, we drop out of the tabular
726 * format. This is inefficient so we print a warning message;
727 * the calling code probably needs to be fixed so that it can
728 * use the more efficient tabular format.
730 * FIXME: If the first row is missing some entries that the
731 * second or later row has, then we'll drop out of tabular
732 * format without an error message. */
733 log_error("In file %s, there is no entry in the registry for\n"
734 "%s.%s (or the entries are out of order). This means\n"
735 "a less efficient non-tabular format will be used.\n"
736 "To avoid this make sure all rows of a table are\n"
737 "filled out with an entry for every column.",
738 real_filename, section_name(psection), expect);
739 /* TRANS: No full stop after the URL, could cause confusion. */
740 log_error(_("Please report this message at %s"), BUG_URL);
741 fz_fprintf(fs, "\n");
743 fz_fprintf(fs, "}\n");
744 break;
747 if (icol > 0) {
748 fz_fprintf(fs, ",");
750 entry_to_file(pentry, fs);
752 ent_iter = entry_list_link_next(ent_iter);
753 col_iter = entry_list_link_next(col_iter);
755 icol++;
756 if (icol == ncol) {
757 fz_fprintf(fs, "\n");
758 irow++;
759 icol = 0;
760 col_iter = save_iter;
763 if (!pentry) {
764 break;
767 if (!pentry) {
768 break;
771 /* Classic entry. */
772 col_entry_name = entry_name(pentry);
773 fz_fprintf(fs, "%s=", col_entry_name);
774 entry_to_file(pentry, fs);
776 /* Check for vector. */
777 for (i = 1;; i++) {
778 col_iter = entry_list_link_next(ent_iter);
779 col_pentry = entry_list_link_data(col_iter);
780 if (NULL == col_pentry) {
781 break;
783 fc_snprintf(pentry_name, sizeof(pentry_name),
784 "%s,%d", col_entry_name, i);
785 if (0 != strcmp(pentry_name, entry_name(col_pentry))) {
786 break;
788 fz_fprintf(fs, ",");
789 entry_to_file(col_pentry, fs);
790 ent_iter = col_iter;
793 comment = entry_comment(pentry);
794 if (comment) {
795 fz_fprintf(fs, "#%s\n", comment);
796 } else {
797 fz_fprintf(fs, "\n");
801 } section_list_iterate_end;
803 if (0 != fz_ferror(fs)) {
804 SECFILE_LOG(secfile, NULL, "Error before closing %s: %s",
805 real_filename, fz_strerror(fs));
806 fz_fclose(fs);
807 return FALSE;
809 if (0 != fz_fclose(fs)) {
810 SECFILE_LOG(secfile, NULL, "Error closing %s", real_filename);
811 return FALSE;
814 return TRUE;
817 /**************************************************************************
818 Print log messages for any entries in the file which have
819 not been looked up -- ie, unused or unrecognised entries.
820 To mark an entry as used without actually doing anything with it,
821 you could do something like:
822 section_file_lookup(&file, "foo.bar"); / * unused * /
823 **************************************************************************/
824 void secfile_check_unused(const struct section_file *secfile)
826 bool any = FALSE;
828 section_list_iterate(secfile_sections(secfile), psection) {
829 entry_list_iterate(section_entries(psection), pentry) {
830 if (!entry_used(pentry)) {
831 if (!any && secfile->name) {
832 log_verbose("Unused entries in file %s:", secfile->name);
833 any = TRUE;
835 if (are_deprecation_warnings_enabled()) {
836 log_deprecation_always("%s: unused entry: %s.%s",
837 secfile->name != NULL ? secfile->name : "nameless",
838 section_name(psection), entry_name(pentry));
839 } else {
840 #ifdef FREECIV_TESTMATIC
841 log_testmatic("%s: unused entry: %s.%s",
842 secfile->name != NULL ? secfile->name : "nameless",
843 section_name(psection), entry_name(pentry));
844 #else /* FREECIV_TESTMATIC */
845 log_verbose(" unused entry: %s.%s",
846 section_name(psection), entry_name(pentry));
847 #endif /* FREECIV_TESTMATIC */
850 } entry_list_iterate_end;
851 } section_list_iterate_end;
854 /**************************************************************************
855 Return the filename the section file was loaded as, or "(anonymous)"
856 if this sectionfile was created rather than loaded from file.
857 The memory is managed internally, and should not be altered,
858 nor used after secfile_destroy() called for the section file.
859 **************************************************************************/
860 const char *secfile_name(const struct section_file *secfile)
862 if (NULL == secfile) {
863 return "NULL";
864 } else if (secfile->name) {
865 return secfile->name;
866 } else {
867 return "(anonymous)";
871 /**************************************************************************
872 Seperates the section and entry names. Create the section if missing.
873 **************************************************************************/
874 static struct section *secfile_insert_base(struct section_file *secfile,
875 const char *path,
876 const char **pent_name)
878 char fullpath[MAX_LEN_SECPATH];
879 char *ent_name;
880 struct section *psection;
882 sz_strlcpy(fullpath, path);
884 ent_name = strchr(fullpath, '.');
885 if (!ent_name) {
886 SECFILE_LOG(secfile, NULL,
887 "Section and entry names must be separated by a dot.");
888 return NULL;
891 /* Separates section and entry names. */
892 *ent_name = '\0';
893 *pent_name = path + (ent_name - fullpath) + 1;
894 psection = secfile_section_by_name(secfile, fullpath);
895 if (psection) {
896 return psection;
897 } else {
898 return secfile_section_new(secfile, fullpath);
902 /**************************************************************************
903 Insert a boolean entry.
904 **************************************************************************/
905 struct entry *secfile_insert_bool_full(struct section_file *secfile,
906 bool value, const char *comment,
907 bool allow_replace,
908 const char *path, ...)
910 char fullpath[MAX_LEN_SECPATH];
911 const char *ent_name;
912 struct section *psection;
913 struct entry *pentry = NULL;
914 va_list args;
916 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
918 va_start(args, path);
919 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
920 va_end(args);
922 psection = secfile_insert_base(secfile, fullpath, &ent_name);
923 if (!psection) {
924 return NULL;
927 if (allow_replace) {
928 pentry = section_entry_by_name(psection, ent_name);
929 if (NULL != pentry) {
930 if (ENTRY_BOOL == entry_type(pentry)) {
931 if (!entry_bool_set(pentry, value)) {
932 return NULL;
934 } else {
935 entry_destroy(pentry);
936 pentry = NULL;
941 if (NULL == pentry) {
942 pentry = section_entry_bool_new(psection, ent_name, value);
945 if (NULL != pentry && NULL != comment) {
946 entry_set_comment(pentry, comment);
949 return pentry;
952 /**************************************************************************
953 Insert 'dim' boolean entries at 'path,0', 'path,1' etc. Returns
954 the number of entries inserted or replaced.
955 **************************************************************************/
956 size_t secfile_insert_bool_vec_full(struct section_file *secfile,
957 const bool *values, size_t dim,
958 const char *comment, bool allow_replace,
959 const char *path, ...)
961 char fullpath[MAX_LEN_SECPATH];
962 size_t i, ret = 0;
963 va_list args;
965 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
967 va_start(args, path);
968 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
969 va_end(args);
971 /* NB: 'path,0' is actually 'path'. See comment in the head
972 * of the file. */
973 if (dim > 0
974 && NULL != secfile_insert_bool_full(secfile, values[0], comment,
975 allow_replace, "%s", fullpath)) {
976 ret++;
978 for (i = 1; i < dim; i++) {
979 if (NULL != secfile_insert_bool_full(secfile, values[i], comment,
980 allow_replace, "%s,%d",
981 fullpath, (int) i)) {
982 ret++;
986 return ret;
989 /**************************************************************************
990 Insert a integer entry.
991 **************************************************************************/
992 struct entry *secfile_insert_int_full(struct section_file *secfile,
993 int value, const char *comment,
994 bool allow_replace,
995 const char *path, ...)
997 char fullpath[MAX_LEN_SECPATH];
998 const char *ent_name;
999 struct section *psection;
1000 struct entry *pentry = NULL;
1001 va_list args;
1003 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1005 va_start(args, path);
1006 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1007 va_end(args);
1009 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1010 if (!psection) {
1011 return NULL;
1014 if (allow_replace) {
1015 pentry = section_entry_by_name(psection, ent_name);
1016 if (NULL != pentry) {
1017 if (ENTRY_INT == entry_type(pentry)) {
1018 if (!entry_int_set(pentry, value)) {
1019 return NULL;
1021 } else {
1022 entry_destroy(pentry);
1023 pentry = NULL;
1028 if (NULL == pentry) {
1029 pentry = section_entry_int_new(psection, ent_name, value);
1032 if (NULL != pentry && NULL != comment) {
1033 entry_set_comment(pentry, comment);
1036 return pentry;
1039 /**************************************************************************
1040 Insert 'dim' integer entries at 'path,0', 'path,1' etc. Returns
1041 the number of entries inserted or replaced.
1042 **************************************************************************/
1043 size_t secfile_insert_int_vec_full(struct section_file *secfile,
1044 const int *values, size_t dim,
1045 const char *comment, bool allow_replace,
1046 const char *path, ...)
1048 char fullpath[MAX_LEN_SECPATH];
1049 size_t i, ret = 0;
1050 va_list args;
1052 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1054 va_start(args, path);
1055 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1056 va_end(args);
1058 /* NB: 'path,0' is actually 'path'. See comment in the head
1059 * of the file. */
1060 if (dim > 0
1061 && NULL != secfile_insert_int_full(secfile, values[0], comment,
1062 allow_replace, "%s", fullpath)) {
1063 ret++;
1065 for (i = 1; i < dim; i++) {
1066 if (NULL != secfile_insert_int_full(secfile, values[i], comment,
1067 allow_replace, "%s,%d",
1068 fullpath, (int) i)) {
1069 ret++;
1073 return ret;
1076 /**************************************************************************
1077 Insert a floating entry.
1078 **************************************************************************/
1079 struct entry *secfile_insert_float_full(struct section_file *secfile,
1080 float value, const char *comment,
1081 bool allow_replace,
1082 const char *path, ...)
1084 char fullpath[MAX_LEN_SECPATH];
1085 const char *ent_name;
1086 struct section *psection;
1087 struct entry *pentry = NULL;
1088 va_list args;
1090 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1092 va_start(args, path);
1093 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1094 va_end(args);
1096 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1097 if (!psection) {
1098 return NULL;
1101 if (allow_replace) {
1102 pentry = section_entry_by_name(psection, ent_name);
1103 if (NULL != pentry) {
1104 if (ENTRY_FLOAT == entry_type(pentry)) {
1105 if (!entry_float_set(pentry, value)) {
1106 return NULL;
1108 } else {
1109 entry_destroy(pentry);
1110 pentry = NULL;
1115 if (NULL == pentry) {
1116 pentry = section_entry_float_new(psection, ent_name, value);
1119 if (NULL != pentry && NULL != comment) {
1120 entry_set_comment(pentry, comment);
1123 return pentry;
1126 /**************************************************************************
1127 Insert a include entry.
1128 **************************************************************************/
1129 struct section *secfile_insert_include(struct section_file *secfile,
1130 const char *filename)
1132 struct section *psection;
1133 char buffer[200];
1135 fc_snprintf(buffer, sizeof(buffer), "include_%u", secfile->num_includes++);
1137 fc_assert_ret_val(secfile_section_by_name(secfile, filename) == NULL, NULL);
1139 /* Create include section. */
1140 psection = secfile_section_new(secfile, buffer);
1141 psection->include = TRUE;
1143 /* Then add string entry "file" to it. */
1144 secfile_insert_str_full(secfile, filename, NULL, FALSE, FALSE, TRUE, "%s.file", buffer);
1146 return psection;
1149 /**************************************************************************
1150 Insert a string entry.
1151 **************************************************************************/
1152 struct entry *secfile_insert_str_full(struct section_file *secfile,
1153 const char *str,
1154 const char *comment,
1155 bool allow_replace,
1156 bool no_escape,
1157 bool include,
1158 const char *path, ...)
1160 char fullpath[MAX_LEN_SECPATH];
1161 const char *ent_name;
1162 struct section *psection;
1163 struct entry *pentry = NULL;
1164 va_list args;
1166 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1168 va_start(args, path);
1169 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1170 va_end(args);
1172 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1173 if (!psection) {
1174 return NULL;
1177 if (psection->include && !include) {
1178 log_error("Tried to insert normal entry to include section");
1179 return NULL;
1182 if (allow_replace) {
1183 pentry = section_entry_by_name(psection, ent_name);
1184 if (NULL != pentry) {
1185 if (ENTRY_STR == entry_type(pentry)) {
1186 if (!entry_str_set(pentry, str)) {
1187 return NULL;
1189 } else {
1190 entry_destroy(pentry);
1191 pentry = NULL;
1196 if (NULL == pentry) {
1197 pentry = section_entry_str_new(psection, ent_name, str, !no_escape);
1200 if (NULL != pentry && NULL != comment) {
1201 entry_set_comment(pentry, comment);
1204 return pentry;
1207 /**************************************************************************
1208 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1209 the number of entries inserted or replaced.
1210 **************************************************************************/
1211 size_t secfile_insert_str_vec_full(struct section_file *secfile,
1212 const char *const *strings, size_t dim,
1213 const char *comment, bool allow_replace,
1214 bool no_escape, const char *path, ...)
1216 char fullpath[MAX_LEN_SECPATH];
1217 size_t i, ret = 0;
1218 va_list args;
1220 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1222 va_start(args, path);
1223 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1224 va_end(args);
1226 /* NB: 'path,0' is actually 'path'. See comment in the head
1227 * of the file. */
1228 if (dim > 0
1229 && NULL != secfile_insert_str_full(secfile, strings[0], comment,
1230 allow_replace, no_escape, FALSE,
1231 "%s", fullpath)) {
1232 ret++;
1234 for (i = 1; i < dim; i++) {
1235 if (NULL != secfile_insert_str_full(secfile, strings[i], comment,
1236 allow_replace, no_escape, FALSE,
1237 "%s,%d", fullpath, (int) i)) {
1238 ret++;
1242 return ret;
1245 /****************************************************************************
1246 Insert a read-from-a-file string entry
1247 ****************************************************************************/
1248 struct entry *secfile_insert_filereference(struct section_file *secfile,
1249 char *filename, char *path, ...)
1251 char fullpath[MAX_LEN_SECPATH];
1252 const char *ent_name;
1253 struct section *psection;
1254 struct entry *pentry = NULL;
1255 va_list args;
1257 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1259 va_start(args, path);
1260 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1261 va_end(args);
1263 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1264 if (!psection) {
1265 return NULL;
1268 if (psection->include) {
1269 log_error("Tried to insert normal entry to include section");
1270 return NULL;
1273 if (NULL == pentry) {
1274 pentry = section_entry_filereference_new(psection, ent_name, filename);
1277 return pentry;
1280 /****************************************************************************
1281 Insert a enumerator entry.
1282 ****************************************************************************/
1283 struct entry *secfile_insert_plain_enum_full(struct section_file *secfile,
1284 int enumerator,
1285 secfile_enum_name_fn_t name_fn,
1286 const char *comment,
1287 bool allow_replace,
1288 const char *path, ...)
1290 char fullpath[MAX_LEN_SECPATH];
1291 const char *str;
1292 const char *ent_name;
1293 struct section *psection;
1294 struct entry *pentry = NULL;
1295 va_list args;
1297 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1298 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1299 str = name_fn(enumerator);
1300 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != str, NULL);
1302 va_start(args, path);
1303 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1304 va_end(args);
1306 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1307 if (!psection) {
1308 return NULL;
1311 if (allow_replace) {
1312 pentry = section_entry_by_name(psection, ent_name);
1313 if (NULL != pentry) {
1314 if (ENTRY_STR == entry_type(pentry)) {
1315 if (!entry_str_set(pentry, str)) {
1316 return NULL;
1318 } else {
1319 entry_destroy(pentry);
1320 pentry = NULL;
1325 if (NULL == pentry) {
1326 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1329 if (NULL != pentry && NULL != comment) {
1330 entry_set_comment(pentry, comment);
1333 return pentry;
1336 /****************************************************************************
1337 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1338 the number of entries inserted or replaced.
1339 ****************************************************************************/
1340 size_t secfile_insert_plain_enum_vec_full(struct section_file *secfile,
1341 const int *enumurators, size_t dim,
1342 secfile_enum_name_fn_t name_fn,
1343 const char *comment,
1344 bool allow_replace,
1345 const char *path, ...)
1347 char fullpath[MAX_LEN_SECPATH];
1348 size_t i, ret = 0;
1349 va_list args;
1351 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1352 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1354 va_start(args, path);
1355 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1356 va_end(args);
1358 /* NB: 'path,0' is actually 'path'. See comment in the head
1359 * of the file. */
1360 if (dim > 0
1361 && NULL != secfile_insert_plain_enum_full(secfile, enumurators[0],
1362 name_fn, comment,
1363 allow_replace, "%s",
1364 fullpath)) {
1365 ret++;
1367 for (i = 1; i < dim; i++) {
1368 if (NULL != secfile_insert_plain_enum_full(secfile, enumurators[i],
1369 name_fn, comment,
1370 allow_replace, "%s,%d",
1371 fullpath, (int) i)) {
1372 ret++;
1376 return ret;
1379 /****************************************************************************
1380 Insert a bitwise value entry.
1381 ****************************************************************************/
1382 struct entry *secfile_insert_bitwise_enum_full(struct section_file *secfile,
1383 int bitwise_val,
1384 secfile_enum_name_fn_t
1385 name_fn,
1386 secfile_enum_iter_fn_t
1387 begin_fn,
1388 secfile_enum_iter_fn_t
1389 end_fn,
1390 secfile_enum_next_fn_t
1391 next_fn,
1392 const char *comment,
1393 bool allow_replace,
1394 const char *path, ...)
1396 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1397 const char *ent_name;
1398 struct section *psection;
1399 struct entry *pentry = NULL;
1400 va_list args;
1401 int i;
1403 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1404 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1405 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, NULL);
1406 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, NULL);
1407 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, NULL);
1409 /* Compute a string containing all the values separated by '|'. */
1410 str[0] = '\0'; /* Insert at least an empty string. */
1411 if (0 != bitwise_val) {
1412 for (i = begin_fn(); i != end_fn(); i = next_fn(i)) {
1413 if (i & bitwise_val) {
1414 if ('\0' == str[0]) {
1415 sz_strlcpy(str, name_fn(i));
1416 } else {
1417 cat_snprintf(str, sizeof(str), "|%s", name_fn(i));
1423 va_start(args, path);
1424 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1425 va_end(args);
1427 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1428 if (!psection) {
1429 return NULL;
1432 if (allow_replace) {
1433 pentry = section_entry_by_name(psection, ent_name);
1434 if (NULL != pentry) {
1435 if (ENTRY_STR == entry_type(pentry)) {
1436 if (!entry_str_set(pentry, str)) {
1437 return NULL;
1439 } else {
1440 entry_destroy(pentry);
1441 pentry = NULL;
1446 if (NULL == pentry) {
1447 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1450 if (NULL != pentry && NULL != comment) {
1451 entry_set_comment(pentry, comment);
1454 return pentry;
1457 /****************************************************************************
1458 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1459 the number of entries inserted or replaced.
1460 ****************************************************************************/
1461 size_t secfile_insert_bitwise_enum_vec_full(struct section_file *secfile,
1462 const int *bitwise_vals,
1463 size_t dim,
1464 secfile_enum_name_fn_t name_fn,
1465 secfile_enum_iter_fn_t begin_fn,
1466 secfile_enum_iter_fn_t end_fn,
1467 secfile_enum_next_fn_t next_fn,
1468 const char *comment,
1469 bool allow_replace,
1470 const char *path, ...)
1472 char fullpath[MAX_LEN_SECPATH];
1473 size_t i, ret = 0;
1474 va_list args;
1476 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1477 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1478 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, 0);
1479 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, 0);
1480 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, 0);
1482 va_start(args, path);
1483 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1484 va_end(args);
1486 /* NB: 'path,0' is actually 'path'. See comment in the head
1487 * of the file. */
1488 if (dim > 0
1489 && NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[0],
1490 name_fn, begin_fn, end_fn,
1491 next_fn, comment,
1492 allow_replace, "%s",
1493 fullpath)) {
1494 ret++;
1496 for (i = 1; i < dim; i++) {
1497 if (NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[i],
1498 name_fn, begin_fn, end_fn,
1499 next_fn, comment,
1500 allow_replace, "%s,%d",
1501 fullpath, (int) i)) {
1502 ret++;
1506 return ret;
1509 /****************************************************************************
1510 Insert an enumerator value entry that we only have a name accessor
1511 function.
1512 ****************************************************************************/
1513 struct entry *secfile_insert_enum_data_full(struct section_file *secfile,
1514 int value, bool bitwise,
1515 secfile_enum_name_data_fn_t name_fn,
1516 secfile_data_t data,
1517 const char *comment,
1518 bool allow_replace,
1519 const char *path, ...)
1521 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1522 const char *ent_name, *val_name;
1523 struct section *psection;
1524 struct entry *pentry = NULL;
1525 va_list args;
1526 int i;
1528 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1529 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1531 if (bitwise) {
1532 /* Compute a string containing all the values separated by '|'. */
1533 str[0] = '\0'; /* Insert at least an empty string. */
1534 if (0 != value) {
1535 for (i = 0; (val_name = name_fn(data, i)); i++) {
1536 if ((1 << i) & value) {
1537 if ('\0' == str[0]) {
1538 sz_strlcpy(str, val_name);
1539 } else {
1540 cat_snprintf(str, sizeof(str), "|%s", val_name);
1545 } else {
1546 if (!(val_name = name_fn(data, value))) {
1547 SECFILE_LOG(secfile, NULL, "Value %d not supported.", value);
1548 return NULL;
1550 sz_strlcpy(str, val_name);
1553 va_start(args, path);
1554 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1555 va_end(args);
1557 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1558 if (!psection) {
1559 return NULL;
1562 if (allow_replace) {
1563 pentry = section_entry_by_name(psection, ent_name);
1564 if (NULL != pentry) {
1565 if (ENTRY_STR == entry_type(pentry)) {
1566 if (!entry_str_set(pentry, str)) {
1567 return NULL;
1569 } else {
1570 entry_destroy(pentry);
1571 pentry = NULL;
1576 if (NULL == pentry) {
1577 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1580 if (NULL != pentry && NULL != comment) {
1581 entry_set_comment(pentry, comment);
1584 return pentry;
1587 /****************************************************************************
1588 Insert 'dim' entries at 'path,0', 'path,1' etc. Returns the number of
1589 entries inserted or replaced.
1590 ****************************************************************************/
1591 size_t secfile_insert_enum_vec_data_full(struct section_file *secfile,
1592 const int *values, size_t dim,
1593 bool bitwise,
1594 secfile_enum_name_data_fn_t name_fn,
1595 secfile_data_t data,
1596 const char *comment,
1597 bool allow_replace,
1598 const char *path, ...)
1600 char fullpath[MAX_LEN_SECPATH];
1601 size_t i, ret = 0;
1602 va_list args;
1604 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1605 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1607 va_start(args, path);
1608 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1609 va_end(args);
1611 /* NB: 'path,0' is actually 'path'. See comment in the head
1612 * of the file. */
1613 if (dim > 0
1614 && NULL != secfile_insert_enum_data_full(secfile, values[0], bitwise,
1615 name_fn, data, comment,
1616 allow_replace, "%s",
1617 fullpath)) {
1618 ret++;
1620 for (i = 1; i < dim; i++) {
1621 if (NULL != secfile_insert_enum_data_full(secfile, values[i], bitwise,
1622 name_fn, data, comment,
1623 allow_replace, "%s,%d",
1624 fullpath, (int) i)) {
1625 ret++;
1629 return ret;
1632 /****************************************************************************
1633 Returns the entry by the name or NULL if not matched.
1634 ****************************************************************************/
1635 struct entry *secfile_entry_by_path(const struct section_file *secfile,
1636 const char *path)
1638 char fullpath[MAX_LEN_SECPATH];
1639 char *ent_name;
1640 size_t len;
1641 struct section *psection;
1643 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1645 sz_strlcpy(fullpath, path);
1647 /* treat "sec.foo,0" as "sec.foo": */
1648 len = strlen(fullpath);
1649 if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1650 fullpath[len - 2] = '\0';
1653 if (NULL != secfile->hash.entries) {
1654 struct entry *pentry;
1656 if (entry_hash_lookup(secfile->hash.entries, fullpath, &pentry)) {
1657 entry_use(pentry);
1659 return pentry;
1662 /* I dont like strtok.
1663 * - Me neither! */
1664 ent_name = strchr(fullpath, '.');
1665 if (!ent_name) {
1666 return NULL;
1669 /* Separates section and entry names. */
1670 *ent_name++ = '\0';
1671 psection = secfile_section_by_name(secfile, fullpath);
1672 if (psection) {
1673 return section_entry_by_name(psection, ent_name);
1674 } else {
1675 return NULL;
1679 /**************************************************************************
1680 Delete an entry.
1681 **************************************************************************/
1682 bool secfile_entry_delete(struct section_file *secfile,
1683 const char *path, ...)
1685 char fullpath[MAX_LEN_SECPATH];
1686 va_list args;
1687 struct entry *pentry;
1689 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1691 va_start(args, path);
1692 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1693 va_end(args);
1695 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1696 SECFILE_LOG(secfile, NULL, "Path %s does not exists.", fullpath);
1697 return FALSE;
1700 entry_destroy(pentry);
1702 return TRUE;
1705 /**************************************************************************
1706 Returns the entry at "fullpath" or NULL if not matched.
1707 **************************************************************************/
1708 struct entry *secfile_entry_lookup(const struct section_file *secfile,
1709 const char *path, ...)
1711 char fullpath[MAX_LEN_SECPATH];
1712 va_list args;
1714 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1716 va_start(args, path);
1717 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1718 va_end(args);
1720 return secfile_entry_by_path(secfile, fullpath);
1723 /**************************************************************************
1724 Lookup a boolean value in the secfile. Returns TRUE on success.
1725 **************************************************************************/
1726 bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1727 const char *path, ...)
1729 char fullpath[MAX_LEN_SECPATH];
1730 const struct entry *pentry;
1731 va_list args;
1733 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1735 va_start(args, path);
1736 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1737 va_end(args);
1739 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1740 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1741 return FALSE;
1744 return entry_bool_get(pentry, bval);
1747 /**************************************************************************
1748 Lookup a boolean value in the secfile. On failure, use the default
1749 value.
1750 **************************************************************************/
1751 bool secfile_lookup_bool_default(const struct section_file *secfile,
1752 bool def, const char *path, ...)
1754 char fullpath[MAX_LEN_SECPATH];
1755 const struct entry *pentry;
1756 bool bval;
1757 va_list args;
1759 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1761 va_start(args, path);
1762 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1763 va_end(args);
1765 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1766 return def;
1769 if (entry_bool_get(pentry, &bval)) {
1770 return bval;
1773 return def;
1776 /**************************************************************************
1777 Lookup a boolean vector in the secfile. Returns NULL on error. This
1778 vector is not owned by the registry module, and should be free by the
1779 user.
1780 **************************************************************************/
1781 bool *secfile_lookup_bool_vec(const struct section_file *secfile,
1782 size_t *dim, const char *path, ...)
1784 char fullpath[MAX_LEN_SECPATH];
1785 size_t i = 0;
1786 bool *vec;
1787 va_list args;
1789 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1790 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
1792 va_start(args, path);
1793 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1794 va_end(args);
1796 /* Check size. */
1797 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1798 i++;
1800 *dim = i;
1802 if (0 == i) {
1803 /* Doesn't exist. */
1804 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1805 return NULL;
1808 vec = fc_malloc(i * sizeof(bool));
1809 for(i = 0; i < *dim; i++) {
1810 if (!secfile_lookup_bool(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1811 SECFILE_LOG(secfile, NULL,
1812 "An error occurred when looking up to \"%s,%d\" entry.",
1813 fullpath, (int) i);
1814 free(vec);
1815 *dim = 0;
1816 return NULL;
1820 return vec;
1823 /**************************************************************************
1824 Lookup a integer value in the secfile. Returns TRUE on success.
1825 **************************************************************************/
1826 bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1827 const char *path, ...)
1829 char fullpath[MAX_LEN_SECPATH];
1830 const struct entry *pentry;
1831 va_list args;
1833 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1835 va_start(args, path);
1836 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1837 va_end(args);
1839 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1840 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1841 return FALSE;
1844 return entry_int_get(pentry, ival);
1847 /**************************************************************************
1848 Lookup a integer value in the secfile. On failure, use the default
1849 value.
1850 **************************************************************************/
1851 int secfile_lookup_int_default(const struct section_file *secfile, int def,
1852 const char *path, ...)
1854 char fullpath[MAX_LEN_SECPATH];
1855 const struct entry *pentry;
1856 int ival;
1857 va_list args;
1859 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1861 va_start(args, path);
1862 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1863 va_end(args);
1865 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1866 return def;
1869 if (entry_int_get(pentry, &ival)) {
1870 return ival;
1873 return def;
1876 /**************************************************************************
1877 Lookup a integer value in the secfile. The value will be arranged to
1878 match the interval [minval, maxval]. On failure, use the default
1879 value.
1880 **************************************************************************/
1881 int secfile_lookup_int_def_min_max(const struct section_file *secfile,
1882 int defval, int minval, int maxval,
1883 const char *path, ...)
1885 char fullpath[MAX_LEN_SECPATH];
1886 const struct entry *pentry;
1887 int value;
1888 va_list args;
1890 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
1892 va_start(args, path);
1893 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1894 va_end(args);
1896 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1897 return defval;
1900 if (!entry_int_get(pentry, &value)) {
1901 return defval;
1904 if (value < minval) {
1905 SECFILE_LOG(secfile, entry_section(pentry),
1906 "\"%s\" should be in the interval [%d, %d] but is %d;"
1907 "using the minimal value.",
1908 fullpath, minval, maxval, value);
1909 value = minval;
1912 if (value > maxval) {
1913 SECFILE_LOG(secfile, entry_section(pentry),
1914 "\"%s\" should be in the interval [%d, %d] but is %d;"
1915 "using the maximal value.",
1916 fullpath, minval, maxval, value);
1917 value = maxval;
1920 return value;
1923 /**************************************************************************
1924 Lookup a integer vector in the secfile. Returns NULL on error. This
1925 vector is not owned by the registry module, and should be free by the
1926 user.
1927 **************************************************************************/
1928 int *secfile_lookup_int_vec(const struct section_file *secfile,
1929 size_t *dim, const char *path, ...)
1931 char fullpath[MAX_LEN_SECPATH];
1932 size_t i = 0;
1933 int *vec;
1934 va_list args;
1936 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1937 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
1939 va_start(args, path);
1940 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1941 va_end(args);
1943 /* Check size. */
1944 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1945 i++;
1947 *dim = i;
1949 if (0 == i) {
1950 /* Doesn't exist. */
1951 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1952 return NULL;
1955 vec = fc_malloc(i * sizeof(int));
1956 for(i = 0; i < *dim; i++) {
1957 if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1958 SECFILE_LOG(secfile, NULL,
1959 "An error occurred when looking up to \"%s,%d\" entry.",
1960 fullpath, (int) i);
1961 free(vec);
1962 *dim = 0;
1963 return NULL;
1967 return vec;
1970 /**************************************************************************
1971 Lookup a floating point value in the secfile. Returns TRUE on success.
1972 **************************************************************************/
1973 bool secfile_lookup_float(const struct section_file *secfile, float *fval,
1974 const char *path, ...)
1976 char fullpath[MAX_LEN_SECPATH];
1977 const struct entry *pentry;
1978 va_list args;
1980 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1982 va_start(args, path);
1983 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1984 va_end(args);
1986 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1987 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1988 return FALSE;
1991 return entry_float_get(pentry, fval);
1994 /**************************************************************************
1995 Lookup a floating point value in the secfile. On failure, use the default
1996 value.
1997 **************************************************************************/
1998 float secfile_lookup_float_default(const struct section_file *secfile,
1999 float def, const char *path, ...)
2001 char fullpath[MAX_LEN_SECPATH];
2002 const struct entry *pentry;
2003 float fval;
2004 va_list args;
2006 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2008 va_start(args, path);
2009 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2010 va_end(args);
2012 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2013 return def;
2016 if (entry_float_get(pentry, &fval)) {
2017 return fval;
2020 return def;
2023 /**************************************************************************
2024 Lookup a string value in the secfile. Returns NULL on error.
2025 **************************************************************************/
2026 const char *secfile_lookup_str(const struct section_file *secfile,
2027 const char *path, ...)
2029 char fullpath[MAX_LEN_SECPATH];
2030 const struct entry *pentry;
2031 const char *str;
2032 va_list args;
2034 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2036 va_start(args, path);
2037 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2038 va_end(args);
2040 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2041 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2042 return NULL;
2045 if (entry_str_get(pentry, &str)) {
2046 return str;
2049 return NULL;
2052 /**************************************************************************
2053 Lookup a string value in the secfile. On failure, use the default
2054 value.
2055 **************************************************************************/
2056 const char *secfile_lookup_str_default(const struct section_file *secfile,
2057 const char *def,
2058 const char *path, ...)
2060 char fullpath[MAX_LEN_SECPATH];
2061 const struct entry *pentry;
2062 const char *str;
2063 va_list args;
2065 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2067 va_start(args, path);
2068 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2069 va_end(args);
2071 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2072 return def;
2075 if (entry_str_get(pentry, &str)) {
2076 return str;
2079 return def;
2082 /**************************************************************************
2083 Lookup a string vector in the secfile. Returns NULL on error. This
2084 vector is not owned by the registry module, and should be free by the
2085 user, but the string pointers stored inside the vector shouldn't be
2086 free.
2087 **************************************************************************/
2088 const char **secfile_lookup_str_vec(const struct section_file *secfile,
2089 size_t *dim, const char *path, ...)
2091 char fullpath[MAX_LEN_SECPATH];
2092 size_t i = 0;
2093 const char **vec;
2094 va_list args;
2096 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2097 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2099 va_start(args, path);
2100 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2101 va_end(args);
2103 /* Check size. */
2104 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2105 i++;
2107 *dim = i;
2109 if (0 == i) {
2110 /* Doesn't exist. */
2111 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2112 return NULL;
2115 vec = fc_malloc(i * sizeof(const char *));
2116 for(i = 0; i < *dim; i++) {
2117 if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d",
2118 fullpath, (int) i))) {
2119 SECFILE_LOG(secfile, NULL,
2120 "An error occurred when looking up to \"%s,%d\" entry.",
2121 fullpath, (int) i);
2122 free(vec);
2123 *dim = 0;
2124 return NULL;
2128 return vec;
2131 /****************************************************************************
2132 Lookup an enumerator value in the secfile. Returns FALSE on error.
2133 ****************************************************************************/
2134 bool secfile_lookup_plain_enum_full(const struct section_file *secfile,
2135 int *penumerator,
2136 secfile_enum_is_valid_fn_t is_valid_fn,
2137 secfile_enum_by_name_fn_t by_name_fn,
2138 const char *path, ...)
2140 char fullpath[MAX_LEN_SECPATH];
2141 const struct entry *pentry;
2142 const char *str;
2143 va_list args;
2145 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2146 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2147 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2148 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2150 va_start(args, path);
2151 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2152 va_end(args);
2154 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2155 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2156 return FALSE;
2159 if (!entry_str_get(pentry, &str)) {
2160 return FALSE;
2163 *penumerator = by_name_fn(str, strcmp);
2164 if (is_valid_fn(*penumerator)) {
2165 return TRUE;
2168 SECFILE_LOG(secfile, entry_section(pentry),
2169 "Entry \"%s\": no match for \"%s\".",
2170 entry_name(pentry), str);
2171 return FALSE;
2174 /****************************************************************************
2175 Lookup an enumerator value in the secfile. Returns 'defval' on error.
2176 ****************************************************************************/
2177 int secfile_lookup_plain_enum_default_full(const struct section_file
2178 *secfile, int defval,
2179 secfile_enum_is_valid_fn_t
2180 is_valid_fn,
2181 secfile_enum_by_name_fn_t
2182 by_name_fn,
2183 const char *path, ...)
2185 char fullpath[MAX_LEN_SECPATH];
2186 const struct entry *pentry;
2187 const char *str;
2188 int val;
2189 va_list args;
2191 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2192 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2193 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2195 va_start(args, path);
2196 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2197 va_end(args);
2199 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2200 return defval;
2203 if (!entry_str_get(pentry, &str)) {
2204 return defval;
2207 val = by_name_fn(str, strcmp);
2208 if (is_valid_fn(val)) {
2209 return val;
2210 } else {
2211 return defval;
2215 /**************************************************************************
2216 Lookup a enumerator vector in the secfile. Returns NULL on error. This
2217 vector is not owned by the registry module, and should be free by the
2218 user.
2219 **************************************************************************/
2220 int *secfile_lookup_plain_enum_vec_full(const struct section_file *secfile,
2221 size_t *dim,
2222 secfile_enum_is_valid_fn_t
2223 is_valid_fn,
2224 secfile_enum_by_name_fn_t
2225 by_name_fn,
2226 const char *path, ...)
2228 char fullpath[MAX_LEN_SECPATH];
2229 size_t i = 0;
2230 int *vec;
2231 va_list args;
2233 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2234 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2235 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2236 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2238 va_start(args, path);
2239 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2240 va_end(args);
2242 /* Check size. */
2243 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2244 i++;
2246 *dim = i;
2248 if (0 == i) {
2249 /* Doesn't exist. */
2250 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2251 return NULL;
2254 vec = fc_malloc(i * sizeof(int));
2255 for(i = 0; i < *dim; i++) {
2256 if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2257 by_name_fn, "%s,%d",
2258 fullpath, (int) i)) {
2259 SECFILE_LOG(secfile, NULL,
2260 "An error occurred when looking up to \"%s,%d\" entry.",
2261 fullpath, (int) i);
2262 free(vec);
2263 *dim = 0;
2264 return NULL;
2268 return vec;
2271 /****************************************************************************
2272 Lookup a bitwise enumerator value in the secfile. Returns FALSE on error.
2273 ****************************************************************************/
2274 bool secfile_lookup_bitwise_enum_full(const struct section_file *secfile,
2275 int *penumerator,
2276 secfile_enum_is_valid_fn_t is_valid_fn,
2277 secfile_enum_by_name_fn_t by_name_fn,
2278 const char *path, ...)
2280 char fullpath[MAX_LEN_SECPATH];
2281 const struct entry *pentry;
2282 const char *str, *p;
2283 char val_name[MAX_LEN_SECPATH];
2284 int val;
2285 va_list args;
2287 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2288 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2289 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2290 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2292 va_start(args, path);
2293 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2294 va_end(args);
2296 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2297 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2298 return FALSE;
2301 if (!entry_str_get(pentry, &str)) {
2302 return FALSE;
2305 *penumerator = 0;
2306 if ('\0' == str[0]) {
2307 /* Empty string = no value. */
2308 return TRUE;
2311 /* Value names are separated by '|'. */
2312 do {
2313 p = strchr(str, '|');
2314 if (NULL != p) {
2315 p++;
2316 fc_strlcpy(val_name, str, p - str);
2317 } else {
2318 /* Last segment, full copy. */
2319 sz_strlcpy(val_name, str);
2321 remove_leading_trailing_spaces(val_name);
2322 val = by_name_fn(val_name, strcmp);
2323 if (!is_valid_fn(val)) {
2324 SECFILE_LOG(secfile, entry_section(pentry),
2325 "Entry \"%s\": no match for \"%s\".",
2326 entry_name(pentry), val_name);
2327 return FALSE;
2329 *penumerator |= val;
2330 str = p;
2331 } while (NULL != p);
2333 return TRUE;
2336 /****************************************************************************
2337 Lookup an enumerator value in the secfile. Returns 'defval' on error.
2338 ****************************************************************************/
2339 int secfile_lookup_bitwise_enum_default_full(const struct section_file
2340 *secfile, int defval,
2341 secfile_enum_is_valid_fn_t
2342 is_valid_fn,
2343 secfile_enum_by_name_fn_t
2344 by_name_fn,
2345 const char *path, ...)
2347 char fullpath[MAX_LEN_SECPATH];
2348 const struct entry *pentry;
2349 const char *str, *p;
2350 char val_name[MAX_LEN_SECPATH];
2351 int val, full_val;
2352 va_list args;
2354 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2355 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2356 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2358 va_start(args, path);
2359 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2360 va_end(args);
2362 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2363 return defval;
2366 if (!entry_str_get(pentry, &str)) {
2367 return defval;
2370 if ('\0' == str[0]) {
2371 /* Empty string = no value. */
2372 return 0;
2375 /* Value names are separated by '|'. */
2376 full_val = 0;
2377 do {
2378 p = strchr(str, '|');
2379 if (NULL != p) {
2380 p++;
2381 fc_strlcpy(val_name, str, p - str);
2382 } else {
2383 /* Last segment, full copy. */
2384 sz_strlcpy(val_name, str);
2386 remove_leading_trailing_spaces(val_name);
2387 val = by_name_fn(val_name, strcmp);
2388 if (!is_valid_fn(val)) {
2389 return defval;
2391 full_val |= val;
2392 str = p;
2393 } while (NULL != p);
2395 return full_val;
2398 /**************************************************************************
2399 Lookup a enumerator vector in the secfile. Returns NULL on error. This
2400 vector is not owned by the registry module, and should be free by the
2401 user.
2402 **************************************************************************/
2403 int *secfile_lookup_bitwise_enum_vec_full(const struct section_file *secfile,
2404 size_t *dim,
2405 secfile_enum_is_valid_fn_t
2406 is_valid_fn,
2407 secfile_enum_by_name_fn_t
2408 by_name_fn,
2409 const char *path, ...)
2411 char fullpath[MAX_LEN_SECPATH];
2412 size_t i = 0;
2413 int *vec;
2414 va_list args;
2416 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2417 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2418 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2419 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2421 va_start(args, path);
2422 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2423 va_end(args);
2425 /* Check size. */
2426 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2427 i++;
2429 *dim = i;
2431 if (0 == i) {
2432 /* Doesn't exist. */
2433 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2434 return NULL;
2437 vec = fc_malloc(i * sizeof(int));
2438 for(i = 0; i < *dim; i++) {
2439 if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2440 by_name_fn, "%s,%d",
2441 fullpath, (int) i)) {
2442 SECFILE_LOG(secfile, NULL,
2443 "An error occurred when looking up to \"%s,%d\" entry.",
2444 fullpath, (int) i);
2445 free(vec);
2446 *dim = 0;
2447 return NULL;
2451 return vec;
2454 /****************************************************************************
2455 Lookup a value saved as string in the secfile. Returns FALSE on error.
2456 ****************************************************************************/
2457 bool secfile_lookup_enum_data(const struct section_file *secfile,
2458 int *pvalue, bool bitwise,
2459 secfile_enum_name_data_fn_t name_fn,
2460 secfile_data_t data, const char *path, ...)
2462 char fullpath[MAX_LEN_SECPATH];
2463 const struct entry *pentry;
2464 const char *str, *p, *name;
2465 char val_name[MAX_LEN_SECPATH];
2466 int val;
2467 va_list args;
2469 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2470 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != pvalue, FALSE);
2471 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, FALSE);
2473 va_start(args, path);
2474 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2475 va_end(args);
2477 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2478 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2479 return FALSE;
2482 if (!entry_str_get(pentry, &str)) {
2483 return FALSE;
2486 if (bitwise) {
2487 *pvalue = 0;
2488 if ('\0' == str[0]) {
2489 /* Empty string = no value. */
2490 return TRUE;
2493 /* Value names are separated by '|'. */
2494 do {
2495 p = strchr(str, '|');
2496 if (NULL != p) {
2497 p++;
2498 fc_strlcpy(val_name, str, p - str);
2499 } else {
2500 /* Last segment, full copy. */
2501 sz_strlcpy(val_name, str);
2503 remove_leading_trailing_spaces(val_name);
2504 for (val = 0; (name = name_fn(data, val)); val++) {
2505 if (0 == fc_strcasecmp(name, val_name)) {
2506 break;
2509 if (NULL == name) {
2510 SECFILE_LOG(secfile, entry_section(pentry),
2511 "Entry \"%s\": no match for \"%s\".",
2512 entry_name(pentry), val_name);
2513 return FALSE;
2515 *pvalue |= 1 << val;
2516 str = p;
2517 } while (NULL != p);
2518 } else {
2519 for (val = 0; (name = name_fn(data, val)); val++) {
2520 if (0 == fc_strcasecmp(name, str)) {
2521 *pvalue = val;
2522 break;
2525 if (NULL == name) {
2526 SECFILE_LOG(secfile, entry_section(pentry),
2527 "Entry \"%s\": no match for \"%s\".",
2528 entry_name(pentry), str);
2529 return FALSE;
2533 return TRUE;
2536 /****************************************************************************
2537 Lookup a value saved as string in the secfile. Returns 'defval' on error.
2538 ****************************************************************************/
2539 int secfile_lookup_enum_default_data(const struct section_file *secfile,
2540 int defval, bool bitwise,
2541 secfile_enum_name_data_fn_t name_fn,
2542 secfile_data_t data,
2543 const char *path, ...)
2545 char fullpath[MAX_LEN_SECPATH];
2546 const struct entry *pentry;
2547 const char *str, *p, *name;
2548 char val_name[MAX_LEN_SECPATH];
2549 int value, val;
2550 va_list args;
2552 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2553 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, defval);
2555 va_start(args, path);
2556 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2557 va_end(args);
2559 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2560 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2561 return defval;
2564 if (!entry_str_get(pentry, &str)) {
2565 return defval;
2568 value = 0;
2569 if (bitwise) {
2570 if ('\0' == str[0]) {
2571 /* Empty string = no value. */
2572 return value;
2575 /* Value names are separated by '|'. */
2576 do {
2577 p = strchr(str, '|');
2578 if (NULL != p) {
2579 p++;
2580 fc_strlcpy(val_name, str, p - str);
2581 } else {
2582 /* Last segment, full copy. */
2583 sz_strlcpy(val_name, str);
2585 remove_leading_trailing_spaces(val_name);
2586 for (val = 0; (name = name_fn(data, val)); val++) {
2587 if (0 == strcmp(name, val_name)) {
2588 break;
2591 if (NULL == name) {
2592 SECFILE_LOG(secfile, entry_section(pentry),
2593 "Entry \"%s\": no match for \"%s\".",
2594 entry_name(pentry), val_name);
2595 return defval;
2597 value |= 1 << val;
2598 str = p;
2599 } while (NULL != p);
2600 } else {
2601 for (val = 0; (name = name_fn(data, val)); val++) {
2602 if (0 == strcmp(name, str)) {
2603 value = val;
2604 break;
2607 if (NULL == name) {
2608 SECFILE_LOG(secfile, entry_section(pentry),
2609 "Entry \"%s\": no match for \"%s\".",
2610 entry_name(pentry), str);
2611 return defval;
2615 return value;
2618 /****************************************************************************
2619 Lookup a vector in the secfile. Returns NULL on error. This vector
2620 is not owned by the registry module, and should be free by the user.
2621 ****************************************************************************/
2622 int *secfile_lookup_enum_vec_data(const struct section_file *secfile,
2623 size_t *dim, bool bitwise,
2624 secfile_enum_name_data_fn_t name_fn,
2625 secfile_data_t data, const char *path, ...)
2627 char fullpath[MAX_LEN_SECPATH];
2628 size_t i = 0;
2629 int *vec;
2630 va_list args;
2632 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2633 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2634 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
2636 va_start(args, path);
2637 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2638 va_end(args);
2640 /* Check size. */
2641 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2642 i++;
2644 *dim = i;
2646 if (0 == i) {
2647 /* Doesn't exist. */
2648 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2649 return NULL;
2652 vec = fc_malloc(i * sizeof(int));
2653 for (i = 0; i < *dim; i++) {
2654 if (!secfile_lookup_enum_data(secfile, vec + i, bitwise, name_fn, data,
2655 "%s,%d", fullpath, (int) i)) {
2656 SECFILE_LOG(secfile, NULL,
2657 "An error occurred when looking up to \"%s,%d\" entry.",
2658 fullpath, (int) i);
2659 free(vec);
2660 *dim = 0;
2661 return NULL;
2665 return vec;
2668 /****************************************************************************
2669 Returns the first section matching the name.
2670 ****************************************************************************/
2671 struct section *secfile_section_by_name(const struct section_file *secfile,
2672 const char *name)
2674 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2676 section_list_iterate(secfile->sections, psection) {
2677 if (0 == strcmp(section_name(psection), name)) {
2678 return psection;
2680 } section_list_iterate_end;
2682 return NULL;
2685 /**************************************************************************
2686 Find a section by path.
2687 **************************************************************************/
2688 struct section *secfile_section_lookup(const struct section_file *secfile,
2689 const char *path, ...)
2691 char fullpath[MAX_LEN_SECPATH];
2692 va_list args;
2694 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2696 va_start(args, path);
2697 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2698 va_end(args);
2700 return secfile_section_by_name(secfile, fullpath);
2703 /**************************************************************************
2704 Returns the list of sections. This list is owned by the registry module
2705 and shouldn't be modified and destroyed.
2706 **************************************************************************/
2707 const struct section_list *
2708 secfile_sections(const struct section_file *secfile)
2710 return (NULL != secfile ? secfile->sections : NULL);
2713 /**************************************************************************
2714 Returns the list of sections which match the name prefix. Returns NULL
2715 if no section was found. This list is not owned by the registry module
2716 and the user must destroy it when he finished to work with it.
2717 **************************************************************************/
2718 struct section_list *
2719 secfile_sections_by_name_prefix(const struct section_file *secfile,
2720 const char *prefix)
2722 struct section_list *matches = NULL;
2723 size_t len;
2725 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2726 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, NULL);
2728 len = strlen(prefix);
2729 if (0 == len) {
2730 return NULL;
2733 section_list_iterate(secfile->sections, psection) {
2734 if (0 == strncmp(section_name(psection), prefix, len)) {
2735 if (NULL == matches) {
2736 matches = section_list_new();
2738 section_list_append(matches, psection);
2740 } section_list_iterate_end;
2742 return matches;
2745 /**************************************************************************
2746 Create a new section in the secfile.
2747 **************************************************************************/
2748 struct section *secfile_section_new(struct section_file *secfile,
2749 const char *name)
2751 struct section *psection;
2753 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2755 if (NULL == name || '\0' == name[0]) {
2756 SECFILE_LOG(secfile, NULL, "Cannot create a section without name.");
2757 return NULL;
2760 if (!is_secfile_entry_name_valid(name)) {
2761 SECFILE_LOG(secfile, NULL, "\"%s\" is not a valid section name.",
2762 name);
2763 return NULL;
2766 if (NULL != secfile_section_by_name(secfile, name)) {
2767 /* We cannot duplicate sections in any case! Not even if one is
2768 * include -section and the other not. */
2769 SECFILE_LOG(secfile, NULL, "Section \"%s\" already exists.", name);
2770 return NULL;
2773 psection = fc_malloc(sizeof(struct section));
2774 psection->include = FALSE;
2775 psection->name = fc_strdup(name);
2776 psection->entries = entry_list_new_full(entry_destroy);
2778 /* Append to secfile. */
2779 psection->secfile = secfile;
2780 section_list_append(secfile->sections, psection);
2782 if (NULL != secfile->hash.sections) {
2783 section_hash_insert(secfile->hash.sections, psection->name, psection);
2786 return psection;
2789 /**************************************************************************
2790 Remove this section from the secfile.
2791 **************************************************************************/
2792 void section_destroy(struct section *psection)
2794 struct section_file *secfile;
2796 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2798 section_clear_all(psection);
2800 if ((secfile = psection->secfile)) {
2801 /* Detach from secfile. */
2802 if (section_list_remove(secfile->sections, psection)) {
2803 /* This has called section_destroy() already then. */
2804 return;
2806 if (NULL != secfile->hash.sections) {
2807 section_hash_remove(secfile->hash.sections, psection->name);
2811 entry_list_destroy(psection->entries);
2812 free(psection->name);
2813 free(psection);
2816 /**************************************************************************
2817 Remove all entries.
2818 **************************************************************************/
2819 void section_clear_all(struct section *psection)
2821 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2823 /* This include the removing of the hash datas. */
2824 entry_list_clear(psection->entries);
2826 if (0 < entry_list_size(psection->entries)) {
2827 SECFILE_LOG(psection->secfile, psection,
2828 "After clearing all, %d entries are still remaining.",
2829 entry_list_size(psection->entries));
2833 /**************************************************************************
2834 Change the section name. Returns TRUE on success.
2835 **************************************************************************/
2836 bool section_set_name(struct section *psection, const char *name)
2838 struct section_file *secfile;
2839 struct section *pother;
2841 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, FALSE);
2842 secfile = psection->secfile;
2843 SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, NULL != secfile, FALSE);
2845 if (NULL == name || '\0' == name[0]) {
2846 SECFILE_LOG(secfile, psection, "No new name for section \"%s\".",
2847 psection->name);
2848 return FALSE;
2851 if (!is_secfile_entry_name_valid(name)) {
2852 SECFILE_LOG(secfile, psection,
2853 "\"%s\" is not a valid section name for section \"%s\".",
2854 name, psection->name);
2855 return FALSE;
2858 if ((pother = secfile_section_by_name(secfile, name))
2859 && pother != psection) {
2860 /* We cannot duplicate sections in any case! */
2861 SECFILE_LOG(secfile, psection, "Section \"%s\" already exists.", name);
2862 return FALSE;
2865 /* Remove old references in the hash tables. */
2866 if (NULL != secfile->hash.sections) {
2867 section_hash_remove(secfile->hash.sections, psection->name);
2869 if (NULL != secfile->hash.entries) {
2870 entry_list_iterate(psection->entries, pentry) {
2871 secfile_hash_delete(secfile, pentry);
2872 } entry_list_iterate_end;
2875 /* Really rename. */
2876 free(psection->name);
2877 psection->name = fc_strdup(name);
2879 /* Reinsert new references into the hash tables. */
2880 if (NULL != secfile->hash.sections) {
2881 section_hash_insert(secfile->hash.sections, psection->name, psection);
2883 if (NULL != secfile->hash.entries) {
2884 entry_list_iterate(psection->entries, pentry) {
2885 secfile_hash_insert(secfile, pentry);
2886 } entry_list_iterate_end;
2889 return TRUE;
2892 /**************************************************************************
2893 Returns a list containing all the entries. This list is owned by the
2894 secfile, so don't modify or destroy it.
2895 **************************************************************************/
2896 const struct entry_list *section_entries(const struct section *psection)
2898 return (NULL != psection ? psection->entries : NULL);
2901 /**************************************************************************
2902 Returns the the first entry matching the name.
2903 **************************************************************************/
2904 struct entry *section_entry_by_name(const struct section *psection,
2905 const char *name)
2907 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2909 entry_list_iterate(psection->entries, pentry) {
2910 if (0 == strcmp(entry_name(pentry), name)) {
2911 entry_use(pentry);
2912 return pentry;
2914 } entry_list_iterate_end;
2916 return NULL;
2919 /**************************************************************************
2920 Returns the entry matching the path.
2921 **************************************************************************/
2922 struct entry *section_entry_lookup(const struct section *psection,
2923 const char *path, ...)
2925 char fullpath[MAX_LEN_SECPATH];
2926 struct entry *pentry;
2927 va_list args;
2929 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2931 va_start(args, path);
2932 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2933 va_end(args);
2935 if ((pentry = section_entry_by_name(psection, fullpath))) {
2936 return pentry;
2939 /* Try with full path. */
2940 if ((pentry = secfile_entry_by_path(psection->secfile, fullpath))
2941 && psection == entry_section(pentry)) {
2942 /* Unsure this is really owned by this section. */
2943 return pentry;
2946 return NULL;
2950 /* An 'entry' is a string, integer, boolean or string vector;
2951 * See enum entry_type in registry.h.
2953 struct entry {
2954 struct section *psection; /* Parent section. */
2955 char *name; /* Name, not including section prefix. */
2956 enum entry_type type; /* The type of the entry. */
2957 int used; /* Number of times entry looked up. */
2958 char *comment; /* Comment, may be NULL. */
2960 union {
2961 /* ENTRY_BOOL */
2962 struct {
2963 bool value;
2964 } boolean;
2965 /* ENTRY_INT */
2966 struct {
2967 int value;
2968 } integer;
2969 /* ENTRY_FLOAT */
2970 struct {
2971 float value;
2972 } floating;
2973 /* ENTRY_STR */
2974 struct {
2975 char *value; /* Malloced string. */
2976 bool escaped; /* " or $. Usually TRUE */
2977 bool gt_marking; /* Save with gettext marking. */
2978 } string;
2982 /**************************************************************************
2983 Returns a new entry.
2984 **************************************************************************/
2985 static struct entry *entry_new(struct section *psection, const char *name)
2987 struct section_file *secfile;
2988 struct entry *pentry;
2990 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2992 secfile = psection->secfile;
2993 if (NULL == name || '\0' == name[0]) {
2994 SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
2995 return NULL;
2998 if (!is_secfile_entry_name_valid(name)) {
2999 SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
3000 name);
3001 return NULL;
3004 if (!secfile->allow_duplicates
3005 && NULL != section_entry_by_name(psection, name)) {
3006 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3007 return NULL;
3010 pentry = fc_malloc(sizeof(struct entry));
3011 pentry->name = fc_strdup(name);
3012 pentry->type = -1; /* Invalid case. */
3013 pentry->used = 0;
3014 pentry->comment = NULL;
3016 /* Append to section. */
3017 pentry->psection = psection;
3018 entry_list_append(psection->entries, pentry);
3020 /* Notify secfile. */
3021 secfile->num_entries++;
3022 secfile_hash_insert(secfile, pentry);
3024 return pentry;
3027 /**************************************************************************
3028 Returns a new entry of type ENTRY_INT.
3029 **************************************************************************/
3030 struct entry *section_entry_int_new(struct section *psection,
3031 const char *name, int value)
3033 struct entry *pentry = entry_new(psection, name);
3035 if (NULL != pentry) {
3036 pentry->type = ENTRY_INT;
3037 pentry->integer.value = value;
3040 return pentry;
3043 /**************************************************************************
3044 Returns a new entry of type ENTRY_BOOL.
3045 **************************************************************************/
3046 struct entry *section_entry_bool_new(struct section *psection,
3047 const char *name, bool value)
3049 struct entry *pentry = entry_new(psection, name);
3051 if (NULL != pentry) {
3052 pentry->type = ENTRY_BOOL;
3053 pentry->boolean.value = value;
3056 return pentry;
3059 /**************************************************************************
3060 Returns a new entry of type ENTRY_FLOAT.
3061 **************************************************************************/
3062 struct entry *section_entry_float_new(struct section *psection,
3063 const char *name, float value)
3065 struct entry *pentry = entry_new(psection, name);
3067 if (NULL != pentry) {
3068 pentry->type = ENTRY_FLOAT;
3069 pentry->floating.value = value;
3072 return pentry;
3075 /**************************************************************************
3076 Returns a new entry of type ENTRY_STR.
3077 **************************************************************************/
3078 struct entry *section_entry_str_new(struct section *psection,
3079 const char *name, const char *value,
3080 bool escaped)
3082 struct entry *pentry = entry_new(psection, name);
3084 if (NULL != pentry) {
3085 pentry->type = ENTRY_STR;
3086 pentry->string.value = fc_strdup(NULL != value ? value : "");
3087 pentry->string.escaped = escaped;
3088 pentry->string.gt_marking = FALSE;
3091 return pentry;
3094 /**************************************************************************
3095 Returns a new entry of type ENTRY_FILEREFERENCE.
3096 **************************************************************************/
3097 static struct entry *section_entry_filereference_new(struct section *psection,
3098 const char *name, const char *value)
3100 struct entry *pentry = entry_new(psection, name);
3102 if (NULL != pentry) {
3103 pentry->type = ENTRY_FILEREFERENCE;
3104 pentry->string.value = fc_strdup(NULL != value ? value : "");
3107 return pentry;
3110 /**************************************************************************
3111 Entry structure destructor.
3112 **************************************************************************/
3113 void entry_destroy(struct entry *pentry)
3115 struct section_file *secfile;
3116 struct section *psection;
3118 if (NULL == pentry) {
3119 return;
3122 if ((psection = pentry->psection)) {
3123 /* Detach from section. */
3124 if (entry_list_remove(psection->entries, pentry)) {
3125 /* This has called entry_destroy() already then. */
3126 return;
3128 if ((secfile = psection->secfile)) {
3129 /* Detach from secfile. */
3130 secfile->num_entries--;
3131 secfile_hash_delete(secfile, pentry);
3135 /* Specific type free. */
3136 switch (pentry->type) {
3137 case ENTRY_BOOL:
3138 case ENTRY_INT:
3139 case ENTRY_FLOAT:
3140 break;
3142 case ENTRY_STR:
3143 case ENTRY_FILEREFERENCE:
3144 free(pentry->string.value);
3145 break;
3148 /* Common free. */
3149 free(pentry->name);
3150 if (NULL != pentry->comment) {
3151 free(pentry->comment);
3153 free(pentry);
3156 /**************************************************************************
3157 Returns the parent section of this entry.
3158 **************************************************************************/
3159 struct section *entry_section(const struct entry *pentry)
3161 return (NULL != pentry ? pentry->psection : NULL);
3164 /**************************************************************************
3165 Returns the type of this entry or -1 or error.
3166 **************************************************************************/
3167 enum entry_type entry_type(const struct entry *pentry)
3169 return (NULL != pentry ? pentry->type : -1);
3172 /**************************************************************************
3173 Build the entry path. Returns like snprintf().
3174 **************************************************************************/
3175 int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3177 return fc_snprintf(buf, buf_len, "%s.%s",
3178 section_name(entry_section(pentry)),
3179 entry_name(pentry));
3182 /**************************************************************************
3183 Returns the name of this entry.
3184 **************************************************************************/
3185 const char *entry_name(const struct entry *pentry)
3187 return (NULL != pentry ? pentry->name : NULL);
3190 /**************************************************************************
3191 Sets the name of the entry. Returns TRUE on success.
3192 **************************************************************************/
3193 bool entry_set_name(struct entry *pentry, const char *name)
3195 struct section *psection;
3196 struct section_file *secfile;
3198 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3199 psection = pentry->psection;
3200 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != psection, FALSE);
3201 secfile = psection->secfile;
3202 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != secfile, FALSE);
3204 if (NULL == name || '\0' == name[0]) {
3205 SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3206 pentry->name);
3207 return FALSE;
3210 if (!is_secfile_entry_name_valid(name)) {
3211 SECFILE_LOG(secfile, psection,
3212 "\"%s\" is not a valid entry name for entry \"%s\".",
3213 name, pentry->name);
3214 return FALSE;
3217 if (!secfile->allow_duplicates) {
3218 struct entry *pother = section_entry_by_name(psection, name);
3220 if (NULL != pother && pother != pentry) {
3221 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3222 return FALSE;
3226 /* Remove from hash table the old path. */
3227 secfile_hash_delete(secfile, pentry);
3229 /* Really rename the entry. */
3230 free(pentry->name);
3231 pentry->name = fc_strdup(name);
3233 /* Insert into hash table the new path. */
3234 secfile_hash_insert(secfile, pentry);
3235 return TRUE;
3238 /**************************************************************************
3239 Returns the comment associated to this entry.
3240 **************************************************************************/
3241 const char *entry_comment(const struct entry *pentry)
3243 return (NULL != pentry ? pentry->comment : NULL);
3246 /**************************************************************************
3247 Sets a comment for the entry. Pass NULL to remove the current one.
3248 **************************************************************************/
3249 void entry_set_comment(struct entry *pentry, const char *comment)
3251 if (NULL == pentry) {
3252 return;
3255 if (NULL != pentry->comment) {
3256 free(pentry->comment);
3259 pentry->comment = (NULL != comment ? fc_strdup(comment) : NULL);
3262 /**************************************************************************
3263 Returns TRUE if this entry has been used.
3264 **************************************************************************/
3265 static inline bool entry_used(const struct entry *pentry)
3267 return (0 < pentry->used);
3270 /**************************************************************************
3271 Increase the used count.
3272 **************************************************************************/
3273 static inline void entry_use(struct entry *pentry)
3275 pentry->used++;
3278 /**************************************************************************
3279 Gets an boolean value. Returns TRUE on success.
3280 On old saved files, 0 and 1 can also be considered as bool.
3281 **************************************************************************/
3282 bool entry_bool_get(const struct entry *pentry, bool *value)
3284 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3286 if (ENTRY_INT == pentry->type
3287 && (pentry->integer.value == 0
3288 || pentry->integer.value == 1)
3289 && NULL != pentry->psection
3290 && NULL != pentry->psection->secfile
3291 && pentry->psection->secfile->allow_digital_boolean) {
3292 *value = (0 != pentry->integer.value);
3293 return TRUE;
3296 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3297 ENTRY_BOOL == pentry->type, FALSE);
3299 if (NULL != value) {
3300 *value = pentry->boolean.value;
3302 return TRUE;
3305 /**************************************************************************
3306 Sets an boolean value. Returns TRUE on success.
3307 **************************************************************************/
3308 bool entry_bool_set(struct entry *pentry, bool value)
3310 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3311 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3312 ENTRY_BOOL == pentry->type, FALSE);
3314 pentry->boolean.value = value;
3315 return TRUE;
3318 /**************************************************************************
3319 Gets an floating value. Returns TRUE on success.
3320 **************************************************************************/
3321 bool entry_float_get(const struct entry *pentry, float *value)
3323 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3324 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3325 ENTRY_FLOAT == pentry->type, FALSE);
3327 if (NULL != value) {
3328 *value = pentry->floating.value;
3331 return TRUE;
3334 /**************************************************************************
3335 Sets an floating value. Returns TRUE on success.
3336 **************************************************************************/
3337 bool entry_float_set(struct entry *pentry, float value)
3339 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3340 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3341 ENTRY_FLOAT == pentry->type, FALSE);
3343 pentry->floating.value = value;
3345 return TRUE;
3348 /**************************************************************************
3349 Gets an integer value. Returns TRUE on success.
3350 **************************************************************************/
3351 bool entry_int_get(const struct entry *pentry, int *value)
3353 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3354 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3355 ENTRY_INT == pentry->type, FALSE);
3357 if (NULL != value) {
3358 *value = pentry->integer.value;
3360 return TRUE;
3363 /**************************************************************************
3364 Sets an integer value. Returns TRUE on success.
3365 **************************************************************************/
3366 bool entry_int_set(struct entry *pentry, int value)
3368 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3369 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3370 ENTRY_INT == pentry->type, FALSE);
3372 pentry->integer.value = value;
3373 return TRUE;
3376 /**************************************************************************
3377 Gets an string value. Returns TRUE on success.
3378 **************************************************************************/
3379 bool entry_str_get(const struct entry *pentry, const char **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_STR == pentry->type, FALSE);
3385 if (NULL != value) {
3386 *value = pentry->string.value;
3388 return TRUE;
3391 /**************************************************************************
3392 Sets an string value. Returns TRUE on success.
3393 **************************************************************************/
3394 bool entry_str_set(struct entry *pentry, const char *value)
3396 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3397 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3398 ENTRY_STR == pentry->type, FALSE);
3400 free(pentry->string.value);
3401 pentry->string.value = fc_strdup(NULL != value ? value : "");
3402 return TRUE;
3405 /**************************************************************************
3406 Returns if the string would be escaped.
3407 **************************************************************************/
3408 bool entry_str_escaped(const struct entry *pentry)
3410 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3411 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3412 ENTRY_STR == pentry->type, FALSE);
3414 return pentry->string.escaped;
3417 /**************************************************************************
3418 Sets if the string would be escaped. Returns TRUE on success.
3419 **************************************************************************/
3420 bool entry_str_set_escaped(struct entry *pentry, bool escaped)
3422 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3423 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3424 ENTRY_STR == pentry->type, FALSE);
3426 pentry->string.escaped = escaped;
3427 return TRUE;
3430 /**************************************************************************
3431 Sets if the string should get gettext marking. Returns TRUE on success.
3432 **************************************************************************/
3433 bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
3435 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3436 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3437 ENTRY_STR == pentry->type, FALSE);
3439 pentry->string.gt_marking = gt_marking;
3441 return TRUE;
3444 /**************************************************************************
3445 Push an entry into a file stream.
3446 **************************************************************************/
3447 static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
3449 static char buf[8192];
3450 char *dot = NULL;
3451 int i;
3453 switch (pentry->type) {
3454 case ENTRY_BOOL:
3455 fz_fprintf(fs, "%s", pentry->boolean.value ? "TRUE" : "FALSE");
3456 break;
3457 case ENTRY_INT:
3458 fz_fprintf(fs, "%d", pentry->integer.value);
3459 break;
3460 case ENTRY_FLOAT:
3461 snprintf(buf, sizeof(buf), "%f", pentry->floating.value);
3462 for (i = 0; buf[i] != '\0' ; i++) {
3463 if (buf[i] == '.') {
3464 dot = &(buf[i]);
3465 break;
3468 if (dot == NULL) {
3469 /* There's no '.' so it would seem like a integer value when loaded.
3470 * Force it not to look like an integer by adding ".0" */
3471 fz_fprintf(fs, "%s.0", buf);
3472 } else {
3473 fz_fprintf(fs, "%s", buf);
3475 break;
3476 case ENTRY_STR:
3477 if (pentry->string.escaped) {
3478 make_escapes(pentry->string.value, buf, sizeof(buf));
3479 if (pentry->string.gt_marking) {
3480 fz_fprintf(fs, "_(\"%s\")", buf);
3481 } else {
3482 fz_fprintf(fs, "\"%s\"", buf);
3484 } else {
3485 fz_fprintf(fs, "$%s$", pentry->string.value);
3487 break;
3488 case ENTRY_FILEREFERENCE:
3489 fz_fprintf(fs, "*%s*", pentry->string.value);
3490 break;
3494 /**************************************************************************
3495 Creates a new entry from the token.
3496 **************************************************************************/
3497 static void entry_from_inf_token(struct section *psection, const char *name,
3498 const char *tok, struct inputfile *inf)
3500 if (!entry_from_token(psection, name, tok)) {
3501 log_error("%s", inf_log_str(inf, "Entry value not recognized: %s", tok));