Freeciv-3.2
Loading...
Searching...
No Matches
registry_ini.c
Go to the documentation of this file.
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.
7
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***********************************************************************/
13
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***************************************************************************/
20
21/**************************************************************************
22 Description of the file format:
23 (This is based on a format by the original authors, with
24 various incremental extensions. --dwp)
25
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.
29
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.
35
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...
40
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.
54
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>.)
58
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.
63
64 - Multiline strings: Strings can have embedded newlines, eg:
65 foo = _("
66 This is a string
67 over multiple lines
68 ")
69 This is equivalent to:
70 foo = _("\nThis is a string\nover multiple lines\n")
71 Note that if you misplace the trailing doublequote you can
72 easily end up with strange errors reading the file...
73
74 - Strings read from a file: A file can be read as a string value:
75 foo = *filename.txt*
76
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.)
92
93 - Tabular format: The lines:
94 foo = { "bar", "baz", "bax"
95 "wow", 10, -5
96 "cool", "str"
97 "hmm", 314, 99, 33, 11
98 }
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 '{'.
118
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...
124
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().)
129
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,
134 11,
135 "x"
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...
139
140***************************************************************************/
141
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**************************************************************************/
150
151#ifdef HAVE_CONFIG_H
152#include <fc_config.h>
153#endif
154
155#include <stdarg.h>
156#include <stdlib.h>
157#include <string.h>
158
159/* utility */
160#include "astring.h"
161#include "bugs.h"
162#include "deprecations.h"
163#include "fcintl.h"
164#include "inputfile.h"
165#include "ioz.h"
166#include "log.h"
167#include "mem.h"
168#include "registry.h"
169#include "section_file.h"
170#include "shared.h"
171#include "support.h"
172
173#include "registry_ini.h"
174
175#define MAX_LEN_SECPATH 1024
176
177/* Set to FALSE for old-style savefiles. */
178#define SAVE_TABLES TRUE
179
180#define SPECVEC_TAG astring
181#include "specvec.h"
182
183static inline bool entry_used(const struct entry *pentry);
184static inline void entry_use(struct entry *pentry);
185
186static void entry_to_file(const struct entry *pentry, fz_FILE *fs);
187static void entry_from_inf_token(struct section *psection, const char *name,
188 const char *tok, struct inputfile *file);
189
190/* An 'entry' is a string, integer, boolean or string vector;
191 * See enum entry_type in registry.h.
192 */
193struct entry {
194 struct section *psection; /* Parent section. */
195 char *name; /* Name, not including section prefix. */
196 enum entry_type type; /* The type of the entry. */
197 int used; /* Number of times entry looked up. */
198 char *comment; /* Comment, may be NULL. */
199
200 union {
201 /* ENTRY_BOOL */
202 struct {
203 bool value;
204 } boolean;
205 /* ENTRY_INT */
206 struct {
207 int value;
208 } integer;
209 /* ENTRY_FLOAT */
210 struct {
211 float value;
212 } floating;
213 /* ENTRY_STR */
214 struct {
215 char *value; /* Malloced string. */
216 bool escaped; /* " or $. Usually TRUE */
217 bool raw; /* Do not add anything. */
218 bool gt_marking; /* Save with gettext marking. */
219 } string;
220 };
221};
222
224 const char *name,
225 const char *value);
226static struct entry *section_entry_comment_new(struct section *psection,
227 const char *comment);
228
229/**********************************************************************/
232static const char *datafilename(const char *filename)
233{
234 return fileinfoname(get_data_dirs(), filename);
235}
236
237/**********************************************************************/
240static bool is_secfile_entry_name_valid(const char *name)
241{
242 static const char *const allowed = "_.,-[]";
243
244 while ('\0' != *name) {
245 if (!fc_isalnum(*name) && NULL == strchr(allowed, *name)) {
246 return FALSE;
247 }
248 name++;
249 }
250 return TRUE;
251}
252
253/**********************************************************************/
256static bool secfile_hash_insert(struct section_file *secfile,
257 struct entry *pentry)
258{
259 char buf[256];
260 struct entry *hentry;
261
262 if (NULL == secfile->hash.entries) {
263 /* Consider as success if this secfile doesn't have built the entries
264 * hash table. */
265 return TRUE;
266 }
267
268 entry_path(pentry, buf, sizeof(buf));
270 NULL, &hentry)) {
272 if (!secfile->allow_duplicates) {
274 "Tried to insert same value twice: %s", buf);
275 return FALSE;
276 }
277 }
278
279 return TRUE;
280}
281
282/**********************************************************************/
285static bool secfile_hash_delete(struct section_file *secfile,
286 struct entry *pentry)
287{
288 char buf[256];
289
290 if (NULL == secfile->hash.entries) {
291 /* Consider as success if this secfile doesn't have built the entries
292 * hash table. */
293 return TRUE;
294 }
295
296 entry_path(pentry, buf, sizeof(buf));
297 return entry_hash_remove(secfile->hash.entries, buf);
298}
299
300/**********************************************************************/
304 const char *filename,
305 const char *section,
306 bool allow_duplicates)
307{
308 struct section_file *secfile;
309 struct section *psection = NULL;
310 struct section *single_section = NULL;
311 bool table_state = FALSE; /* TRUE when within tabular format. */
312 int table_lineno = 0; /* Row number in tabular, 0 top data row. */
313 const char *tok;
314 int i;
315 struct astring base_name = ASTRING_INIT; /* for table or single entry */
317 struct astring_vector columns; /* astrings for column headings */
318 bool found_my_section = FALSE;
319 bool error = FALSE;
320
321 if (!inf) {
322 return NULL;
323 }
324
325 /* Assign the real value later, to speed up the creation of new entries. */
326 secfile = secfile_new(TRUE);
327 if (filename) {
328 secfile->name = fc_strdup(filename);
329 } else {
330 secfile->name = NULL;
331 }
332
334
335 if (filename) {
336 log_verbose("Reading registry from \"%s\"", filename);
337 } else {
338 log_verbose("Reading registry");
339 }
340
341 while (!inf_at_eof(inf)) {
342 if (inf_token(inf, INF_TOK_EOL)) {
343 continue;
344 }
345 if (inf_at_eof(inf)) {
346 /* may only realise at eof after trying to read eol above */
347 break;
348 }
350 if (tok) {
351 if (found_my_section) {
352 /* This shortcut will stop any further loading after the requested
353 * section has been loaded (i.e., at the start of a new section).
354 * This is needed to make the behavior useful, since the whole
355 * purpose is to short-cut further loading of the file. However
356 * normally a section may be split up, and that will no longer
357 * work here because it will be short-cut. */
358 SECFILE_LOG(secfile, psection, "%s",
359 inf_log_str(inf, "Found requested section; finishing"));
360 goto END;
361 }
362 if (table_state) {
363 SECFILE_LOG(secfile, psection, "%s",
364 inf_log_str(inf, "New section during table"));
365 error = TRUE;
366 goto END;
367 }
368 /* Check if we already have a section with this name.
369 (Could ignore this and have a duplicate sections internally,
370 but then secfile_get_secnames_prefix would return duplicates.)
371 Duplicate section in input are likely to be useful for includes.
372 */
373 psection = secfile_section_by_name(secfile, tok);
374 if (!psection) {
375 if (!section || strcmp(tok, section) == 0) {
376 psection = secfile_section_new(secfile, tok);
377 if (section) {
378 single_section = psection;
380 }
381 }
382 }
383 if (!inf_token(inf, INF_TOK_EOL)) {
384 SECFILE_LOG(secfile, psection, "%s",
385 inf_log_str(inf, "Expected end of line"));
386 error = TRUE;
387 goto END;
388 }
389 continue;
390 }
392 if (!table_state) {
393 SECFILE_LOG(secfile, psection, "%s",
394 inf_log_str(inf, "Misplaced \"}\""));
395 error = TRUE;
396 goto END;
397 }
398 if (!inf_token(inf, INF_TOK_EOL)) {
399 SECFILE_LOG(secfile, psection, "%s",
400 inf_log_str(inf, "Expected end of line"));
401 error = TRUE;
402 goto END;
403 }
405 continue;
406 }
407 if (table_state) {
408 i = -1;
409 do {
411
412 i++;
413
414 if (i < num_columns) {
415 astr_set(&field_name, "%s%d.%s", astr_str(&base_name),
417 } else {
418 astr_set(&field_name, "%s%d.%s,%d", astr_str(&base_name),
420 (int) (i - num_columns + 1));
421 }
422
423 inf_discard_tokens(inf, INF_TOK_EOL); /* Allow newlines */
424 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
425 SECFILE_LOG(secfile, psection, "%s",
426 inf_log_str(inf, "Expected value for %s",
428 error = TRUE;
429 goto END;
430 }
431
433 } while (inf_token(inf, INF_TOK_COMMA));
434
435 if (!inf_token(inf, INF_TOK_EOL)) {
436 SECFILE_LOG(secfile, psection, "%s",
437 inf_log_str(inf, "Expected end of line or comma"));
438 error = TRUE;
439 goto END;
440 }
441 table_lineno++;
442 continue;
443 }
444
445 if (!(tok = inf_token(inf, INF_TOK_ENTRY_NAME))) {
446 SECFILE_LOG(secfile, psection, "%s",
447 inf_log_str(inf, "Expected entry name"));
448 error = TRUE;
449 goto END;
450 }
451
452 /* need to store tok before next calls: */
453 astr_set(&base_name, "%s", tok);
454
455 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
456
458 i = -1;
459 do {
460 i++;
461 inf_discard_tokens(inf, INF_TOK_EOL); /* Allow newlines */
462 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
463 SECFILE_LOG(secfile, psection, "%s",
464 inf_log_str(inf, "Expected column header %s,%d",
465 astr_str(&base_name), i));
466 error = TRUE;
467 goto END;
468 }
469 if (tok[0] != '\"') {
470 SECFILE_LOG(secfile, psection, "%s",
471 inf_log_str(inf, "Table column header non-string"));
472 error = TRUE;
473 goto END;
474 }
475 { /* Expand columns: */
476 int j, n_prev;
477
479 for (j = i + 1; j < n_prev; j++) {
480 astr_free(&columns.p[j]);
481 }
483 for (j = n_prev; j < i + 1; j++) {
484 astr_init(&columns.p[j]);
485 }
486 }
487 astr_set(&columns.p[i], "%s", tok + 1);
488
489 } while (inf_token(inf, INF_TOK_COMMA));
490
491 if (!inf_token(inf, INF_TOK_EOL)) {
492 SECFILE_LOG(secfile, psection, "%s",
493 inf_log_str(inf, "Expected end of line or comma"));
494 error = TRUE;
495 goto END;
496 }
498 table_lineno = 0;
499 continue;
500 }
501 /* ordinary value: */
502 i = -1;
503 do {
504 i++;
505 inf_discard_tokens(inf, INF_TOK_EOL); /* Allow newlines */
506 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
507 if (i == 0) {
508 SECFILE_LOG(secfile, psection, "%s",
509 inf_log_str(inf, "Expected value for %s",
511 } else {
512 SECFILE_LOG(secfile, psection, "%s",
513 inf_log_str(inf, "Expected value for %s,%d",
514 astr_str(&base_name), i));
515 }
516 error = TRUE;
517 goto END;
518 }
519 if (i == 0) {
521 } else {
522 astr_set(&field_name, "%s,%d", astr_str(&base_name), i);
524 }
525 } while (inf_token(inf, INF_TOK_COMMA));
526 if (!inf_token(inf, INF_TOK_EOL)) {
527 SECFILE_LOG(secfile, psection, "%s",
528 inf_log_str(inf, "Expected end of line or comma"));
529 error = TRUE;
530 goto END;
531 }
532 }
533
534 if (table_state) {
535 SECFILE_LOG(secfile, psection,
536 "Finished registry before end of table");
537 error = TRUE;
538 }
539
540END:
541 inf_close(inf);
544 for (i = 0; i < astring_vector_size(&columns); i++) {
545 astr_free(&columns.p[i]);
546 }
548
549 if (section != NULL) {
550 if (!found_my_section) {
551 secfile_destroy(secfile);
552 return NULL;
553 }
554
555 /* Build the entry hash table with single section information */
556 secfile->allow_duplicates = allow_duplicates;
558 if (!secfile_hash_insert(secfile, pentry)) {
559 secfile_destroy(secfile);
560 return NULL;
561 }
563
564 return secfile;
565 }
566
567 if (!error) {
568 /* Build the entry hash table. */
569 secfile->allow_duplicates = allow_duplicates;
570 secfile->hash.entries = entry_hash_new_nentries(secfile->num_entries);
571
574 if (!secfile_hash_insert(secfile, pentry)) {
575 error = TRUE;
576 break;
577 }
579 if (error) {
580 break;
581 }
583 }
584 if (error) {
585 secfile_destroy(secfile);
586 return NULL;
587 } else {
588 return secfile;
589 }
590}
591
592/**********************************************************************/
596struct section_file *secfile_load_section(const char *filename,
597 const char *section,
598 bool allow_duplicates)
599{
600 char real_filename[1024];
601
602 interpret_tilde(real_filename, sizeof(real_filename), filename);
604 filename, section, allow_duplicates);
605}
606
607/**********************************************************************/
616
617/**********************************************************************/
620static bool is_legal_table_entry_name(char c, bool num)
621{
622 return (num ? fc_isalnum(c) : fc_isalpha(c)) || c == '_';
623}
624
625/**********************************************************************/
644bool secfile_save(const struct section_file *secfile, const char *filename,
646{
647 char real_filename[1024];
648 char pentry_name[128];
649 const char *col_entry_name;
650 fz_FILE *fs;
651 const struct entry_list_link *ent_iter, *save_iter, *col_iter;
652 struct entry *pentry, *col_pentry;
653 int i;
654
655 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
656
657 if (NULL == filename) {
658 filename = secfile->name;
659 }
660
661 interpret_tilde(real_filename, sizeof(real_filename), filename);
664
665 if (!fs) {
666 SECFILE_LOG(secfile, NULL, _("Could not open %s for writing"), real_filename);
667
668 return FALSE;
669 }
670
672 if (psection->special == EST_INCLUDE) {
676
677 fc_assert(!strcmp(entry_name(pentry), "file"));
678
679 fz_fprintf(fs, "*include ");
681 fz_fprintf(fs, "\n");
682 }
683 } else if (psection->special == EST_COMMENT) {
687
688 fc_assert(!strcmp(entry_name(pentry), "comment"));
689
691 fz_fprintf(fs, "\n");
692 }
693 } else {
694 fz_fprintf(fs, "\n[%s]\n", section_name(psection));
695
696 /* Following doesn't use entry_list_iterate() because we want to do
697 * tricky things with the iterators...
698 */
702 const char *comment;
703
704 /* Tables: break out of this loop if this is a non-table
705 * entry (pentry and ent_iter unchanged) or after table (pentry
706 * and ent_iter suitably updated, pentry possibly NULL).
707 * After each table, loop again in case the next entry
708 * is another table.
709 */
710 for (;;) {
711 char *c, *first, base[64];
712 int offset, irow, icol, ncol;
713
714 /* Example: for first table name of "xyz0.blah":
715 * first points to the original string pentry->name
716 * base contains "xyz";
717 * offset = 5 (so first+offset gives "blah")
718 * note strlen(base) = offset - 2
719 */
720
721 if (!SAVE_TABLES) {
722 break;
723 }
724
725 if (pentry->type == ENTRY_LONG_COMMENT) {
726 break;
727 }
728
730 c = first = pentry_name;
731 if (*c == '\0' || !is_legal_table_entry_name(*c, FALSE)) {
732 break;
733 }
734 for (; *c != '\0' && is_legal_table_entry_name(*c, FALSE); c++) {
735 /* nothing */
736 }
737 if (fc_strncmp(c, "0.", 2)) {
738 break;
739 }
740 c += 2;
741 if (*c == '\0' || !is_legal_table_entry_name(*c, TRUE)) {
742 break;
743 }
744
745 offset = c - first;
746 first[offset - 2] = '\0';
747 sz_strlcpy(base, first);
748 first[offset - 2] = '0';
749 fz_fprintf(fs, "%s={", base);
750
751 /* Save an iterator at this first entry, which we can later use
752 * to repeatedly iterate over column names:
753 */
755
756 /* Write the column names, and calculate ncol: */
757 ncol = 0;
761 if (col_pentry->type == ENTRY_LONG_COMMENT) {
762 continue;
763 }
765 if (fc_strncmp(col_entry_name, first, offset)) {
766 break;
767 }
768 fz_fprintf(fs, "%s\"%s\"", (ncol == 0 ? "" : ","),
769 col_entry_name + offset);
770 ncol++;
771 }
772 fz_fprintf(fs, "\n");
773
774 /* Iterate over rows and columns, incrementing ent_iter as we go,
775 * and writing values to the table. Have a separate iterator
776 * to the column names to check they all match.
777 */
778 irow = icol = 0;
780 for (;;) {
781 char expect[128]; /* pentry->name we're expecting */
782
785
786 if (pentry && pentry->type == ENTRY_LONG_COMMENT) {
787 if (icol == 0) {
789 } else {
790 bugreport_request("In file %s, section %s there was\n"
791 "an attempt to insert comment in the middle of table row.",
793 }
795 continue;
796 } else {
797
798 fc_snprintf(expect, sizeof(expect), "%s%d.%s",
799 base, irow, entry_name(col_pentry) + offset);
800
801 /* break out of tabular if doesn't match: */
802 if ((!pentry) || (strcmp(entry_name(pentry), expect) != 0)) {
803 if (icol != 0) {
804 /* If the second or later row of a table is missing some
805 * entries that the first row had, we drop out of the tabular
806 * format. This is inefficient so we print a warning message;
807 * the calling code probably needs to be fixed so that it can
808 * use the more efficient tabular format.
809 *
810 * FIXME: If the first row is missing some entries that the
811 * second or later row has, then we'll drop out of tabular
812 * format without an error message. */
813 bugreport_request("In file %s, there is no entry in the registry for\n"
814 "%s.%s (or the entries are out of order). This means\n"
815 "a less efficient non-tabular format will be used.\n"
816 "To avoid this make sure all rows of a table are\n"
817 "filled out with an entry for every column.",
819 fz_fprintf(fs, "\n");
820 }
821 fz_fprintf(fs, "}\n");
822 break;
823 }
824 }
825
826 if (icol > 0) {
827 fz_fprintf(fs, ",");
828 }
830
833
834 icol++;
835 if (icol == ncol) {
836 fz_fprintf(fs, "\n");
837 irow++;
838 icol = 0;
840 }
841 }
842 if (!pentry) {
843 break;
844 }
845 }
846 if (!pentry) {
847 break;
848 }
849
850 if (pentry->type == ENTRY_LONG_COMMENT) {
852 } else {
853 /* Classic entry. */
857
858 /* Check for vector. */
859 for (i = 1;; i++) {
862 if (NULL == col_pentry || col_pentry->type == ENTRY_LONG_COMMENT) {
863 break;
864 }
866 "%s,%d", col_entry_name, i);
868 break;
869 }
870 fz_fprintf(fs, ",");
873 }
874
876 if (comment) {
877 fz_fprintf(fs, " # %s\n", comment);
878 } else {
879 fz_fprintf(fs, "\n");
880 }
881 }
882 }
883 }
885
886 if (0 != fz_ferror(fs)) {
887 SECFILE_LOG(secfile, NULL, "Error before closing %s: %s",
889 fz_fclose(fs);
890 return FALSE;
891 }
892 if (0 != fz_fclose(fs)) {
893 SECFILE_LOG(secfile, NULL, "Error closing %s", real_filename);
894 return FALSE;
895 }
896
897 return TRUE;
898}
899
900/**********************************************************************/
907void secfile_check_unused(const struct section_file *secfile)
908{
909 bool any = FALSE;
910
913 if (!entry_used(pentry)) {
914 if (!any && secfile->name) {
915 log_verbose("Unused entries in file %s:", secfile->name);
916 any = TRUE;
917 }
919 log_deprecation_always("%s: unused entry: %s.%s",
920 secfile->name != NULL ? secfile->name : "nameless",
922 } else {
923#ifdef FREECIV_TESTMATIC
924 log_testmatic("%s: unused entry: %s.%s",
925 secfile->name != NULL ? secfile->name : "nameless",
927#else /* FREECIV_TESTMATIC */
928 log_verbose(" unused entry: %s.%s",
930#endif /* FREECIV_TESTMATIC */
931 }
932 }
935}
936
937/**********************************************************************/
943const char *secfile_name(const struct section_file *secfile)
944{
945 if (NULL == secfile) {
946 return "NULL";
947 } else if (secfile->name) {
948 return secfile->name;
949 } else {
950 return "(anonymous)";
951 }
952}
953
954/**********************************************************************/
958 const char *path,
959 const char **pent_name)
960{
962 char *ent_name;
963 struct section *psection;
964
965 sz_strlcpy(fullpath, path);
966
967 ent_name = strchr(fullpath, '.');
968 if (!ent_name) {
970 "Section and entry names must be separated by a dot.");
971 return NULL;
972 }
973
974 /* Separates section and entry names. */
975 *ent_name = '\0';
976 *pent_name = path + (ent_name - fullpath) + 1;
978 if (psection) {
979 return psection;
980 } else {
982 }
983}
984
985/**********************************************************************/
989 bool value, const char *comment,
990 bool allow_replace,
991 const char *path, ...)
992{
994 const char *ent_name;
995 struct section *psection;
996 struct entry *pentry = NULL;
997 va_list args;
998
999 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1000
1001 va_start(args, path);
1002 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1003 va_end(args);
1004
1006 if (!psection) {
1007 return NULL;
1008 }
1009
1010 if (allow_replace) {
1012 if (NULL != pentry) {
1014 if (!entry_bool_set(pentry, value)) {
1015 return NULL;
1016 }
1017 } else {
1019 pentry = NULL;
1020 }
1021 }
1022 }
1023
1024 if (NULL == pentry) {
1026 }
1027
1028 if (NULL != pentry && NULL != comment) {
1030 }
1031
1032 return pentry;
1033}
1034
1035/**********************************************************************/
1040 const bool *values, size_t dim,
1041 const char *comment, bool allow_replace,
1042 const char *path, ...)
1043{
1045 size_t i, ret = 0;
1046 va_list args;
1047
1048 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1049
1050 va_start(args, path);
1051 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1052 va_end(args);
1053
1054 /* NB: 'path,0' is actually 'path'. See comment in the head
1055 * of the file. */
1056 if (dim > 0
1057 && NULL != secfile_insert_bool_full(secfile, values[0], comment,
1058 allow_replace, "%s", fullpath)) {
1059 ret++;
1060 }
1061 for (i = 1; i < dim; i++) {
1062 if (NULL != secfile_insert_bool_full(secfile, values[i], comment,
1063 allow_replace, "%s,%d",
1064 fullpath, (int) i)) {
1065 ret++;
1066 }
1067 }
1068
1069 return ret;
1070}
1071
1072/**********************************************************************/
1076 int value, const char *comment,
1077 bool allow_replace,
1078 const char *path, ...)
1079{
1081 const char *ent_name;
1082 struct section *psection;
1083 struct entry *pentry = NULL;
1084 va_list args;
1085
1086 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1087
1088 va_start(args, path);
1089 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1090 va_end(args);
1091
1093 if (!psection) {
1094 return NULL;
1095 }
1096
1097 if (allow_replace) {
1099 if (NULL != pentry) {
1101 if (!entry_int_set(pentry, value)) {
1102 return NULL;
1103 }
1104 } else {
1106 pentry = NULL;
1107 }
1108 }
1109 }
1110
1111 if (NULL == pentry) {
1113 }
1114
1115 if (NULL != pentry && NULL != comment) {
1117 }
1118
1119 return pentry;
1120}
1121
1122/**********************************************************************/
1127 const int *values, size_t dim,
1128 const char *comment, bool allow_replace,
1129 const char *path, ...)
1130{
1132 size_t i, ret = 0;
1133 va_list args;
1134
1135 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1136
1137 va_start(args, path);
1138 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1139 va_end(args);
1140
1141 /* NB: 'path,0' is actually 'path'. See comment in the head
1142 * of the file. */
1143 if (dim > 0
1144 && NULL != secfile_insert_int_full(secfile, values[0], comment,
1145 allow_replace, "%s", fullpath)) {
1146 ret++;
1147 }
1148 for (i = 1; i < dim; i++) {
1149 if (NULL != secfile_insert_int_full(secfile, values[i], comment,
1150 allow_replace, "%s,%d",
1151 fullpath, (int) i)) {
1152 ret++;
1153 }
1154 }
1155
1156 return ret;
1157}
1158
1159/**********************************************************************/
1163 float value, const char *comment,
1164 bool allow_replace,
1165 const char *path, ...)
1166{
1168 const char *ent_name;
1169 struct section *psection;
1170 struct entry *pentry = NULL;
1171 va_list args;
1172
1173 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1174
1175 va_start(args, path);
1176 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1177 va_end(args);
1178
1180 if (!psection) {
1181 return NULL;
1182 }
1183
1184 if (allow_replace) {
1186 if (NULL != pentry) {
1188 if (!entry_float_set(pentry, value)) {
1189 return NULL;
1190 }
1191 } else {
1193 pentry = NULL;
1194 }
1195 }
1196 }
1197
1198 if (NULL == pentry) {
1200 }
1201
1202 if (NULL != pentry && NULL != comment) {
1204 }
1205
1206 return pentry;
1207}
1208
1209/**********************************************************************/
1213 const char *filename)
1214{
1215 struct section *psection;
1216 char buffer[200];
1217
1218 fc_snprintf(buffer, sizeof(buffer), "include_%u", secfile->num_includes++);
1219
1221
1222 /* Create include section. */
1223 psection = secfile_section_new(secfile, buffer);
1224 psection->special = EST_INCLUDE;
1225
1226 /* Then add string entry "file" to it. */
1228 EST_INCLUDE, "%s.file", buffer);
1229
1230 return psection;
1231}
1232
1233/**********************************************************************/
1237 const char *comment)
1238{
1239 struct section *psection;
1240 char buffer[200];
1241
1242 fc_snprintf(buffer, sizeof(buffer), "long_comment_%u", secfile->num_long_comments++);
1243
1245
1246 /* Create long comment section. */
1247 psection = secfile_section_new(secfile, buffer);
1248 psection->special = EST_COMMENT;
1249
1250 /* Then add string entry "comment" to it. */
1252 EST_COMMENT, "%s.comment", buffer);
1253
1254 return psection;
1255}
1256
1257/**********************************************************************/
1261 const char *str,
1262 const char *comment,
1263 bool allow_replace,
1264 bool no_escape,
1265 enum entry_special_type stype,
1266 const char *path, ...)
1267{
1269 const char *ent_name;
1270 struct section *psection;
1271 struct entry *pentry = NULL;
1272 va_list args;
1273
1274 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1275
1276 va_start(args, path);
1277 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1278 va_end(args);
1279
1281 if (!psection) {
1282 return NULL;
1283 }
1284
1285 if (psection->special != stype) {
1286 log_error("Tried to insert wrong type of entry to section");
1287 return NULL;
1288 }
1289
1290 if (allow_replace) {
1292 if (NULL != pentry) {
1294 if (!entry_str_set(pentry, str)) {
1295 return NULL;
1296 }
1297 } else {
1299 pentry = NULL;
1300 }
1301 }
1302 }
1303
1304 if (NULL == pentry) {
1306 }
1307
1308 if (NULL != pentry && NULL != comment) {
1310 }
1311
1312 if (stype == EST_COMMENT) {
1313 pentry->string.raw = TRUE;
1314 }
1315
1316 return pentry;
1317}
1318
1319/**********************************************************************/
1323 const char *str,
1324 const char *path, ...)
1325{
1327 const char *ent_name;
1328 struct section *psection;
1329 struct entry *pentry = NULL;
1330 va_list args;
1331
1332 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1333
1334 va_start(args, path);
1335 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1336 va_end(args);
1337
1338 sz_strlcat(fullpath, ".#");
1339
1341 if (!psection) {
1342 return NULL;
1343 }
1344
1345 if (psection->special != EST_NORMAL) {
1346 log_error("Tried to insert wrong type of entry to section");
1347 return NULL;
1348 }
1349
1351
1352 return pentry;
1353}
1354
1355/**********************************************************************/
1360 const char *const *strings, size_t dim,
1361 const char *comment, bool allow_replace,
1362 bool no_escape, const char *path, ...)
1363{
1365 size_t i, ret = 0;
1366 va_list args;
1367
1368 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1369
1370 va_start(args, path);
1371 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1372 va_end(args);
1373
1374 /* NB: 'path,0' is actually 'path'. See comment in the head
1375 * of the file. */
1376 if (dim > 0
1377 && NULL != secfile_insert_str_full(secfile, strings[0], comment,
1379 "%s", fullpath)) {
1380 ret++;
1381 }
1382 for (i = 1; i < dim; i++) {
1383 if (NULL != secfile_insert_str_full(secfile, strings[i], comment,
1385 "%s,%d", fullpath, (int) i)) {
1386 ret++;
1387 }
1388 }
1389
1390 return ret;
1391}
1392
1393/**********************************************************************/
1397 const char *filename,
1398 const char *path, ...)
1399{
1401 const char *ent_name;
1402 struct section *psection;
1403 struct entry *pentry = NULL;
1404 va_list args;
1405
1406 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1407
1408 va_start(args, path);
1409 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1410 va_end(args);
1411
1413 if (!psection) {
1414 return NULL;
1415 }
1416
1417 if (psection->special != EST_NORMAL) {
1418 log_error("Tried to insert normal entry to different kind of section");
1419 return NULL;
1420 }
1421
1422 if (NULL == pentry) {
1424 }
1425
1426 return pentry;
1427}
1428
1429/**********************************************************************/
1433 int enumerator,
1435 const char *comment,
1436 bool allow_replace,
1437 const char *path, ...)
1438{
1440 const char *str;
1441 const char *ent_name;
1442 struct section *psection;
1443 struct entry *pentry = NULL;
1444 va_list args;
1445
1446 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1448 str = name_fn(enumerator);
1450
1451 va_start(args, path);
1452 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1453 va_end(args);
1454
1456 if (!psection) {
1457 return NULL;
1458 }
1459
1460 if (allow_replace) {
1462 if (NULL != pentry) {
1464 if (!entry_str_set(pentry, str)) {
1465 return NULL;
1466 }
1467 } else {
1469 pentry = NULL;
1470 }
1471 }
1472 }
1473
1474 if (NULL == pentry) {
1476 }
1477
1478 if (NULL != pentry && NULL != comment) {
1480 }
1481
1482 return pentry;
1483}
1484
1485/**********************************************************************/
1490 const int *enumurators, size_t dim,
1492 const char *comment,
1493 bool allow_replace,
1494 const char *path, ...)
1495{
1497 size_t i, ret = 0;
1498 va_list args;
1499
1500 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1502
1503 va_start(args, path);
1504 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1505 va_end(args);
1506
1507 /* NB: 'path,0' is actually 'path'. See comment in the head
1508 * of the file. */
1509 if (dim > 0
1512 allow_replace, "%s",
1513 fullpath)) {
1514 ret++;
1515 }
1516 for (i = 1; i < dim; i++) {
1519 allow_replace, "%s,%d",
1520 fullpath, (int) i)) {
1521 ret++;
1522 }
1523 }
1524
1525 return ret;
1526}
1527
1528/**********************************************************************/
1532 int bitwise_val,
1534 name_fn,
1536 begin_fn,
1538 end_fn,
1540 next_fn,
1541 const char *comment,
1542 bool allow_replace,
1543 const char *path, ...)
1544{
1546 const char *ent_name;
1547 struct section *psection;
1548 struct entry *pentry = NULL;
1549 va_list args;
1550 int i;
1551
1552 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1557
1558 /* Compute a string containing all the values separated by '|'. */
1559 str[0] = '\0'; /* Insert at least an empty string. */
1560 if (0 != bitwise_val) {
1561 for (i = begin_fn(); i != end_fn(); i = next_fn(i)) {
1562 if (i & bitwise_val) {
1563 if ('\0' == str[0]) {
1565 } else {
1566 cat_snprintf(str, sizeof(str), "|%s", name_fn(i));
1567 }
1568 }
1569 }
1570 }
1571
1572 va_start(args, path);
1573 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1574 va_end(args);
1575
1577 if (!psection) {
1578 return NULL;
1579 }
1580
1581 if (allow_replace) {
1583 if (NULL != pentry) {
1585 if (!entry_str_set(pentry, str)) {
1586 return NULL;
1587 }
1588 } else {
1590 pentry = NULL;
1591 }
1592 }
1593 }
1594
1595 if (NULL == pentry) {
1597 }
1598
1599 if (NULL != pentry && NULL != comment) {
1601 }
1602
1603 return pentry;
1604}
1605
1606/**********************************************************************/
1611 const int *bitwise_vals,
1612 size_t dim,
1617 const char *comment,
1618 bool allow_replace,
1619 const char *path, ...)
1620{
1622 size_t i, ret = 0;
1623 va_list args;
1624
1625 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1628 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, 0);
1630
1631 va_start(args, path);
1632 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1633 va_end(args);
1634
1635 /* NB: 'path,0' is actually 'path'. See comment in the head
1636 * of the file. */
1637 if (dim > 0
1641 allow_replace, "%s",
1642 fullpath)) {
1643 ret++;
1644 }
1645 for (i = 1; i < dim; i++) {
1649 allow_replace, "%s,%d",
1650 fullpath, (int) i)) {
1651 ret++;
1652 }
1653 }
1654
1655 return ret;
1656}
1657
1658/**********************************************************************/
1663 int value, bool bitwise,
1665 secfile_data_t data,
1666 const char *comment,
1667 bool allow_replace,
1668 const char *path, ...)
1669{
1671 const char *ent_name, *val_name;
1672 struct section *psection;
1673 struct entry *pentry = NULL;
1674 va_list args;
1675 int i;
1676
1677 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1679
1680 if (bitwise) {
1681 /* Compute a string containing all the values separated by '|'. */
1682 str[0] = '\0'; /* Insert at least an empty string. */
1683 if (0 != value) {
1684 for (i = 0; (val_name = name_fn(data, i)); i++) {
1685 if ((1 << i) & value) {
1686 if ('\0' == str[0]) {
1688 } else {
1689 cat_snprintf(str, sizeof(str), "|%s", val_name);
1690 }
1691 }
1692 }
1693 }
1694 } else {
1695 if (!(val_name = name_fn(data, value))) {
1696 SECFILE_LOG(secfile, NULL, "Value %d not supported.", value);
1697 return NULL;
1698 }
1700 }
1701
1702 va_start(args, path);
1703 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1704 va_end(args);
1705
1707 if (!psection) {
1708 return NULL;
1709 }
1710
1711 if (allow_replace) {
1713 if (NULL != pentry) {
1715 if (!entry_str_set(pentry, str)) {
1716 return NULL;
1717 }
1718 } else {
1720 pentry = NULL;
1721 }
1722 }
1723 }
1724
1725 if (NULL == pentry) {
1727 }
1728
1729 if (NULL != pentry && NULL != comment) {
1731 }
1732
1733 return pentry;
1734}
1735
1736/**********************************************************************/
1741 const int *values, size_t dim,
1742 bool bitwise,
1744 secfile_data_t data,
1745 const char *comment,
1746 bool allow_replace,
1747 const char *path, ...)
1748{
1750 size_t i, ret = 0;
1751 va_list args;
1752
1753 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1755
1756 va_start(args, path);
1757 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1758 va_end(args);
1759
1760 /* NB: 'path,0' is actually 'path'. See comment in the head
1761 * of the file. */
1762 if (dim > 0
1763 && NULL != secfile_insert_enum_data_full(secfile, values[0], bitwise,
1764 name_fn, data, comment,
1765 allow_replace, "%s",
1766 fullpath)) {
1767 ret++;
1768 }
1769 for (i = 1; i < dim; i++) {
1770 if (NULL != secfile_insert_enum_data_full(secfile, values[i], bitwise,
1771 name_fn, data, comment,
1772 allow_replace, "%s,%d",
1773 fullpath, (int) i)) {
1774 ret++;
1775 }
1776 }
1777
1778 return ret;
1779}
1780
1781/**********************************************************************/
1784struct entry *secfile_entry_by_path(const struct section_file *secfile,
1785 const char *path)
1786{
1788 char *ent_name;
1789 size_t len;
1790 struct section *psection;
1791
1793
1794 sz_strlcpy(fullpath, path);
1795
1796 /* treat "sec.foo,0" as "sec.foo": */
1797 len = strlen(fullpath);
1798 if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1799 fullpath[len - 2] = '\0';
1800 }
1801
1802 if (NULL != secfile->hash.entries) {
1803 struct entry *pentry;
1804
1805 if (entry_hash_lookup(secfile->hash.entries, fullpath, &pentry)) {
1807 }
1808 return pentry;
1809 }
1810
1811 /* I dont like strtok.
1812 * - Me neither! */
1813 ent_name = strchr(fullpath, '.');
1814 if (!ent_name) {
1815 return NULL;
1816 }
1817
1818 /* Separates section and entry names. */
1819 *ent_name++ = '\0';
1821 if (psection) {
1823 } else {
1824 return NULL;
1825 }
1826}
1827
1828/**********************************************************************/
1832 const char *path, ...)
1833{
1835 va_list args;
1836 struct entry *pentry;
1837
1838 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1839
1840 va_start(args, path);
1841 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1842 va_end(args);
1843
1844 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1845 SECFILE_LOG(secfile, NULL, "Path %s does not exists.", fullpath);
1846 return FALSE;
1847 }
1848
1850
1851 return TRUE;
1852}
1853
1854/**********************************************************************/
1857struct entry *secfile_entry_lookup(const struct section_file *secfile,
1858 const char *path, ...)
1859{
1861 va_list args;
1862
1863 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1864
1865 va_start(args, path);
1866 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1867 va_end(args);
1868
1869 return secfile_entry_by_path(secfile, fullpath);
1870}
1871
1872/**********************************************************************/
1875bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1876 const char *path, ...)
1877{
1879 const struct entry *pentry;
1880 va_list args;
1881
1882 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1883
1884 va_start(args, path);
1885 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1886 va_end(args);
1887
1888 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1889 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1890 return FALSE;
1891 }
1892
1893 return entry_bool_get(pentry, bval);
1894}
1895
1896/**********************************************************************/
1901 bool def, const char *path, ...)
1902{
1904 const struct entry *pentry;
1905 bool bval;
1906 va_list args;
1907
1908 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1909
1910 va_start(args, path);
1911 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1912 va_end(args);
1913
1914 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1915 return def;
1916 }
1917
1918 if (entry_bool_get(pentry, &bval)) {
1919 return bval;
1920 }
1921
1922 return def;
1923}
1924
1925/**********************************************************************/
1930bool *secfile_lookup_bool_vec(const struct section_file *secfile,
1931 size_t *dim, const char *path, ...)
1932{
1934 size_t i = 0;
1935 bool *vec;
1936 va_list args;
1937
1938 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1940
1941 va_start(args, path);
1942 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1943 va_end(args);
1944
1945 /* Check size. */
1946 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1947 i++;
1948 }
1949 *dim = i;
1950
1951 if (0 == i) {
1952 /* Doesn't exist. */
1953 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1954 return NULL;
1955 }
1956
1957 vec = fc_malloc(i * sizeof(bool));
1958 for (i = 0; i < *dim; i++) {
1959 if (!secfile_lookup_bool(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;
1966 }
1967 }
1968
1969 return vec;
1970}
1971
1972/**********************************************************************/
1975bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1976 const char *path, ...)
1977{
1979 const struct entry *pentry;
1980 va_list args;
1981
1982 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1983
1984 va_start(args, path);
1985 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1986 va_end(args);
1987
1988 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1989 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1990 return FALSE;
1991 }
1992
1993 return entry_int_get(pentry, ival);
1994}
1995
1996/**********************************************************************/
2000int secfile_lookup_int_default(const struct section_file *secfile, int def,
2001 const char *path, ...)
2002{
2004 const struct entry *pentry;
2005 int ival;
2006 va_list args;
2007
2008 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2009
2010 va_start(args, path);
2011 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2012 va_end(args);
2013
2014 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2015 return def;
2016 }
2017
2018 if (entry_int_get(pentry, &ival)) {
2019 return ival;
2020 }
2021
2022 return def;
2023}
2024
2025/**********************************************************************/
2031 int defval, int minval, int maxval,
2032 const char *path, ...)
2033{
2035 const struct entry *pentry;
2036 int value;
2037 va_list args;
2038
2039 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2040
2041 va_start(args, path);
2042 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2043 va_end(args);
2044
2045 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2046 return defval;
2047 }
2048
2049 if (!entry_int_get(pentry, &value)) {
2050 return defval;
2051 }
2052
2053 if (value < minval) {
2055 "\"%s\" should be in the interval [%d, %d] but is %d;"
2056 "using the minimal value.",
2058 value = minval;
2059 }
2060
2061 if (value > maxval) {
2063 "\"%s\" should be in the interval [%d, %d] but is %d;"
2064 "using the maximal value.",
2066 value = maxval;
2067 }
2068
2069 return value;
2070}
2071
2072/**********************************************************************/
2077int *secfile_lookup_int_vec(const struct section_file *secfile,
2078 size_t *dim, const char *path, ...)
2079{
2081 size_t i = 0;
2082 int *vec;
2083 va_list args;
2084
2085 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2087
2088 va_start(args, path);
2089 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2090 va_end(args);
2091
2092 /* Check size. */
2093 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2094 i++;
2095 }
2096 *dim = i;
2097
2098 if (0 == i) {
2099 /* Doesn't exist. */
2100 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2101 return NULL;
2102 }
2103
2104 vec = fc_malloc(i * sizeof(int));
2105 for (i = 0; i < *dim; i++) {
2106 if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
2107 SECFILE_LOG(secfile, NULL,
2108 "An error occurred when looking up to \"%s,%d\" entry.",
2109 fullpath, (int) i);
2110 free(vec);
2111 *dim = 0;
2112 return NULL;
2113 }
2114 }
2115
2116 return vec;
2117}
2118
2119/**********************************************************************/
2122bool secfile_lookup_float(const struct section_file *secfile, float *fval,
2123 const char *path, ...)
2124{
2126 const struct entry *pentry;
2127 va_list args;
2128
2129 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2130
2131 va_start(args, path);
2132 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2133 va_end(args);
2134
2135 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2136 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2137 return FALSE;
2138 }
2139
2140 return entry_float_get(pentry, fval);
2141}
2142
2143/**********************************************************************/
2147float secfile_lookup_float_default(const struct section_file *secfile,
2148 float def, const char *path, ...)
2149{
2151 const struct entry *pentry;
2152 float fval;
2153 va_list args;
2154
2155 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2156
2157 va_start(args, path);
2158 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2159 va_end(args);
2160
2161 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2162 return def;
2163 }
2164
2165 if (entry_float_get(pentry, &fval)) {
2166 return fval;
2167 }
2168
2169 return def;
2170}
2171
2172/**********************************************************************/
2175const char *secfile_lookup_str(const struct section_file *secfile,
2176 const char *path, ...)
2177{
2179 const struct entry *pentry;
2180 const char *str;
2181 va_list args;
2182
2183 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2184
2185 va_start(args, path);
2186 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2187 va_end(args);
2188
2189 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2190 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2191 return NULL;
2192 }
2193
2194 if (entry_str_get(pentry, &str)) {
2195 return str;
2196 }
2197
2198 return NULL;
2199}
2200
2201/**********************************************************************/
2205const char *secfile_lookup_str_default(const struct section_file *secfile,
2206 const char *def,
2207 const char *path, ...)
2208{
2210 const struct entry *pentry;
2211 const char *str;
2212 va_list args;
2213
2214 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2215
2216 va_start(args, path);
2217 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2218 va_end(args);
2219
2220 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2221 return def;
2222 }
2223
2224 if (entry_str_get(pentry, &str)) {
2225 return str;
2226 }
2227
2228 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't have a string.", fullpath);
2229
2230 return def;
2231}
2232
2233/**********************************************************************/
2239const char **secfile_lookup_str_vec(const struct section_file *secfile,
2240 size_t *dim, const char *path, ...)
2241{
2243 size_t i = 0;
2244 const char **vec;
2245 va_list args;
2246
2247 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2249
2250 va_start(args, path);
2251 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2252 va_end(args);
2253
2254 /* Check size. */
2255 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2256 i++;
2257 }
2258 *dim = i;
2259
2260 if (0 == i) {
2261 /* Doesn't exist. */
2262 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2263 return NULL;
2264 }
2265
2266 vec = fc_malloc(i * sizeof(const char *));
2267 for (i = 0; i < *dim; i++) {
2268 if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d",
2269 fullpath, (int) i))) {
2270 SECFILE_LOG(secfile, NULL,
2271 "An error occurred when looking up to \"%s,%d\" entry.",
2272 fullpath, (int) i);
2273 free(vec);
2274 *dim = 0;
2275 return NULL;
2276 }
2277 }
2278
2279 return vec;
2280}
2281
2282/**********************************************************************/
2286 int *penumerator,
2289 const char *path, ...)
2290{
2292 const struct entry *pentry;
2293 const char *str;
2294 va_list args;
2295
2296 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2300
2301 va_start(args, path);
2302 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2303 va_end(args);
2304
2305 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2306 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2307 return FALSE;
2308 }
2309
2310 if (!entry_str_get(pentry, &str)) {
2311 return FALSE;
2312 }
2313
2315 if (is_valid_fn(*penumerator)) {
2316 return TRUE;
2317 }
2318
2320 "Entry \"%s\": no match for \"%s\".",
2322 return FALSE;
2323}
2324
2325/**********************************************************************/
2329 *secfile, int defval,
2333 by_name_fn,
2334 const char *path, ...)
2335{
2337 const struct entry *pentry;
2338 const char *str;
2339 int val;
2340 va_list args;
2341
2342 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2345
2346 va_start(args, path);
2347 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2348 va_end(args);
2349
2350 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2351 return defval;
2352 }
2353
2354 if (!entry_str_get(pentry, &str)) {
2355 return defval;
2356 }
2357
2358 val = by_name_fn(str, strcmp);
2359 if (is_valid_fn(val)) {
2360 return val;
2361 } else {
2362 return defval;
2363 }
2364}
2365
2366/**********************************************************************/
2372 size_t *dim,
2376 by_name_fn,
2377 const char *path, ...)
2378{
2380 size_t i = 0;
2381 int *vec;
2382 va_list args;
2383
2384 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2388
2389 va_start(args, path);
2390 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2391 va_end(args);
2392
2393 /* Check size. */
2394 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2395 i++;
2396 }
2397 *dim = i;
2398
2399 if (0 == i) {
2400 /* Doesn't exist. */
2401 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2402 return NULL;
2403 }
2404
2405 vec = fc_malloc(i * sizeof(int));
2406 for (i = 0; i < *dim; i++) {
2407 if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2408 by_name_fn, "%s,%d",
2409 fullpath, (int) i)) {
2410 SECFILE_LOG(secfile, NULL,
2411 "An error occurred when looking up to \"%s,%d\" entry.",
2412 fullpath, (int) i);
2413 free(vec);
2414 *dim = 0;
2415 return NULL;
2416 }
2417 }
2418
2419 return vec;
2420}
2421
2422/**********************************************************************/
2426 int *penumerator,
2429 const char *path, ...)
2430{
2432 const struct entry *pentry;
2433 const char *str, *p;
2435 int val;
2436 va_list args;
2437
2438 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2442
2443 va_start(args, path);
2444 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2445 va_end(args);
2446
2447 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2448 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2449 return FALSE;
2450 }
2451
2452 if (!entry_str_get(pentry, &str)) {
2453 return FALSE;
2454 }
2455
2456 *penumerator = 0;
2457 if ('\0' == str[0]) {
2458 /* Empty string = no value. */
2459 return TRUE;
2460 }
2461
2462 /* Value names are separated by '|'. */
2463 do {
2464 p = strchr(str, '|');
2465 if (NULL != p) {
2466 p++;
2467 fc_strlcpy(val_name, str, p - str);
2468 } else {
2469 /* Last segment, full copy. */
2471 }
2473 val = by_name_fn(val_name, strcmp);
2474 if (!is_valid_fn(val)) {
2476 "Entry \"%s\": no match for \"%s\".",
2478 return FALSE;
2479 }
2480 *penumerator |= val;
2481 str = p;
2482 } while (NULL != p);
2483
2484 return TRUE;
2485}
2486
2487/**********************************************************************/
2491 *secfile, int defval,
2495 by_name_fn,
2496 const char *path, ...)
2497{
2499 const struct entry *pentry;
2500 const char *str, *p;
2502 int val, full_val;
2503 va_list args;
2504
2505 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2508
2509 va_start(args, path);
2510 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2511 va_end(args);
2512
2513 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2514 return defval;
2515 }
2516
2517 if (!entry_str_get(pentry, &str)) {
2518 return defval;
2519 }
2520
2521 if ('\0' == str[0]) {
2522 /* Empty string = no value. */
2523 return 0;
2524 }
2525
2526 /* Value names are separated by '|'. */
2527 full_val = 0;
2528 do {
2529 p = strchr(str, '|');
2530 if (NULL != p) {
2531 p++;
2532 fc_strlcpy(val_name, str, p - str);
2533 } else {
2534 /* Last segment, full copy. */
2536 }
2538 val = by_name_fn(val_name, strcmp);
2539 if (!is_valid_fn(val)) {
2540 return defval;
2541 }
2542 full_val |= val;
2543 str = p;
2544 } while (NULL != p);
2545
2546 return full_val;
2547}
2548
2549/**********************************************************************/
2555 size_t *dim,
2559 by_name_fn,
2560 const char *path, ...)
2561{
2563 size_t i = 0;
2564 int *vec;
2565 va_list args;
2566
2567 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2571
2572 va_start(args, path);
2573 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2574 va_end(args);
2575
2576 /* Check size. */
2577 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2578 i++;
2579 }
2580 *dim = i;
2581
2582 if (0 == i) {
2583 /* Doesn't exist. */
2584 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2585 return NULL;
2586 }
2587
2588 vec = fc_malloc(i * sizeof(int));
2589 for (i = 0; i < *dim; i++) {
2590 if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2591 by_name_fn, "%s,%d",
2592 fullpath, (int) i)) {
2593 SECFILE_LOG(secfile, NULL,
2594 "An error occurred when looking up to \"%s,%d\" entry.",
2595 fullpath, (int) i);
2596 free(vec);
2597 *dim = 0;
2598
2599 return NULL;
2600 }
2601 }
2602
2603 return vec;
2604}
2605
2606/**********************************************************************/
2609bool secfile_lookup_enum_data(const struct section_file *secfile,
2610 int *pvalue, bool bitwise,
2612 secfile_data_t data, const char *path, ...)
2613{
2615 const struct entry *pentry;
2616 const char *str, *p, *name;
2618 int val;
2619 va_list args;
2620
2621 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2622 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != pvalue, FALSE);
2624
2625 va_start(args, path);
2626 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2627 va_end(args);
2628
2629 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2630 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2631 return FALSE;
2632 }
2633
2634 if (!entry_str_get(pentry, &str)) {
2635 return FALSE;
2636 }
2637
2638 if (bitwise) {
2639 *pvalue = 0;
2640 if ('\0' == str[0]) {
2641 /* Empty string = no value. */
2642 return TRUE;
2643 }
2644
2645 /* Value names are separated by '|'. */
2646 do {
2647 p = strchr(str, '|');
2648 if (NULL != p) {
2649 p++;
2650 fc_strlcpy(val_name, str, p - str);
2651 } else {
2652 /* Last segment, full copy. */
2654 }
2656 for (val = 0; (name = name_fn(data, val)); val++) {
2657 if (0 == fc_strcasecmp(name, val_name)) {
2658 break;
2659 }
2660 }
2661 if (NULL == name) {
2663 "Entry \"%s\": no match for \"%s\".",
2665 return FALSE;
2666 }
2667 *pvalue |= 1 << val;
2668 str = p;
2669 } while (NULL != p);
2670 } else {
2671 for (val = 0; (name = name_fn(data, val)); val++) {
2672 if (0 == fc_strcasecmp(name, str)) {
2673 *pvalue = val;
2674 break;
2675 }
2676 }
2677 if (NULL == name) {
2679 "Entry \"%s\": no match for \"%s\".",
2681 return FALSE;
2682 }
2683 }
2684
2685 return TRUE;
2686}
2687
2688/**********************************************************************/
2692 int defval, bool bitwise,
2694 secfile_data_t data,
2695 const char *path, ...)
2696{
2698 const struct entry *pentry;
2699 const char *str, *p, *name;
2701 int value, val;
2702 va_list args;
2703
2704 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2706
2707 va_start(args, path);
2708 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2709 va_end(args);
2710
2711 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2712 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2713 return defval;
2714 }
2715
2716 if (!entry_str_get(pentry, &str)) {
2717 return defval;
2718 }
2719
2720 value = 0;
2721 if (bitwise) {
2722 if ('\0' == str[0]) {
2723 /* Empty string = no value. */
2724 return value;
2725 }
2726
2727 /* Value names are separated by '|'. */
2728 do {
2729 p = strchr(str, '|');
2730 if (NULL != p) {
2731 p++;
2732 fc_strlcpy(val_name, str, p - str);
2733 } else {
2734 /* Last segment, full copy. */
2736 }
2738 for (val = 0; (name = name_fn(data, val)); val++) {
2739 if (0 == strcmp(name, val_name)) {
2740 break;
2741 }
2742 }
2743 if (NULL == name) {
2745 "Entry \"%s\": no match for \"%s\".",
2747 return defval;
2748 }
2749 value |= 1 << val;
2750 str = p;
2751 } while (NULL != p);
2752 } else {
2753 for (val = 0; (name = name_fn(data, val)); val++) {
2754 if (0 == strcmp(name, str)) {
2755 value = val;
2756 break;
2757 }
2758 }
2759 if (NULL == name) {
2761 "Entry \"%s\": no match for \"%s\".",
2763 return defval;
2764 }
2765 }
2766
2767 return value;
2768}
2769
2770/**********************************************************************/
2775 size_t *dim, bool bitwise,
2777 secfile_data_t data, const char *path, ...)
2778{
2780 size_t i = 0;
2781 int *vec;
2782 va_list args;
2783
2784 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2787
2788 va_start(args, path);
2789 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2790 va_end(args);
2791
2792 /* Check size. */
2793 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2794 i++;
2795 }
2796 *dim = i;
2797
2798 if (0 == i) {
2799 /* Doesn't exist. */
2800 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2801 return NULL;
2802 }
2803
2804 vec = fc_malloc(i * sizeof(int));
2805 for (i = 0; i < *dim; i++) {
2806 if (!secfile_lookup_enum_data(secfile, vec + i, bitwise, name_fn, data,
2807 "%s,%d", fullpath, (int) i)) {
2808 SECFILE_LOG(secfile, NULL,
2809 "An error occurred when looking up to \"%s,%d\" entry.",
2810 fullpath, (int) i);
2811 free(vec);
2812 *dim = 0;
2813 return NULL;
2814 }
2815 }
2816
2817 return vec;
2818}
2819
2820/**********************************************************************/
2824 const char *name)
2825{
2827
2829 if (0 == strcmp(section_name(psection), name)) {
2830 return psection;
2831 }
2833
2834 return NULL;
2835}
2836
2837/**********************************************************************/
2841 const char *path, ...)
2842{
2844 va_list args;
2845
2847
2848 va_start(args, path);
2849 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2850 va_end(args);
2851
2853}
2854
2855/**********************************************************************/
2859const struct section_list *
2860secfile_sections(const struct section_file *secfile)
2861{
2862 return (NULL != secfile ? secfile->sections : NULL);
2863}
2864
2865/**********************************************************************/
2870struct section_list *
2872 const char *prefix)
2873{
2874 struct section_list *matches = NULL;
2875 size_t len;
2876
2877 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2878 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, NULL);
2879
2880 len = strlen(prefix);
2881 if (0 == len) {
2882 return NULL;
2883 }
2884
2885 section_list_iterate(secfile->sections, psection) {
2886 if (!fc_strncmp(section_name(psection), prefix, len)) {
2887 if (NULL == matches) {
2889 }
2890 section_list_append(matches, psection);
2891 }
2893
2894 return matches;
2895}
2896
2897/**********************************************************************/
2901 const char *prefix)
2902{
2903 size_t len;
2904
2905 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2906 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, FALSE);
2907
2908 len = strlen(prefix);
2909 if (0 == len) {
2910 return FALSE;
2911 }
2912
2913 section_list_iterate(secfile->sections, psection) {
2914 if (!fc_strncmp(section_name(psection), prefix, len)) {
2915 return TRUE;
2916 }
2918
2919 return FALSE;
2920}
2921
2922/**********************************************************************/
2926 const char *name)
2927{
2928 struct section *psection;
2929
2931
2932 if (NULL == name || '\0' == name[0]) {
2933 SECFILE_LOG(secfile, NULL, "Cannot create a section without name.");
2934 return NULL;
2935 }
2936
2938 SECFILE_LOG(secfile, NULL, "\"%s\" is not a valid section name.",
2939 name);
2940 return NULL;
2941 }
2942
2944 /* We cannot duplicate sections in any case! Not even if one is
2945 * include -section and the other not. */
2946 SECFILE_LOG(secfile, NULL, "Section \"%s\" already exists.", name);
2947 return NULL;
2948 }
2949
2950 psection = fc_malloc(sizeof(struct section));
2951 psection->special = EST_NORMAL;
2952 psection->name = fc_strdup(name);
2954
2955 /* Append to secfile. */
2956 psection->secfile = secfile;
2958
2959 if (NULL != secfile->hash.sections) {
2960 section_hash_insert(secfile->hash.sections, psection->name, psection);
2961 }
2962
2963 return psection;
2964}
2965
2966/**********************************************************************/
2969void section_destroy(struct section *psection)
2970{
2971 struct section_file *secfile;
2972
2973 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2974
2975 section_clear_all(psection);
2976
2977 if ((secfile = psection->secfile)) {
2978 /* Detach from secfile. */
2979 if (section_list_remove(secfile->sections, psection)) {
2980 /* This has called section_destroy() already then. */
2981 return;
2982 }
2983 if (NULL != secfile->hash.sections) {
2984 section_hash_remove(secfile->hash.sections, psection->name);
2985 }
2986 }
2987
2988 entry_list_destroy(psection->entries);
2989 free(psection->name);
2990 free(psection);
2991}
2992
2993/**********************************************************************/
2996void section_clear_all(struct section *psection)
2997{
2998 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2999
3000 /* This include the removing of the hash data. */
3001 entry_list_clear(psection->entries);
3002
3003 if (0 < entry_list_size(psection->entries)) {
3004 SECFILE_LOG(psection->secfile, psection,
3005 "After clearing all, %d entries are still remaining.",
3006 entry_list_size(psection->entries));
3007 }
3008}
3009
3010/**********************************************************************/
3013bool section_set_name(struct section *psection, const char *name)
3014{
3015 struct section_file *secfile;
3016 struct section *pother;
3017
3018 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, FALSE);
3019 secfile = psection->secfile;
3021
3022 if (NULL == name || '\0' == name[0]) {
3023 SECFILE_LOG(secfile, psection, "No new name for section \"%s\".",
3024 psection->name);
3025 return FALSE;
3026 }
3027
3029 SECFILE_LOG(secfile, psection,
3030 "\"%s\" is not a valid section name for section \"%s\".",
3031 name, psection->name);
3032 return FALSE;
3033 }
3034
3036 && pother != psection) {
3037 /* We cannot duplicate sections in any case! */
3038 SECFILE_LOG(secfile, psection, "Section \"%s\" already exists.", name);
3039 return FALSE;
3040 }
3041
3042 /* Remove old references in the hash tables. */
3043 if (NULL != secfile->hash.sections) {
3045 }
3046 if (NULL != secfile->hash.entries) {
3047 entry_list_iterate(psection->entries, pentry) {
3050 }
3051
3052 /* Really rename. */
3053 free(psection->name);
3054 psection->name = fc_strdup(name);
3055
3056 /* Reinsert new references into the hash tables. */
3057 if (NULL != secfile->hash.sections) {
3058 section_hash_insert(secfile->hash.sections, psection->name, psection);
3059 }
3060 if (NULL != secfile->hash.entries) {
3061 entry_list_iterate(psection->entries, pentry) {
3064 }
3065
3066 return TRUE;
3067}
3068
3069/**********************************************************************/
3073const struct entry_list *section_entries(const struct section *psection)
3074{
3075 return (NULL != psection ? psection->entries : NULL);
3076}
3077
3078/**********************************************************************/
3082 const char *name)
3083{
3085
3087 if (0 == strcmp(entry_name(pentry), name)) {
3089 return pentry;
3090 }
3092
3093 return NULL;
3094}
3095
3096/**********************************************************************/
3100 const char *path, ...)
3101{
3103 struct entry *pentry;
3104 va_list args;
3105
3107
3108 va_start(args, path);
3109 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
3110 va_end(args);
3111
3113 return pentry;
3114 }
3115
3116 /* Try with full path. */
3118 && psection == entry_section(pentry)) {
3119 /* Ensured this is really owned by this section. */
3120 return pentry;
3121 }
3122
3123 return NULL;
3124}
3125
3126/**********************************************************************/
3129static struct entry *entry_new(struct section *psection, const char *name)
3130{
3131 struct section_file *secfile;
3132 struct entry *pentry;
3133 bool long_comment = !strcmp("#", name);
3134
3136
3137 secfile = psection->secfile;
3138 if (NULL == name || '\0' == name[0]) {
3139 SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
3140 return NULL;
3141 }
3142
3144 SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
3145 name);
3146 return NULL;
3147 }
3148
3149 if (!secfile->allow_duplicates
3151 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3152 return NULL;
3153 }
3154
3155 pentry = fc_malloc(sizeof(struct entry));
3156 if (long_comment) {
3157 pentry->name = NULL;
3158 } else {
3159 pentry->name = fc_strdup(name);
3160 }
3161 pentry->type = ENTRY_ILLEGAL;
3162 pentry->used = 0;
3163 pentry->comment = NULL;
3164
3165 /* Append to section. */
3166 pentry->psection = psection;
3168
3169 /* Notify secfile. */
3170 secfile->num_entries++;
3171 secfile_hash_insert(secfile, pentry);
3172
3173 return pentry;
3174}
3175
3176/**********************************************************************/
3180 const char *name, int value)
3181{
3182 struct entry *pentry = entry_new(psection, name);
3183
3184 if (NULL != pentry) {
3185 pentry->type = ENTRY_INT;
3186 pentry->integer.value = value;
3187 }
3188
3189 return pentry;
3190}
3191
3192/**********************************************************************/
3196 const char *name, bool value)
3197{
3198 struct entry *pentry = entry_new(psection, name);
3199
3200 if (NULL != pentry) {
3201 pentry->type = ENTRY_BOOL;
3202 pentry->boolean.value = value;
3203 }
3204
3205 return pentry;
3206}
3207
3208/**********************************************************************/
3212 const char *name, float value)
3213{
3214 struct entry *pentry = entry_new(psection, name);
3215
3216 if (NULL != pentry) {
3217 pentry->type = ENTRY_FLOAT;
3218 pentry->floating.value = value;
3219 }
3220
3221 return pentry;
3222}
3223
3224/**********************************************************************/
3228 const char *name, const char *value,
3229 bool escaped)
3230{
3231 struct entry *pentry = entry_new(psection, name);
3232
3233 if (NULL != pentry) {
3234 pentry->type = ENTRY_STR;
3235 pentry->string.value = fc_strdup(NULL != value ? value : "");
3236 pentry->string.escaped = escaped;
3237 pentry->string.raw = FALSE;
3238 pentry->string.gt_marking = FALSE;
3239 }
3240
3241 return pentry;
3242}
3243
3244/**********************************************************************/
3248 const char *name,
3249 const char *value)
3250{
3251 struct entry *pentry = entry_new(psection, name);
3252
3253 if (NULL != pentry) {
3255 pentry->string.value = fc_strdup(NULL != value ? value : "");
3256 }
3257
3258 return pentry;
3259}
3260
3261/**********************************************************************/
3265 const char *comment)
3266{
3267 struct entry *pentry = entry_new(psection, "#");
3268
3269 if (NULL != pentry) {
3270 pentry->type = ENTRY_LONG_COMMENT;
3271 pentry->comment = fc_strdup(NULL != comment ? comment : "");
3272 }
3273
3274 return pentry;
3275}
3276
3277/**********************************************************************/
3281{
3282 struct section_file *secfile;
3283 struct section *psection;
3284
3285 if (NULL == pentry) {
3286 return;
3287 }
3288
3289 if ((psection = pentry->psection)) {
3290 /* Detach from section. */
3291 if (entry_list_remove(psection->entries, pentry)) {
3292 /* This has called entry_destroy() already then. */
3293 return;
3294 }
3295 if ((secfile = psection->secfile)) {
3296 /* Detach from secfile. */
3299 }
3300 }
3301
3302 /* Specific type free. */
3303 switch (pentry->type) {
3304 case ENTRY_BOOL:
3305 case ENTRY_INT:
3306 case ENTRY_FLOAT:
3307 case ENTRY_LONG_COMMENT:
3308 break;
3309
3310 case ENTRY_STR:
3312 free(pentry->string.value);
3313 break;
3314
3315 case ENTRY_ILLEGAL:
3316 fc_assert(pentry->type != ENTRY_ILLEGAL);
3317 break;
3318 }
3319
3320 /* Common free. */
3321 free(pentry->name);
3322 if (NULL != pentry->comment) {
3323 free(pentry->comment);
3324 }
3325 free(pentry);
3326}
3327
3328/**********************************************************************/
3331struct section *entry_section(const struct entry *pentry)
3332{
3333 return (NULL != pentry ? pentry->psection : NULL);
3334}
3335
3336/**********************************************************************/
3340{
3341 return (NULL != pentry ? pentry->type : ENTRY_ILLEGAL);
3342}
3343
3344/**********************************************************************/
3347int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3348{
3349 return fc_snprintf(buf, buf_len, "%s.%s",
3352}
3353
3354/**********************************************************************/
3357const char *entry_name(const struct entry *pentry)
3358{
3359 return (NULL != pentry ? pentry->name : NULL);
3360}
3361
3362/**********************************************************************/
3365bool entry_set_name(struct entry *pentry, const char *name)
3366{
3367 struct section *psection;
3368 struct section_file *secfile;
3369
3371 psection = pentry->psection;
3373 secfile = psection->secfile;
3374 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != secfile, FALSE);
3375
3376 if (NULL == name || '\0' == name[0]) {
3377 SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3378 pentry->name);
3379 return FALSE;
3380 }
3381
3383 SECFILE_LOG(secfile, psection,
3384 "\"%s\" is not a valid entry name for entry \"%s\".",
3385 name, pentry->name);
3386 return FALSE;
3387 }
3388
3389 if (!secfile->allow_duplicates) {
3391
3392 if (NULL != pother && pother != pentry) {
3393 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3394 return FALSE;
3395 }
3396 }
3397
3398 /* Remove from hash table the old path. */
3399 secfile_hash_delete(secfile, pentry);
3400
3401 /* Really rename the entry. */
3402 free(pentry->name);
3403 pentry->name = fc_strdup(name);
3404
3405 /* Insert into hash table the new path. */
3406 secfile_hash_insert(secfile, pentry);
3407 return TRUE;
3408}
3409
3410/**********************************************************************/
3413const char *entry_comment(const struct entry *pentry)
3414{
3415 return (NULL != pentry ? pentry->comment : NULL);
3416}
3417
3418/**********************************************************************/
3421void entry_set_comment(struct entry *pentry, const char *comment)
3422{
3423 if (NULL == pentry) {
3424 return;
3425 }
3426
3427 if (NULL != pentry->comment) {
3428 free(pentry->comment);
3429 }
3430
3431 pentry->comment = (NULL != comment ? fc_strdup(comment) : NULL);
3432}
3433
3434/**********************************************************************/
3437static inline bool entry_used(const struct entry *pentry)
3438{
3439 return (0 < pentry->used);
3440}
3441
3442/**********************************************************************/
3445static inline void entry_use(struct entry *pentry)
3446{
3447 pentry->used++;
3448}
3449
3450/**********************************************************************/
3454bool entry_bool_get(const struct entry *pentry, bool *value)
3455{
3457
3458 if (ENTRY_INT == pentry->type
3459 && (pentry->integer.value == 0
3460 || pentry->integer.value == 1)
3461 && NULL != pentry->psection
3462 && NULL != pentry->psection->secfile
3463 && pentry->psection->secfile->allow_digital_boolean) {
3464 *value = (0 != pentry->integer.value);
3465 return TRUE;
3466 }
3467
3469 ? pentry->psection->secfile : NULL,
3470 pentry->psection,
3471 ENTRY_BOOL == pentry->type, FALSE);
3472
3473 if (NULL != value) {
3474 *value = pentry->boolean.value;
3475 }
3476 return TRUE;
3477}
3478
3479/**********************************************************************/
3483{
3485 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3486 ENTRY_BOOL == pentry->type, FALSE);
3487
3488 pentry->boolean.value = value;
3489 return TRUE;
3490}
3491
3492/**********************************************************************/
3495bool entry_float_get(const struct entry *pentry, float *value)
3496{
3498 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3499 ENTRY_FLOAT == pentry->type, FALSE);
3500
3501 if (NULL != value) {
3502 *value = pentry->floating.value;
3503 }
3504
3505 return TRUE;
3506}
3507
3508/**********************************************************************/
3511bool entry_float_set(struct entry *pentry, float value)
3512{
3514 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3515 ENTRY_FLOAT == pentry->type, FALSE);
3516
3517 pentry->floating.value = value;
3518
3519 return TRUE;
3520}
3521
3522/**********************************************************************/
3525bool entry_int_get(const struct entry *pentry, int *value)
3526{
3528 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3529 ENTRY_INT == pentry->type, FALSE);
3530
3531 if (NULL != value) {
3532 *value = pentry->integer.value;
3533 }
3534 return TRUE;
3535}
3536
3537/**********************************************************************/
3541{
3543 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3544 ENTRY_INT == pentry->type, FALSE);
3545
3546 pentry->integer.value = value;
3547 return TRUE;
3548}
3549
3550/**********************************************************************/
3553bool entry_str_get(const struct entry *pentry, const char **value)
3554{
3556 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3557 ENTRY_STR == pentry->type, FALSE);
3558
3559 if (NULL != value) {
3560 *value = pentry->string.value;
3561 }
3562 return TRUE;
3563}
3564
3565/**********************************************************************/
3568bool entry_str_set(struct entry *pentry, const char *value)
3569{
3570 char *old_val;
3571
3573 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3574 ENTRY_STR == pentry->type, FALSE);
3575
3576 /* We free() old value only after we've placed the new one, to
3577 * support secfile_replace_str_vec() calls that want to keep some of
3578 * the entries from the old vector in the new one. We don't want
3579 * to lose the entry in between. */
3580 old_val = pentry->string.value;
3581 pentry->string.value = fc_strdup(NULL != value ? value : "");
3582 free(old_val);
3583 return TRUE;
3584}
3585
3586/**********************************************************************/
3589bool entry_str_escaped(const struct entry *pentry)
3590{
3592 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3593 ENTRY_STR == pentry->type, FALSE);
3594
3595 return pentry->string.escaped;
3596}
3597
3598/**********************************************************************/
3602{
3604 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3605 ENTRY_STR == pentry->type, FALSE);
3606
3607 pentry->string.escaped = escaped;
3608 return TRUE;
3609}
3610
3611/**********************************************************************/
3615{
3617 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3618 ENTRY_STR == pentry->type, FALSE);
3619
3620 pentry->string.gt_marking = gt_marking;
3621
3622 return TRUE;
3623}
3624
3625/**********************************************************************/
3628static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
3629{
3630 static char buf[8192];
3631 char *dot = NULL;
3632 int i;
3633
3634 switch (pentry->type) {
3635 case ENTRY_BOOL:
3636 fz_fprintf(fs, "%s", pentry->boolean.value ? "TRUE" : "FALSE");
3637 break;
3638 case ENTRY_INT:
3639 fz_fprintf(fs, "%d", pentry->integer.value);
3640 break;
3641 case ENTRY_FLOAT:
3642 snprintf(buf, sizeof(buf), "%f", pentry->floating.value);
3643 for (i = 0; buf[i] != '\0' ; i++) {
3644 if (buf[i] == '.') {
3645 dot = &(buf[i]);
3646 break;
3647 }
3648 }
3649 if (dot == NULL) {
3650 /* There's no '.' so it would seem like a integer value when loaded.
3651 * Force it not to look like an integer by adding ".0" */
3652 fz_fprintf(fs, "%s.0", buf);
3653 } else {
3654 fz_fprintf(fs, "%s", buf);
3655 }
3656 break;
3657 case ENTRY_STR:
3658 if (pentry->string.escaped) {
3659 make_escapes(pentry->string.value, buf, sizeof(buf));
3660 if (pentry->string.gt_marking) {
3661 fz_fprintf(fs, "_(\"%s\")", buf);
3662 } else {
3663 fz_fprintf(fs, "\"%s\"", buf);
3664 }
3665 } else if (pentry->string.raw) {
3666 fz_fprintf(fs, "%s", pentry->string.value);
3667 } else {
3668 fz_fprintf(fs, "$%s$", pentry->string.value);
3669 }
3670 break;
3672 fz_fprintf(fs, "*%s*", pentry->string.value);
3673 break;
3674 case ENTRY_LONG_COMMENT:
3675 fz_fprintf(fs, "%s\n", pentry->comment);
3676 break;
3677 case ENTRY_ILLEGAL:
3678 fc_assert(pentry->type != ENTRY_ILLEGAL);
3679 break;
3680 }
3681}
3682
3683/**********************************************************************/
3686static void entry_from_inf_token(struct section *psection, const char *name,
3687 const char *tok, struct inputfile *inf)
3688{
3690 log_error("%s", inf_log_str(inf, "Entry value not recognized: %s", tok));
3691 }
3692}
void astr_free(struct astring *astr)
Definition astring.c:153
void astr_set(struct astring *astr, const char *format,...)
Definition astring.c:267
void astr_init(struct astring *astr)
Definition astring.c:144
#define str
Definition astring.c:76
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
void bugreport_request(const char *reason_format,...)
Definition bugs.c:31
char * incite_cost
Definition comments.c:75
bool are_deprecation_warnings_enabled(void)
#define log_deprecation_always(message,...)
static void base(QVariant data1, QVariant data2)
Definition dialogs.cpp:2940
#define _(String)
Definition fcintl.h:67
char * inf_log_str(struct inputfile *inf, const char *message,...)
Definition inputfile.c:567
bool inf_at_eof(struct inputfile *inf)
Definition inputfile.c:346
struct inputfile * inf_from_file(const char *filename, datafilename_fn_t datafn)
Definition inputfile.c:219
struct inputfile * inf_from_stream(fz_FILE *stream, datafilename_fn_t datafn)
Definition inputfile.c:241
const char * name
Definition inputfile.c:127
void inf_close(struct inputfile *inf)
Definition inputfile.c:300
int inf_discard_tokens(struct inputfile *inf, enum inf_token_type type)
Definition inputfile.c:645
const char * inf_token(struct inputfile *inf, enum inf_token_type type)
Definition inputfile.c:607
@ INF_TOK_EOL
Definition inputfile.h:45
@ INF_TOK_COMMA
Definition inputfile.h:48
@ INF_TOK_TABLE_END
Definition inputfile.h:47
@ INF_TOK_VALUE
Definition inputfile.h:49
@ INF_TOK_TABLE_START
Definition inputfile.h:46
@ INF_TOK_ENTRY_NAME
Definition inputfile.h:44
@ INF_TOK_SECTION_NAME
Definition inputfile.h:43
int fz_fprintf(fz_FILE *fp, const char *format,...)
Definition ioz.c:971
fz_FILE * fz_from_file(const char *filename, const char *in_mode, enum fz_method method, int compress_level)
Definition ioz.c:230
const char * fz_strerror(fz_FILE *fp)
Definition ioz.c:1157
int fz_fclose(fz_FILE *fp)
Definition ioz.c:571
int fz_ferror(fz_FILE *fp)
Definition ioz.c:1099
fz_method
Definition ioz.h:36
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define log_error(message,...)
Definition log.h:103
#define log_testmatic(message,...)
Definition log.h:123
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
int len
Definition packhand.c:127
struct section_file * secfile_new(bool allow_duplicates)
const char * section_name(const struct section *psection)
void secfile_destroy(struct section_file *secfile)
static struct entry * entry_new(struct section *psection, const char *name)
int secfile_lookup_bitwise_enum_default_full(const struct section_file *secfile, int defval, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
void entry_set_comment(struct entry *pentry, const char *comment)
size_t secfile_insert_bool_vec_full(struct section_file *secfile, const bool *values, size_t dim, const char *comment, bool allow_replace, const char *path,...)
bool entry_bool_get(const struct entry *pentry, bool *value)
void section_destroy(struct section *psection)
bool secfile_lookup_float(const struct section_file *secfile, float *fval, const char *path,...)
void secfile_check_unused(const struct section_file *secfile)
int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
struct section * secfile_insert_long_comment(struct section_file *secfile, const char *comment)
static struct entry * section_entry_filereference_new(struct section *psection, const char *name, const char *value)
#define MAX_LEN_SECPATH
bool secfile_entry_delete(struct section_file *secfile, const char *path,...)
bool entry_set_name(struct entry *pentry, const char *name)
bool secfile_lookup_enum_data(const struct section_file *secfile, int *pvalue, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *path,...)
static bool secfile_hash_insert(struct section_file *secfile, struct entry *pentry)
bool entry_str_escaped(const struct entry *pentry)
struct entry * section_entry_int_new(struct section *psection, const char *name, int value)
struct entry * secfile_insert_bool_full(struct section_file *secfile, bool value, const char *comment, bool allow_replace, const char *path,...)
struct entry * secfile_insert_comment(struct section_file *secfile, const char *str, const char *path,...)
struct entry * secfile_insert_int_full(struct section_file *secfile, int value, const char *comment, bool allow_replace, const char *path,...)
struct section * entry_section(const struct entry *pentry)
static struct entry * section_entry_comment_new(struct section *psection, const char *comment)
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
int secfile_lookup_enum_default_data(const struct section_file *secfile, int defval, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *path,...)
const struct entry_list * section_entries(const struct section *psection)
struct section_file * secfile_load_section(const char *filename, const char *section, bool allow_duplicates)
bool entry_bool_set(struct entry *pentry, bool value)
struct section_file * secfile_from_stream(fz_FILE *stream, bool allow_duplicates)
size_t secfile_insert_bitwise_enum_vec_full(struct section_file *secfile, const int *bitwise_vals, size_t dim, secfile_enum_name_fn_t name_fn, secfile_enum_iter_fn_t begin_fn, secfile_enum_iter_fn_t end_fn, secfile_enum_next_fn_t next_fn, const char *comment, bool allow_replace, const char *path,...)
static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
static void entry_from_inf_token(struct section *psection, const char *name, const char *tok, struct inputfile *file)
bool entry_float_get(const struct entry *pentry, float *value)
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
bool entry_str_set_escaped(struct entry *pentry, bool escaped)
const char * entry_name(const struct entry *pentry)
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
bool entry_str_get(const struct entry *pentry, const char **value)
struct entry * secfile_insert_enum_data_full(struct section_file *secfile, int value, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *comment, bool allow_replace, const char *path,...)
bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
#define SAVE_TABLES
size_t secfile_insert_int_vec_full(struct section_file *secfile, const int *values, size_t dim, const char *comment, bool allow_replace, const char *path,...)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
void entry_destroy(struct entry *pentry)
static bool entry_used(const struct entry *pentry)
void section_clear_all(struct section *psection)
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
bool entry_float_set(struct entry *pentry, float value)
float secfile_lookup_float_default(const struct section_file *secfile, float def, const char *path,...)
bool * secfile_lookup_bool_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
int secfile_lookup_plain_enum_default_full(const struct section_file *secfile, int defval, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
size_t secfile_insert_str_vec_full(struct section_file *secfile, const char *const *strings, size_t dim, const char *comment, bool allow_replace, bool no_escape, const char *path,...)
size_t secfile_insert_plain_enum_vec_full(struct section_file *secfile, const int *enumurators, size_t dim, secfile_enum_name_fn_t name_fn, const char *comment, bool allow_replace, const char *path,...)
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
struct entry * secfile_insert_float_full(struct section_file *secfile, float value, const char *comment, bool allow_replace, const char *path,...)
struct section * secfile_insert_include(struct section_file *secfile, const char *filename)
struct entry * secfile_insert_plain_enum_full(struct section_file *secfile, int enumerator, secfile_enum_name_fn_t name_fn, const char *comment, bool allow_replace, const char *path,...)
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
bool entry_int_set(struct entry *pentry, int value)
static bool is_secfile_entry_name_valid(const char *name)
struct entry * section_entry_by_name(const struct section *psection, const char *name)
const struct section_list * secfile_sections(const struct section_file *secfile)
struct entry * secfile_insert_filereference(struct section_file *secfile, const char *filename, const char *path,...)
bool section_set_name(struct section *psection, const char *name)
struct entry * section_entry_str_new(struct section *psection, const char *name, const char *value, bool escaped)
struct entry * section_entry_float_new(struct section *psection, const char *name, float value)
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
struct entry * section_entry_lookup(const struct section *psection, const char *path,...)
bool entry_int_get(const struct entry *pentry, int *value)
int * secfile_lookup_bitwise_enum_vec_full(const struct section_file *secfile, size_t *dim, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
static void entry_use(struct entry *pentry)
int * secfile_lookup_enum_vec_data(const struct section_file *secfile, size_t *dim, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *path,...)
struct entry * section_entry_bool_new(struct section *psection, const char *name, bool value)
bool secfile_lookup_plain_enum_full(const struct section_file *secfile, int *penumerator, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
const char * secfile_name(const struct section_file *secfile)
struct section * secfile_section_new(struct section_file *secfile, const char *name)
const char * entry_comment(const struct entry *pentry)
static bool secfile_hash_delete(struct section_file *secfile, struct entry *pentry)
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
static struct section_file * secfile_from_input_file(struct inputfile *inf, const char *filename, const char *section, bool allow_duplicates)
struct section * secfile_section_by_name(const struct section_file *secfile, const char *name)
struct entry * secfile_insert_bitwise_enum_full(struct section_file *secfile, int bitwise_val, secfile_enum_name_fn_t name_fn, secfile_enum_iter_fn_t begin_fn, secfile_enum_iter_fn_t end_fn, secfile_enum_next_fn_t next_fn, const char *comment, bool allow_replace, const char *path,...)
struct entry * secfile_insert_str_full(struct section_file *secfile, const char *str, const char *comment, bool allow_replace, bool no_escape, enum entry_special_type stype, const char *path,...)
int * secfile_lookup_plain_enum_vec_full(const struct section_file *secfile, size_t *dim, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
bool secfile_section_prefix_present(const struct section_file *secfile, const char *prefix)
static bool is_legal_table_entry_name(char c, bool num)
bool entry_str_set(struct entry *pentry, const char *value)
bool secfile_lookup_bitwise_enum_full(const struct section_file *secfile, int *penumerator, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
size_t secfile_insert_enum_vec_data_full(struct section_file *secfile, const int *values, size_t dim, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *comment, bool allow_replace, const char *path,...)
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
static const char * datafilename(const char *filename)
int secfile_lookup_int_def_min_max(const struct section_file *secfile, int defval, int minval, int maxval, const char *path,...)
static struct section * secfile_insert_base(struct section_file *secfile, const char *path, const char **pent_name)
enum entry_type entry_type_get(const struct entry *pentry)
int(* secfile_enum_iter_fn_t)(void)
const char *(* secfile_enum_name_data_fn_t)(secfile_data_t data, int enumerator)
entry_type
@ ENTRY_FILEREFERENCE
@ ENTRY_LONG_COMMENT
@ ENTRY_INT
@ ENTRY_FLOAT
@ ENTRY_STR
@ ENTRY_ILLEGAL
@ ENTRY_BOOL
#define section_list_iterate(seclist, psection)
#define entry_list_iterate_end
bool(* secfile_enum_is_valid_fn_t)(int enumerator)
entry_special_type
@ EST_COMMENT
@ EST_NORMAL
@ EST_INCLUDE
const char *(* secfile_enum_name_fn_t)(int enumerator)
#define section_list_iterate_end
#define entry_list_iterate(entlist, pentry)
int(* secfile_enum_by_name_fn_t)(const char *enum_name, int(*strcmp_fn)(const char *, const char *))
int(* secfile_enum_next_fn_t)(int enumerator)
const void * secfile_data_t
bool entry_from_token(struct section *psection, const char *name, const char *tok)
#define SECFILE_LOG(secfile, psection, format,...)
#define SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, condition, value)
#define SECFILE_RETURN_IF_FAIL(secfile, psection, condition)
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1101
void interpret_tilde(char *buf, size_t buf_size, const char *filename)
Definition shared.c:1720
void remove_leading_trailing_spaces(char *s)
Definition shared.c:444
const struct strvec * get_data_dirs(void)
Definition shared.c:893
enum entry_type type
int value
bool gt_marking
char * value
bool raw
struct section * psection
float value
bool escaped
bool value
char * comment
char * name
struct entry_hash * entries
struct section_file::@8 hash
struct section_list * sections
bool allow_duplicates
unsigned int num_includes
unsigned int num_long_comments
size_t num_entries
struct entry_list * entries
char * name
enum entry_special_type special
struct section_file * secfile
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
bool fc_isalpha(char c)
Definition support.c:1221
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
void make_escapes(const char *str, char *buf, size_t buf_len)
Definition support.c:297
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:1000
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:900
bool fc_isalnum(char c)
Definition support.c:1210
#define sz_strlcpy(dest, src)
Definition support.h:195
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sz_strlcat(dest, src)
Definition support.h:196
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:160