Allow using things that were deprecated in gtk+-3.22.
[freeciv.git] / utility / registry_ini.c
blob8762cc1673037b2055bc3cfa54a39d6915d89228
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 SECFILE_LOG(secfile, NULL, _("Could not open %s for writing"), real_filename);
619 return FALSE;
622 section_list_iterate(secfile->sections, psection) {
623 if (psection->include) {
624 for (ent_iter = entry_list_head(section_entries(psection));
625 ent_iter && (pentry = entry_list_link_data(ent_iter));
626 ent_iter = entry_list_link_next(ent_iter)) {
628 fc_assert(!strcmp(entry_name(pentry), "file"));
630 fz_fprintf(fs, "*include ");
631 entry_to_file(pentry, fs);
632 fz_fprintf(fs, "\n");
634 } else {
635 fz_fprintf(fs, "\n[%s]\n", section_name(psection));
637 /* Following doesn't use entry_list_iterate() because we want to do
638 * tricky things with the iterators...
640 for (ent_iter = entry_list_head(section_entries(psection));
641 ent_iter && (pentry = entry_list_link_data(ent_iter));
642 ent_iter = entry_list_link_next(ent_iter)) {
643 const char *comment;
645 /* Tables: break out of this loop if this is a non-table
646 * entry (pentry and ent_iter unchanged) or after table (pentry
647 * and ent_iter suitably updated, pentry possibly NULL).
648 * After each table, loop again in case the next entry
649 * is another table.
651 for (;;) {
652 char *c, *first, base[64];
653 int offset, irow, icol, ncol;
655 /* Example: for first table name of "xyz0.blah":
656 * first points to the original string pentry->name
657 * base contains "xyz";
658 * offset = 5 (so first+offset gives "blah")
659 * note strlen(base) = offset - 2
662 if (!SAVE_TABLES) {
663 break;
666 sz_strlcpy(pentry_name, entry_name(pentry));
667 c = first = pentry_name;
668 if (*c == '\0' || !is_legal_table_entry_name(*c, FALSE)) {
669 break;
671 for (; *c != '\0' && is_legal_table_entry_name(*c, FALSE); c++) {
672 /* nothing */
674 if (0 != strncmp(c, "0.", 2)) {
675 break;
677 c += 2;
678 if (*c == '\0' || !is_legal_table_entry_name(*c, TRUE)) {
679 break;
682 offset = c - first;
683 first[offset - 2] = '\0';
684 sz_strlcpy(base, first);
685 first[offset - 2] = '0';
686 fz_fprintf(fs, "%s={", base);
688 /* Save an iterator at this first entry, which we can later use
689 * to repeatedly iterate over column names:
691 save_iter = ent_iter;
693 /* write the column names, and calculate ncol: */
694 ncol = 0;
695 col_iter = save_iter;
696 for(; (col_pentry = entry_list_link_data(col_iter));
697 col_iter = entry_list_link_next(col_iter)) {
698 col_entry_name = entry_name(col_pentry);
699 if (strncmp(col_entry_name, first, offset) != 0) {
700 break;
702 fz_fprintf(fs, "%s\"%s\"", (ncol == 0 ? "" : ","),
703 col_entry_name + offset);
704 ncol++;
706 fz_fprintf(fs, "\n");
708 /* Iterate over rows and columns, incrementing ent_iter as we go,
709 * and writing values to the table. Have a separate iterator
710 * to the column names to check they all match.
712 irow = icol = 0;
713 col_iter = save_iter;
714 for (;;) {
715 char expect[128]; /* pentry->name we're expecting */
717 pentry = entry_list_link_data(ent_iter);
718 col_pentry = entry_list_link_data(col_iter);
720 fc_snprintf(expect, sizeof(expect), "%s%d.%s",
721 base, irow, entry_name(col_pentry) + offset);
723 /* break out of tabular if doesn't match: */
724 if ((!pentry) || (strcmp(entry_name(pentry), expect) != 0)) {
725 if (icol != 0) {
726 /* If the second or later row of a table is missing some
727 * entries that the first row had, we drop out of the tabular
728 * format. This is inefficient so we print a warning message;
729 * the calling code probably needs to be fixed so that it can
730 * use the more efficient tabular format.
732 * FIXME: If the first row is missing some entries that the
733 * second or later row has, then we'll drop out of tabular
734 * format without an error message. */
735 log_error("In file %s, there is no entry in the registry for\n"
736 "%s.%s (or the entries are out of order). This means\n"
737 "a less efficient non-tabular format will be used.\n"
738 "To avoid this make sure all rows of a table are\n"
739 "filled out with an entry for every column.",
740 real_filename, section_name(psection), expect);
741 /* TRANS: No full stop after the URL, could cause confusion. */
742 log_error(_("Please report this message at %s"), BUG_URL);
743 fz_fprintf(fs, "\n");
745 fz_fprintf(fs, "}\n");
746 break;
749 if (icol > 0) {
750 fz_fprintf(fs, ",");
752 entry_to_file(pentry, fs);
754 ent_iter = entry_list_link_next(ent_iter);
755 col_iter = entry_list_link_next(col_iter);
757 icol++;
758 if (icol == ncol) {
759 fz_fprintf(fs, "\n");
760 irow++;
761 icol = 0;
762 col_iter = save_iter;
765 if (!pentry) {
766 break;
769 if (!pentry) {
770 break;
773 /* Classic entry. */
774 col_entry_name = entry_name(pentry);
775 fz_fprintf(fs, "%s=", col_entry_name);
776 entry_to_file(pentry, fs);
778 /* Check for vector. */
779 for (i = 1;; i++) {
780 col_iter = entry_list_link_next(ent_iter);
781 col_pentry = entry_list_link_data(col_iter);
782 if (NULL == col_pentry) {
783 break;
785 fc_snprintf(pentry_name, sizeof(pentry_name),
786 "%s,%d", col_entry_name, i);
787 if (0 != strcmp(pentry_name, entry_name(col_pentry))) {
788 break;
790 fz_fprintf(fs, ",");
791 entry_to_file(col_pentry, fs);
792 ent_iter = col_iter;
795 comment = entry_comment(pentry);
796 if (comment) {
797 fz_fprintf(fs, "#%s\n", comment);
798 } else {
799 fz_fprintf(fs, "\n");
803 } section_list_iterate_end;
805 if (0 != fz_ferror(fs)) {
806 SECFILE_LOG(secfile, NULL, "Error before closing %s: %s",
807 real_filename, fz_strerror(fs));
808 fz_fclose(fs);
809 return FALSE;
811 if (0 != fz_fclose(fs)) {
812 SECFILE_LOG(secfile, NULL, "Error closing %s", real_filename);
813 return FALSE;
816 return TRUE;
819 /**************************************************************************
820 Print log messages for any entries in the file which have
821 not been looked up -- ie, unused or unrecognised entries.
822 To mark an entry as used without actually doing anything with it,
823 you could do something like:
824 section_file_lookup(&file, "foo.bar"); / * unused * /
825 **************************************************************************/
826 void secfile_check_unused(const struct section_file *secfile)
828 bool any = FALSE;
830 section_list_iterate(secfile_sections(secfile), psection) {
831 entry_list_iterate(section_entries(psection), pentry) {
832 if (!entry_used(pentry)) {
833 if (!any && secfile->name) {
834 log_verbose("Unused entries in file %s:", secfile->name);
835 any = TRUE;
837 if (are_deprecation_warnings_enabled()) {
838 log_deprecation_always("%s: unused entry: %s.%s",
839 secfile->name != NULL ? secfile->name : "nameless",
840 section_name(psection), entry_name(pentry));
841 } else {
842 #ifdef FREECIV_TESTMATIC
843 log_testmatic("%s: unused entry: %s.%s",
844 secfile->name != NULL ? secfile->name : "nameless",
845 section_name(psection), entry_name(pentry));
846 #else /* FREECIV_TESTMATIC */
847 log_verbose(" unused entry: %s.%s",
848 section_name(psection), entry_name(pentry));
849 #endif /* FREECIV_TESTMATIC */
852 } entry_list_iterate_end;
853 } section_list_iterate_end;
856 /**************************************************************************
857 Return the filename the section file was loaded as, or "(anonymous)"
858 if this sectionfile was created rather than loaded from file.
859 The memory is managed internally, and should not be altered,
860 nor used after secfile_destroy() called for the section file.
861 **************************************************************************/
862 const char *secfile_name(const struct section_file *secfile)
864 if (NULL == secfile) {
865 return "NULL";
866 } else if (secfile->name) {
867 return secfile->name;
868 } else {
869 return "(anonymous)";
873 /**************************************************************************
874 Seperates the section and entry names. Create the section if missing.
875 **************************************************************************/
876 static struct section *secfile_insert_base(struct section_file *secfile,
877 const char *path,
878 const char **pent_name)
880 char fullpath[MAX_LEN_SECPATH];
881 char *ent_name;
882 struct section *psection;
884 sz_strlcpy(fullpath, path);
886 ent_name = strchr(fullpath, '.');
887 if (!ent_name) {
888 SECFILE_LOG(secfile, NULL,
889 "Section and entry names must be separated by a dot.");
890 return NULL;
893 /* Separates section and entry names. */
894 *ent_name = '\0';
895 *pent_name = path + (ent_name - fullpath) + 1;
896 psection = secfile_section_by_name(secfile, fullpath);
897 if (psection) {
898 return psection;
899 } else {
900 return secfile_section_new(secfile, fullpath);
904 /**************************************************************************
905 Insert a boolean entry.
906 **************************************************************************/
907 struct entry *secfile_insert_bool_full(struct section_file *secfile,
908 bool value, const char *comment,
909 bool allow_replace,
910 const char *path, ...)
912 char fullpath[MAX_LEN_SECPATH];
913 const char *ent_name;
914 struct section *psection;
915 struct entry *pentry = NULL;
916 va_list args;
918 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
920 va_start(args, path);
921 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
922 va_end(args);
924 psection = secfile_insert_base(secfile, fullpath, &ent_name);
925 if (!psection) {
926 return NULL;
929 if (allow_replace) {
930 pentry = section_entry_by_name(psection, ent_name);
931 if (NULL != pentry) {
932 if (ENTRY_BOOL == entry_type(pentry)) {
933 if (!entry_bool_set(pentry, value)) {
934 return NULL;
936 } else {
937 entry_destroy(pentry);
938 pentry = NULL;
943 if (NULL == pentry) {
944 pentry = section_entry_bool_new(psection, ent_name, value);
947 if (NULL != pentry && NULL != comment) {
948 entry_set_comment(pentry, comment);
951 return pentry;
954 /**************************************************************************
955 Insert 'dim' boolean entries at 'path,0', 'path,1' etc. Returns
956 the number of entries inserted or replaced.
957 **************************************************************************/
958 size_t secfile_insert_bool_vec_full(struct section_file *secfile,
959 const bool *values, size_t dim,
960 const char *comment, bool allow_replace,
961 const char *path, ...)
963 char fullpath[MAX_LEN_SECPATH];
964 size_t i, ret = 0;
965 va_list args;
967 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
969 va_start(args, path);
970 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
971 va_end(args);
973 /* NB: 'path,0' is actually 'path'. See comment in the head
974 * of the file. */
975 if (dim > 0
976 && NULL != secfile_insert_bool_full(secfile, values[0], comment,
977 allow_replace, "%s", fullpath)) {
978 ret++;
980 for (i = 1; i < dim; i++) {
981 if (NULL != secfile_insert_bool_full(secfile, values[i], comment,
982 allow_replace, "%s,%d",
983 fullpath, (int) i)) {
984 ret++;
988 return ret;
991 /**************************************************************************
992 Insert a integer entry.
993 **************************************************************************/
994 struct entry *secfile_insert_int_full(struct section_file *secfile,
995 int value, const char *comment,
996 bool allow_replace,
997 const char *path, ...)
999 char fullpath[MAX_LEN_SECPATH];
1000 const char *ent_name;
1001 struct section *psection;
1002 struct entry *pentry = NULL;
1003 va_list args;
1005 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1007 va_start(args, path);
1008 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1009 va_end(args);
1011 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1012 if (!psection) {
1013 return NULL;
1016 if (allow_replace) {
1017 pentry = section_entry_by_name(psection, ent_name);
1018 if (NULL != pentry) {
1019 if (ENTRY_INT == entry_type(pentry)) {
1020 if (!entry_int_set(pentry, value)) {
1021 return NULL;
1023 } else {
1024 entry_destroy(pentry);
1025 pentry = NULL;
1030 if (NULL == pentry) {
1031 pentry = section_entry_int_new(psection, ent_name, value);
1034 if (NULL != pentry && NULL != comment) {
1035 entry_set_comment(pentry, comment);
1038 return pentry;
1041 /**************************************************************************
1042 Insert 'dim' integer entries at 'path,0', 'path,1' etc. Returns
1043 the number of entries inserted or replaced.
1044 **************************************************************************/
1045 size_t secfile_insert_int_vec_full(struct section_file *secfile,
1046 const int *values, size_t dim,
1047 const char *comment, bool allow_replace,
1048 const char *path, ...)
1050 char fullpath[MAX_LEN_SECPATH];
1051 size_t i, ret = 0;
1052 va_list args;
1054 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1056 va_start(args, path);
1057 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1058 va_end(args);
1060 /* NB: 'path,0' is actually 'path'. See comment in the head
1061 * of the file. */
1062 if (dim > 0
1063 && NULL != secfile_insert_int_full(secfile, values[0], comment,
1064 allow_replace, "%s", fullpath)) {
1065 ret++;
1067 for (i = 1; i < dim; i++) {
1068 if (NULL != secfile_insert_int_full(secfile, values[i], comment,
1069 allow_replace, "%s,%d",
1070 fullpath, (int) i)) {
1071 ret++;
1075 return ret;
1078 /**************************************************************************
1079 Insert a floating entry.
1080 **************************************************************************/
1081 struct entry *secfile_insert_float_full(struct section_file *secfile,
1082 float value, const char *comment,
1083 bool allow_replace,
1084 const char *path, ...)
1086 char fullpath[MAX_LEN_SECPATH];
1087 const char *ent_name;
1088 struct section *psection;
1089 struct entry *pentry = NULL;
1090 va_list args;
1092 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1094 va_start(args, path);
1095 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1096 va_end(args);
1098 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1099 if (!psection) {
1100 return NULL;
1103 if (allow_replace) {
1104 pentry = section_entry_by_name(psection, ent_name);
1105 if (NULL != pentry) {
1106 if (ENTRY_FLOAT == entry_type(pentry)) {
1107 if (!entry_float_set(pentry, value)) {
1108 return NULL;
1110 } else {
1111 entry_destroy(pentry);
1112 pentry = NULL;
1117 if (NULL == pentry) {
1118 pentry = section_entry_float_new(psection, ent_name, value);
1121 if (NULL != pentry && NULL != comment) {
1122 entry_set_comment(pentry, comment);
1125 return pentry;
1128 /**************************************************************************
1129 Insert a include entry.
1130 **************************************************************************/
1131 struct section *secfile_insert_include(struct section_file *secfile,
1132 const char *filename)
1134 struct section *psection;
1135 char buffer[200];
1137 fc_snprintf(buffer, sizeof(buffer), "include_%u", secfile->num_includes++);
1139 fc_assert_ret_val(secfile_section_by_name(secfile, filename) == NULL, NULL);
1141 /* Create include section. */
1142 psection = secfile_section_new(secfile, buffer);
1143 psection->include = TRUE;
1145 /* Then add string entry "file" to it. */
1146 secfile_insert_str_full(secfile, filename, NULL, FALSE, FALSE, TRUE, "%s.file", buffer);
1148 return psection;
1151 /**************************************************************************
1152 Insert a string entry.
1153 **************************************************************************/
1154 struct entry *secfile_insert_str_full(struct section_file *secfile,
1155 const char *str,
1156 const char *comment,
1157 bool allow_replace,
1158 bool no_escape,
1159 bool include,
1160 const char *path, ...)
1162 char fullpath[MAX_LEN_SECPATH];
1163 const char *ent_name;
1164 struct section *psection;
1165 struct entry *pentry = NULL;
1166 va_list args;
1168 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1170 va_start(args, path);
1171 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1172 va_end(args);
1174 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1175 if (!psection) {
1176 return NULL;
1179 if (psection->include && !include) {
1180 log_error("Tried to insert normal entry to include section");
1181 return NULL;
1184 if (allow_replace) {
1185 pentry = section_entry_by_name(psection, ent_name);
1186 if (NULL != pentry) {
1187 if (ENTRY_STR == entry_type(pentry)) {
1188 if (!entry_str_set(pentry, str)) {
1189 return NULL;
1191 } else {
1192 entry_destroy(pentry);
1193 pentry = NULL;
1198 if (NULL == pentry) {
1199 pentry = section_entry_str_new(psection, ent_name, str, !no_escape);
1202 if (NULL != pentry && NULL != comment) {
1203 entry_set_comment(pentry, comment);
1206 return pentry;
1209 /**************************************************************************
1210 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1211 the number of entries inserted or replaced.
1212 **************************************************************************/
1213 size_t secfile_insert_str_vec_full(struct section_file *secfile,
1214 const char *const *strings, size_t dim,
1215 const char *comment, bool allow_replace,
1216 bool no_escape, const char *path, ...)
1218 char fullpath[MAX_LEN_SECPATH];
1219 size_t i, ret = 0;
1220 va_list args;
1222 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1224 va_start(args, path);
1225 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1226 va_end(args);
1228 /* NB: 'path,0' is actually 'path'. See comment in the head
1229 * of the file. */
1230 if (dim > 0
1231 && NULL != secfile_insert_str_full(secfile, strings[0], comment,
1232 allow_replace, no_escape, FALSE,
1233 "%s", fullpath)) {
1234 ret++;
1236 for (i = 1; i < dim; i++) {
1237 if (NULL != secfile_insert_str_full(secfile, strings[i], comment,
1238 allow_replace, no_escape, FALSE,
1239 "%s,%d", fullpath, (int) i)) {
1240 ret++;
1244 return ret;
1247 /****************************************************************************
1248 Insert a read-from-a-file string entry
1249 ****************************************************************************/
1250 struct entry *secfile_insert_filereference(struct section_file *secfile,
1251 char *filename, char *path, ...)
1253 char fullpath[MAX_LEN_SECPATH];
1254 const char *ent_name;
1255 struct section *psection;
1256 struct entry *pentry = NULL;
1257 va_list args;
1259 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1261 va_start(args, path);
1262 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1263 va_end(args);
1265 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1266 if (!psection) {
1267 return NULL;
1270 if (psection->include) {
1271 log_error("Tried to insert normal entry to include section");
1272 return NULL;
1275 if (NULL == pentry) {
1276 pentry = section_entry_filereference_new(psection, ent_name, filename);
1279 return pentry;
1282 /****************************************************************************
1283 Insert a enumerator entry.
1284 ****************************************************************************/
1285 struct entry *secfile_insert_plain_enum_full(struct section_file *secfile,
1286 int enumerator,
1287 secfile_enum_name_fn_t name_fn,
1288 const char *comment,
1289 bool allow_replace,
1290 const char *path, ...)
1292 char fullpath[MAX_LEN_SECPATH];
1293 const char *str;
1294 const char *ent_name;
1295 struct section *psection;
1296 struct entry *pentry = NULL;
1297 va_list args;
1299 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1300 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1301 str = name_fn(enumerator);
1302 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != str, NULL);
1304 va_start(args, path);
1305 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1306 va_end(args);
1308 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1309 if (!psection) {
1310 return NULL;
1313 if (allow_replace) {
1314 pentry = section_entry_by_name(psection, ent_name);
1315 if (NULL != pentry) {
1316 if (ENTRY_STR == entry_type(pentry)) {
1317 if (!entry_str_set(pentry, str)) {
1318 return NULL;
1320 } else {
1321 entry_destroy(pentry);
1322 pentry = NULL;
1327 if (NULL == pentry) {
1328 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1331 if (NULL != pentry && NULL != comment) {
1332 entry_set_comment(pentry, comment);
1335 return pentry;
1338 /****************************************************************************
1339 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1340 the number of entries inserted or replaced.
1341 ****************************************************************************/
1342 size_t secfile_insert_plain_enum_vec_full(struct section_file *secfile,
1343 const int *enumurators, size_t dim,
1344 secfile_enum_name_fn_t name_fn,
1345 const char *comment,
1346 bool allow_replace,
1347 const char *path, ...)
1349 char fullpath[MAX_LEN_SECPATH];
1350 size_t i, ret = 0;
1351 va_list args;
1353 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1354 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1356 va_start(args, path);
1357 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1358 va_end(args);
1360 /* NB: 'path,0' is actually 'path'. See comment in the head
1361 * of the file. */
1362 if (dim > 0
1363 && NULL != secfile_insert_plain_enum_full(secfile, enumurators[0],
1364 name_fn, comment,
1365 allow_replace, "%s",
1366 fullpath)) {
1367 ret++;
1369 for (i = 1; i < dim; i++) {
1370 if (NULL != secfile_insert_plain_enum_full(secfile, enumurators[i],
1371 name_fn, comment,
1372 allow_replace, "%s,%d",
1373 fullpath, (int) i)) {
1374 ret++;
1378 return ret;
1381 /****************************************************************************
1382 Insert a bitwise value entry.
1383 ****************************************************************************/
1384 struct entry *secfile_insert_bitwise_enum_full(struct section_file *secfile,
1385 int bitwise_val,
1386 secfile_enum_name_fn_t
1387 name_fn,
1388 secfile_enum_iter_fn_t
1389 begin_fn,
1390 secfile_enum_iter_fn_t
1391 end_fn,
1392 secfile_enum_next_fn_t
1393 next_fn,
1394 const char *comment,
1395 bool allow_replace,
1396 const char *path, ...)
1398 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1399 const char *ent_name;
1400 struct section *psection;
1401 struct entry *pentry = NULL;
1402 va_list args;
1403 int i;
1405 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1406 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1407 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, NULL);
1408 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, NULL);
1409 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, NULL);
1411 /* Compute a string containing all the values separated by '|'. */
1412 str[0] = '\0'; /* Insert at least an empty string. */
1413 if (0 != bitwise_val) {
1414 for (i = begin_fn(); i != end_fn(); i = next_fn(i)) {
1415 if (i & bitwise_val) {
1416 if ('\0' == str[0]) {
1417 sz_strlcpy(str, name_fn(i));
1418 } else {
1419 cat_snprintf(str, sizeof(str), "|%s", name_fn(i));
1425 va_start(args, path);
1426 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1427 va_end(args);
1429 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1430 if (!psection) {
1431 return NULL;
1434 if (allow_replace) {
1435 pentry = section_entry_by_name(psection, ent_name);
1436 if (NULL != pentry) {
1437 if (ENTRY_STR == entry_type(pentry)) {
1438 if (!entry_str_set(pentry, str)) {
1439 return NULL;
1441 } else {
1442 entry_destroy(pentry);
1443 pentry = NULL;
1448 if (NULL == pentry) {
1449 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1452 if (NULL != pentry && NULL != comment) {
1453 entry_set_comment(pentry, comment);
1456 return pentry;
1459 /****************************************************************************
1460 Insert 'dim' string entries at 'path,0', 'path,1' etc. Returns
1461 the number of entries inserted or replaced.
1462 ****************************************************************************/
1463 size_t secfile_insert_bitwise_enum_vec_full(struct section_file *secfile,
1464 const int *bitwise_vals,
1465 size_t dim,
1466 secfile_enum_name_fn_t name_fn,
1467 secfile_enum_iter_fn_t begin_fn,
1468 secfile_enum_iter_fn_t end_fn,
1469 secfile_enum_next_fn_t next_fn,
1470 const char *comment,
1471 bool allow_replace,
1472 const char *path, ...)
1474 char fullpath[MAX_LEN_SECPATH];
1475 size_t i, ret = 0;
1476 va_list args;
1478 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1479 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1480 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, 0);
1481 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, 0);
1482 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, 0);
1484 va_start(args, path);
1485 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1486 va_end(args);
1488 /* NB: 'path,0' is actually 'path'. See comment in the head
1489 * of the file. */
1490 if (dim > 0
1491 && NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[0],
1492 name_fn, begin_fn, end_fn,
1493 next_fn, comment,
1494 allow_replace, "%s",
1495 fullpath)) {
1496 ret++;
1498 for (i = 1; i < dim; i++) {
1499 if (NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[i],
1500 name_fn, begin_fn, end_fn,
1501 next_fn, comment,
1502 allow_replace, "%s,%d",
1503 fullpath, (int) i)) {
1504 ret++;
1508 return ret;
1511 /****************************************************************************
1512 Insert an enumerator value entry that we only have a name accessor
1513 function.
1514 ****************************************************************************/
1515 struct entry *secfile_insert_enum_data_full(struct section_file *secfile,
1516 int value, bool bitwise,
1517 secfile_enum_name_data_fn_t name_fn,
1518 secfile_data_t data,
1519 const char *comment,
1520 bool allow_replace,
1521 const char *path, ...)
1523 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1524 const char *ent_name, *val_name;
1525 struct section *psection;
1526 struct entry *pentry = NULL;
1527 va_list args;
1528 int i;
1530 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1531 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1533 if (bitwise) {
1534 /* Compute a string containing all the values separated by '|'. */
1535 str[0] = '\0'; /* Insert at least an empty string. */
1536 if (0 != value) {
1537 for (i = 0; (val_name = name_fn(data, i)); i++) {
1538 if ((1 << i) & value) {
1539 if ('\0' == str[0]) {
1540 sz_strlcpy(str, val_name);
1541 } else {
1542 cat_snprintf(str, sizeof(str), "|%s", val_name);
1547 } else {
1548 if (!(val_name = name_fn(data, value))) {
1549 SECFILE_LOG(secfile, NULL, "Value %d not supported.", value);
1550 return NULL;
1552 sz_strlcpy(str, val_name);
1555 va_start(args, path);
1556 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1557 va_end(args);
1559 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1560 if (!psection) {
1561 return NULL;
1564 if (allow_replace) {
1565 pentry = section_entry_by_name(psection, ent_name);
1566 if (NULL != pentry) {
1567 if (ENTRY_STR == entry_type(pentry)) {
1568 if (!entry_str_set(pentry, str)) {
1569 return NULL;
1571 } else {
1572 entry_destroy(pentry);
1573 pentry = NULL;
1578 if (NULL == pentry) {
1579 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1582 if (NULL != pentry && NULL != comment) {
1583 entry_set_comment(pentry, comment);
1586 return pentry;
1589 /****************************************************************************
1590 Insert 'dim' entries at 'path,0', 'path,1' etc. Returns the number of
1591 entries inserted or replaced.
1592 ****************************************************************************/
1593 size_t secfile_insert_enum_vec_data_full(struct section_file *secfile,
1594 const int *values, size_t dim,
1595 bool bitwise,
1596 secfile_enum_name_data_fn_t name_fn,
1597 secfile_data_t data,
1598 const char *comment,
1599 bool allow_replace,
1600 const char *path, ...)
1602 char fullpath[MAX_LEN_SECPATH];
1603 size_t i, ret = 0;
1604 va_list args;
1606 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1607 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1609 va_start(args, path);
1610 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1611 va_end(args);
1613 /* NB: 'path,0' is actually 'path'. See comment in the head
1614 * of the file. */
1615 if (dim > 0
1616 && NULL != secfile_insert_enum_data_full(secfile, values[0], bitwise,
1617 name_fn, data, comment,
1618 allow_replace, "%s",
1619 fullpath)) {
1620 ret++;
1622 for (i = 1; i < dim; i++) {
1623 if (NULL != secfile_insert_enum_data_full(secfile, values[i], bitwise,
1624 name_fn, data, comment,
1625 allow_replace, "%s,%d",
1626 fullpath, (int) i)) {
1627 ret++;
1631 return ret;
1634 /****************************************************************************
1635 Returns the entry by the name or NULL if not matched.
1636 ****************************************************************************/
1637 struct entry *secfile_entry_by_path(const struct section_file *secfile,
1638 const char *path)
1640 char fullpath[MAX_LEN_SECPATH];
1641 char *ent_name;
1642 size_t len;
1643 struct section *psection;
1645 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1647 sz_strlcpy(fullpath, path);
1649 /* treat "sec.foo,0" as "sec.foo": */
1650 len = strlen(fullpath);
1651 if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1652 fullpath[len - 2] = '\0';
1655 if (NULL != secfile->hash.entries) {
1656 struct entry *pentry;
1658 if (entry_hash_lookup(secfile->hash.entries, fullpath, &pentry)) {
1659 entry_use(pentry);
1661 return pentry;
1664 /* I dont like strtok.
1665 * - Me neither! */
1666 ent_name = strchr(fullpath, '.');
1667 if (!ent_name) {
1668 return NULL;
1671 /* Separates section and entry names. */
1672 *ent_name++ = '\0';
1673 psection = secfile_section_by_name(secfile, fullpath);
1674 if (psection) {
1675 return section_entry_by_name(psection, ent_name);
1676 } else {
1677 return NULL;
1681 /**************************************************************************
1682 Delete an entry.
1683 **************************************************************************/
1684 bool secfile_entry_delete(struct section_file *secfile,
1685 const char *path, ...)
1687 char fullpath[MAX_LEN_SECPATH];
1688 va_list args;
1689 struct entry *pentry;
1691 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1693 va_start(args, path);
1694 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1695 va_end(args);
1697 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1698 SECFILE_LOG(secfile, NULL, "Path %s does not exists.", fullpath);
1699 return FALSE;
1702 entry_destroy(pentry);
1704 return TRUE;
1707 /**************************************************************************
1708 Returns the entry at "fullpath" or NULL if not matched.
1709 **************************************************************************/
1710 struct entry *secfile_entry_lookup(const struct section_file *secfile,
1711 const char *path, ...)
1713 char fullpath[MAX_LEN_SECPATH];
1714 va_list args;
1716 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1718 va_start(args, path);
1719 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1720 va_end(args);
1722 return secfile_entry_by_path(secfile, fullpath);
1725 /**************************************************************************
1726 Lookup a boolean value in the secfile. Returns TRUE on success.
1727 **************************************************************************/
1728 bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1729 const char *path, ...)
1731 char fullpath[MAX_LEN_SECPATH];
1732 const struct entry *pentry;
1733 va_list args;
1735 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1737 va_start(args, path);
1738 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1739 va_end(args);
1741 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1742 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1743 return FALSE;
1746 return entry_bool_get(pentry, bval);
1749 /**************************************************************************
1750 Lookup a boolean value in the secfile. On failure, use the default
1751 value.
1752 **************************************************************************/
1753 bool secfile_lookup_bool_default(const struct section_file *secfile,
1754 bool def, const char *path, ...)
1756 char fullpath[MAX_LEN_SECPATH];
1757 const struct entry *pentry;
1758 bool bval;
1759 va_list args;
1761 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1763 va_start(args, path);
1764 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1765 va_end(args);
1767 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1768 return def;
1771 if (entry_bool_get(pentry, &bval)) {
1772 return bval;
1775 return def;
1778 /**************************************************************************
1779 Lookup a boolean vector in the secfile. Returns NULL on error. This
1780 vector is not owned by the registry module, and should be free by the
1781 user.
1782 **************************************************************************/
1783 bool *secfile_lookup_bool_vec(const struct section_file *secfile,
1784 size_t *dim, const char *path, ...)
1786 char fullpath[MAX_LEN_SECPATH];
1787 size_t i = 0;
1788 bool *vec;
1789 va_list args;
1791 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1792 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
1794 va_start(args, path);
1795 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1796 va_end(args);
1798 /* Check size. */
1799 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1800 i++;
1802 *dim = i;
1804 if (0 == i) {
1805 /* Doesn't exist. */
1806 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1807 return NULL;
1810 vec = fc_malloc(i * sizeof(bool));
1811 for(i = 0; i < *dim; i++) {
1812 if (!secfile_lookup_bool(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1813 SECFILE_LOG(secfile, NULL,
1814 "An error occurred when looking up to \"%s,%d\" entry.",
1815 fullpath, (int) i);
1816 free(vec);
1817 *dim = 0;
1818 return NULL;
1822 return vec;
1825 /**************************************************************************
1826 Lookup a integer value in the secfile. Returns TRUE on success.
1827 **************************************************************************/
1828 bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1829 const char *path, ...)
1831 char fullpath[MAX_LEN_SECPATH];
1832 const struct entry *pentry;
1833 va_list args;
1835 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1837 va_start(args, path);
1838 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1839 va_end(args);
1841 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1842 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1843 return FALSE;
1846 return entry_int_get(pentry, ival);
1849 /**************************************************************************
1850 Lookup a integer value in the secfile. On failure, use the default
1851 value.
1852 **************************************************************************/
1853 int secfile_lookup_int_default(const struct section_file *secfile, int def,
1854 const char *path, ...)
1856 char fullpath[MAX_LEN_SECPATH];
1857 const struct entry *pentry;
1858 int ival;
1859 va_list args;
1861 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1863 va_start(args, path);
1864 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1865 va_end(args);
1867 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1868 return def;
1871 if (entry_int_get(pentry, &ival)) {
1872 return ival;
1875 return def;
1878 /**************************************************************************
1879 Lookup a integer value in the secfile. The value will be arranged to
1880 match the interval [minval, maxval]. On failure, use the default
1881 value.
1882 **************************************************************************/
1883 int secfile_lookup_int_def_min_max(const struct section_file *secfile,
1884 int defval, int minval, int maxval,
1885 const char *path, ...)
1887 char fullpath[MAX_LEN_SECPATH];
1888 const struct entry *pentry;
1889 int value;
1890 va_list args;
1892 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
1894 va_start(args, path);
1895 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1896 va_end(args);
1898 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1899 return defval;
1902 if (!entry_int_get(pentry, &value)) {
1903 return defval;
1906 if (value < minval) {
1907 SECFILE_LOG(secfile, entry_section(pentry),
1908 "\"%s\" should be in the interval [%d, %d] but is %d;"
1909 "using the minimal value.",
1910 fullpath, minval, maxval, value);
1911 value = minval;
1914 if (value > maxval) {
1915 SECFILE_LOG(secfile, entry_section(pentry),
1916 "\"%s\" should be in the interval [%d, %d] but is %d;"
1917 "using the maximal value.",
1918 fullpath, minval, maxval, value);
1919 value = maxval;
1922 return value;
1925 /**************************************************************************
1926 Lookup a integer vector in the secfile. Returns NULL on error. This
1927 vector is not owned by the registry module, and should be free by the
1928 user.
1929 **************************************************************************/
1930 int *secfile_lookup_int_vec(const struct section_file *secfile,
1931 size_t *dim, const char *path, ...)
1933 char fullpath[MAX_LEN_SECPATH];
1934 size_t i = 0;
1935 int *vec;
1936 va_list args;
1938 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1939 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
1941 va_start(args, path);
1942 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1943 va_end(args);
1945 /* Check size. */
1946 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1947 i++;
1949 *dim = i;
1951 if (0 == i) {
1952 /* Doesn't exist. */
1953 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1954 return NULL;
1957 vec = fc_malloc(i * sizeof(int));
1958 for(i = 0; i < *dim; i++) {
1959 if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1960 SECFILE_LOG(secfile, NULL,
1961 "An error occurred when looking up to \"%s,%d\" entry.",
1962 fullpath, (int) i);
1963 free(vec);
1964 *dim = 0;
1965 return NULL;
1969 return vec;
1972 /**************************************************************************
1973 Lookup a floating point value in the secfile. Returns TRUE on success.
1974 **************************************************************************/
1975 bool secfile_lookup_float(const struct section_file *secfile, float *fval,
1976 const char *path, ...)
1978 char fullpath[MAX_LEN_SECPATH];
1979 const struct entry *pentry;
1980 va_list args;
1982 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1984 va_start(args, path);
1985 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1986 va_end(args);
1988 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1989 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1990 return FALSE;
1993 return entry_float_get(pentry, fval);
1996 /**************************************************************************
1997 Lookup a floating point value in the secfile. On failure, use the default
1998 value.
1999 **************************************************************************/
2000 float secfile_lookup_float_default(const struct section_file *secfile,
2001 float def, const char *path, ...)
2003 char fullpath[MAX_LEN_SECPATH];
2004 const struct entry *pentry;
2005 float fval;
2006 va_list args;
2008 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2010 va_start(args, path);
2011 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2012 va_end(args);
2014 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2015 return def;
2018 if (entry_float_get(pentry, &fval)) {
2019 return fval;
2022 return def;
2025 /**************************************************************************
2026 Lookup a string value in the secfile. Returns NULL on error.
2027 **************************************************************************/
2028 const char *secfile_lookup_str(const struct section_file *secfile,
2029 const char *path, ...)
2031 char fullpath[MAX_LEN_SECPATH];
2032 const struct entry *pentry;
2033 const char *str;
2034 va_list args;
2036 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2038 va_start(args, path);
2039 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2040 va_end(args);
2042 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2043 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2044 return NULL;
2047 if (entry_str_get(pentry, &str)) {
2048 return str;
2051 return NULL;
2054 /**************************************************************************
2055 Lookup a string value in the secfile. On failure, use the default
2056 value.
2057 **************************************************************************/
2058 const char *secfile_lookup_str_default(const struct section_file *secfile,
2059 const char *def,
2060 const char *path, ...)
2062 char fullpath[MAX_LEN_SECPATH];
2063 const struct entry *pentry;
2064 const char *str;
2065 va_list args;
2067 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2069 va_start(args, path);
2070 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2071 va_end(args);
2073 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2074 return def;
2077 if (entry_str_get(pentry, &str)) {
2078 return str;
2081 return def;
2084 /**************************************************************************
2085 Lookup a string vector in the secfile. Returns NULL on error. This
2086 vector is not owned by the registry module, and should be free by the
2087 user, but the string pointers stored inside the vector shouldn't be
2088 free.
2089 **************************************************************************/
2090 const char **secfile_lookup_str_vec(const struct section_file *secfile,
2091 size_t *dim, const char *path, ...)
2093 char fullpath[MAX_LEN_SECPATH];
2094 size_t i = 0;
2095 const char **vec;
2096 va_list args;
2098 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2099 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2101 va_start(args, path);
2102 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2103 va_end(args);
2105 /* Check size. */
2106 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2107 i++;
2109 *dim = i;
2111 if (0 == i) {
2112 /* Doesn't exist. */
2113 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2114 return NULL;
2117 vec = fc_malloc(i * sizeof(const char *));
2118 for(i = 0; i < *dim; i++) {
2119 if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d",
2120 fullpath, (int) i))) {
2121 SECFILE_LOG(secfile, NULL,
2122 "An error occurred when looking up to \"%s,%d\" entry.",
2123 fullpath, (int) i);
2124 free(vec);
2125 *dim = 0;
2126 return NULL;
2130 return vec;
2133 /****************************************************************************
2134 Lookup an enumerator value in the secfile. Returns FALSE on error.
2135 ****************************************************************************/
2136 bool secfile_lookup_plain_enum_full(const struct section_file *secfile,
2137 int *penumerator,
2138 secfile_enum_is_valid_fn_t is_valid_fn,
2139 secfile_enum_by_name_fn_t by_name_fn,
2140 const char *path, ...)
2142 char fullpath[MAX_LEN_SECPATH];
2143 const struct entry *pentry;
2144 const char *str;
2145 va_list args;
2147 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2148 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2149 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2150 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2152 va_start(args, path);
2153 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2154 va_end(args);
2156 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2157 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2158 return FALSE;
2161 if (!entry_str_get(pentry, &str)) {
2162 return FALSE;
2165 *penumerator = by_name_fn(str, strcmp);
2166 if (is_valid_fn(*penumerator)) {
2167 return TRUE;
2170 SECFILE_LOG(secfile, entry_section(pentry),
2171 "Entry \"%s\": no match for \"%s\".",
2172 entry_name(pentry), str);
2173 return FALSE;
2176 /****************************************************************************
2177 Lookup an enumerator value in the secfile. Returns 'defval' on error.
2178 ****************************************************************************/
2179 int secfile_lookup_plain_enum_default_full(const struct section_file
2180 *secfile, int defval,
2181 secfile_enum_is_valid_fn_t
2182 is_valid_fn,
2183 secfile_enum_by_name_fn_t
2184 by_name_fn,
2185 const char *path, ...)
2187 char fullpath[MAX_LEN_SECPATH];
2188 const struct entry *pentry;
2189 const char *str;
2190 int val;
2191 va_list args;
2193 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2194 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2195 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2197 va_start(args, path);
2198 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2199 va_end(args);
2201 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2202 return defval;
2205 if (!entry_str_get(pentry, &str)) {
2206 return defval;
2209 val = by_name_fn(str, strcmp);
2210 if (is_valid_fn(val)) {
2211 return val;
2212 } else {
2213 return defval;
2217 /**************************************************************************
2218 Lookup a enumerator vector in the secfile. Returns NULL on error. This
2219 vector is not owned by the registry module, and should be free by the
2220 user.
2221 **************************************************************************/
2222 int *secfile_lookup_plain_enum_vec_full(const struct section_file *secfile,
2223 size_t *dim,
2224 secfile_enum_is_valid_fn_t
2225 is_valid_fn,
2226 secfile_enum_by_name_fn_t
2227 by_name_fn,
2228 const char *path, ...)
2230 char fullpath[MAX_LEN_SECPATH];
2231 size_t i = 0;
2232 int *vec;
2233 va_list args;
2235 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2236 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2237 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2238 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2240 va_start(args, path);
2241 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2242 va_end(args);
2244 /* Check size. */
2245 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2246 i++;
2248 *dim = i;
2250 if (0 == i) {
2251 /* Doesn't exist. */
2252 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2253 return NULL;
2256 vec = fc_malloc(i * sizeof(int));
2257 for(i = 0; i < *dim; i++) {
2258 if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2259 by_name_fn, "%s,%d",
2260 fullpath, (int) i)) {
2261 SECFILE_LOG(secfile, NULL,
2262 "An error occurred when looking up to \"%s,%d\" entry.",
2263 fullpath, (int) i);
2264 free(vec);
2265 *dim = 0;
2266 return NULL;
2270 return vec;
2273 /****************************************************************************
2274 Lookup a bitwise enumerator value in the secfile. Returns FALSE on error.
2275 ****************************************************************************/
2276 bool secfile_lookup_bitwise_enum_full(const struct section_file *secfile,
2277 int *penumerator,
2278 secfile_enum_is_valid_fn_t is_valid_fn,
2279 secfile_enum_by_name_fn_t by_name_fn,
2280 const char *path, ...)
2282 char fullpath[MAX_LEN_SECPATH];
2283 const struct entry *pentry;
2284 const char *str, *p;
2285 char val_name[MAX_LEN_SECPATH];
2286 int val;
2287 va_list args;
2289 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2290 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2291 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2292 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2294 va_start(args, path);
2295 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2296 va_end(args);
2298 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2299 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2300 return FALSE;
2303 if (!entry_str_get(pentry, &str)) {
2304 return FALSE;
2307 *penumerator = 0;
2308 if ('\0' == str[0]) {
2309 /* Empty string = no value. */
2310 return TRUE;
2313 /* Value names are separated by '|'. */
2314 do {
2315 p = strchr(str, '|');
2316 if (NULL != p) {
2317 p++;
2318 fc_strlcpy(val_name, str, p - str);
2319 } else {
2320 /* Last segment, full copy. */
2321 sz_strlcpy(val_name, str);
2323 remove_leading_trailing_spaces(val_name);
2324 val = by_name_fn(val_name, strcmp);
2325 if (!is_valid_fn(val)) {
2326 SECFILE_LOG(secfile, entry_section(pentry),
2327 "Entry \"%s\": no match for \"%s\".",
2328 entry_name(pentry), val_name);
2329 return FALSE;
2331 *penumerator |= val;
2332 str = p;
2333 } while (NULL != p);
2335 return TRUE;
2338 /****************************************************************************
2339 Lookup an enumerator value in the secfile. Returns 'defval' on error.
2340 ****************************************************************************/
2341 int secfile_lookup_bitwise_enum_default_full(const struct section_file
2342 *secfile, int defval,
2343 secfile_enum_is_valid_fn_t
2344 is_valid_fn,
2345 secfile_enum_by_name_fn_t
2346 by_name_fn,
2347 const char *path, ...)
2349 char fullpath[MAX_LEN_SECPATH];
2350 const struct entry *pentry;
2351 const char *str, *p;
2352 char val_name[MAX_LEN_SECPATH];
2353 int val, full_val;
2354 va_list args;
2356 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2357 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2358 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2360 va_start(args, path);
2361 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2362 va_end(args);
2364 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2365 return defval;
2368 if (!entry_str_get(pentry, &str)) {
2369 return defval;
2372 if ('\0' == str[0]) {
2373 /* Empty string = no value. */
2374 return 0;
2377 /* Value names are separated by '|'. */
2378 full_val = 0;
2379 do {
2380 p = strchr(str, '|');
2381 if (NULL != p) {
2382 p++;
2383 fc_strlcpy(val_name, str, p - str);
2384 } else {
2385 /* Last segment, full copy. */
2386 sz_strlcpy(val_name, str);
2388 remove_leading_trailing_spaces(val_name);
2389 val = by_name_fn(val_name, strcmp);
2390 if (!is_valid_fn(val)) {
2391 return defval;
2393 full_val |= val;
2394 str = p;
2395 } while (NULL != p);
2397 return full_val;
2400 /**************************************************************************
2401 Lookup a enumerator vector in the secfile. Returns NULL on error. This
2402 vector is not owned by the registry module, and should be free by the
2403 user.
2404 **************************************************************************/
2405 int *secfile_lookup_bitwise_enum_vec_full(const struct section_file *secfile,
2406 size_t *dim,
2407 secfile_enum_is_valid_fn_t
2408 is_valid_fn,
2409 secfile_enum_by_name_fn_t
2410 by_name_fn,
2411 const char *path, ...)
2413 char fullpath[MAX_LEN_SECPATH];
2414 size_t i = 0;
2415 int *vec;
2416 va_list args;
2418 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2419 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2420 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2421 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2423 va_start(args, path);
2424 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2425 va_end(args);
2427 /* Check size. */
2428 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2429 i++;
2431 *dim = i;
2433 if (0 == i) {
2434 /* Doesn't exist. */
2435 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2436 return NULL;
2439 vec = fc_malloc(i * sizeof(int));
2440 for(i = 0; i < *dim; i++) {
2441 if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2442 by_name_fn, "%s,%d",
2443 fullpath, (int) i)) {
2444 SECFILE_LOG(secfile, NULL,
2445 "An error occurred when looking up to \"%s,%d\" entry.",
2446 fullpath, (int) i);
2447 free(vec);
2448 *dim = 0;
2449 return NULL;
2453 return vec;
2456 /****************************************************************************
2457 Lookup a value saved as string in the secfile. Returns FALSE on error.
2458 ****************************************************************************/
2459 bool secfile_lookup_enum_data(const struct section_file *secfile,
2460 int *pvalue, bool bitwise,
2461 secfile_enum_name_data_fn_t name_fn,
2462 secfile_data_t data, const char *path, ...)
2464 char fullpath[MAX_LEN_SECPATH];
2465 const struct entry *pentry;
2466 const char *str, *p, *name;
2467 char val_name[MAX_LEN_SECPATH];
2468 int val;
2469 va_list args;
2471 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2472 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != pvalue, FALSE);
2473 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, FALSE);
2475 va_start(args, path);
2476 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2477 va_end(args);
2479 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2480 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2481 return FALSE;
2484 if (!entry_str_get(pentry, &str)) {
2485 return FALSE;
2488 if (bitwise) {
2489 *pvalue = 0;
2490 if ('\0' == str[0]) {
2491 /* Empty string = no value. */
2492 return TRUE;
2495 /* Value names are separated by '|'. */
2496 do {
2497 p = strchr(str, '|');
2498 if (NULL != p) {
2499 p++;
2500 fc_strlcpy(val_name, str, p - str);
2501 } else {
2502 /* Last segment, full copy. */
2503 sz_strlcpy(val_name, str);
2505 remove_leading_trailing_spaces(val_name);
2506 for (val = 0; (name = name_fn(data, val)); val++) {
2507 if (0 == fc_strcasecmp(name, val_name)) {
2508 break;
2511 if (NULL == name) {
2512 SECFILE_LOG(secfile, entry_section(pentry),
2513 "Entry \"%s\": no match for \"%s\".",
2514 entry_name(pentry), val_name);
2515 return FALSE;
2517 *pvalue |= 1 << val;
2518 str = p;
2519 } while (NULL != p);
2520 } else {
2521 for (val = 0; (name = name_fn(data, val)); val++) {
2522 if (0 == fc_strcasecmp(name, str)) {
2523 *pvalue = val;
2524 break;
2527 if (NULL == name) {
2528 SECFILE_LOG(secfile, entry_section(pentry),
2529 "Entry \"%s\": no match for \"%s\".",
2530 entry_name(pentry), str);
2531 return FALSE;
2535 return TRUE;
2538 /****************************************************************************
2539 Lookup a value saved as string in the secfile. Returns 'defval' on error.
2540 ****************************************************************************/
2541 int secfile_lookup_enum_default_data(const struct section_file *secfile,
2542 int defval, bool bitwise,
2543 secfile_enum_name_data_fn_t name_fn,
2544 secfile_data_t data,
2545 const char *path, ...)
2547 char fullpath[MAX_LEN_SECPATH];
2548 const struct entry *pentry;
2549 const char *str, *p, *name;
2550 char val_name[MAX_LEN_SECPATH];
2551 int value, val;
2552 va_list args;
2554 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2555 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, defval);
2557 va_start(args, path);
2558 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2559 va_end(args);
2561 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2562 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2563 return defval;
2566 if (!entry_str_get(pentry, &str)) {
2567 return defval;
2570 value = 0;
2571 if (bitwise) {
2572 if ('\0' == str[0]) {
2573 /* Empty string = no value. */
2574 return value;
2577 /* Value names are separated by '|'. */
2578 do {
2579 p = strchr(str, '|');
2580 if (NULL != p) {
2581 p++;
2582 fc_strlcpy(val_name, str, p - str);
2583 } else {
2584 /* Last segment, full copy. */
2585 sz_strlcpy(val_name, str);
2587 remove_leading_trailing_spaces(val_name);
2588 for (val = 0; (name = name_fn(data, val)); val++) {
2589 if (0 == strcmp(name, val_name)) {
2590 break;
2593 if (NULL == name) {
2594 SECFILE_LOG(secfile, entry_section(pentry),
2595 "Entry \"%s\": no match for \"%s\".",
2596 entry_name(pentry), val_name);
2597 return defval;
2599 value |= 1 << val;
2600 str = p;
2601 } while (NULL != p);
2602 } else {
2603 for (val = 0; (name = name_fn(data, val)); val++) {
2604 if (0 == strcmp(name, str)) {
2605 value = val;
2606 break;
2609 if (NULL == name) {
2610 SECFILE_LOG(secfile, entry_section(pentry),
2611 "Entry \"%s\": no match for \"%s\".",
2612 entry_name(pentry), str);
2613 return defval;
2617 return value;
2620 /****************************************************************************
2621 Lookup a vector in the secfile. Returns NULL on error. This vector
2622 is not owned by the registry module, and should be free by the user.
2623 ****************************************************************************/
2624 int *secfile_lookup_enum_vec_data(const struct section_file *secfile,
2625 size_t *dim, bool bitwise,
2626 secfile_enum_name_data_fn_t name_fn,
2627 secfile_data_t data, const char *path, ...)
2629 char fullpath[MAX_LEN_SECPATH];
2630 size_t i = 0;
2631 int *vec;
2632 va_list args;
2634 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2635 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2636 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
2638 va_start(args, path);
2639 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2640 va_end(args);
2642 /* Check size. */
2643 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2644 i++;
2646 *dim = i;
2648 if (0 == i) {
2649 /* Doesn't exist. */
2650 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2651 return NULL;
2654 vec = fc_malloc(i * sizeof(int));
2655 for (i = 0; i < *dim; i++) {
2656 if (!secfile_lookup_enum_data(secfile, vec + i, bitwise, name_fn, data,
2657 "%s,%d", fullpath, (int) i)) {
2658 SECFILE_LOG(secfile, NULL,
2659 "An error occurred when looking up to \"%s,%d\" entry.",
2660 fullpath, (int) i);
2661 free(vec);
2662 *dim = 0;
2663 return NULL;
2667 return vec;
2670 /****************************************************************************
2671 Returns the first section matching the name.
2672 ****************************************************************************/
2673 struct section *secfile_section_by_name(const struct section_file *secfile,
2674 const char *name)
2676 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2678 section_list_iterate(secfile->sections, psection) {
2679 if (0 == strcmp(section_name(psection), name)) {
2680 return psection;
2682 } section_list_iterate_end;
2684 return NULL;
2687 /**************************************************************************
2688 Find a section by path.
2689 **************************************************************************/
2690 struct section *secfile_section_lookup(const struct section_file *secfile,
2691 const char *path, ...)
2693 char fullpath[MAX_LEN_SECPATH];
2694 va_list args;
2696 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2698 va_start(args, path);
2699 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2700 va_end(args);
2702 return secfile_section_by_name(secfile, fullpath);
2705 /**************************************************************************
2706 Returns the list of sections. This list is owned by the registry module
2707 and shouldn't be modified and destroyed.
2708 **************************************************************************/
2709 const struct section_list *
2710 secfile_sections(const struct section_file *secfile)
2712 return (NULL != secfile ? secfile->sections : NULL);
2715 /**************************************************************************
2716 Returns the list of sections which match the name prefix. Returns NULL
2717 if no section was found. This list is not owned by the registry module
2718 and the user must destroy it when he finished to work with it.
2719 **************************************************************************/
2720 struct section_list *
2721 secfile_sections_by_name_prefix(const struct section_file *secfile,
2722 const char *prefix)
2724 struct section_list *matches = NULL;
2725 size_t len;
2727 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2728 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, NULL);
2730 len = strlen(prefix);
2731 if (0 == len) {
2732 return NULL;
2735 section_list_iterate(secfile->sections, psection) {
2736 if (0 == strncmp(section_name(psection), prefix, len)) {
2737 if (NULL == matches) {
2738 matches = section_list_new();
2740 section_list_append(matches, psection);
2742 } section_list_iterate_end;
2744 return matches;
2747 /**************************************************************************
2748 Create a new section in the secfile.
2749 **************************************************************************/
2750 struct section *secfile_section_new(struct section_file *secfile,
2751 const char *name)
2753 struct section *psection;
2755 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2757 if (NULL == name || '\0' == name[0]) {
2758 SECFILE_LOG(secfile, NULL, "Cannot create a section without name.");
2759 return NULL;
2762 if (!is_secfile_entry_name_valid(name)) {
2763 SECFILE_LOG(secfile, NULL, "\"%s\" is not a valid section name.",
2764 name);
2765 return NULL;
2768 if (NULL != secfile_section_by_name(secfile, name)) {
2769 /* We cannot duplicate sections in any case! Not even if one is
2770 * include -section and the other not. */
2771 SECFILE_LOG(secfile, NULL, "Section \"%s\" already exists.", name);
2772 return NULL;
2775 psection = fc_malloc(sizeof(struct section));
2776 psection->include = FALSE;
2777 psection->name = fc_strdup(name);
2778 psection->entries = entry_list_new_full(entry_destroy);
2780 /* Append to secfile. */
2781 psection->secfile = secfile;
2782 section_list_append(secfile->sections, psection);
2784 if (NULL != secfile->hash.sections) {
2785 section_hash_insert(secfile->hash.sections, psection->name, psection);
2788 return psection;
2791 /**************************************************************************
2792 Remove this section from the secfile.
2793 **************************************************************************/
2794 void section_destroy(struct section *psection)
2796 struct section_file *secfile;
2798 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2800 section_clear_all(psection);
2802 if ((secfile = psection->secfile)) {
2803 /* Detach from secfile. */
2804 if (section_list_remove(secfile->sections, psection)) {
2805 /* This has called section_destroy() already then. */
2806 return;
2808 if (NULL != secfile->hash.sections) {
2809 section_hash_remove(secfile->hash.sections, psection->name);
2813 entry_list_destroy(psection->entries);
2814 free(psection->name);
2815 free(psection);
2818 /**************************************************************************
2819 Remove all entries.
2820 **************************************************************************/
2821 void section_clear_all(struct section *psection)
2823 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2825 /* This include the removing of the hash datas. */
2826 entry_list_clear(psection->entries);
2828 if (0 < entry_list_size(psection->entries)) {
2829 SECFILE_LOG(psection->secfile, psection,
2830 "After clearing all, %d entries are still remaining.",
2831 entry_list_size(psection->entries));
2835 /**************************************************************************
2836 Change the section name. Returns TRUE on success.
2837 **************************************************************************/
2838 bool section_set_name(struct section *psection, const char *name)
2840 struct section_file *secfile;
2841 struct section *pother;
2843 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, FALSE);
2844 secfile = psection->secfile;
2845 SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, NULL != secfile, FALSE);
2847 if (NULL == name || '\0' == name[0]) {
2848 SECFILE_LOG(secfile, psection, "No new name for section \"%s\".",
2849 psection->name);
2850 return FALSE;
2853 if (!is_secfile_entry_name_valid(name)) {
2854 SECFILE_LOG(secfile, psection,
2855 "\"%s\" is not a valid section name for section \"%s\".",
2856 name, psection->name);
2857 return FALSE;
2860 if ((pother = secfile_section_by_name(secfile, name))
2861 && pother != psection) {
2862 /* We cannot duplicate sections in any case! */
2863 SECFILE_LOG(secfile, psection, "Section \"%s\" already exists.", name);
2864 return FALSE;
2867 /* Remove old references in the hash tables. */
2868 if (NULL != secfile->hash.sections) {
2869 section_hash_remove(secfile->hash.sections, psection->name);
2871 if (NULL != secfile->hash.entries) {
2872 entry_list_iterate(psection->entries, pentry) {
2873 secfile_hash_delete(secfile, pentry);
2874 } entry_list_iterate_end;
2877 /* Really rename. */
2878 free(psection->name);
2879 psection->name = fc_strdup(name);
2881 /* Reinsert new references into the hash tables. */
2882 if (NULL != secfile->hash.sections) {
2883 section_hash_insert(secfile->hash.sections, psection->name, psection);
2885 if (NULL != secfile->hash.entries) {
2886 entry_list_iterate(psection->entries, pentry) {
2887 secfile_hash_insert(secfile, pentry);
2888 } entry_list_iterate_end;
2891 return TRUE;
2894 /**************************************************************************
2895 Returns a list containing all the entries. This list is owned by the
2896 secfile, so don't modify or destroy it.
2897 **************************************************************************/
2898 const struct entry_list *section_entries(const struct section *psection)
2900 return (NULL != psection ? psection->entries : NULL);
2903 /**************************************************************************
2904 Returns the the first entry matching the name.
2905 **************************************************************************/
2906 struct entry *section_entry_by_name(const struct section *psection,
2907 const char *name)
2909 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2911 entry_list_iterate(psection->entries, pentry) {
2912 if (0 == strcmp(entry_name(pentry), name)) {
2913 entry_use(pentry);
2914 return pentry;
2916 } entry_list_iterate_end;
2918 return NULL;
2921 /**************************************************************************
2922 Returns the entry matching the path.
2923 **************************************************************************/
2924 struct entry *section_entry_lookup(const struct section *psection,
2925 const char *path, ...)
2927 char fullpath[MAX_LEN_SECPATH];
2928 struct entry *pentry;
2929 va_list args;
2931 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2933 va_start(args, path);
2934 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2935 va_end(args);
2937 if ((pentry = section_entry_by_name(psection, fullpath))) {
2938 return pentry;
2941 /* Try with full path. */
2942 if ((pentry = secfile_entry_by_path(psection->secfile, fullpath))
2943 && psection == entry_section(pentry)) {
2944 /* Unsure this is really owned by this section. */
2945 return pentry;
2948 return NULL;
2952 /* An 'entry' is a string, integer, boolean or string vector;
2953 * See enum entry_type in registry.h.
2955 struct entry {
2956 struct section *psection; /* Parent section. */
2957 char *name; /* Name, not including section prefix. */
2958 enum entry_type type; /* The type of the entry. */
2959 int used; /* Number of times entry looked up. */
2960 char *comment; /* Comment, may be NULL. */
2962 union {
2963 /* ENTRY_BOOL */
2964 struct {
2965 bool value;
2966 } boolean;
2967 /* ENTRY_INT */
2968 struct {
2969 int value;
2970 } integer;
2971 /* ENTRY_FLOAT */
2972 struct {
2973 float value;
2974 } floating;
2975 /* ENTRY_STR */
2976 struct {
2977 char *value; /* Malloced string. */
2978 bool escaped; /* " or $. Usually TRUE */
2979 bool gt_marking; /* Save with gettext marking. */
2980 } string;
2984 /**************************************************************************
2985 Returns a new entry.
2986 **************************************************************************/
2987 static struct entry *entry_new(struct section *psection, const char *name)
2989 struct section_file *secfile;
2990 struct entry *pentry;
2992 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2994 secfile = psection->secfile;
2995 if (NULL == name || '\0' == name[0]) {
2996 SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
2997 return NULL;
3000 if (!is_secfile_entry_name_valid(name)) {
3001 SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
3002 name);
3003 return NULL;
3006 if (!secfile->allow_duplicates
3007 && NULL != section_entry_by_name(psection, name)) {
3008 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3009 return NULL;
3012 pentry = fc_malloc(sizeof(struct entry));
3013 pentry->name = fc_strdup(name);
3014 pentry->type = -1; /* Invalid case. */
3015 pentry->used = 0;
3016 pentry->comment = NULL;
3018 /* Append to section. */
3019 pentry->psection = psection;
3020 entry_list_append(psection->entries, pentry);
3022 /* Notify secfile. */
3023 secfile->num_entries++;
3024 secfile_hash_insert(secfile, pentry);
3026 return pentry;
3029 /**************************************************************************
3030 Returns a new entry of type ENTRY_INT.
3031 **************************************************************************/
3032 struct entry *section_entry_int_new(struct section *psection,
3033 const char *name, int value)
3035 struct entry *pentry = entry_new(psection, name);
3037 if (NULL != pentry) {
3038 pentry->type = ENTRY_INT;
3039 pentry->integer.value = value;
3042 return pentry;
3045 /**************************************************************************
3046 Returns a new entry of type ENTRY_BOOL.
3047 **************************************************************************/
3048 struct entry *section_entry_bool_new(struct section *psection,
3049 const char *name, bool value)
3051 struct entry *pentry = entry_new(psection, name);
3053 if (NULL != pentry) {
3054 pentry->type = ENTRY_BOOL;
3055 pentry->boolean.value = value;
3058 return pentry;
3061 /**************************************************************************
3062 Returns a new entry of type ENTRY_FLOAT.
3063 **************************************************************************/
3064 struct entry *section_entry_float_new(struct section *psection,
3065 const char *name, float value)
3067 struct entry *pentry = entry_new(psection, name);
3069 if (NULL != pentry) {
3070 pentry->type = ENTRY_FLOAT;
3071 pentry->floating.value = value;
3074 return pentry;
3077 /**************************************************************************
3078 Returns a new entry of type ENTRY_STR.
3079 **************************************************************************/
3080 struct entry *section_entry_str_new(struct section *psection,
3081 const char *name, const char *value,
3082 bool escaped)
3084 struct entry *pentry = entry_new(psection, name);
3086 if (NULL != pentry) {
3087 pentry->type = ENTRY_STR;
3088 pentry->string.value = fc_strdup(NULL != value ? value : "");
3089 pentry->string.escaped = escaped;
3090 pentry->string.gt_marking = FALSE;
3093 return pentry;
3096 /**************************************************************************
3097 Returns a new entry of type ENTRY_FILEREFERENCE.
3098 **************************************************************************/
3099 static struct entry *section_entry_filereference_new(struct section *psection,
3100 const char *name, const char *value)
3102 struct entry *pentry = entry_new(psection, name);
3104 if (NULL != pentry) {
3105 pentry->type = ENTRY_FILEREFERENCE;
3106 pentry->string.value = fc_strdup(NULL != value ? value : "");
3109 return pentry;
3112 /**************************************************************************
3113 Entry structure destructor.
3114 **************************************************************************/
3115 void entry_destroy(struct entry *pentry)
3117 struct section_file *secfile;
3118 struct section *psection;
3120 if (NULL == pentry) {
3121 return;
3124 if ((psection = pentry->psection)) {
3125 /* Detach from section. */
3126 if (entry_list_remove(psection->entries, pentry)) {
3127 /* This has called entry_destroy() already then. */
3128 return;
3130 if ((secfile = psection->secfile)) {
3131 /* Detach from secfile. */
3132 secfile->num_entries--;
3133 secfile_hash_delete(secfile, pentry);
3137 /* Specific type free. */
3138 switch (pentry->type) {
3139 case ENTRY_BOOL:
3140 case ENTRY_INT:
3141 case ENTRY_FLOAT:
3142 break;
3144 case ENTRY_STR:
3145 case ENTRY_FILEREFERENCE:
3146 free(pentry->string.value);
3147 break;
3150 /* Common free. */
3151 free(pentry->name);
3152 if (NULL != pentry->comment) {
3153 free(pentry->comment);
3155 free(pentry);
3158 /**************************************************************************
3159 Returns the parent section of this entry.
3160 **************************************************************************/
3161 struct section *entry_section(const struct entry *pentry)
3163 return (NULL != pentry ? pentry->psection : NULL);
3166 /**************************************************************************
3167 Returns the type of this entry or -1 or error.
3168 **************************************************************************/
3169 enum entry_type entry_type(const struct entry *pentry)
3171 return (NULL != pentry ? pentry->type : -1);
3174 /**************************************************************************
3175 Build the entry path. Returns like snprintf().
3176 **************************************************************************/
3177 int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3179 return fc_snprintf(buf, buf_len, "%s.%s",
3180 section_name(entry_section(pentry)),
3181 entry_name(pentry));
3184 /**************************************************************************
3185 Returns the name of this entry.
3186 **************************************************************************/
3187 const char *entry_name(const struct entry *pentry)
3189 return (NULL != pentry ? pentry->name : NULL);
3192 /**************************************************************************
3193 Sets the name of the entry. Returns TRUE on success.
3194 **************************************************************************/
3195 bool entry_set_name(struct entry *pentry, const char *name)
3197 struct section *psection;
3198 struct section_file *secfile;
3200 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3201 psection = pentry->psection;
3202 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != psection, FALSE);
3203 secfile = psection->secfile;
3204 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != secfile, FALSE);
3206 if (NULL == name || '\0' == name[0]) {
3207 SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3208 pentry->name);
3209 return FALSE;
3212 if (!is_secfile_entry_name_valid(name)) {
3213 SECFILE_LOG(secfile, psection,
3214 "\"%s\" is not a valid entry name for entry \"%s\".",
3215 name, pentry->name);
3216 return FALSE;
3219 if (!secfile->allow_duplicates) {
3220 struct entry *pother = section_entry_by_name(psection, name);
3222 if (NULL != pother && pother != pentry) {
3223 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3224 return FALSE;
3228 /* Remove from hash table the old path. */
3229 secfile_hash_delete(secfile, pentry);
3231 /* Really rename the entry. */
3232 free(pentry->name);
3233 pentry->name = fc_strdup(name);
3235 /* Insert into hash table the new path. */
3236 secfile_hash_insert(secfile, pentry);
3237 return TRUE;
3240 /**************************************************************************
3241 Returns the comment associated to this entry.
3242 **************************************************************************/
3243 const char *entry_comment(const struct entry *pentry)
3245 return (NULL != pentry ? pentry->comment : NULL);
3248 /**************************************************************************
3249 Sets a comment for the entry. Pass NULL to remove the current one.
3250 **************************************************************************/
3251 void entry_set_comment(struct entry *pentry, const char *comment)
3253 if (NULL == pentry) {
3254 return;
3257 if (NULL != pentry->comment) {
3258 free(pentry->comment);
3261 pentry->comment = (NULL != comment ? fc_strdup(comment) : NULL);
3264 /**************************************************************************
3265 Returns TRUE if this entry has been used.
3266 **************************************************************************/
3267 static inline bool entry_used(const struct entry *pentry)
3269 return (0 < pentry->used);
3272 /**************************************************************************
3273 Increase the used count.
3274 **************************************************************************/
3275 static inline void entry_use(struct entry *pentry)
3277 pentry->used++;
3280 /**************************************************************************
3281 Gets an boolean value. Returns TRUE on success.
3282 On old saved files, 0 and 1 can also be considered as bool.
3283 **************************************************************************/
3284 bool entry_bool_get(const struct entry *pentry, bool *value)
3286 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3288 if (ENTRY_INT == pentry->type
3289 && (pentry->integer.value == 0
3290 || pentry->integer.value == 1)
3291 && NULL != pentry->psection
3292 && NULL != pentry->psection->secfile
3293 && pentry->psection->secfile->allow_digital_boolean) {
3294 *value = (0 != pentry->integer.value);
3295 return TRUE;
3298 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3299 ENTRY_BOOL == pentry->type, FALSE);
3301 if (NULL != value) {
3302 *value = pentry->boolean.value;
3304 return TRUE;
3307 /**************************************************************************
3308 Sets an boolean value. Returns TRUE on success.
3309 **************************************************************************/
3310 bool entry_bool_set(struct entry *pentry, bool value)
3312 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3313 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3314 ENTRY_BOOL == pentry->type, FALSE);
3316 pentry->boolean.value = value;
3317 return TRUE;
3320 /**************************************************************************
3321 Gets an floating value. Returns TRUE on success.
3322 **************************************************************************/
3323 bool entry_float_get(const struct entry *pentry, float *value)
3325 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3326 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3327 ENTRY_FLOAT == pentry->type, FALSE);
3329 if (NULL != value) {
3330 *value = pentry->floating.value;
3333 return TRUE;
3336 /**************************************************************************
3337 Sets an floating value. Returns TRUE on success.
3338 **************************************************************************/
3339 bool entry_float_set(struct entry *pentry, float value)
3341 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3342 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3343 ENTRY_FLOAT == pentry->type, FALSE);
3345 pentry->floating.value = value;
3347 return TRUE;
3350 /**************************************************************************
3351 Gets an integer value. Returns TRUE on success.
3352 **************************************************************************/
3353 bool entry_int_get(const struct entry *pentry, int *value)
3355 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3356 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3357 ENTRY_INT == pentry->type, FALSE);
3359 if (NULL != value) {
3360 *value = pentry->integer.value;
3362 return TRUE;
3365 /**************************************************************************
3366 Sets an integer value. Returns TRUE on success.
3367 **************************************************************************/
3368 bool entry_int_set(struct entry *pentry, int value)
3370 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3371 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3372 ENTRY_INT == pentry->type, FALSE);
3374 pentry->integer.value = value;
3375 return TRUE;
3378 /**************************************************************************
3379 Gets an string value. Returns TRUE on success.
3380 **************************************************************************/
3381 bool entry_str_get(const struct entry *pentry, const char **value)
3383 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3384 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3385 ENTRY_STR == pentry->type, FALSE);
3387 if (NULL != value) {
3388 *value = pentry->string.value;
3390 return TRUE;
3393 /**************************************************************************
3394 Sets an string value. Returns TRUE on success.
3395 **************************************************************************/
3396 bool entry_str_set(struct entry *pentry, const char *value)
3398 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3399 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3400 ENTRY_STR == pentry->type, FALSE);
3402 free(pentry->string.value);
3403 pentry->string.value = fc_strdup(NULL != value ? value : "");
3404 return TRUE;
3407 /**************************************************************************
3408 Returns if the string would be escaped.
3409 **************************************************************************/
3410 bool entry_str_escaped(const struct entry *pentry)
3412 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3413 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3414 ENTRY_STR == pentry->type, FALSE);
3416 return pentry->string.escaped;
3419 /**************************************************************************
3420 Sets if the string would be escaped. Returns TRUE on success.
3421 **************************************************************************/
3422 bool entry_str_set_escaped(struct entry *pentry, bool escaped)
3424 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3425 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3426 ENTRY_STR == pentry->type, FALSE);
3428 pentry->string.escaped = escaped;
3429 return TRUE;
3432 /**************************************************************************
3433 Sets if the string should get gettext marking. Returns TRUE on success.
3434 **************************************************************************/
3435 bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
3437 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3438 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3439 ENTRY_STR == pentry->type, FALSE);
3441 pentry->string.gt_marking = gt_marking;
3443 return TRUE;
3446 /**************************************************************************
3447 Push an entry into a file stream.
3448 **************************************************************************/
3449 static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
3451 static char buf[8192];
3452 char *dot = NULL;
3453 int i;
3455 switch (pentry->type) {
3456 case ENTRY_BOOL:
3457 fz_fprintf(fs, "%s", pentry->boolean.value ? "TRUE" : "FALSE");
3458 break;
3459 case ENTRY_INT:
3460 fz_fprintf(fs, "%d", pentry->integer.value);
3461 break;
3462 case ENTRY_FLOAT:
3463 snprintf(buf, sizeof(buf), "%f", pentry->floating.value);
3464 for (i = 0; buf[i] != '\0' ; i++) {
3465 if (buf[i] == '.') {
3466 dot = &(buf[i]);
3467 break;
3470 if (dot == NULL) {
3471 /* There's no '.' so it would seem like a integer value when loaded.
3472 * Force it not to look like an integer by adding ".0" */
3473 fz_fprintf(fs, "%s.0", buf);
3474 } else {
3475 fz_fprintf(fs, "%s", buf);
3477 break;
3478 case ENTRY_STR:
3479 if (pentry->string.escaped) {
3480 make_escapes(pentry->string.value, buf, sizeof(buf));
3481 if (pentry->string.gt_marking) {
3482 fz_fprintf(fs, "_(\"%s\")", buf);
3483 } else {
3484 fz_fprintf(fs, "\"%s\"", buf);
3486 } else {
3487 fz_fprintf(fs, "$%s$", pentry->string.value);
3489 break;
3490 case ENTRY_FILEREFERENCE:
3491 fz_fprintf(fs, "*%s*", pentry->string.value);
3492 break;
3496 /**************************************************************************
3497 Creates a new entry from the token.
3498 **************************************************************************/
3499 static void entry_from_inf_token(struct section *psection, const char *name,
3500 const char *tok, struct inputfile *inf)
3502 if (!entry_from_token(psection, name, tok)) {
3503 log_error("%s", inf_log_str(inf, "Entry value not recognized: %s", tok));