Freeciv-3.3: /fast/freeciv/nightly/main/utility/registry_ini.c Source File

Freeciv-3.3

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 embeded 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 missplace 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 */
193 struct entry {
194 struct section *psection; /* Parent section. */
195 char *name; /* Name, not including section prefix. */
196 enum entry_type type; /* The type of the entry. */
197 int used; /* Number of times entry looked up. */
198 char *comment; /* Comment, may be nullptr. */
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
223static struct entry *section_entry_filereference_new(struct section *psection,
224 const char *name,
225 const char *value);
226static struct entry *section_entry_comment_new(struct section *psection,
227 const char *comment);
228
229/**********************************************************************/
232 static const char *datafilename(const char *filename)
233{
234 return fileinfoname(get_data_dirs(), filename);
235}
236
237/**********************************************************************/
240 static 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) && strchr(allowed, *name) == nullptr) {
246 return FALSE;
247 }
248 name++;
249 }
250 return TRUE;
251}
252
253/**********************************************************************/
256 static bool secfile_hash_insert(struct section_file *secfile,
257 struct entry *pentry)
258{
259 char buf[256];
260 struct entry *hentry;
261
262 if (secfile->hash.entries == nullptr) {
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));
269 if (entry_hash_replace_full(secfile->hash.entries, buf, pentry,
270 nullptr, &hentry)) {
271 entry_use(hentry);
272 if (!secfile->allow_duplicates) {
273 SECFILE_LOG(secfile, entry_section(hentry),
274 "Tried to insert same value twice: %s", buf);
275 return FALSE;
276 }
277 }
278
279 return TRUE;
280}
281
282/**********************************************************************/
285 static bool secfile_hash_delete(struct section_file *secfile,
286 struct entry *pentry)
287{
288 char buf[256];
289
290 if (secfile->hash.entries == nullptr) {
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/**********************************************************************/
303 static struct section_file *secfile_from_input_file(struct inputfile *inf,
304 const char *filename,
305 const char *section,
306 bool allow_duplicates)
307{
308 struct section_file *secfile;
309 struct section *psection = nullptr;
310 struct section *single_section = nullptr;
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 */
316 struct astring field_name = ASTRING_INIT;
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 nullptr;
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 = nullptr;
331 }
332
333 astring_vector_init(&columns);
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 }
349 tok = inf_token(inf, INF_TOK_SECTION_NAME);
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;
379 found_my_section = TRUE;
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 }
391 if (inf_token(inf, INF_TOK_TABLE_END)) {
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 }
404 table_state = FALSE;
405 continue;
406 }
407 if (table_state) {
408 i = -1;
409 do {
410 int num_columns = astring_vector_size(&columns);
411
412 i++;
413
414 if (i < num_columns) {
415 astr_set(&field_name, "%s%d.%s", astr_str(&base_name),
416 table_lineno, astr_str(&columns.p[i]));
417 } else {
418 astr_set(&field_name, "%s%d.%s,%d", astr_str(&base_name),
419 table_lineno, astr_str(&columns.p[num_columns - 1]),
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",
427 astr_str(&field_name)));
428 error = TRUE;
429 goto END;
430 }
431
432 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
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
457 if (inf_token(inf, INF_TOK_TABLE_START)) {
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
478 n_prev = astring_vector_size(&columns);
479 for (j = i + 1; j < n_prev; j++) {
480 astr_free(&columns.p[j]);
481 }
482 astring_vector_reserve(&columns, i + 1);
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 }
497 table_state = TRUE;
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",
510 astr_str(&base_name)));
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) {
520 entry_from_inf_token(psection, astr_str(&base_name), tok, inf);
521 } else {
522 astr_set(&field_name, "%s,%d", astr_str(&base_name), i);
523 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
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
540 END:
541 inf_close(inf);
542 astr_free(&base_name);
543 astr_free(&field_name);
544 for (i = 0; i < astring_vector_size(&columns); i++) {
545 astr_free(&columns.p[i]);
546 }
547 astring_vector_free(&columns);
548
549 if (section != nullptr) {
550 if (!found_my_section) {
551 secfile_destroy(secfile);
552 return nullptr;
553 }
554
555 /* Build the entry hash table with single section information */
556 secfile->allow_duplicates = allow_duplicates;
557 entry_list_iterate(section_entries(single_section), pentry) {
558 if (!secfile_hash_insert(secfile, pentry)) {
559 secfile_destroy(secfile);
560 return nullptr;
561 }
562 } entry_list_iterate_end;
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
572 section_list_iterate(secfile->sections, hashing_section) {
573 entry_list_iterate(section_entries(hashing_section), pentry) {
574 if (!secfile_hash_insert(secfile, pentry)) {
575 error = TRUE;
576 break;
577 }
578 } entry_list_iterate_end;
579 if (error) {
580 break;
581 }
582 } section_list_iterate_end;
583 }
584 if (error) {
585 secfile_destroy(secfile);
586 return nullptr;
587 } else {
588 return secfile;
589 }
590}
591
592/**********************************************************************/
596 struct 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);
603 return secfile_from_input_file(inf_from_file(real_filename, datafilename),
604 filename, section, allow_duplicates);
605}
606
607/**********************************************************************/
610 struct section_file *secfile_from_stream(fz_FILE *stream,
611 bool allow_duplicates)
612{
613 return secfile_from_input_file(inf_from_stream(stream, datafilename),
614 nullptr, nullptr, allow_duplicates);
615}
616
617/**********************************************************************/
620 static bool is_legal_table_entry_name(char c, bool num)
621{
622 return (num ? fc_isalnum(c) : fc_isalpha(c)) || c == '_';
623}
624
625/**********************************************************************/
644 bool secfile_save(const struct section_file *secfile, const char *filename,
645 int compression_level, enum fz_method compression_method)
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, nullptr, secfile != nullptr, FALSE);
656
657 if (filename == nullptr) {
658 filename = secfile->name;
659 }
660
661 interpret_tilde(real_filename, sizeof(real_filename), filename);
662 fs = fz_from_file(real_filename, "w",
663 compression_method, compression_level);
664
665 if (!fs) {
666 SECFILE_LOG(secfile, nullptr, _("Could not open %s for writing"), real_filename);
667
668 return FALSE;
669 }
670
671 section_list_iterate(secfile->sections, psection) {
672 if (psection->special == EST_INCLUDE) {
673 for (ent_iter = entry_list_head(section_entries(psection));
674 ent_iter && (pentry = entry_list_link_data(ent_iter));
675 ent_iter = entry_list_link_next(ent_iter)) {
676
677 fc_assert(!strcmp(entry_name(pentry), "file"));
678
679 fz_fprintf(fs, "*include ");
680 entry_to_file(pentry, fs);
681 fz_fprintf(fs, "\n");
682 }
683 } else if (psection->special == EST_COMMENT) {
684 for (ent_iter = entry_list_head(section_entries(psection));
685 ent_iter && (pentry = entry_list_link_data(ent_iter));
686 ent_iter = entry_list_link_next(ent_iter)) {
687
688 fc_assert(!strcmp(entry_name(pentry), "comment"));
689
690 entry_to_file(pentry, fs);
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 */
699 for (ent_iter = entry_list_head(section_entries(psection));
700 ent_iter && (pentry = entry_list_link_data(ent_iter));
701 ent_iter = entry_list_link_next(ent_iter)) {
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 nullptr).
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
729 sz_strlcpy(pentry_name, entry_name(pentry));
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 */
754 save_iter = ent_iter;
755
756 /* Write the column names, and calculate ncol: */
757 ncol = 0;
758 col_iter = save_iter;
759 for (; (col_pentry = entry_list_link_data(col_iter));
760 col_iter = entry_list_link_next(col_iter)) {
761 if (col_pentry->type == ENTRY_LONG_COMMENT) {
762 continue;
763 }
764 col_entry_name = entry_name(col_pentry);
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;
779 col_iter = save_iter;
780 for (;;) {
781 char expect[128]; /* pentry->name we're expecting */
782
783 pentry = entry_list_link_data(ent_iter);
784 col_pentry = entry_list_link_data(col_iter);
785
786 if (pentry && pentry->type == ENTRY_LONG_COMMENT) {
787 if (icol == 0) {
788 entry_to_file(pentry, fs);
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.",
792 real_filename, section_name(psection));
793 }
794 ent_iter = entry_list_link_next(ent_iter);
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.",
818 real_filename, section_name(psection), expect);
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 }
829 entry_to_file(pentry, fs);
830
831 ent_iter = entry_list_link_next(ent_iter);
832 col_iter = entry_list_link_next(col_iter);
833
834 icol++;
835 if (icol == ncol) {
836 fz_fprintf(fs, "\n");
837 irow++;
838 icol = 0;
839 col_iter = save_iter;
840 }
841 }
842 if (!pentry) {
843 break;
844 }
845 }
846 if (!pentry) {
847 break;
848 }
849
850 if (pentry->type == ENTRY_LONG_COMMENT) {
851 entry_to_file(pentry, fs);
852 } else {
853 /* Classic entry. */
854 col_entry_name = entry_name(pentry);
855 fz_fprintf(fs, "%s=", col_entry_name);
856 entry_to_file(pentry, fs);
857
858 /* Check for vector. */
859 for (i = 1;; i++) {
860 col_iter = entry_list_link_next(ent_iter);
861 col_pentry = entry_list_link_data(col_iter);
862 if (col_pentry == nullptr || col_pentry->type == ENTRY_LONG_COMMENT) {
863 break;
864 }
865 fc_snprintf(pentry_name, sizeof(pentry_name),
866 "%s,%d", col_entry_name, i);
867 if (0 != strcmp(pentry_name, entry_name(col_pentry))) {
868 break;
869 }
870 fz_fprintf(fs, ",");
871 entry_to_file(col_pentry, fs);
872 ent_iter = col_iter;
873 }
874
875 comment = entry_comment(pentry);
876 if (comment) {
877 fz_fprintf(fs, " # %s\n", comment);
878 } else {
879 fz_fprintf(fs, "\n");
880 }
881 }
882 }
883 }
884 } section_list_iterate_end;
885
886 if (0 != fz_ferror(fs)) {
887 SECFILE_LOG(secfile, nullptr, "Error before closing %s: %s",
888 real_filename, fz_strerror(fs));
889 fz_fclose(fs);
890 return FALSE;
891 }
892 if (0 != fz_fclose(fs)) {
893 SECFILE_LOG(secfile, nullptr, "Error closing %s", real_filename);
894 return FALSE;
895 }
896
897 return TRUE;
898}
899
900/**********************************************************************/
907 void secfile_check_unused(const struct section_file *secfile)
908{
909 bool any = FALSE;
910
911 section_list_iterate(secfile_sections(secfile), psection) {
912 entry_list_iterate(section_entries(psection), pentry) {
913 if (!entry_used(pentry)) {
914 if (!any && secfile->name) {
915 log_verbose("Unused entries in file %s:", secfile->name);
916 any = TRUE;
917 }
918 if (are_deprecation_warnings_enabled()) {
919 log_deprecation_always("%s: unused entry: %s.%s",
920 secfile->name != nullptr ? secfile->name : "nameless",
921 section_name(psection), entry_name(pentry));
922 } else {
923#ifdef FREECIV_TESTMATIC
924 log_testmatic("%s: unused entry: %s.%s",
925 secfile->name != nullptr ? secfile->name : "nameless",
926 section_name(psection), entry_name(pentry));
927#else /* FREECIV_TESTMATIC */
928 log_verbose(" unused entry: %s.%s",
929 section_name(psection), entry_name(pentry));
930#endif /* FREECIV_TESTMATIC */
931 }
932 }
933 } entry_list_iterate_end;
934 } section_list_iterate_end;
935}
936
937/**********************************************************************/
943 const char *secfile_name(const struct section_file *secfile)
944{
945 if (secfile == nullptr) {
946 return "nullptr";
947 } else if (secfile->name) {
948 return secfile->name;
949 } else {
950 return "(anonymous)";
951 }
952}
953
954/**********************************************************************/
957 static struct section *secfile_insert_base(struct section_file *secfile,
958 const char *path,
959 const char **pent_name)
960{
961 char fullpath[MAX_LEN_SECPATH];
962 char *ent_name;
963 struct section *psection;
964
965 sz_strlcpy(fullpath, path);
966
967 ent_name = strchr(fullpath, '.');
968 if (!ent_name) {
969 SECFILE_LOG(secfile, nullptr,
970 "Section and entry names must be separated by a dot.");
971 return nullptr;
972 }
973
974 /* Separates section and entry names. */
975 *ent_name = '\0';
976 *pent_name = path + (ent_name - fullpath) + 1;
977 psection = secfile_section_by_name(secfile, fullpath);
978 if (psection) {
979 return psection;
980 } else {
981 return secfile_section_new(secfile, fullpath);
982 }
983}
984
985/**********************************************************************/
988 struct entry *secfile_insert_bool_full(struct section_file *secfile,
989 bool value, const char *comment,
990 bool allow_replace,
991 const char *path, ...)
992{
993 char fullpath[MAX_LEN_SECPATH];
994 const char *ent_name;
995 struct section *psection;
996 struct entry *pentry = nullptr;
997 va_list args;
998
999 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1000
1001 va_start(args, path);
1002 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1003 va_end(args);
1004
1005 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1006 if (!psection) {
1007 return nullptr;
1008 }
1009
1010 if (allow_replace) {
1011 pentry = section_entry_by_name(psection, ent_name);
1012 if (pentry != nullptr) {
1013 if (ENTRY_BOOL == entry_type_get(pentry)) {
1014 if (!entry_bool_set(pentry, value)) {
1015 return nullptr;
1016 }
1017 } else {
1018 entry_destroy(pentry);
1019 pentry = nullptr;
1020 }
1021 }
1022 }
1023
1024 if (pentry == nullptr) {
1025 pentry = section_entry_bool_new(psection, ent_name, value);
1026 }
1027
1028 if (pentry != nullptr && comment != nullptr) {
1029 entry_set_comment(pentry, comment);
1030 }
1031
1032 return pentry;
1033}
1034
1035/**********************************************************************/
1039 size_t secfile_insert_bool_vec_full(struct section_file *secfile,
1040 const bool *values, size_t dim,
1041 const char *comment, bool allow_replace,
1042 const char *path, ...)
1043{
1044 char fullpath[MAX_LEN_SECPATH];
1045 size_t i, ret = 0;
1046 va_list args;
1047
1048 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, 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 && secfile_insert_bool_full(secfile, values[0], comment,
1058 allow_replace, "%s", fullpath) != nullptr) {
1059 ret++;
1060 }
1061 for (i = 1; i < dim; i++) {
1062 if (secfile_insert_bool_full(secfile, values[i], comment,
1063 allow_replace, "%s,%d",
1064 fullpath, (int) i) != nullptr) {
1065 ret++;
1066 }
1067 }
1068
1069 return ret;
1070}
1071
1072/**********************************************************************/
1075 struct entry *secfile_insert_int_full(struct section_file *secfile,
1076 int value, const char *comment,
1077 bool allow_replace,
1078 const char *path, ...)
1079{
1080 char fullpath[MAX_LEN_SECPATH];
1081 const char *ent_name;
1082 struct section *psection;
1083 struct entry *pentry = nullptr;
1084 va_list args;
1085
1086 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1087
1088 va_start(args, path);
1089 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1090 va_end(args);
1091
1092 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1093 if (!psection) {
1094 return nullptr;
1095 }
1096
1097 if (allow_replace) {
1098 pentry = section_entry_by_name(psection, ent_name);
1099 if (pentry != nullptr) {
1100 if (ENTRY_INT == entry_type_get(pentry)) {
1101 if (!entry_int_set(pentry, value)) {
1102 return nullptr;
1103 }
1104 } else {
1105 entry_destroy(pentry);
1106 pentry = nullptr;
1107 }
1108 }
1109 }
1110
1111 if (pentry == nullptr) {
1112 pentry = section_entry_int_new(psection, ent_name, value);
1113 }
1114
1115 if (pentry != nullptr && comment != nullptr) {
1116 entry_set_comment(pentry, comment);
1117 }
1118
1119 return pentry;
1120}
1121
1122/**********************************************************************/
1126 size_t secfile_insert_int_vec_full(struct section_file *secfile,
1127 const int *values, size_t dim,
1128 const char *comment, bool allow_replace,
1129 const char *path, ...)
1130{
1131 char fullpath[MAX_LEN_SECPATH];
1132 size_t i, ret = 0;
1133 va_list args;
1134
1135 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, 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 && secfile_insert_int_full(secfile, values[0], comment,
1145 allow_replace, "%s", fullpath) != nullptr) {
1146 ret++;
1147 }
1148 for (i = 1; i < dim; i++) {
1149 if (secfile_insert_int_full(secfile, values[i], comment,
1150 allow_replace, "%s,%d",
1151 fullpath, (int) i) != nullptr) {
1152 ret++;
1153 }
1154 }
1155
1156 return ret;
1157}
1158
1159/**********************************************************************/
1162 struct entry *secfile_insert_float_full(struct section_file *secfile,
1163 float value, const char *comment,
1164 bool allow_replace,
1165 const char *path, ...)
1166{
1167 char fullpath[MAX_LEN_SECPATH];
1168 const char *ent_name;
1169 struct section *psection;
1170 struct entry *pentry = nullptr;
1171 va_list args;
1172
1173 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1174
1175 va_start(args, path);
1176 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1177 va_end(args);
1178
1179 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1180 if (!psection) {
1181 return nullptr;
1182 }
1183
1184 if (allow_replace) {
1185 pentry = section_entry_by_name(psection, ent_name);
1186 if (pentry != nullptr) {
1187 if (ENTRY_FLOAT == entry_type_get(pentry)) {
1188 if (!entry_float_set(pentry, value)) {
1189 return nullptr;
1190 }
1191 } else {
1192 entry_destroy(pentry);
1193 pentry = nullptr;
1194 }
1195 }
1196 }
1197
1198 if (pentry == nullptr) {
1199 pentry = section_entry_float_new(psection, ent_name, value);
1200 }
1201
1202 if (pentry != nullptr && comment != nullptr) {
1203 entry_set_comment(pentry, comment);
1204 }
1205
1206 return pentry;
1207}
1208
1209/**********************************************************************/
1212 struct section *secfile_insert_include(struct section_file *secfile,
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
1220 fc_assert_ret_val(secfile_section_by_name(secfile, buffer) == nullptr, nullptr);
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. */
1227 secfile_insert_str_full(secfile, filename, nullptr, FALSE, FALSE,
1228 EST_INCLUDE, "%s.file", buffer);
1229
1230 return psection;
1231}
1232
1233/**********************************************************************/
1236 struct section *secfile_insert_long_comment(struct section_file *secfile,
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
1244 fc_assert_ret_val(secfile_section_by_name(secfile, buffer) == nullptr, nullptr);
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. */
1251 secfile_insert_str_full(secfile, comment, nullptr, FALSE, TRUE,
1252 EST_COMMENT, "%s.comment", buffer);
1253
1254 return psection;
1255}
1256
1257/**********************************************************************/
1260 struct entry *secfile_insert_str_full(struct section_file *secfile,
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{
1268 char fullpath[MAX_LEN_SECPATH];
1269 const char *ent_name;
1270 struct section *psection;
1271 struct entry *pentry = nullptr;
1272 va_list args;
1273
1274 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1275
1276 va_start(args, path);
1277 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1278 va_end(args);
1279
1280 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1281 if (!psection) {
1282 return nullptr;
1283 }
1284
1285 if (psection->special != stype) {
1286 log_error("Tried to insert wrong type of entry to section");
1287 return nullptr;
1288 }
1289
1290 if (allow_replace) {
1291 pentry = section_entry_by_name(psection, ent_name);
1292 if (pentry != nullptr) {
1293 if (ENTRY_STR == entry_type_get(pentry)) {
1294 if (!entry_str_set(pentry, str)) {
1295 return nullptr;
1296 }
1297 } else {
1298 entry_destroy(pentry);
1299 pentry = nullptr;
1300 }
1301 }
1302 }
1303
1304 if (pentry == nullptr) {
1305 pentry = section_entry_str_new(psection, ent_name, str, !no_escape);
1306 }
1307
1308 if (pentry != nullptr && comment != nullptr) {
1309 entry_set_comment(pentry, comment);
1310 }
1311
1312 if (stype == EST_COMMENT) {
1313 pentry->string.raw = TRUE;
1314 }
1315
1316 return pentry;
1317}
1318
1319/**********************************************************************/
1322 struct entry *secfile_insert_comment(struct section_file *secfile,
1323 const char *str,
1324 const char *path, ...)
1325{
1326 char fullpath[MAX_LEN_SECPATH];
1327 const char *ent_name;
1328 struct section *psection;
1329 struct entry *pentry = nullptr;
1330 va_list args;
1331
1332 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1333
1334 va_start(args, path);
1335 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1336 va_end(args);
1337
1338 sz_strlcat(fullpath, ".#");
1339
1340 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1341 if (!psection) {
1342 return nullptr;
1343 }
1344
1345 if (psection->special != EST_NORMAL) {
1346 log_error("Tried to insert wrong type of entry to section");
1347 return nullptr;
1348 }
1349
1350 pentry = section_entry_comment_new(psection, str);
1351
1352 return pentry;
1353}
1354
1355/**********************************************************************/
1359 size_t secfile_insert_str_vec_full(struct section_file *secfile,
1360 const char *const *strings, size_t dim,
1361 const char *comment, bool allow_replace,
1362 bool no_escape, const char *path, ...)
1363{
1364 char fullpath[MAX_LEN_SECPATH];
1365 size_t i, ret = 0;
1366 va_list args;
1367
1368 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, 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 && secfile_insert_str_full(secfile, strings[0], comment,
1378 allow_replace, no_escape, FALSE,
1379 "%s", fullpath) != nullptr) {
1380 ret++;
1381 }
1382 for (i = 1; i < dim; i++) {
1383 if (secfile_insert_str_full(secfile, strings[i], comment,
1384 allow_replace, no_escape, FALSE,
1385 "%s,%d", fullpath, (int) i) != nullptr) {
1386 ret++;
1387 }
1388 }
1389
1390 return ret;
1391}
1392
1393/**********************************************************************/
1396 struct entry *secfile_insert_filereference(struct section_file *secfile,
1397 const char *filename,
1398 const char *path, ...)
1399{
1400 char fullpath[MAX_LEN_SECPATH];
1401 const char *ent_name;
1402 struct section *psection;
1403 struct entry *pentry = nullptr;
1404 va_list args;
1405
1406 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1407
1408 va_start(args, path);
1409 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1410 va_end(args);
1411
1412 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1413 if (!psection) {
1414 return nullptr;
1415 }
1416
1417 if (psection->special != EST_NORMAL) {
1418 log_error("Tried to insert normal entry to different kind of section");
1419 return nullptr;
1420 }
1421
1422 if (pentry == nullptr) {
1423 pentry = section_entry_filereference_new(psection, ent_name, filename);
1424 }
1425
1426 return pentry;
1427}
1428
1429/**********************************************************************/
1432 struct entry *secfile_insert_plain_enum_full(struct section_file *secfile,
1433 int enumerator,
1434 secfile_enum_name_fn_t name_fn,
1435 const char *comment,
1436 bool allow_replace,
1437 const char *path, ...)
1438{
1439 char fullpath[MAX_LEN_SECPATH];
1440 const char *str;
1441 const char *ent_name;
1442 struct section *psection;
1443 struct entry *pentry = nullptr;
1444 va_list args;
1445
1446 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1447 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, nullptr);
1448 str = name_fn(enumerator);
1449 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, str != nullptr, nullptr);
1450
1451 va_start(args, path);
1452 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1453 va_end(args);
1454
1455 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1456 if (!psection) {
1457 return nullptr;
1458 }
1459
1460 if (allow_replace) {
1461 pentry = section_entry_by_name(psection, ent_name);
1462 if (pentry != nullptr) {
1463 if (ENTRY_STR == entry_type_get(pentry)) {
1464 if (!entry_str_set(pentry, str)) {
1465 return nullptr;
1466 }
1467 } else {
1468 entry_destroy(pentry);
1469 pentry = nullptr;
1470 }
1471 }
1472 }
1473
1474 if (pentry == nullptr) {
1475 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1476 }
1477
1478 if (pentry != nullptr && comment != nullptr) {
1479 entry_set_comment(pentry, comment);
1480 }
1481
1482 return pentry;
1483}
1484
1485/**********************************************************************/
1489 size_t secfile_insert_plain_enum_vec_full(struct section_file *secfile,
1490 const int *enumurators, size_t dim,
1491 secfile_enum_name_fn_t name_fn,
1492 const char *comment,
1493 bool allow_replace,
1494 const char *path, ...)
1495{
1496 char fullpath[MAX_LEN_SECPATH];
1497 size_t i, ret = 0;
1498 va_list args;
1499
1500 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, 0);
1501 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, 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
1510 && secfile_insert_plain_enum_full(secfile, enumurators[0],
1511 name_fn, comment,
1512 allow_replace, "%s",
1513 fullpath) != nullptr) {
1514 ret++;
1515 }
1516 for (i = 1; i < dim; i++) {
1517 if (secfile_insert_plain_enum_full(secfile, enumurators[i],
1518 name_fn, comment,
1519 allow_replace, "%s,%d",
1520 fullpath, (int) i) != nullptr) {
1521 ret++;
1522 }
1523 }
1524
1525 return ret;
1526}
1527
1528/**********************************************************************/
1531 struct entry *secfile_insert_bitwise_enum_full(struct section_file *secfile,
1532 int bitwise_val,
1533 secfile_enum_name_fn_t
1534 name_fn,
1535 secfile_enum_iter_fn_t
1536 begin_fn,
1537 secfile_enum_iter_fn_t
1538 end_fn,
1539 secfile_enum_next_fn_t
1540 next_fn,
1541 const char *comment,
1542 bool allow_replace,
1543 const char *path, ...)
1544{
1545 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1546 const char *ent_name;
1547 struct section *psection;
1548 struct entry *pentry = nullptr;
1549 va_list args;
1550 int i;
1551
1552 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1553 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, nullptr);
1554 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, begin_fn != nullptr, nullptr);
1555 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, end_fn != nullptr, nullptr);
1556 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, next_fn != nullptr, nullptr);
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]) {
1564 sz_strlcpy(str, name_fn(i));
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
1576 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1577 if (!psection) {
1578 return nullptr;
1579 }
1580
1581 if (allow_replace) {
1582 pentry = section_entry_by_name(psection, ent_name);
1583 if (pentry != nullptr) {
1584 if (ENTRY_STR == entry_type_get(pentry)) {
1585 if (!entry_str_set(pentry, str)) {
1586 return nullptr;
1587 }
1588 } else {
1589 entry_destroy(pentry);
1590 pentry = nullptr;
1591 }
1592 }
1593 }
1594
1595 if (pentry == nullptr) {
1596 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1597 }
1598
1599 if (pentry != nullptr && comment != nullptr) {
1600 entry_set_comment(pentry, comment);
1601 }
1602
1603 return pentry;
1604}
1605
1606/**********************************************************************/
1610 size_t secfile_insert_bitwise_enum_vec_full(struct section_file *secfile,
1611 const int *bitwise_vals,
1612 size_t dim,
1613 secfile_enum_name_fn_t name_fn,
1614 secfile_enum_iter_fn_t begin_fn,
1615 secfile_enum_iter_fn_t end_fn,
1616 secfile_enum_next_fn_t next_fn,
1617 const char *comment,
1618 bool allow_replace,
1619 const char *path, ...)
1620{
1621 char fullpath[MAX_LEN_SECPATH];
1622 size_t i, ret = 0;
1623 va_list args;
1624
1625 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, 0);
1626 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, 0);
1627 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, begin_fn != nullptr, 0);
1628 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, end_fn != nullptr, 0);
1629 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, next_fn != nullptr, 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
1638 && secfile_insert_bitwise_enum_full(secfile, bitwise_vals[0],
1639 name_fn, begin_fn, end_fn,
1640 next_fn, comment,
1641 allow_replace, "%s",
1642 fullpath) != nullptr) {
1643 ret++;
1644 }
1645 for (i = 1; i < dim; i++) {
1646 if (secfile_insert_bitwise_enum_full(secfile, bitwise_vals[i],
1647 name_fn, begin_fn, end_fn,
1648 next_fn, comment,
1649 allow_replace, "%s,%d",
1650 fullpath, (int) i) != nullptr) {
1651 ret++;
1652 }
1653 }
1654
1655 return ret;
1656}
1657
1658/**********************************************************************/
1662 struct entry *secfile_insert_enum_data_full(struct section_file *secfile,
1663 int value, bool bitwise,
1664 secfile_enum_name_data_fn_t name_fn,
1665 secfile_data_t data,
1666 const char *comment,
1667 bool allow_replace,
1668 const char *path, ...)
1669{
1670 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1671 const char *ent_name, *val_name;
1672 struct section *psection;
1673 struct entry *pentry = nullptr;
1674 va_list args;
1675 int i;
1676
1677 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1678 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, nullptr);
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]) {
1687 sz_strlcpy(str, val_name);
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, nullptr, "Value %d not supported.", value);
1697
1698 return nullptr;
1699 }
1700 sz_strlcpy(str, val_name);
1701 }
1702
1703 va_start(args, path);
1704 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1705 va_end(args);
1706
1707 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1708 if (!psection) {
1709 return nullptr;
1710 }
1711
1712 if (allow_replace) {
1713 pentry = section_entry_by_name(psection, ent_name);
1714 if (pentry != nullptr) {
1715 if (ENTRY_STR == entry_type_get(pentry)) {
1716 if (!entry_str_set(pentry, str)) {
1717 return nullptr;
1718 }
1719 } else {
1720 entry_destroy(pentry);
1721 pentry = nullptr;
1722 }
1723 }
1724 }
1725
1726 if (pentry == nullptr) {
1727 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1728 }
1729
1730 if (pentry != nullptr && comment != nullptr) {
1731 entry_set_comment(pentry, comment);
1732 }
1733
1734 return pentry;
1735}
1736
1737/**********************************************************************/
1741 size_t secfile_insert_enum_vec_data_full(struct section_file *secfile,
1742 const int *values, size_t dim,
1743 bool bitwise,
1744 secfile_enum_name_data_fn_t name_fn,
1745 secfile_data_t data,
1746 const char *comment,
1747 bool allow_replace,
1748 const char *path, ...)
1749{
1750 char fullpath[MAX_LEN_SECPATH];
1751 size_t i, ret = 0;
1752 va_list args;
1753
1754 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, 0);
1755 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, 0);
1756
1757 va_start(args, path);
1758 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1759 va_end(args);
1760
1761 /* NB: 'path,0' is actually 'path'. See comment in the head
1762 * of the file. */
1763 if (dim > 0
1764 && secfile_insert_enum_data_full(secfile, values[0], bitwise,
1765 name_fn, data, comment,
1766 allow_replace, "%s",
1767 fullpath) != nullptr) {
1768 ret++;
1769 }
1770 for (i = 1; i < dim; i++) {
1771 if (secfile_insert_enum_data_full(secfile, values[i], bitwise,
1772 name_fn, data, comment,
1773 allow_replace, "%s,%d",
1774 fullpath, (int) i) != nullptr) {
1775 ret++;
1776 }
1777 }
1778
1779 return ret;
1780}
1781
1782/**********************************************************************/
1785 struct entry *secfile_entry_by_path(const struct section_file *secfile,
1786 const char *path)
1787{
1788 char fullpath[MAX_LEN_SECPATH];
1789 char *ent_name;
1790 size_t len;
1791 struct section *psection;
1792
1793 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1794
1795 sz_strlcpy(fullpath, path);
1796
1797 /* Treat "sec.foo,0" as "sec.foo": */
1798 len = strlen(fullpath);
1799 if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1800 fullpath[len - 2] = '\0';
1801 }
1802
1803 if (secfile->hash.entries != nullptr) {
1804 struct entry *pentry;
1805
1806 if (entry_hash_lookup(secfile->hash.entries, fullpath, &pentry)) {
1807 entry_use(pentry);
1808 }
1809 return pentry;
1810 }
1811
1812 /* I dont like strtok().
1813 * - Me neither! */
1814 ent_name = strchr(fullpath, '.');
1815 if (!ent_name) {
1816 return nullptr;
1817 }
1818
1819 /* Separates section and entry names. */
1820 *ent_name++ = '\0';
1821 psection = secfile_section_by_name(secfile, fullpath);
1822 if (psection) {
1823 return section_entry_by_name(psection, ent_name);
1824 } else {
1825 return nullptr;
1826 }
1827}
1828
1829/**********************************************************************/
1832 bool secfile_entry_delete(struct section_file *secfile,
1833 const char *path, ...)
1834{
1835 char fullpath[MAX_LEN_SECPATH];
1836 va_list args;
1837 struct entry *pentry;
1838
1839 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
1840
1841 va_start(args, path);
1842 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1843 va_end(args);
1844
1845 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1846 SECFILE_LOG(secfile, nullptr, "Path %s does not exists.", fullpath);
1847 return FALSE;
1848 }
1849
1850 entry_destroy(pentry);
1851
1852 return TRUE;
1853}
1854
1855/**********************************************************************/
1858 struct entry *secfile_entry_lookup(const struct section_file *secfile,
1859 const char *path, ...)
1860{
1861 char fullpath[MAX_LEN_SECPATH];
1862 va_list args;
1863
1864 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1865
1866 va_start(args, path);
1867 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1868 va_end(args);
1869
1870 return secfile_entry_by_path(secfile, fullpath);
1871}
1872
1873/**********************************************************************/
1876 bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1877 const char *path, ...)
1878{
1879 char fullpath[MAX_LEN_SECPATH];
1880 const struct entry *pentry;
1881 va_list args;
1882
1883 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
1884
1885 va_start(args, path);
1886 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1887 va_end(args);
1888
1889 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1890 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
1891
1892 return FALSE;
1893 }
1894
1895 return entry_bool_get(pentry, bval);
1896}
1897
1898/**********************************************************************/
1902 bool secfile_lookup_bool_default(const struct section_file *secfile,
1903 bool def, const char *path, ...)
1904{
1905 char fullpath[MAX_LEN_SECPATH];
1906 const struct entry *pentry;
1907 bool bval;
1908 va_list args;
1909
1910 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, def);
1911
1912 va_start(args, path);
1913 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1914 va_end(args);
1915
1916 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1917 return def;
1918 }
1919
1920 if (entry_bool_get(pentry, &bval)) {
1921 return bval;
1922 }
1923
1924 return def;
1925}
1926
1927/**********************************************************************/
1932 bool *secfile_lookup_bool_vec(const struct section_file *secfile,
1933 size_t *dim, const char *path, ...)
1934{
1935 char fullpath[MAX_LEN_SECPATH];
1936 size_t i = 0;
1937 bool *vec;
1938 va_list args;
1939
1940 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
1941 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, dim != nullptr, nullptr);
1942
1943 va_start(args, path);
1944 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1945 va_end(args);
1946
1947 /* Check size. */
1948 while (secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i) != nullptr) {
1949 i++;
1950 }
1951 *dim = i;
1952
1953 if (0 == i) {
1954 /* Doesn't exist. */
1955 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
1956 return nullptr;
1957 }
1958
1959 vec = fc_malloc(i * sizeof(bool));
1960 for (i = 0; i < *dim; i++) {
1961 if (!secfile_lookup_bool(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1962 SECFILE_LOG(secfile, nullptr,
1963 "An error occurred when looking up to \"%s,%d\" entry.",
1964 fullpath, (int) i);
1965 free(vec);
1966 *dim = 0;
1967
1968 return nullptr;
1969 }
1970 }
1971
1972 return vec;
1973}
1974
1975/**********************************************************************/
1978 bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1979 const char *path, ...)
1980{
1981 char fullpath[MAX_LEN_SECPATH];
1982 const struct entry *pentry;
1983 va_list args;
1984
1985 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
1986
1987 va_start(args, path);
1988 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1989 va_end(args);
1990
1991 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1992 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
1993
1994 return FALSE;
1995 }
1996
1997 return entry_int_get(pentry, ival);
1998}
1999
2000/**********************************************************************/
2004 int secfile_lookup_int_default(const struct section_file *secfile, int def,
2005 const char *path, ...)
2006{
2007 char fullpath[MAX_LEN_SECPATH];
2008 const struct entry *pentry;
2009 int ival;
2010 va_list args;
2011
2012 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, def);
2013
2014 va_start(args, path);
2015 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2016 va_end(args);
2017
2018 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2019 return def;
2020 }
2021
2022 if (entry_int_get(pentry, &ival)) {
2023 return ival;
2024 }
2025
2026 return def;
2027}
2028
2029/**********************************************************************/
2034 int secfile_lookup_int_def_min_max(const struct section_file *secfile,
2035 int defval, int minval, int maxval,
2036 const char *path, ...)
2037{
2038 char fullpath[MAX_LEN_SECPATH];
2039 const struct entry *pentry;
2040 int value;
2041 va_list args;
2042
2043 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, defval);
2044
2045 va_start(args, path);
2046 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2047 va_end(args);
2048
2049 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2050 return defval;
2051 }
2052
2053 if (!entry_int_get(pentry, &value)) {
2054 return defval;
2055 }
2056
2057 if (value < minval) {
2058 SECFILE_LOG(secfile, entry_section(pentry),
2059 "\"%s\" should be in the interval [%d, %d] but is %d;"
2060 "using the minimal value.",
2061 fullpath, minval, maxval, value);
2062 value = minval;
2063 }
2064
2065 if (value > maxval) {
2066 SECFILE_LOG(secfile, entry_section(pentry),
2067 "\"%s\" should be in the interval [%d, %d] but is %d;"
2068 "using the maximal value.",
2069 fullpath, minval, maxval, value);
2070 value = maxval;
2071 }
2072
2073 return value;
2074}
2075
2076/**********************************************************************/
2081 int *secfile_lookup_int_vec(const struct section_file *secfile,
2082 size_t *dim, const char *path, ...)
2083{
2084 char fullpath[MAX_LEN_SECPATH];
2085 size_t i = 0;
2086 int *vec;
2087 va_list args;
2088
2089 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2090 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, dim != nullptr, nullptr);
2091
2092 va_start(args, path);
2093 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2094 va_end(args);
2095
2096 /* Check size. */
2097 while (secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i) != nullptr) {
2098 i++;
2099 }
2100 *dim = i;
2101
2102 if (0 == i) {
2103 /* Doesn't exist. */
2104 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2105
2106 return nullptr;
2107 }
2108
2109 vec = fc_malloc(i * sizeof(int));
2110 for (i = 0; i < *dim; i++) {
2111 if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
2112 SECFILE_LOG(secfile, nullptr,
2113 "An error occurred when looking up to \"%s,%d\" entry.",
2114 fullpath, (int) i);
2115 free(vec);
2116 *dim = 0;
2117 return nullptr;
2118 }
2119 }
2120
2121 return vec;
2122}
2123
2124/**********************************************************************/
2127 bool secfile_lookup_float(const struct section_file *secfile, float *fval,
2128 const char *path, ...)
2129{
2130 char fullpath[MAX_LEN_SECPATH];
2131 const struct entry *pentry;
2132 va_list args;
2133
2134 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
2135
2136 va_start(args, path);
2137 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2138 va_end(args);
2139
2140 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2141 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2142 return FALSE;
2143 }
2144
2145 return entry_float_get(pentry, fval);
2146}
2147
2148/**********************************************************************/
2152 float secfile_lookup_float_default(const struct section_file *secfile,
2153 float def, const char *path, ...)
2154{
2155 char fullpath[MAX_LEN_SECPATH];
2156 const struct entry *pentry;
2157 float fval;
2158 va_list args;
2159
2160 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, def);
2161
2162 va_start(args, path);
2163 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2164 va_end(args);
2165
2166 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2167 return def;
2168 }
2169
2170 if (entry_float_get(pentry, &fval)) {
2171 return fval;
2172 }
2173
2174 return def;
2175}
2176
2177/**********************************************************************/
2180 const char *secfile_lookup_str(const struct section_file *secfile,
2181 const char *path, ...)
2182{
2183 char fullpath[MAX_LEN_SECPATH];
2184 const struct entry *pentry;
2185 const char *str;
2186 va_list args;
2187
2188 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2189
2190 va_start(args, path);
2191 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2192 va_end(args);
2193
2194 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2195 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2196 return nullptr;
2197 }
2198
2199 if (entry_str_get(pentry, &str)) {
2200 return str;
2201 }
2202
2203 return nullptr;
2204}
2205
2206/**********************************************************************/
2210 const char *secfile_lookup_str_default(const struct section_file *secfile,
2211 const char *def,
2212 const char *path, ...)
2213{
2214 char fullpath[MAX_LEN_SECPATH];
2215 const struct entry *pentry;
2216 const char *str;
2217 va_list args;
2218
2219 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, def);
2220
2221 va_start(args, path);
2222 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2223 va_end(args);
2224
2225 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2226 return def;
2227 }
2228
2229 if (entry_str_get(pentry, &str)) {
2230 return str;
2231 }
2232
2233 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't have a string.", fullpath);
2234
2235 return def;
2236}
2237
2238/**********************************************************************/
2244 const char **secfile_lookup_str_vec(const struct section_file *secfile,
2245 size_t *dim, const char *path, ...)
2246{
2247 char fullpath[MAX_LEN_SECPATH];
2248 size_t i = 0;
2249 const char **vec;
2250 va_list args;
2251
2252 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2253 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, dim != nullptr, nullptr);
2254
2255 va_start(args, path);
2256 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2257 va_end(args);
2258
2259 /* Check size. */
2260 while (secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i) != nullptr) {
2261 i++;
2262 }
2263 *dim = i;
2264
2265 if (0 == i) {
2266 /* Doesn't exist. */
2267 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2268 return nullptr;
2269 }
2270
2271 vec = fc_malloc(i * sizeof(const char *));
2272 for (i = 0; i < *dim; i++) {
2273 if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d",
2274 fullpath, (int) i))) {
2275 SECFILE_LOG(secfile, nullptr,
2276 "An error occurred when looking up to \"%s,%d\" entry.",
2277 fullpath, (int) i);
2278 free(vec);
2279 *dim = 0;
2280 return nullptr;
2281 }
2282 }
2283
2284 return vec;
2285}
2286
2287/**********************************************************************/
2290 bool secfile_lookup_plain_enum_full(const struct section_file *secfile,
2291 int *penumerator,
2292 secfile_enum_is_valid_fn_t is_valid_fn,
2293 secfile_enum_by_name_fn_t by_name_fn,
2294 const char *path, ...)
2295{
2296 char fullpath[MAX_LEN_SECPATH];
2297 const struct entry *pentry;
2298 const char *str;
2299 va_list args;
2300
2301 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
2302 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, penumerator != nullptr, FALSE);
2303 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, is_valid_fn != nullptr, FALSE);
2304 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, by_name_fn != nullptr, FALSE);
2305
2306 va_start(args, path);
2307 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2308 va_end(args);
2309
2310 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2311 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2312 return FALSE;
2313 }
2314
2315 if (!entry_str_get(pentry, &str)) {
2316 return FALSE;
2317 }
2318
2319 *penumerator = by_name_fn(str, strcmp);
2320 if (is_valid_fn(*penumerator)) {
2321 return TRUE;
2322 }
2323
2324 SECFILE_LOG(secfile, entry_section(pentry),
2325 "Entry \"%s\": no match for \"%s\".",
2326 entry_name(pentry), str);
2327 return FALSE;
2328}
2329
2330/**********************************************************************/
2333 int secfile_lookup_plain_enum_default_full(const struct section_file
2334 *secfile, int defval,
2335 secfile_enum_is_valid_fn_t
2336 is_valid_fn,
2337 secfile_enum_by_name_fn_t
2338 by_name_fn,
2339 const char *path, ...)
2340{
2341 char fullpath[MAX_LEN_SECPATH];
2342 const struct entry *pentry;
2343 const char *str;
2344 int val;
2345 va_list args;
2346
2347 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, defval);
2348 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, is_valid_fn != nullptr, defval);
2349 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, by_name_fn != nullptr, defval);
2350
2351 va_start(args, path);
2352 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2353 va_end(args);
2354
2355 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2356 return defval;
2357 }
2358
2359 if (!entry_str_get(pentry, &str)) {
2360 return defval;
2361 }
2362
2363 val = by_name_fn(str, strcmp);
2364 if (is_valid_fn(val)) {
2365 return val;
2366 } else {
2367 return defval;
2368 }
2369}
2370
2371/**********************************************************************/
2376 int *secfile_lookup_plain_enum_vec_full(const struct section_file *secfile,
2377 size_t *dim,
2378 secfile_enum_is_valid_fn_t
2379 is_valid_fn,
2380 secfile_enum_by_name_fn_t
2381 by_name_fn,
2382 const char *path, ...)
2383{
2384 char fullpath[MAX_LEN_SECPATH];
2385 size_t i = 0;
2386 int *vec;
2387 va_list args;
2388
2389 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2390 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, dim != nullptr, nullptr);
2391 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, is_valid_fn != nullptr, nullptr);
2392 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, by_name_fn != nullptr, nullptr);
2393
2394 va_start(args, path);
2395 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2396 va_end(args);
2397
2398 /* Check size. */
2399 while (secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i) != nullptr) {
2400 i++;
2401 }
2402 *dim = i;
2403
2404 if (0 == i) {
2405 /* Doesn't exist. */
2406 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2407 return nullptr;
2408 }
2409
2410 vec = fc_malloc(i * sizeof(int));
2411 for (i = 0; i < *dim; i++) {
2412 if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2413 by_name_fn, "%s,%d",
2414 fullpath, (int) i)) {
2415 SECFILE_LOG(secfile, nullptr,
2416 "An error occurred when looking up to \"%s,%d\" entry.",
2417 fullpath, (int) i);
2418 free(vec);
2419 *dim = 0;
2420 return nullptr;
2421 }
2422 }
2423
2424 return vec;
2425}
2426
2427/**********************************************************************/
2430 bool secfile_lookup_bitwise_enum_full(const struct section_file *secfile,
2431 int *penumerator,
2432 secfile_enum_is_valid_fn_t is_valid_fn,
2433 secfile_enum_by_name_fn_t by_name_fn,
2434 const char *path, ...)
2435{
2436 char fullpath[MAX_LEN_SECPATH];
2437 const struct entry *pentry;
2438 const char *str, *p;
2439 char val_name[MAX_LEN_SECPATH];
2440 int val;
2441 va_list args;
2442
2443 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
2444 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, penumerator != nullptr, FALSE);
2445 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, is_valid_fn != nullptr, FALSE);
2446 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, by_name_fn != nullptr, FALSE);
2447
2448 va_start(args, path);
2449 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2450 va_end(args);
2451
2452 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2453 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2454 return FALSE;
2455 }
2456
2457 if (!entry_str_get(pentry, &str)) {
2458 return FALSE;
2459 }
2460
2461 *penumerator = 0;
2462 if ('\0' == str[0]) {
2463 /* Empty string = no value. */
2464 return TRUE;
2465 }
2466
2467 /* Value names are separated by '|'. */
2468 do {
2469 p = strchr(str, '|');
2470 if (p != nullptr) {
2471 p++;
2472 fc_strlcpy(val_name, str, p - str);
2473 } else {
2474 /* Last segment, full copy. */
2475 sz_strlcpy(val_name, str);
2476 }
2477 remove_leading_trailing_spaces(val_name);
2478 val = by_name_fn(val_name, strcmp);
2479 if (!is_valid_fn(val)) {
2480 SECFILE_LOG(secfile, entry_section(pentry),
2481 "Entry \"%s\": no match for \"%s\".",
2482 entry_name(pentry), val_name);
2483 return FALSE;
2484 }
2485 *penumerator |= val;
2486 str = p;
2487 } while (p != nullptr);
2488
2489 return TRUE;
2490}
2491
2492/**********************************************************************/
2495 int secfile_lookup_bitwise_enum_default_full(const struct section_file
2496 *secfile, int defval,
2497 secfile_enum_is_valid_fn_t
2498 is_valid_fn,
2499 secfile_enum_by_name_fn_t
2500 by_name_fn,
2501 const char *path, ...)
2502{
2503 char fullpath[MAX_LEN_SECPATH];
2504 const struct entry *pentry;
2505 const char *str, *p;
2506 char val_name[MAX_LEN_SECPATH];
2507 int val, full_val;
2508 va_list args;
2509
2510 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, defval);
2511 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, is_valid_fn != nullptr, defval);
2512 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, by_name_fn != nullptr, defval);
2513
2514 va_start(args, path);
2515 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2516 va_end(args);
2517
2518 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2519 return defval;
2520 }
2521
2522 if (!entry_str_get(pentry, &str)) {
2523 return defval;
2524 }
2525
2526 if ('\0' == str[0]) {
2527 /* Empty string = no value. */
2528 return 0;
2529 }
2530
2531 /* Value names are separated by '|'. */
2532 full_val = 0;
2533 do {
2534 p = strchr(str, '|');
2535 if (p != nullptr) {
2536 p++;
2537 fc_strlcpy(val_name, str, p - str);
2538 } else {
2539 /* Last segment, full copy. */
2540 sz_strlcpy(val_name, str);
2541 }
2542 remove_leading_trailing_spaces(val_name);
2543 val = by_name_fn(val_name, strcmp);
2544 if (!is_valid_fn(val)) {
2545 return defval;
2546 }
2547 full_val |= val;
2548 str = p;
2549 } while (p != nullptr);
2550
2551 return full_val;
2552}
2553
2554/**********************************************************************/
2559 int *secfile_lookup_bitwise_enum_vec_full(const struct section_file *secfile,
2560 size_t *dim,
2561 secfile_enum_is_valid_fn_t
2562 is_valid_fn,
2563 secfile_enum_by_name_fn_t
2564 by_name_fn,
2565 const char *path, ...)
2566{
2567 char fullpath[MAX_LEN_SECPATH];
2568 size_t i = 0;
2569 int *vec;
2570 va_list args;
2571
2572 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2573 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, dim != nullptr, nullptr);
2574 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, is_valid_fn != nullptr, nullptr);
2575 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, by_name_fn != nullptr, nullptr);
2576
2577 va_start(args, path);
2578 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2579 va_end(args);
2580
2581 /* Check size. */
2582 while (secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i) != nullptr) {
2583 i++;
2584 }
2585 *dim = i;
2586
2587 if (0 == i) {
2588 /* Doesn't exist. */
2589 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2590 return nullptr;
2591 }
2592
2593 vec = fc_malloc(i * sizeof(int));
2594 for (i = 0; i < *dim; i++) {
2595 if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2596 by_name_fn, "%s,%d",
2597 fullpath, (int) i)) {
2598 SECFILE_LOG(secfile, nullptr,
2599 "An error occurred when looking up to \"%s,%d\" entry.",
2600 fullpath, (int) i);
2601 free(vec);
2602 *dim = 0;
2603
2604 return nullptr;
2605 }
2606 }
2607
2608 return vec;
2609}
2610
2611/**********************************************************************/
2614 bool secfile_lookup_enum_data(const struct section_file *secfile,
2615 int *pvalue, bool bitwise,
2616 secfile_enum_name_data_fn_t name_fn,
2617 secfile_data_t data, const char *path, ...)
2618{
2619 char fullpath[MAX_LEN_SECPATH];
2620 const struct entry *pentry;
2621 const char *str, *p, *name;
2622 char val_name[MAX_LEN_SECPATH];
2623 int val;
2624 va_list args;
2625
2626 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
2627 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, pvalue != nullptr, FALSE);
2628 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, FALSE);
2629
2630 va_start(args, path);
2631 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2632 va_end(args);
2633
2634 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2635 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2636 return FALSE;
2637 }
2638
2639 if (!entry_str_get(pentry, &str)) {
2640 return FALSE;
2641 }
2642
2643 if (bitwise) {
2644 *pvalue = 0;
2645 if ('\0' == str[0]) {
2646 /* Empty string = no value. */
2647 return TRUE;
2648 }
2649
2650 /* Value names are separated by '|'. */
2651 do {
2652 p = strchr(str, '|');
2653 if (p != nullptr) {
2654 p++;
2655 fc_strlcpy(val_name, str, p - str);
2656 } else {
2657 /* Last segment, full copy. */
2658 sz_strlcpy(val_name, str);
2659 }
2660 remove_leading_trailing_spaces(val_name);
2661 for (val = 0; (name = name_fn(data, val)); val++) {
2662 if (0 == fc_strcasecmp(name, val_name)) {
2663 break;
2664 }
2665 }
2666 if (name == nullptr) {
2667 SECFILE_LOG(secfile, entry_section(pentry),
2668 "Entry \"%s\": no match for \"%s\".",
2669 entry_name(pentry), val_name);
2670 return FALSE;
2671 }
2672 *pvalue |= 1 << val;
2673 str = p;
2674 } while (p != nullptr);
2675 } else {
2676 for (val = 0; (name = name_fn(data, val)); val++) {
2677 if (0 == fc_strcasecmp(name, str)) {
2678 *pvalue = val;
2679 break;
2680 }
2681 }
2682 if (name == nullptr) {
2683 SECFILE_LOG(secfile, entry_section(pentry),
2684 "Entry \"%s\": no match for \"%s\".",
2685 entry_name(pentry), str);
2686 return FALSE;
2687 }
2688 }
2689
2690 return TRUE;
2691}
2692
2693/**********************************************************************/
2696 int secfile_lookup_enum_default_data(const struct section_file *secfile,
2697 int defval, bool bitwise,
2698 secfile_enum_name_data_fn_t name_fn,
2699 secfile_data_t data,
2700 const char *path, ...)
2701{
2702 char fullpath[MAX_LEN_SECPATH];
2703 const struct entry *pentry;
2704 const char *str, *p, *name;
2705 char val_name[MAX_LEN_SECPATH];
2706 int value, val;
2707 va_list args;
2708
2709 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, defval);
2710 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, defval);
2711
2712 va_start(args, path);
2713 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2714 va_end(args);
2715
2716 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2717 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2718 return defval;
2719 }
2720
2721 if (!entry_str_get(pentry, &str)) {
2722 return defval;
2723 }
2724
2725 value = 0;
2726 if (bitwise) {
2727 if ('\0' == str[0]) {
2728 /* Empty string = no value. */
2729 return value;
2730 }
2731
2732 /* Value names are separated by '|'. */
2733 do {
2734 p = strchr(str, '|');
2735 if (p != nullptr) {
2736 p++;
2737 fc_strlcpy(val_name, str, p - str);
2738 } else {
2739 /* Last segment, full copy. */
2740 sz_strlcpy(val_name, str);
2741 }
2742 remove_leading_trailing_spaces(val_name);
2743 for (val = 0; (name = name_fn(data, val)); val++) {
2744 if (0 == strcmp(name, val_name)) {
2745 break;
2746 }
2747 }
2748 if (name == nullptr) {
2749 SECFILE_LOG(secfile, entry_section(pentry),
2750 "Entry \"%s\": no match for \"%s\".",
2751 entry_name(pentry), val_name);
2752 return defval;
2753 }
2754 value |= 1 << val;
2755 str = p;
2756 } while (p != nullptr);
2757 } else {
2758 for (val = 0; (name = name_fn(data, val)); val++) {
2759 if (0 == strcmp(name, str)) {
2760 value = val;
2761 break;
2762 }
2763 }
2764 if (name == nullptr) {
2765 SECFILE_LOG(secfile, entry_section(pentry),
2766 "Entry \"%s\": no match for \"%s\".",
2767 entry_name(pentry), str);
2768 return defval;
2769 }
2770 }
2771
2772 return value;
2773}
2774
2775/**********************************************************************/
2779 int *secfile_lookup_enum_vec_data(const struct section_file *secfile,
2780 size_t *dim, bool bitwise,
2781 secfile_enum_name_data_fn_t name_fn,
2782 secfile_data_t data, const char *path, ...)
2783{
2784 char fullpath[MAX_LEN_SECPATH];
2785 size_t i = 0;
2786 int *vec;
2787 va_list args;
2788
2789 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2790 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, dim != nullptr, nullptr);
2791 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, name_fn != nullptr, nullptr);
2792
2793 va_start(args, path);
2794 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2795 va_end(args);
2796
2797 /* Check size. */
2798 while (secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i) != nullptr) {
2799 i++;
2800 }
2801 *dim = i;
2802
2803 if (0 == i) {
2804 /* Doesn't exist. */
2805 SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2806 return nullptr;
2807 }
2808
2809 vec = fc_malloc(i * sizeof(int));
2810 for (i = 0; i < *dim; i++) {
2811 if (!secfile_lookup_enum_data(secfile, vec + i, bitwise, name_fn, data,
2812 "%s,%d", fullpath, (int) i)) {
2813 SECFILE_LOG(secfile, nullptr,
2814 "An error occurred when looking up to \"%s,%d\" entry.",
2815 fullpath, (int) i);
2816 free(vec);
2817 *dim = 0;
2818
2819 return nullptr;
2820 }
2821 }
2822
2823 return vec;
2824}
2825
2826/**********************************************************************/
2829 struct section *secfile_section_by_name(const struct section_file *secfile,
2830 const char *name)
2831{
2832 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2833
2834 section_list_iterate(secfile->sections, psection) {
2835 if (0 == strcmp(section_name(psection), name)) {
2836 return psection;
2837 }
2838 } section_list_iterate_end;
2839
2840 return nullptr;
2841}
2842
2843/**********************************************************************/
2846 struct section *secfile_section_lookup(const struct section_file *secfile,
2847 const char *path, ...)
2848{
2849 char fullpath[MAX_LEN_SECPATH];
2850 va_list args;
2851
2852 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2853
2854 va_start(args, path);
2855 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2856 va_end(args);
2857
2858 return secfile_section_by_name(secfile, fullpath);
2859}
2860
2861/**********************************************************************/
2865const struct section_list *
2866secfile_sections(const struct section_file *secfile)
2867{
2868 return (secfile != nullptr ? secfile->sections : nullptr);
2869}
2870
2871/**********************************************************************/
2876struct section_list *
2877secfile_sections_by_name_prefix(const struct section_file *secfile,
2878 const char *prefix)
2879{
2880 struct section_list *matches = nullptr;
2881 size_t len;
2882
2883 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2884 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, prefix != nullptr, nullptr);
2885
2886 len = strlen(prefix);
2887 if (0 == len) {
2888 return nullptr;
2889 }
2890
2891 section_list_iterate(secfile->sections, psection) {
2892 if (!fc_strncmp(section_name(psection), prefix, len)) {
2893 if (matches == nullptr) {
2894 matches = section_list_new();
2895 }
2896 section_list_append(matches, psection);
2897 }
2898 } section_list_iterate_end;
2899
2900 return matches;
2901}
2902
2903/**********************************************************************/
2906 bool secfile_section_prefix_present(const struct section_file *secfile,
2907 const char *prefix)
2908{
2909 size_t len;
2910
2911 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, FALSE);
2912 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, prefix != nullptr, FALSE);
2913
2914 len = strlen(prefix);
2915 if (0 == len) {
2916 return FALSE;
2917 }
2918
2919 section_list_iterate(secfile->sections, psection) {
2920 if (!fc_strncmp(section_name(psection), prefix, len)) {
2921 return TRUE;
2922 }
2923 } section_list_iterate_end;
2924
2925 return FALSE;
2926}
2927
2928/**********************************************************************/
2931 struct section *secfile_section_new(struct section_file *secfile,
2932 const char *name)
2933{
2934 struct section *psection;
2935
2936 SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, secfile != nullptr, nullptr);
2937
2938 if (name == nullptr || '\0' == name[0]) {
2939 SECFILE_LOG(secfile, nullptr, "Cannot create a section without name.");
2940 return nullptr;
2941 }
2942
2943 if (!is_secfile_entry_name_valid(name)) {
2944 SECFILE_LOG(secfile, nullptr, "\"%s\" is not a valid section name.",
2945 name);
2946 return nullptr;
2947 }
2948
2949 if (secfile_section_by_name(secfile, name) != nullptr) {
2950 /* We cannot duplicate sections in any case! Not even if one is
2951 * include -section and the other not. */
2952 SECFILE_LOG(secfile, nullptr, "Section \"%s\" already exists.", name);
2953 return nullptr;
2954 }
2955
2956 psection = fc_malloc(sizeof(struct section));
2957 psection->special = EST_NORMAL;
2958 psection->name = fc_strdup(name);
2959 psection->entries = entry_list_new_full(entry_destroy);
2960
2961 /* Append to secfile. */
2962 psection->secfile = secfile;
2963 section_list_append(secfile->sections, psection);
2964
2965 if (secfile->hash.sections != nullptr) {
2966 section_hash_insert(secfile->hash.sections, psection->name, psection);
2967 }
2968
2969 return psection;
2970}
2971
2972/**********************************************************************/
2975 void section_destroy(struct section *psection)
2976{
2977 struct section_file *secfile;
2978
2979 SECFILE_RETURN_IF_FAIL(nullptr, psection, psection != nullptr);
2980
2981 section_clear_all(psection);
2982
2983 if ((secfile = psection->secfile)) {
2984 /* Detach from secfile. */
2985 if (section_list_remove(secfile->sections, psection)) {
2986 /* This has called section_destroy() already then. */
2987 return;
2988 }
2989 if (secfile->hash.sections != nullptr) {
2990 section_hash_remove(secfile->hash.sections, psection->name);
2991 }
2992 }
2993
2994 entry_list_destroy(psection->entries);
2995 free(psection->name);
2996 free(psection);
2997}
2998
2999/**********************************************************************/
3002 void section_clear_all(struct section *psection)
3003{
3004 SECFILE_RETURN_IF_FAIL(nullptr, psection, psection != nullptr);
3005
3006 /* This include the removing of the hash datas. */
3007 entry_list_clear(psection->entries);
3008
3009 if (0 < entry_list_size(psection->entries)) {
3010 SECFILE_LOG(psection->secfile, psection,
3011 "After clearing all, %d entries are still remaining.",
3012 entry_list_size(psection->entries));
3013 }
3014}
3015
3016/**********************************************************************/
3019 bool section_set_name(struct section *psection, const char *name)
3020{
3021 struct section_file *secfile;
3022 struct section *pother;
3023
3024 SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, psection != nullptr, FALSE);
3025 secfile = psection->secfile;
3026 SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, secfile != nullptr, FALSE);
3027
3028 if (name == nullptr || '\0' == name[0]) {
3029 SECFILE_LOG(secfile, psection, "No new name for section \"%s\".",
3030 psection->name);
3031 return FALSE;
3032 }
3033
3034 if (!is_secfile_entry_name_valid(name)) {
3035 SECFILE_LOG(secfile, psection,
3036 "\"%s\" is not a valid section name for section \"%s\".",
3037 name, psection->name);
3038 return FALSE;
3039 }
3040
3041 if ((pother = secfile_section_by_name(secfile, name))
3042 && pother != psection) {
3043 /* We cannot duplicate sections in any case! */
3044 SECFILE_LOG(secfile, psection, "Section \"%s\" already exists.", name);
3045 return FALSE;
3046 }
3047
3048 /* Remove old references in the hash tables. */
3049 if (secfile->hash.sections != nullptr) {
3050 section_hash_remove(secfile->hash.sections, psection->name);
3051 }
3052 if (secfile->hash.entries != nullptr) {
3053 entry_list_iterate(psection->entries, pentry) {
3054 secfile_hash_delete(secfile, pentry);
3055 } entry_list_iterate_end;
3056 }
3057
3058 /* Really rename. */
3059 free(psection->name);
3060 psection->name = fc_strdup(name);
3061
3062 /* Reinsert new references into the hash tables. */
3063 if (secfile->hash.sections != nullptr) {
3064 section_hash_insert(secfile->hash.sections, psection->name, psection);
3065 }
3066 if (secfile->hash.entries != nullptr) {
3067 entry_list_iterate(psection->entries, pentry) {
3068 secfile_hash_insert(secfile, pentry);
3069 } entry_list_iterate_end;
3070 }
3071
3072 return TRUE;
3073}
3074
3075/**********************************************************************/
3079 const struct entry_list *section_entries(const struct section *psection)
3080{
3081 return (psection != nullptr ? psection->entries : nullptr);
3082}
3083
3084/**********************************************************************/
3087 struct entry *section_entry_by_name(const struct section *psection,
3088 const char *name)
3089{
3090 SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, psection != nullptr, nullptr);
3091
3092 entry_list_iterate(psection->entries, pentry) {
3093 if (0 == strcmp(entry_name(pentry), name)) {
3094 entry_use(pentry);
3095 return pentry;
3096 }
3097 } entry_list_iterate_end;
3098
3099 return nullptr;
3100}
3101
3102/**********************************************************************/
3105 struct entry *section_entry_lookup(const struct section *psection,
3106 const char *path, ...)
3107{
3108 char fullpath[MAX_LEN_SECPATH];
3109 struct entry *pentry;
3110 va_list args;
3111
3112 SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, psection != nullptr, nullptr);
3113
3114 va_start(args, path);
3115 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
3116 va_end(args);
3117
3118 if ((pentry = section_entry_by_name(psection, fullpath))) {
3119 return pentry;
3120 }
3121
3122 /* Try with full path. */
3123 if ((pentry = secfile_entry_by_path(psection->secfile, fullpath))
3124 && psection == entry_section(pentry)) {
3125 /* Ensured this is really owned by this section. */
3126 return pentry;
3127 }
3128
3129 return nullptr;
3130}
3131
3132/**********************************************************************/
3135 static struct entry *entry_new(struct section *psection, const char *name)
3136{
3137 struct section_file *secfile;
3138 struct entry *pentry;
3139 bool long_comment = !strcmp("#", name);
3140
3141 SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, psection != nullptr, nullptr);
3142
3143 secfile = psection->secfile;
3144 if (name == nullptr || '\0' == name[0]) {
3145 SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
3146 return nullptr;
3147 }
3148
3149 if (!is_secfile_entry_name_valid(name) && !long_comment) {
3150 SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
3151 name);
3152 return nullptr;
3153 }
3154
3155 if (!secfile->allow_duplicates
3156 && section_entry_by_name(psection, name) != nullptr) {
3157 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3158 return nullptr;
3159 }
3160
3161 pentry = fc_malloc(sizeof(struct entry));
3162 if (long_comment) {
3163 pentry->name = nullptr;
3164 } else {
3165 pentry->name = fc_strdup(name);
3166 }
3167 pentry->type = -1; /* Invalid case. */
3168 pentry->used = 0;
3169 pentry->comment = nullptr;
3170
3171 /* Append to section. */
3172 pentry->psection = psection;
3173 entry_list_append(psection->entries, pentry);
3174
3175 /* Notify secfile. */
3176 secfile->num_entries++;
3177 secfile_hash_insert(secfile, pentry);
3178
3179 return pentry;
3180}
3181
3182/**********************************************************************/
3185 struct entry *section_entry_int_new(struct section *psection,
3186 const char *name, int value)
3187{
3188 struct entry *pentry = entry_new(psection, name);
3189
3190 if (pentry != nullptr) {
3191 pentry->type = ENTRY_INT;
3192 pentry->integer.value = value;
3193 }
3194
3195 return pentry;
3196}
3197
3198/**********************************************************************/
3201 struct entry *section_entry_bool_new(struct section *psection,
3202 const char *name, bool value)
3203{
3204 struct entry *pentry = entry_new(psection, name);
3205
3206 if (pentry != nullptr) {
3207 pentry->type = ENTRY_BOOL;
3208 pentry->boolean.value = value;
3209 }
3210
3211 return pentry;
3212}
3213
3214/**********************************************************************/
3217 struct entry *section_entry_float_new(struct section *psection,
3218 const char *name, float value)
3219{
3220 struct entry *pentry = entry_new(psection, name);
3221
3222 if (pentry != nullptr) {
3223 pentry->type = ENTRY_FLOAT;
3224 pentry->floating.value = value;
3225 }
3226
3227 return pentry;
3228}
3229
3230/**********************************************************************/
3233 struct entry *section_entry_str_new(struct section *psection,
3234 const char *name, const char *value,
3235 bool escaped)
3236{
3237 struct entry *pentry = entry_new(psection, name);
3238
3239 if (pentry != nullptr) {
3240 pentry->type = ENTRY_STR;
3241 pentry->string.value = fc_strdup(value != nullptr ? value : "");
3242 pentry->string.escaped = escaped;
3243 pentry->string.raw = FALSE;
3244 pentry->string.gt_marking = FALSE;
3245 }
3246
3247 return pentry;
3248}
3249
3250/**********************************************************************/
3253 static struct entry *section_entry_filereference_new(struct section *psection,
3254 const char *name,
3255 const char *value)
3256{
3257 struct entry *pentry = entry_new(psection, name);
3258
3259 if (pentry != nullptr) {
3260 pentry->type = ENTRY_FILEREFERENCE;
3261 pentry->string.value = fc_strdup(value != nullptr ? value : "");
3262 }
3263
3264 return pentry;
3265}
3266
3267/**********************************************************************/
3270 static struct entry *section_entry_comment_new(struct section *psection,
3271 const char *comment)
3272{
3273 struct entry *pentry = entry_new(psection, "#");
3274
3275 if (pentry != nullptr) {
3276 pentry->type = ENTRY_LONG_COMMENT;
3277 pentry->comment = fc_strdup(comment != nullptr ? comment : "");
3278 }
3279
3280 return pentry;
3281}
3282
3283/**********************************************************************/
3286 void entry_destroy(struct entry *pentry)
3287{
3288 struct section_file *secfile;
3289 struct section *psection;
3290
3291 if (pentry == nullptr) {
3292 return;
3293 }
3294
3295 if ((psection = pentry->psection)) {
3296 /* Detach from section. */
3297 if (entry_list_remove(psection->entries, pentry)) {
3298 /* This has called entry_destroy() already then. */
3299 return;
3300 }
3301 if ((secfile = psection->secfile)) {
3302 /* Detach from secfile. */
3303 secfile->num_entries--;
3304 secfile_hash_delete(secfile, pentry);
3305 }
3306 }
3307
3308 /* Specific type free. */
3309 switch (pentry->type) {
3310 case ENTRY_BOOL:
3311 case ENTRY_INT:
3312 case ENTRY_FLOAT:
3313 case ENTRY_LONG_COMMENT:
3314 break;
3315
3316 case ENTRY_STR:
3317 case ENTRY_FILEREFERENCE:
3318 free(pentry->string.value);
3319 break;
3320
3321 case ENTRY_ILLEGAL:
3322 fc_assert(pentry->type != ENTRY_ILLEGAL);
3323 break;
3324 }
3325
3326 /* Common free. */
3327 free(pentry->name);
3328 if (pentry->comment != nullptr) {
3329 free(pentry->comment);
3330 }
3331 free(pentry);
3332}
3333
3334/**********************************************************************/
3337 struct section *entry_section(const struct entry *pentry)
3338{
3339 return (pentry != nullptr ? pentry->psection : nullptr);
3340}
3341
3342/**********************************************************************/
3345 enum entry_type entry_type_get(const struct entry *pentry)
3346{
3347 return (pentry != nullptr ? pentry->type : ENTRY_ILLEGAL);
3348}
3349
3350/**********************************************************************/
3353 int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3354{
3355 return fc_snprintf(buf, buf_len, "%s.%s",
3356 section_name(entry_section(pentry)),
3357 entry_name(pentry));
3358}
3359
3360/**********************************************************************/
3363 const char *entry_name(const struct entry *pentry)
3364{
3365 return (pentry != nullptr ? pentry->name : nullptr);
3366}
3367
3368/**********************************************************************/
3371 bool entry_set_name(struct entry *pentry, const char *name)
3372{
3373 struct section *psection;
3374 struct section_file *secfile;
3375
3376 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3377 psection = pentry->psection;
3378 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, psection != nullptr, FALSE);
3379 secfile = psection->secfile;
3380 SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, secfile != nullptr, FALSE);
3381
3382 if (name == nullptr || '\0' == name[0]) {
3383 SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3384 pentry->name);
3385 return FALSE;
3386 }
3387
3388 if (!is_secfile_entry_name_valid(name)) {
3389 SECFILE_LOG(secfile, psection,
3390 "\"%s\" is not a valid entry name for entry \"%s\".",
3391 name, pentry->name);
3392 return FALSE;
3393 }
3394
3395 if (!secfile->allow_duplicates) {
3396 struct entry *pother = section_entry_by_name(psection, name);
3397
3398 if (pother != nullptr && pother != pentry) {
3399 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3400 return FALSE;
3401 }
3402 }
3403
3404 /* Remove from hash table the old path. */
3405 secfile_hash_delete(secfile, pentry);
3406
3407 /* Really rename the entry. */
3408 free(pentry->name);
3409 pentry->name = fc_strdup(name);
3410
3411 /* Insert into hash table the new path. */
3412 secfile_hash_insert(secfile, pentry);
3413 return TRUE;
3414}
3415
3416/**********************************************************************/
3419 const char *entry_comment(const struct entry *pentry)
3420{
3421 return (pentry != nullptr ? pentry->comment : nullptr);
3422}
3423
3424/**********************************************************************/
3427 void entry_set_comment(struct entry *pentry, const char *comment)
3428{
3429 if (pentry == nullptr) {
3430 return;
3431 }
3432
3433 if (pentry->comment != nullptr) {
3434 free(pentry->comment);
3435 }
3436
3437 pentry->comment = (comment != nullptr ? fc_strdup(comment) : nullptr);
3438}
3439
3440/**********************************************************************/
3443 static inline bool entry_used(const struct entry *pentry)
3444{
3445 return (0 < pentry->used);
3446}
3447
3448/**********************************************************************/
3451 static inline void entry_use(struct entry *pentry)
3452{
3453 pentry->used++;
3454}
3455
3456/**********************************************************************/
3460 bool entry_bool_get(const struct entry *pentry, bool *value)
3461{
3462 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3463
3464 if (ENTRY_INT == pentry->type
3465 && (pentry->integer.value == 0
3466 || pentry->integer.value == 1)
3467 && pentry->psection != nullptr
3468 && pentry->psection->secfile != nullptr
3469 && pentry->psection->secfile->allow_digital_boolean) {
3470 *value = (0 != pentry->integer.value);
3471 return TRUE;
3472 }
3473
3474 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection != nullptr
3475 ? pentry->psection->secfile : nullptr,
3476 pentry->psection,
3477 ENTRY_BOOL == pentry->type, FALSE);
3478
3479 if (value != nullptr) {
3480 *value = pentry->boolean.value;
3481 }
3482
3483 return TRUE;
3484}
3485
3486/**********************************************************************/
3489 bool entry_bool_set(struct entry *pentry, bool value)
3490{
3491 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3492 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3493 ENTRY_BOOL == pentry->type, FALSE);
3494
3495 pentry->boolean.value = value;
3496 return TRUE;
3497}
3498
3499/**********************************************************************/
3502 bool entry_float_get(const struct entry *pentry, float *value)
3503{
3504 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3505 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3506 ENTRY_FLOAT == pentry->type, FALSE);
3507
3508 if (value != nullptr) {
3509 *value = pentry->floating.value;
3510 }
3511
3512 return TRUE;
3513}
3514
3515/**********************************************************************/
3518 bool entry_float_set(struct entry *pentry, float value)
3519{
3520 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3521 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3522 ENTRY_FLOAT == pentry->type, FALSE);
3523
3524 pentry->floating.value = value;
3525
3526 return TRUE;
3527}
3528
3529/**********************************************************************/
3532 bool entry_int_get(const struct entry *pentry, int *value)
3533{
3534 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3535 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3536 ENTRY_INT == pentry->type, FALSE);
3537
3538 if (value != nullptr) {
3539 *value = pentry->integer.value;
3540 }
3541
3542 return TRUE;
3543}
3544
3545/**********************************************************************/
3548 bool entry_int_set(struct entry *pentry, int value)
3549{
3550 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3551 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3552 ENTRY_INT == pentry->type, FALSE);
3553
3554 pentry->integer.value = value;
3555 return TRUE;
3556}
3557
3558/**********************************************************************/
3561 bool entry_str_get(const struct entry *pentry, const char **value)
3562{
3563 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3564 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3565 ENTRY_STR == pentry->type, FALSE);
3566
3567 if (value != nullptr) {
3568 *value = pentry->string.value;
3569 }
3570
3571 return TRUE;
3572}
3573
3574/**********************************************************************/
3577 bool entry_str_set(struct entry *pentry, const char *value)
3578{
3579 char *old_val;
3580
3581 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3582 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3583 ENTRY_STR == pentry->type, FALSE);
3584
3585 /* We free() old value only after we've placed the new one, to
3586 * support secfile_replace_str_vec() calls that want to keep some of
3587 * the entries from the old vector in the new one. We don't want
3588 * to lose the entry in between. */
3589 old_val = pentry->string.value;
3590 pentry->string.value = fc_strdup(value != nullptr ? value : "");
3591 free(old_val);
3592
3593 return TRUE;
3594}
3595
3596/**********************************************************************/
3599 bool entry_str_escaped(const struct entry *pentry)
3600{
3601 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3602 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3603 ENTRY_STR == pentry->type, FALSE);
3604
3605 return pentry->string.escaped;
3606}
3607
3608/**********************************************************************/
3611 bool entry_str_set_escaped(struct entry *pentry, bool escaped)
3612{
3613 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3614 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3615 ENTRY_STR == pentry->type, FALSE);
3616
3617 pentry->string.escaped = escaped;
3618
3619 return TRUE;
3620}
3621
3622/**********************************************************************/
3625 bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
3626{
3627 SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, pentry != nullptr, FALSE);
3628 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3629 ENTRY_STR == pentry->type, FALSE);
3630
3631 pentry->string.gt_marking = gt_marking;
3632
3633 return TRUE;
3634}
3635
3636/**********************************************************************/
3639 static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
3640{
3641 static char buf[8192];
3642 char *dot = nullptr;
3643 int i;
3644
3645 switch (pentry->type) {
3646 case ENTRY_BOOL:
3647 fz_fprintf(fs, "%s", pentry->boolean.value ? "TRUE" : "FALSE");
3648 break;
3649 case ENTRY_INT:
3650 fz_fprintf(fs, "%d", pentry->integer.value);
3651 break;
3652 case ENTRY_FLOAT:
3653 snprintf(buf, sizeof(buf), "%f", pentry->floating.value);
3654 for (i = 0; buf[i] != '\0' ; i++) {
3655 if (buf[i] == '.') {
3656 dot = &(buf[i]);
3657 break;
3658 }
3659 }
3660 if (dot == nullptr) {
3661 /* There's no '.' so it would seem like a integer value when loaded.
3662 * Force it not to look like an integer by adding ".0" */
3663 fz_fprintf(fs, "%s.0", buf);
3664 } else {
3665 fz_fprintf(fs, "%s", buf);
3666 }
3667 break;
3668 case ENTRY_STR:
3669 if (pentry->string.escaped) {
3670 make_escapes(pentry->string.value, buf, sizeof(buf));
3671 if (pentry->string.gt_marking) {
3672 fz_fprintf(fs, "_(\"%s\")", buf);
3673 } else {
3674 fz_fprintf(fs, "\"%s\"", buf);
3675 }
3676 } else if (pentry->string.raw) {
3677 fz_fprintf(fs, "%s", pentry->string.value);
3678 } else {
3679 fz_fprintf(fs, "$%s$", pentry->string.value);
3680 }
3681 break;
3682 case ENTRY_FILEREFERENCE:
3683 fz_fprintf(fs, "*%s*", pentry->string.value);
3684 break;
3685 case ENTRY_LONG_COMMENT:
3686 fz_fprintf(fs, "%s\n", pentry->comment);
3687 break;
3688 case ENTRY_ILLEGAL:
3689 fc_assert(pentry->type != ENTRY_ILLEGAL);
3690 break;
3691 }
3692}
3693
3694/**********************************************************************/
3697 static void entry_from_inf_token(struct section *psection, const char *name,
3698 const char *tok, struct inputfile *inf)
3699{
3700 if (!entry_from_token(psection, name, tok)) {
3701 log_error("%s", inf_log_str(inf, "Entry value not recognized: %s", tok));
3702 }
3703}
astr_free
void astr_free(struct astring *astr)
Definition astring.c:148
astr_set
void astr_set(struct astring *astr, const char *format,...)
Definition astring.c:251
astr_init
void astr_init(struct astring *astr)
Definition astring.c:139
str
#define str
Definition astring.c:76
astring.h
astr_str
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
ASTRING_INIT
#define ASTRING_INIT
Definition astring.h:44
bugreport_request
void bugreport_request(const char *reason_format,...)
Definition bugs.c:31
bugs.h
incite_cost
char * incite_cost
Definition comments.c:74
are_deprecation_warnings_enabled
bool are_deprecation_warnings_enabled(void)
Definition deprecations.c:43
deprecations.h
log_deprecation_always
#define log_deprecation_always(message,...)
Definition deprecations.h:51
base
static void base(QVariant data1, QVariant data2)
Definition dialogs.cpp:2938
fcintl.h
_
#define _(String)
Definition fcintl.h:67
inf_log_str
char * inf_log_str(struct inputfile *inf, const char *message,...)
Definition inputfile.c:571
inf_at_eof
bool inf_at_eof(struct inputfile *inf)
Definition inputfile.c:349
inf_from_file
struct inputfile * inf_from_file(const char *filename, datafilename_fn_t datafn)
Definition inputfile.c:220
inf_from_stream
struct inputfile * inf_from_stream(fz_FILE *stream, datafilename_fn_t datafn)
Definition inputfile.c:244
name
const char * name
Definition inputfile.c:127
inf_close
void inf_close(struct inputfile *inf)
Definition inputfile.c:303
inf_discard_tokens
int inf_discard_tokens(struct inputfile *inf, enum inf_token_type type)
Definition inputfile.c:650
inf_token
const char * inf_token(struct inputfile *inf, enum inf_token_type type)
Definition inputfile.c:611
inputfile.h
INF_TOK_EOL
@ INF_TOK_EOL
Definition inputfile.h:45
INF_TOK_COMMA
@ INF_TOK_COMMA
Definition inputfile.h:48
INF_TOK_TABLE_END
@ INF_TOK_TABLE_END
Definition inputfile.h:47
INF_TOK_VALUE
@ INF_TOK_VALUE
Definition inputfile.h:49
INF_TOK_TABLE_START
@ INF_TOK_TABLE_START
Definition inputfile.h:46
INF_TOK_ENTRY_NAME
@ INF_TOK_ENTRY_NAME
Definition inputfile.h:44
INF_TOK_SECTION_NAME
@ INF_TOK_SECTION_NAME
Definition inputfile.h:43
fz_fprintf
int fz_fprintf(fz_FILE *fp, const char *format,...)
Definition ioz.c:971
fz_from_file
fz_FILE * fz_from_file(const char *filename, const char *in_mode, enum fz_method method, int compress_level)
Definition ioz.c:230
fz_strerror
const char * fz_strerror(fz_FILE *fp)
Definition ioz.c:1157
fz_fclose
int fz_fclose(fz_FILE *fp)
Definition ioz.c:571
fz_ferror
int fz_ferror(fz_FILE *fp)
Definition ioz.c:1099
ioz.h
fz_method
fz_method
Definition ioz.h:36
log.h
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
log_error
#define log_error(message,...)
Definition log.h:103
log_testmatic
#define log_testmatic(message,...)
Definition log.h:123
mem.h
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
len
int len
Definition packhand.c:127
registry.h
secfile_new
struct section_file * secfile_new(bool allow_duplicates)
Definition section_file.c:73
section_name
const char * section_name(const struct section *psection)
Definition section_file.c:65
secfile_destroy
void secfile_destroy(struct section_file *secfile)
Definition section_file.c:95
entry_new
static struct entry * entry_new(struct section *psection, const char *name)
Definition registry_ini.c:3135
secfile_lookup_bitwise_enum_default_full
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,...)
Definition registry_ini.c:2495
entry_set_comment
void entry_set_comment(struct entry *pentry, const char *comment)
Definition registry_ini.c:3427
secfile_insert_bool_vec_full
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,...)
Definition registry_ini.c:1039
entry_bool_get
bool entry_bool_get(const struct entry *pentry, bool *value)
Definition registry_ini.c:3460
section_destroy
void section_destroy(struct section *psection)
Definition registry_ini.c:2975
secfile_lookup_float
bool secfile_lookup_float(const struct section_file *secfile, float *fval, const char *path,...)
Definition registry_ini.c:2127
secfile_check_unused
void secfile_check_unused(const struct section_file *secfile)
Definition registry_ini.c:907
entry_path
int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
Definition registry_ini.c:3353
secfile_lookup_int
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
Definition registry_ini.c:1978
secfile_insert_long_comment
struct section * secfile_insert_long_comment(struct section_file *secfile, const char *comment)
Definition registry_ini.c:1236
section_entry_filereference_new
static struct entry * section_entry_filereference_new(struct section *psection, const char *name, const char *value)
Definition registry_ini.c:3253
MAX_LEN_SECPATH
#define MAX_LEN_SECPATH
Definition registry_ini.c:175
secfile_entry_delete
bool secfile_entry_delete(struct section_file *secfile, const char *path,...)
Definition registry_ini.c:1832
entry_set_name
bool entry_set_name(struct entry *pentry, const char *name)
Definition registry_ini.c:3371
secfile_lookup_enum_data
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,...)
Definition registry_ini.c:2614
secfile_hash_insert
static bool secfile_hash_insert(struct section_file *secfile, struct entry *pentry)
Definition registry_ini.c:256
entry_str_escaped
bool entry_str_escaped(const struct entry *pentry)
Definition registry_ini.c:3599
section_entry_int_new
struct entry * section_entry_int_new(struct section *psection, const char *name, int value)
Definition registry_ini.c:3185
secfile_insert_bool_full
struct entry * secfile_insert_bool_full(struct section_file *secfile, bool value, const char *comment, bool allow_replace, const char *path,...)
Definition registry_ini.c:988
secfile_insert_comment
struct entry * secfile_insert_comment(struct section_file *secfile, const char *str, const char *path,...)
Definition registry_ini.c:1322
secfile_insert_int_full
struct entry * secfile_insert_int_full(struct section_file *secfile, int value, const char *comment, bool allow_replace, const char *path,...)
Definition registry_ini.c:1075
entry_section
struct section * entry_section(const struct entry *pentry)
Definition registry_ini.c:3337
section_entry_comment_new
static struct entry * section_entry_comment_new(struct section *psection, const char *comment)
Definition registry_ini.c:3270
secfile_sections_by_name_prefix
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
Definition registry_ini.c:2877
secfile_lookup_enum_default_data
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,...)
Definition registry_ini.c:2696
section_entries
const struct entry_list * section_entries(const struct section *psection)
Definition registry_ini.c:3079
secfile_load_section
struct section_file * secfile_load_section(const char *filename, const char *section, bool allow_duplicates)
Definition registry_ini.c:596
entry_bool_set
bool entry_bool_set(struct entry *pentry, bool value)
Definition registry_ini.c:3489
secfile_from_stream
struct section_file * secfile_from_stream(fz_FILE *stream, bool allow_duplicates)
Definition registry_ini.c:610
secfile_insert_bitwise_enum_vec_full
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,...)
Definition registry_ini.c:1610
entry_to_file
static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
Definition registry_ini.c:3639
entry_from_inf_token
static void entry_from_inf_token(struct section *psection, const char *name, const char *tok, struct inputfile *file)
Definition registry_ini.c:3697
entry_float_get
bool entry_float_get(const struct entry *pentry, float *value)
Definition registry_ini.c:3502
secfile_lookup_str_vec
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Definition registry_ini.c:2244
entry_str_set_escaped
bool entry_str_set_escaped(struct entry *pentry, bool escaped)
Definition registry_ini.c:3611
entry_name
const char * entry_name(const struct entry *pentry)
Definition registry_ini.c:3363
secfile_entry_lookup
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:1858
entry_str_get
bool entry_str_get(const struct entry *pentry, const char **value)
Definition registry_ini.c:3561
secfile_insert_enum_data_full
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,...)
Definition registry_ini.c:1662
entry_str_set_gt_marking
bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
Definition registry_ini.c:3625
SAVE_TABLES
#define SAVE_TABLES
Definition registry_ini.c:178
secfile_insert_int_vec_full
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,...)
Definition registry_ini.c:1126
secfile_lookup_str
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:2180
entry_destroy
void entry_destroy(struct entry *pentry)
Definition registry_ini.c:3286
entry_used
static bool entry_used(const struct entry *pentry)
Definition registry_ini.c:3443
section_clear_all
void section_clear_all(struct section *psection)
Definition registry_ini.c:3002
secfile_lookup_int_vec
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Definition registry_ini.c:2081
entry_float_set
bool entry_float_set(struct entry *pentry, float value)
Definition registry_ini.c:3518
secfile_lookup_float_default
float secfile_lookup_float_default(const struct section_file *secfile, float def, const char *path,...)
Definition registry_ini.c:2152
secfile_lookup_bool_vec
bool * secfile_lookup_bool_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Definition registry_ini.c:1932
secfile_lookup_plain_enum_default_full
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,...)
Definition registry_ini.c:2333
secfile_insert_str_vec_full
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,...)
Definition registry_ini.c:1359
secfile_insert_plain_enum_vec_full
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,...)
Definition registry_ini.c:1489
secfile_save
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
Definition registry_ini.c:644
secfile_insert_float_full
struct entry * secfile_insert_float_full(struct section_file *secfile, float value, const char *comment, bool allow_replace, const char *path,...)
Definition registry_ini.c:1162
secfile_insert_include
struct section * secfile_insert_include(struct section_file *secfile, const char *filename)
Definition registry_ini.c:1212
secfile_insert_plain_enum_full
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,...)
Definition registry_ini.c:1432
secfile_lookup_bool_default
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Definition registry_ini.c:1902
entry_int_set
bool entry_int_set(struct entry *pentry, int value)
Definition registry_ini.c:3548
is_secfile_entry_name_valid
static bool is_secfile_entry_name_valid(const char *name)
Definition registry_ini.c:240
section_entry_by_name
struct entry * section_entry_by_name(const struct section *psection, const char *name)
Definition registry_ini.c:3087
secfile_sections
const struct section_list * secfile_sections(const struct section_file *secfile)
Definition registry_ini.c:2866
secfile_insert_filereference
struct entry * secfile_insert_filereference(struct section_file *secfile, const char *filename, const char *path,...)
Definition registry_ini.c:1396
section_set_name
bool section_set_name(struct section *psection, const char *name)
Definition registry_ini.c:3019
section_entry_str_new
struct entry * section_entry_str_new(struct section *psection, const char *name, const char *value, bool escaped)
Definition registry_ini.c:3233
section_entry_float_new
struct entry * section_entry_float_new(struct section *psection, const char *name, float value)
Definition registry_ini.c:3217
secfile_lookup_int_default
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Definition registry_ini.c:2004
section_entry_lookup
struct entry * section_entry_lookup(const struct section *psection, const char *path,...)
Definition registry_ini.c:3105
entry_int_get
bool entry_int_get(const struct entry *pentry, int *value)
Definition registry_ini.c:3532
secfile_lookup_bitwise_enum_vec_full
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,...)
Definition registry_ini.c:2559
entry_use
static void entry_use(struct entry *pentry)
Definition registry_ini.c:3451
secfile_lookup_enum_vec_data
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,...)
Definition registry_ini.c:2779
section_entry_bool_new
struct entry * section_entry_bool_new(struct section *psection, const char *name, bool value)
Definition registry_ini.c:3201
secfile_lookup_plain_enum_full
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,...)
Definition registry_ini.c:2290
secfile_name
const char * secfile_name(const struct section_file *secfile)
Definition registry_ini.c:943
secfile_section_new
struct section * secfile_section_new(struct section_file *secfile, const char *name)
Definition registry_ini.c:2931
entry_comment
const char * entry_comment(const struct entry *pentry)
Definition registry_ini.c:3419
secfile_hash_delete
static bool secfile_hash_delete(struct section_file *secfile, struct entry *pentry)
Definition registry_ini.c:285
secfile_entry_by_path
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
Definition registry_ini.c:1785
secfile_from_input_file
static struct section_file * secfile_from_input_file(struct inputfile *inf, const char *filename, const char *section, bool allow_duplicates)
Definition registry_ini.c:303
secfile_section_by_name
struct section * secfile_section_by_name(const struct section_file *secfile, const char *name)
Definition registry_ini.c:2829
secfile_insert_bitwise_enum_full
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,...)
Definition registry_ini.c:1531
secfile_insert_str_full
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,...)
Definition registry_ini.c:1260
secfile_lookup_plain_enum_vec_full
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,...)
Definition registry_ini.c:2376
secfile_section_lookup
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:2846
secfile_lookup_str_default
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Definition registry_ini.c:2210
secfile_section_prefix_present
bool secfile_section_prefix_present(const struct section_file *secfile, const char *prefix)
Definition registry_ini.c:2906
is_legal_table_entry_name
static bool is_legal_table_entry_name(char c, bool num)
Definition registry_ini.c:620
entry_str_set
bool entry_str_set(struct entry *pentry, const char *value)
Definition registry_ini.c:3577
secfile_lookup_bitwise_enum_full
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,...)
Definition registry_ini.c:2430
secfile_insert_enum_vec_data_full
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,...)
Definition registry_ini.c:1741
secfile_lookup_bool
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
Definition registry_ini.c:1876
datafilename
static const char * datafilename(const char *filename)
Definition registry_ini.c:232
secfile_lookup_int_def_min_max
int secfile_lookup_int_def_min_max(const struct section_file *secfile, int defval, int minval, int maxval, const char *path,...)
Definition registry_ini.c:2034
secfile_insert_base
static struct section * secfile_insert_base(struct section_file *secfile, const char *path, const char **pent_name)
Definition registry_ini.c:957
entry_type_get
enum entry_type entry_type_get(const struct entry *pentry)
Definition registry_ini.c:3345
registry_ini.h
secfile_enum_iter_fn_t
int(* secfile_enum_iter_fn_t)(void)
Definition registry_ini.h:37
secfile_enum_name_data_fn_t
const char *(* secfile_enum_name_data_fn_t)(secfile_data_t data, int enumerator)
Definition registry_ini.h:39
entry_type
entry_type
Definition registry_ini.h:631
ENTRY_FILEREFERENCE
@ ENTRY_FILEREFERENCE
Definition registry_ini.h:636
ENTRY_LONG_COMMENT
@ ENTRY_LONG_COMMENT
Definition registry_ini.h:637
ENTRY_INT
@ ENTRY_INT
Definition registry_ini.h:633
ENTRY_FLOAT
@ ENTRY_FLOAT
Definition registry_ini.h:634
ENTRY_STR
@ ENTRY_STR
Definition registry_ini.h:635
ENTRY_ILLEGAL
@ ENTRY_ILLEGAL
Definition registry_ini.h:638
ENTRY_BOOL
@ ENTRY_BOOL
Definition registry_ini.h:632
section_list_iterate
#define section_list_iterate(seclist, psection)
Definition registry_ini.h:45
entry_list_iterate_end
#define entry_list_iterate_end
Definition registry_ini.h:57
secfile_enum_is_valid_fn_t
bool(* secfile_enum_is_valid_fn_t)(int enumerator)
Definition registry_ini.h:32
entry_special_type
entry_special_type
Definition registry_ini.h:71
EST_COMMENT
@ EST_COMMENT
Definition registry_ini.h:71
EST_NORMAL
@ EST_NORMAL
Definition registry_ini.h:71
EST_INCLUDE
@ EST_INCLUDE
Definition registry_ini.h:71
secfile_enum_name_fn_t
const char *(* secfile_enum_name_fn_t)(int enumerator)
Definition registry_ini.h:33
section_list_iterate_end
#define section_list_iterate_end
Definition registry_ini.h:47
entry_list_iterate
#define entry_list_iterate(entlist, pentry)
Definition registry_ini.h:55
secfile_enum_by_name_fn_t
int(* secfile_enum_by_name_fn_t)(const char *enum_name, int(*strcmp_fn)(const char *, const char *))
Definition registry_ini.h:34
secfile_enum_next_fn_t
int(* secfile_enum_next_fn_t)(int enumerator)
Definition registry_ini.h:38
secfile_data_t
const void * secfile_data_t
Definition registry_ini.h:30
entry_from_token
bool entry_from_token(struct section *psection, const char *name, const char *tok)
Definition section_file.c:134
section_file.h
SECFILE_LOG
#define SECFILE_LOG(secfile, psection, format,...)
Definition section_file.h:59
SECFILE_RETURN_VAL_IF_FAIL
#define SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, condition, value)
Definition section_file.h:67
SECFILE_RETURN_IF_FAIL
#define SECFILE_RETURN_IF_FAIL(secfile, psection, condition)
Definition section_file.h:62
fileinfoname
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1094
interpret_tilde
void interpret_tilde(char *buf, size_t buf_size, const char *filename)
Definition shared.c:1710
remove_leading_trailing_spaces
void remove_leading_trailing_spaces(char *s)
Definition shared.c:444
get_data_dirs
const struct strvec * get_data_dirs(void)
Definition shared.c:886
shared.h
specvec.h
astring
Definition astring.h:36
entry
Definition registry_ini.c:193
entry::type
enum entry_type type
Definition registry_ini.c:196
entry::value
int value
Definition registry_ini.c:207
entry::gt_marking
bool gt_marking
Definition registry_ini.c:218
entry::value
char * value
Definition registry_ini.c:215
entry::raw
bool raw
Definition registry_ini.c:217
entry::used
int used
Definition registry_ini.c:197
entry::psection
struct section * psection
Definition registry_ini.c:194
entry::value
float value
Definition registry_ini.c:211
entry::escaped
bool escaped
Definition registry_ini.c:216
entry::value
bool value
Definition registry_ini.c:203
entry::comment
char * comment
Definition registry_ini.c:198
entry::name
char * name
Definition registry_ini.c:195
fz_FILE_s
Definition ioz.c:149
inputfile
Definition inputfile.c:90
section_file
Definition section_file.h:36
section_file::entries
struct entry_hash * entries
Definition section_file.h:49
section_file::hash
struct section_file::@8 hash
section_file::name
char * name
Definition section_file.h:37
section_file::sections
struct section_list * sections
Definition section_file.h:44
section_file::allow_duplicates
bool allow_duplicates
Definition section_file.h:45
section_file::num_includes
unsigned int num_includes
Definition section_file.h:42
section_file::num_long_comments
unsigned int num_long_comments
Definition section_file.h:43
section_file::num_entries
size_t num_entries
Definition section_file.h:38
section
Definition section_file.h:28
section::entries
struct entry_list * entries
Definition section_file.h:32
section::name
char * name
Definition section_file.h:31
section::special
enum entry_special_type special
Definition section_file.h:30
section::secfile
struct section_file * secfile
Definition section_file.h:29
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
fc_isalpha
bool fc_isalpha(char c)
Definition support.c:1207
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
make_escapes
void make_escapes(const char *str, char *buf, size_t buf_len)
Definition support.c:294
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:186
cat_snprintf
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:986
fc_vsnprintf
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:886
fc_isalnum
bool fc_isalnum(char c)
Definition support.c:1196
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
sz_strlcat
#define sz_strlcat(dest, src)
Definition support.h:190
fc_strncmp
#define fc_strncmp(_s1_, _s2_, _len_)
Definition support.h:154