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 NULL. */
199
200 union {
201 /* ENTRY_BOOL */
202 struct {
203 bool value;
204 } boolean;
205 /* ENTRY_INT */
206 struct {
207 int value;
208 } integer;
209 /* ENTRY_FLOAT */
210 struct {
211 float value;
212 } floating;
213 /* ENTRY_STR */
214 struct {
215 char *value; /* Malloced string. */
216 bool escaped; /* " or $. Usually TRUE */
217 bool raw; /* Do not add anything. */
218 bool gt_marking; /* Save with gettext marking. */
219 } string;
220 };
221};
222
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) && NULL == strchr(allowed, *name)) {
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 (NULL == secfile->hash.entries) {
263 /* Consider as success if this secfile doesn't have built the entries
264 * hash table. */
265 return TRUE;
266 }
267
268 entry_path(pentry, buf, sizeof(buf));
269 if (entry_hash_replace_full(secfile->hash.entries, buf, pentry,
270 NULL, &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 (NULL == secfile->hash.entries) {
291 /* Consider as success if this secfile doesn't have built the entries
292 * hash table. */
293 return TRUE;
294 }
295
296 entry_path(pentry, buf, sizeof(buf));
297 return entry_hash_remove(secfile->hash.entries, buf);
298}
299
300/**********************************************************************/
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 = NULL;
310 struct section *single_section = NULL;
311 bool table_state = FALSE; /* TRUE when within tabular format. */
312 int table_lineno = 0; /* Row number in tabular, 0 top data row. */
313 const char *tok;
314 int i;
315 struct astring base_name = ASTRING_INIT; /* for table or single entry */
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 NULL;
323 }
324
325 /* Assign the real value later, to speed up the creation of new entries. */
326 secfile = secfile_new(TRUE);
327 if (filename) {
328 secfile->name = fc_strdup(filename);
329 } else {
330 secfile->name = NULL;
331 }
332
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 != NULL) {
550 if (!found_my_section) {
551 secfile_destroy(secfile);
552 return NULL;
553 }
554
555 /* Build the entry hash table with single section information */
556 secfile->allow_duplicates = allow_duplicates;
557 entry_list_iterate(section_entries(single_section), pentry) {
558 if (!secfile_hash_insert(secfile, pentry)) {
559 secfile_destroy(secfile);
560 return NULL;
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 NULL;
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 NULL, NULL, 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, NULL, NULL != secfile, FALSE);
656
657 if (NULL == filename) {
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, NULL, _("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 NULL).
707 * After each table, loop again in case the next entry
708 * is another table.
709 */
710 for (;;) {
711 char *c, *first, base[64];
712 int offset, irow, icol, ncol;
713
714 /* Example: for first table name of "xyz0.blah":
715 * first points to the original string pentry->name
716 * base contains "xyz";
717 * offset = 5 (so first+offset gives "blah")
718 * note strlen(base) = offset - 2
719 */
720
721 if (!SAVE_TABLES) {
722 break;
723 }
724
725 if (pentry->type == ENTRY_LONG_COMMENT) {
726 break;
727 }
728
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 (NULL == col_pentry || 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, NULL, "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, NULL, "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 != NULL ? 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 != NULL ? 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 (NULL == secfile) {
946 return "NULL";
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, NULL,
970 "Section and entry names must be separated by a dot.");
971 return NULL;
972 }
973
974 /* Separates section and entry names. */
975 *ent_name = '\0';
976 *pent_name = path + (ent_name - fullpath) + 1;
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 = NULL;
997 va_list args;
998
999 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1000
1001 va_start(args, path);
1002 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1003 va_end(args);
1004
1005 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1006 if (!psection) {
1007 return NULL;
1008 }
1009
1010 if (allow_replace) {
1011 pentry = section_entry_by_name(psection, ent_name);
1012 if (NULL != pentry) {
1013 if (ENTRY_BOOL == entry_type_get(pentry)) {
1014 if (!entry_bool_set(pentry, value)) {
1015 return NULL;
1016 }
1017 } else {
1018 entry_destroy(pentry);
1019 pentry = NULL;
1020 }
1021 }
1022 }
1023
1024 if (NULL == pentry) {
1025 pentry = section_entry_bool_new(psection, ent_name, value);
1026 }
1027
1028 if (NULL != pentry && NULL != comment) {
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, NULL, NULL != secfile, 0);
1049
1050 va_start(args, path);
1051 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1052 va_end(args);
1053
1054 /* NB: 'path,0' is actually 'path'. See comment in the head
1055 * of the file. */
1056 if (dim > 0
1057 && NULL != secfile_insert_bool_full(secfile, values[0], comment,
1058 allow_replace, "%s", fullpath)) {
1059 ret++;
1060 }
1061 for (i = 1; i < dim; i++) {
1062 if (NULL != secfile_insert_bool_full(secfile, values[i], comment,
1063 allow_replace, "%s,%d",
1064 fullpath, (int) i)) {
1065 ret++;
1066 }
1067 }
1068
1069 return ret;
1070}
1071
1072/**********************************************************************/
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 = NULL;
1084 va_list args;
1085
1086 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1087
1088 va_start(args, path);
1089 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1090 va_end(args);
1091
1092 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1093 if (!psection) {
1094 return NULL;
1095 }
1096
1097 if (allow_replace) {
1098 pentry = section_entry_by_name(psection, ent_name);
1099 if (NULL != pentry) {
1100 if (ENTRY_INT == entry_type_get(pentry)) {
1101 if (!entry_int_set(pentry, value)) {
1102 return NULL;
1103 }
1104 } else {
1105 entry_destroy(pentry);
1106 pentry = NULL;
1107 }
1108 }
1109 }
1110
1111 if (NULL == pentry) {
1112 pentry = section_entry_int_new(psection, ent_name, value);
1113 }
1114
1115 if (NULL != pentry && NULL != comment) {
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, NULL, NULL != secfile, 0);
1136
1137 va_start(args, path);
1138 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1139 va_end(args);
1140
1141 /* NB: 'path,0' is actually 'path'. See comment in the head
1142 * of the file. */
1143 if (dim > 0
1144 && NULL != secfile_insert_int_full(secfile, values[0], comment,
1145 allow_replace, "%s", fullpath)) {
1146 ret++;
1147 }
1148 for (i = 1; i < dim; i++) {
1149 if (NULL != secfile_insert_int_full(secfile, values[i], comment,
1150 allow_replace, "%s,%d",
1151 fullpath, (int) i)) {
1152 ret++;
1153 }
1154 }
1155
1156 return ret;
1157}
1158
1159/**********************************************************************/
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 = NULL;
1171 va_list args;
1172
1173 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1174
1175 va_start(args, path);
1176 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1177 va_end(args);
1178
1179 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1180 if (!psection) {
1181 return NULL;
1182 }
1183
1184 if (allow_replace) {
1185 pentry = section_entry_by_name(psection, ent_name);
1186 if (NULL != pentry) {
1187 if (ENTRY_FLOAT == entry_type_get(pentry)) {
1188 if (!entry_float_set(pentry, value)) {
1189 return NULL;
1190 }
1191 } else {
1192 entry_destroy(pentry);
1193 pentry = NULL;
1194 }
1195 }
1196 }
1197
1198 if (NULL == pentry) {
1199 pentry = section_entry_float_new(psection, ent_name, value);
1200 }
1201
1202 if (NULL != pentry && NULL != comment) {
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) == NULL, NULL);
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, NULL, 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) == NULL, NULL);
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, NULL, 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 = NULL;
1272 va_list args;
1273
1274 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1275
1276 va_start(args, path);
1277 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1278 va_end(args);
1279
1280 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1281 if (!psection) {
1282 return NULL;
1283 }
1284
1285 if (psection->special != stype) {
1286 log_error("Tried to insert wrong type of entry to section");
1287 return NULL;
1288 }
1289
1290 if (allow_replace) {
1291 pentry = section_entry_by_name(psection, ent_name);
1292 if (NULL != pentry) {
1293 if (ENTRY_STR == entry_type_get(pentry)) {
1294 if (!entry_str_set(pentry, str)) {
1295 return NULL;
1296 }
1297 } else {
1298 entry_destroy(pentry);
1299 pentry = NULL;
1300 }
1301 }
1302 }
1303
1304 if (NULL == pentry) {
1305 pentry = section_entry_str_new(psection, ent_name, str, !no_escape);
1306 }
1307
1308 if (NULL != pentry && NULL != comment) {
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 = NULL;
1330 va_list args;
1331
1332 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1333
1334 va_start(args, path);
1335 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1336 va_end(args);
1337
1338 sz_strlcat(fullpath, ".#");
1339
1340 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1341 if (!psection) {
1342 return NULL;
1343 }
1344
1345 if (psection->special != EST_NORMAL) {
1346 log_error("Tried to insert wrong type of entry to section");
1347 return NULL;
1348 }
1349
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, NULL, NULL != secfile, 0);
1369
1370 va_start(args, path);
1371 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1372 va_end(args);
1373
1374 /* NB: 'path,0' is actually 'path'. See comment in the head
1375 * of the file. */
1376 if (dim > 0
1377 && NULL != secfile_insert_str_full(secfile, strings[0], comment,
1378 allow_replace, no_escape, FALSE,
1379 "%s", fullpath)) {
1380 ret++;
1381 }
1382 for (i = 1; i < dim; i++) {
1383 if (NULL != secfile_insert_str_full(secfile, strings[i], comment,
1384 allow_replace, no_escape, FALSE,
1385 "%s,%d", fullpath, (int) i)) {
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 = NULL;
1404 va_list args;
1405
1406 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1407
1408 va_start(args, path);
1409 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1410 va_end(args);
1411
1412 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1413 if (!psection) {
1414 return NULL;
1415 }
1416
1417 if (psection->special != EST_NORMAL) {
1418 log_error("Tried to insert normal entry to different kind of section");
1419 return NULL;
1420 }
1421
1422 if (NULL == pentry) {
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 = NULL;
1444 va_list args;
1445
1446 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1447 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1448 str = name_fn(enumerator);
1449 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != str, NULL);
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 NULL;
1458 }
1459
1460 if (allow_replace) {
1461 pentry = section_entry_by_name(psection, ent_name);
1462 if (NULL != pentry) {
1463 if (ENTRY_STR == entry_type_get(pentry)) {
1464 if (!entry_str_set(pentry, str)) {
1465 return NULL;
1466 }
1467 } else {
1468 entry_destroy(pentry);
1469 pentry = NULL;
1470 }
1471 }
1472 }
1473
1474 if (NULL == pentry) {
1475 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1476 }
1477
1478 if (NULL != pentry && NULL != comment) {
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, NULL, NULL != secfile, 0);
1501 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 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 && NULL != secfile_insert_plain_enum_full(secfile, enumurators[0],
1511 name_fn, comment,
1512 allow_replace, "%s",
1513 fullpath)) {
1514 ret++;
1515 }
1516 for (i = 1; i < dim; i++) {
1517 if (NULL != secfile_insert_plain_enum_full(secfile, enumurators[i],
1518 name_fn, comment,
1519 allow_replace, "%s,%d",
1520 fullpath, (int) i)) {
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 = NULL;
1549 va_list args;
1550 int i;
1551
1552 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1553 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1554 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, NULL);
1555 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, NULL);
1556 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, NULL);
1557
1558 /* Compute a string containing all the values separated by '|'. */
1559 str[0] = '\0'; /* Insert at least an empty string. */
1560 if (0 != bitwise_val) {
1561 for (i = begin_fn(); i != end_fn(); i = next_fn(i)) {
1562 if (i & bitwise_val) {
1563 if ('\0' == str[0]) {
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 NULL;
1579 }
1580
1581 if (allow_replace) {
1582 pentry = section_entry_by_name(psection, ent_name);
1583 if (NULL != pentry) {
1584 if (ENTRY_STR == entry_type_get(pentry)) {
1585 if (!entry_str_set(pentry, str)) {
1586 return NULL;
1587 }
1588 } else {
1589 entry_destroy(pentry);
1590 pentry = NULL;
1591 }
1592 }
1593 }
1594
1595 if (NULL == pentry) {
1596 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1597 }
1598
1599 if (NULL != pentry && NULL != comment) {
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, NULL, NULL != secfile, 0);
1626 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1627 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, 0);
1628 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, 0);
1629 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, 0);
1630
1631 va_start(args, path);
1632 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1633 va_end(args);
1634
1635 /* NB: 'path,0' is actually 'path'. See comment in the head
1636 * of the file. */
1637 if (dim > 0
1638 && NULL != 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)) {
1643 ret++;
1644 }
1645 for (i = 1; i < dim; i++) {
1646 if (NULL != 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)) {
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 = NULL;
1674 va_list args;
1675 int i;
1676
1677 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1678 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1679
1680 if (bitwise) {
1681 /* Compute a string containing all the values separated by '|'. */
1682 str[0] = '\0'; /* Insert at least an empty string. */
1683 if (0 != value) {
1684 for (i = 0; (val_name = name_fn(data, i)); i++) {
1685 if ((1 << i) & value) {
1686 if ('\0' == str[0]) {
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, NULL, "Value %d not supported.", value);
1697 return NULL;
1698 }
1699 sz_strlcpy(str, val_name);
1700 }
1701
1702 va_start(args, path);
1703 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1704 va_end(args);
1705
1706 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1707 if (!psection) {
1708 return NULL;
1709 }
1710
1711 if (allow_replace) {
1712 pentry = section_entry_by_name(psection, ent_name);
1713 if (NULL != pentry) {
1714 if (ENTRY_STR == entry_type_get(pentry)) {
1715 if (!entry_str_set(pentry, str)) {
1716 return NULL;
1717 }
1718 } else {
1719 entry_destroy(pentry);
1720 pentry = NULL;
1721 }
1722 }
1723 }
1724
1725 if (NULL == pentry) {
1726 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1727 }
1728
1729 if (NULL != pentry && NULL != comment) {
1730 entry_set_comment(pentry, comment);
1731 }
1732
1733 return pentry;
1734}
1735
1736/**********************************************************************/
1740 size_t secfile_insert_enum_vec_data_full(struct section_file *secfile,
1741 const int *values, size_t dim,
1742 bool bitwise,
1743 secfile_enum_name_data_fn_t name_fn,
1744 secfile_data_t data,
1745 const char *comment,
1746 bool allow_replace,
1747 const char *path, ...)
1748{
1749 char fullpath[MAX_LEN_SECPATH];
1750 size_t i, ret = 0;
1751 va_list args;
1752
1753 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1754 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1755
1756 va_start(args, path);
1757 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1758 va_end(args);
1759
1760 /* NB: 'path,0' is actually 'path'. See comment in the head
1761 * of the file. */
1762 if (dim > 0
1763 && NULL != secfile_insert_enum_data_full(secfile, values[0], bitwise,
1764 name_fn, data, comment,
1765 allow_replace, "%s",
1766 fullpath)) {
1767 ret++;
1768 }
1769 for (i = 1; i < dim; i++) {
1770 if (NULL != secfile_insert_enum_data_full(secfile, values[i], bitwise,
1771 name_fn, data, comment,
1772 allow_replace, "%s,%d",
1773 fullpath, (int) i)) {
1774 ret++;
1775 }
1776 }
1777
1778 return ret;
1779}
1780
1781/**********************************************************************/
1784 struct entry *secfile_entry_by_path(const struct section_file *secfile,
1785 const char *path)
1786{
1787 char fullpath[MAX_LEN_SECPATH];
1788 char *ent_name;
1789 size_t len;
1790 struct section *psection;
1791
1792 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1793
1794 sz_strlcpy(fullpath, path);
1795
1796 /* treat "sec.foo,0" as "sec.foo": */
1797 len = strlen(fullpath);
1798 if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1799 fullpath[len - 2] = '\0';
1800 }
1801
1802 if (NULL != secfile->hash.entries) {
1803 struct entry *pentry;
1804
1805 if (entry_hash_lookup(secfile->hash.entries, fullpath, &pentry)) {
1806 entry_use(pentry);
1807 }
1808 return pentry;
1809 }
1810
1811 /* I dont like strtok.
1812 * - Me neither! */
1813 ent_name = strchr(fullpath, '.');
1814 if (!ent_name) {
1815 return NULL;
1816 }
1817
1818 /* Separates section and entry names. */
1819 *ent_name++ = '\0';
1820 psection = secfile_section_by_name(secfile, fullpath);
1821 if (psection) {
1822 return section_entry_by_name(psection, ent_name);
1823 } else {
1824 return NULL;
1825 }
1826}
1827
1828/**********************************************************************/
1831 bool secfile_entry_delete(struct section_file *secfile,
1832 const char *path, ...)
1833{
1834 char fullpath[MAX_LEN_SECPATH];
1835 va_list args;
1836 struct entry *pentry;
1837
1838 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1839
1840 va_start(args, path);
1841 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1842 va_end(args);
1843
1844 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1845 SECFILE_LOG(secfile, NULL, "Path %s does not exists.", fullpath);
1846 return FALSE;
1847 }
1848
1849 entry_destroy(pentry);
1850
1851 return TRUE;
1852}
1853
1854/**********************************************************************/
1857 struct entry *secfile_entry_lookup(const struct section_file *secfile,
1858 const char *path, ...)
1859{
1860 char fullpath[MAX_LEN_SECPATH];
1861 va_list args;
1862
1863 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1864
1865 va_start(args, path);
1866 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1867 va_end(args);
1868
1869 return secfile_entry_by_path(secfile, fullpath);
1870}
1871
1872/**********************************************************************/
1875 bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1876 const char *path, ...)
1877{
1878 char fullpath[MAX_LEN_SECPATH];
1879 const struct entry *pentry;
1880 va_list args;
1881
1882 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1883
1884 va_start(args, path);
1885 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1886 va_end(args);
1887
1888 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1889 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1890 return FALSE;
1891 }
1892
1893 return entry_bool_get(pentry, bval);
1894}
1895
1896/**********************************************************************/
1900 bool secfile_lookup_bool_default(const struct section_file *secfile,
1901 bool def, const char *path, ...)
1902{
1903 char fullpath[MAX_LEN_SECPATH];
1904 const struct entry *pentry;
1905 bool bval;
1906 va_list args;
1907
1908 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1909
1910 va_start(args, path);
1911 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1912 va_end(args);
1913
1914 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1915 return def;
1916 }
1917
1918 if (entry_bool_get(pentry, &bval)) {
1919 return bval;
1920 }
1921
1922 return def;
1923}
1924
1925/**********************************************************************/
1930 bool *secfile_lookup_bool_vec(const struct section_file *secfile,
1931 size_t *dim, const char *path, ...)
1932{
1933 char fullpath[MAX_LEN_SECPATH];
1934 size_t i = 0;
1935 bool *vec;
1936 va_list args;
1937
1938 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1939 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
1940
1941 va_start(args, path);
1942 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1943 va_end(args);
1944
1945 /* Check size. */
1946 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1947 i++;
1948 }
1949 *dim = i;
1950
1951 if (0 == i) {
1952 /* Doesn't exist. */
1953 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1954 return NULL;
1955 }
1956
1957 vec = fc_malloc(i * sizeof(bool));
1958 for (i = 0; i < *dim; i++) {
1959 if (!secfile_lookup_bool(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1960 SECFILE_LOG(secfile, NULL,
1961 "An error occurred when looking up to \"%s,%d\" entry.",
1962 fullpath, (int) i);
1963 free(vec);
1964 *dim = 0;
1965 return NULL;
1966 }
1967 }
1968
1969 return vec;
1970}
1971
1972/**********************************************************************/
1975 bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1976 const char *path, ...)
1977{
1978 char fullpath[MAX_LEN_SECPATH];
1979 const struct entry *pentry;
1980 va_list args;
1981
1982 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1983
1984 va_start(args, path);
1985 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1986 va_end(args);
1987
1988 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1989 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1990 return FALSE;
1991 }
1992
1993 return entry_int_get(pentry, ival);
1994}
1995
1996/**********************************************************************/
2000 int secfile_lookup_int_default(const struct section_file *secfile, int def,
2001 const char *path, ...)
2002{
2003 char fullpath[MAX_LEN_SECPATH];
2004 const struct entry *pentry;
2005 int ival;
2006 va_list args;
2007
2008 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2009
2010 va_start(args, path);
2011 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2012 va_end(args);
2013
2014 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2015 return def;
2016 }
2017
2018 if (entry_int_get(pentry, &ival)) {
2019 return ival;
2020 }
2021
2022 return def;
2023}
2024
2025/**********************************************************************/
2030 int secfile_lookup_int_def_min_max(const struct section_file *secfile,
2031 int defval, int minval, int maxval,
2032 const char *path, ...)
2033{
2034 char fullpath[MAX_LEN_SECPATH];
2035 const struct entry *pentry;
2036 int value;
2037 va_list args;
2038
2039 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2040
2041 va_start(args, path);
2042 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2043 va_end(args);
2044
2045 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2046 return defval;
2047 }
2048
2049 if (!entry_int_get(pentry, &value)) {
2050 return defval;
2051 }
2052
2053 if (value < minval) {
2054 SECFILE_LOG(secfile, entry_section(pentry),
2055 "\"%s\" should be in the interval [%d, %d] but is %d;"
2056 "using the minimal value.",
2057 fullpath, minval, maxval, value);
2058 value = minval;
2059 }
2060
2061 if (value > maxval) {
2062 SECFILE_LOG(secfile, entry_section(pentry),
2063 "\"%s\" should be in the interval [%d, %d] but is %d;"
2064 "using the maximal value.",
2065 fullpath, minval, maxval, value);
2066 value = maxval;
2067 }
2068
2069 return value;
2070}
2071
2072/**********************************************************************/
2077 int *secfile_lookup_int_vec(const struct section_file *secfile,
2078 size_t *dim, const char *path, ...)
2079{
2080 char fullpath[MAX_LEN_SECPATH];
2081 size_t i = 0;
2082 int *vec;
2083 va_list args;
2084
2085 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2086 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2087
2088 va_start(args, path);
2089 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2090 va_end(args);
2091
2092 /* Check size. */
2093 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2094 i++;
2095 }
2096 *dim = i;
2097
2098 if (0 == i) {
2099 /* Doesn't exist. */
2100 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2101 return NULL;
2102 }
2103
2104 vec = fc_malloc(i * sizeof(int));
2105 for (i = 0; i < *dim; i++) {
2106 if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
2107 SECFILE_LOG(secfile, NULL,
2108 "An error occurred when looking up to \"%s,%d\" entry.",
2109 fullpath, (int) i);
2110 free(vec);
2111 *dim = 0;
2112 return NULL;
2113 }
2114 }
2115
2116 return vec;
2117}
2118
2119/**********************************************************************/
2122 bool secfile_lookup_float(const struct section_file *secfile, float *fval,
2123 const char *path, ...)
2124{
2125 char fullpath[MAX_LEN_SECPATH];
2126 const struct entry *pentry;
2127 va_list args;
2128
2129 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2130
2131 va_start(args, path);
2132 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2133 va_end(args);
2134
2135 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2136 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2137 return FALSE;
2138 }
2139
2140 return entry_float_get(pentry, fval);
2141}
2142
2143/**********************************************************************/
2147 float secfile_lookup_float_default(const struct section_file *secfile,
2148 float def, const char *path, ...)
2149{
2150 char fullpath[MAX_LEN_SECPATH];
2151 const struct entry *pentry;
2152 float fval;
2153 va_list args;
2154
2155 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2156
2157 va_start(args, path);
2158 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2159 va_end(args);
2160
2161 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2162 return def;
2163 }
2164
2165 if (entry_float_get(pentry, &fval)) {
2166 return fval;
2167 }
2168
2169 return def;
2170}
2171
2172/**********************************************************************/
2175 const char *secfile_lookup_str(const struct section_file *secfile,
2176 const char *path, ...)
2177{
2178 char fullpath[MAX_LEN_SECPATH];
2179 const struct entry *pentry;
2180 const char *str;
2181 va_list args;
2182
2183 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2184
2185 va_start(args, path);
2186 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2187 va_end(args);
2188
2189 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2190 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2191 return NULL;
2192 }
2193
2194 if (entry_str_get(pentry, &str)) {
2195 return str;
2196 }
2197
2198 return NULL;
2199}
2200
2201/**********************************************************************/
2205 const char *secfile_lookup_str_default(const struct section_file *secfile,
2206 const char *def,
2207 const char *path, ...)
2208{
2209 char fullpath[MAX_LEN_SECPATH];
2210 const struct entry *pentry;
2211 const char *str;
2212 va_list args;
2213
2214 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2215
2216 va_start(args, path);
2217 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2218 va_end(args);
2219
2220 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2221 return def;
2222 }
2223
2224 if (entry_str_get(pentry, &str)) {
2225 return str;
2226 }
2227
2228 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't have a string.", fullpath);
2229
2230 return def;
2231}
2232
2233/**********************************************************************/
2239 const char **secfile_lookup_str_vec(const struct section_file *secfile,
2240 size_t *dim, const char *path, ...)
2241{
2242 char fullpath[MAX_LEN_SECPATH];
2243 size_t i = 0;
2244 const char **vec;
2245 va_list args;
2246
2247 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2248 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2249
2250 va_start(args, path);
2251 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2252 va_end(args);
2253
2254 /* Check size. */
2255 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2256 i++;
2257 }
2258 *dim = i;
2259
2260 if (0 == i) {
2261 /* Doesn't exist. */
2262 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2263 return NULL;
2264 }
2265
2266 vec = fc_malloc(i * sizeof(const char *));
2267 for (i = 0; i < *dim; i++) {
2268 if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d",
2269 fullpath, (int) i))) {
2270 SECFILE_LOG(secfile, NULL,
2271 "An error occurred when looking up to \"%s,%d\" entry.",
2272 fullpath, (int) i);
2273 free(vec);
2274 *dim = 0;
2275 return NULL;
2276 }
2277 }
2278
2279 return vec;
2280}
2281
2282/**********************************************************************/
2285 bool secfile_lookup_plain_enum_full(const struct section_file *secfile,
2286 int *penumerator,
2287 secfile_enum_is_valid_fn_t is_valid_fn,
2288 secfile_enum_by_name_fn_t by_name_fn,
2289 const char *path, ...)
2290{
2291 char fullpath[MAX_LEN_SECPATH];
2292 const struct entry *pentry;
2293 const char *str;
2294 va_list args;
2295
2296 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2297 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2298 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2299 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2300
2301 va_start(args, path);
2302 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2303 va_end(args);
2304
2305 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2306 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2307 return FALSE;
2308 }
2309
2310 if (!entry_str_get(pentry, &str)) {
2311 return FALSE;
2312 }
2313
2314 *penumerator = by_name_fn(str, strcmp);
2315 if (is_valid_fn(*penumerator)) {
2316 return TRUE;
2317 }
2318
2319 SECFILE_LOG(secfile, entry_section(pentry),
2320 "Entry \"%s\": no match for \"%s\".",
2321 entry_name(pentry), str);
2322 return FALSE;
2323}
2324
2325/**********************************************************************/
2328 int secfile_lookup_plain_enum_default_full(const struct section_file
2329 *secfile, int defval,
2330 secfile_enum_is_valid_fn_t
2331 is_valid_fn,
2332 secfile_enum_by_name_fn_t
2333 by_name_fn,
2334 const char *path, ...)
2335{
2336 char fullpath[MAX_LEN_SECPATH];
2337 const struct entry *pentry;
2338 const char *str;
2339 int val;
2340 va_list args;
2341
2342 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2343 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2344 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2345
2346 va_start(args, path);
2347 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2348 va_end(args);
2349
2350 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2351 return defval;
2352 }
2353
2354 if (!entry_str_get(pentry, &str)) {
2355 return defval;
2356 }
2357
2358 val = by_name_fn(str, strcmp);
2359 if (is_valid_fn(val)) {
2360 return val;
2361 } else {
2362 return defval;
2363 }
2364}
2365
2366/**********************************************************************/
2371 int *secfile_lookup_plain_enum_vec_full(const struct section_file *secfile,
2372 size_t *dim,
2373 secfile_enum_is_valid_fn_t
2374 is_valid_fn,
2375 secfile_enum_by_name_fn_t
2376 by_name_fn,
2377 const char *path, ...)
2378{
2379 char fullpath[MAX_LEN_SECPATH];
2380 size_t i = 0;
2381 int *vec;
2382 va_list args;
2383
2384 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2385 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2386 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2387 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2388
2389 va_start(args, path);
2390 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2391 va_end(args);
2392
2393 /* Check size. */
2394 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2395 i++;
2396 }
2397 *dim = i;
2398
2399 if (0 == i) {
2400 /* Doesn't exist. */
2401 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2402 return NULL;
2403 }
2404
2405 vec = fc_malloc(i * sizeof(int));
2406 for (i = 0; i < *dim; i++) {
2407 if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2408 by_name_fn, "%s,%d",
2409 fullpath, (int) i)) {
2410 SECFILE_LOG(secfile, NULL,
2411 "An error occurred when looking up to \"%s,%d\" entry.",
2412 fullpath, (int) i);
2413 free(vec);
2414 *dim = 0;
2415 return NULL;
2416 }
2417 }
2418
2419 return vec;
2420}
2421
2422/**********************************************************************/
2425 bool secfile_lookup_bitwise_enum_full(const struct section_file *secfile,
2426 int *penumerator,
2427 secfile_enum_is_valid_fn_t is_valid_fn,
2428 secfile_enum_by_name_fn_t by_name_fn,
2429 const char *path, ...)
2430{
2431 char fullpath[MAX_LEN_SECPATH];
2432 const struct entry *pentry;
2433 const char *str, *p;
2434 char val_name[MAX_LEN_SECPATH];
2435 int val;
2436 va_list args;
2437
2438 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2439 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2440 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2441 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2442
2443 va_start(args, path);
2444 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2445 va_end(args);
2446
2447 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2448 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2449 return FALSE;
2450 }
2451
2452 if (!entry_str_get(pentry, &str)) {
2453 return FALSE;
2454 }
2455
2456 *penumerator = 0;
2457 if ('\0' == str[0]) {
2458 /* Empty string = no value. */
2459 return TRUE;
2460 }
2461
2462 /* Value names are separated by '|'. */
2463 do {
2464 p = strchr(str, '|');
2465 if (NULL != p) {
2466 p++;
2467 fc_strlcpy(val_name, str, p - str);
2468 } else {
2469 /* Last segment, full copy. */
2470 sz_strlcpy(val_name, str);
2471 }
2472 remove_leading_trailing_spaces(val_name);
2473 val = by_name_fn(val_name, strcmp);
2474 if (!is_valid_fn(val)) {
2475 SECFILE_LOG(secfile, entry_section(pentry),
2476 "Entry \"%s\": no match for \"%s\".",
2477 entry_name(pentry), val_name);
2478 return FALSE;
2479 }
2480 *penumerator |= val;
2481 str = p;
2482 } while (NULL != p);
2483
2484 return TRUE;
2485}
2486
2487/**********************************************************************/
2490 int secfile_lookup_bitwise_enum_default_full(const struct section_file
2491 *secfile, int defval,
2492 secfile_enum_is_valid_fn_t
2493 is_valid_fn,
2494 secfile_enum_by_name_fn_t
2495 by_name_fn,
2496 const char *path, ...)
2497{
2498 char fullpath[MAX_LEN_SECPATH];
2499 const struct entry *pentry;
2500 const char *str, *p;
2501 char val_name[MAX_LEN_SECPATH];
2502 int val, full_val;
2503 va_list args;
2504
2505 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2506 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2507 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2508
2509 va_start(args, path);
2510 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2511 va_end(args);
2512
2513 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2514 return defval;
2515 }
2516
2517 if (!entry_str_get(pentry, &str)) {
2518 return defval;
2519 }
2520
2521 if ('\0' == str[0]) {
2522 /* Empty string = no value. */
2523 return 0;
2524 }
2525
2526 /* Value names are separated by '|'. */
2527 full_val = 0;
2528 do {
2529 p = strchr(str, '|');
2530 if (NULL != p) {
2531 p++;
2532 fc_strlcpy(val_name, str, p - str);
2533 } else {
2534 /* Last segment, full copy. */
2535 sz_strlcpy(val_name, str);
2536 }
2537 remove_leading_trailing_spaces(val_name);
2538 val = by_name_fn(val_name, strcmp);
2539 if (!is_valid_fn(val)) {
2540 return defval;
2541 }
2542 full_val |= val;
2543 str = p;
2544 } while (NULL != p);
2545
2546 return full_val;
2547}
2548
2549/**********************************************************************/
2554 int *secfile_lookup_bitwise_enum_vec_full(const struct section_file *secfile,
2555 size_t *dim,
2556 secfile_enum_is_valid_fn_t
2557 is_valid_fn,
2558 secfile_enum_by_name_fn_t
2559 by_name_fn,
2560 const char *path, ...)
2561{
2562 char fullpath[MAX_LEN_SECPATH];
2563 size_t i = 0;
2564 int *vec;
2565 va_list args;
2566
2567 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2568 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2569 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2570 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2571
2572 va_start(args, path);
2573 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2574 va_end(args);
2575
2576 /* Check size. */
2577 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2578 i++;
2579 }
2580 *dim = i;
2581
2582 if (0 == i) {
2583 /* Doesn't exist. */
2584 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2585 return NULL;
2586 }
2587
2588 vec = fc_malloc(i * sizeof(int));
2589 for (i = 0; i < *dim; i++) {
2590 if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2591 by_name_fn, "%s,%d",
2592 fullpath, (int) i)) {
2593 SECFILE_LOG(secfile, NULL,
2594 "An error occurred when looking up to \"%s,%d\" entry.",
2595 fullpath, (int) i);
2596 free(vec);
2597 *dim = 0;
2598
2599 return NULL;
2600 }
2601 }
2602
2603 return vec;
2604}
2605
2606/**********************************************************************/
2609 bool secfile_lookup_enum_data(const struct section_file *secfile,
2610 int *pvalue, bool bitwise,
2611 secfile_enum_name_data_fn_t name_fn,
2612 secfile_data_t data, const char *path, ...)
2613{
2614 char fullpath[MAX_LEN_SECPATH];
2615 const struct entry *pentry;
2616 const char *str, *p, *name;
2617 char val_name[MAX_LEN_SECPATH];
2618 int val;
2619 va_list args;
2620
2621 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2622 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != pvalue, FALSE);
2623 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, FALSE);
2624
2625 va_start(args, path);
2626 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2627 va_end(args);
2628
2629 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2630 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2631 return FALSE;
2632 }
2633
2634 if (!entry_str_get(pentry, &str)) {
2635 return FALSE;
2636 }
2637
2638 if (bitwise) {
2639 *pvalue = 0;
2640 if ('\0' == str[0]) {
2641 /* Empty string = no value. */
2642 return TRUE;
2643 }
2644
2645 /* Value names are separated by '|'. */
2646 do {
2647 p = strchr(str, '|');
2648 if (NULL != p) {
2649 p++;
2650 fc_strlcpy(val_name, str, p - str);
2651 } else {
2652 /* Last segment, full copy. */
2653 sz_strlcpy(val_name, str);
2654 }
2655 remove_leading_trailing_spaces(val_name);
2656 for (val = 0; (name = name_fn(data, val)); val++) {
2657 if (0 == fc_strcasecmp(name, val_name)) {
2658 break;
2659 }
2660 }
2661 if (NULL == name) {
2662 SECFILE_LOG(secfile, entry_section(pentry),
2663 "Entry \"%s\": no match for \"%s\".",
2664 entry_name(pentry), val_name);
2665 return FALSE;
2666 }
2667 *pvalue |= 1 << val;
2668 str = p;
2669 } while (NULL != p);
2670 } else {
2671 for (val = 0; (name = name_fn(data, val)); val++) {
2672 if (0 == fc_strcasecmp(name, str)) {
2673 *pvalue = val;
2674 break;
2675 }
2676 }
2677 if (NULL == name) {
2678 SECFILE_LOG(secfile, entry_section(pentry),
2679 "Entry \"%s\": no match for \"%s\".",
2680 entry_name(pentry), str);
2681 return FALSE;
2682 }
2683 }
2684
2685 return TRUE;
2686}
2687
2688/**********************************************************************/
2691 int secfile_lookup_enum_default_data(const struct section_file *secfile,
2692 int defval, bool bitwise,
2693 secfile_enum_name_data_fn_t name_fn,
2694 secfile_data_t data,
2695 const char *path, ...)
2696{
2697 char fullpath[MAX_LEN_SECPATH];
2698 const struct entry *pentry;
2699 const char *str, *p, *name;
2700 char val_name[MAX_LEN_SECPATH];
2701 int value, val;
2702 va_list args;
2703
2704 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2705 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, defval);
2706
2707 va_start(args, path);
2708 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2709 va_end(args);
2710
2711 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2712 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2713 return defval;
2714 }
2715
2716 if (!entry_str_get(pentry, &str)) {
2717 return defval;
2718 }
2719
2720 value = 0;
2721 if (bitwise) {
2722 if ('\0' == str[0]) {
2723 /* Empty string = no value. */
2724 return value;
2725 }
2726
2727 /* Value names are separated by '|'. */
2728 do {
2729 p = strchr(str, '|');
2730 if (NULL != p) {
2731 p++;
2732 fc_strlcpy(val_name, str, p - str);
2733 } else {
2734 /* Last segment, full copy. */
2735 sz_strlcpy(val_name, str);
2736 }
2737 remove_leading_trailing_spaces(val_name);
2738 for (val = 0; (name = name_fn(data, val)); val++) {
2739 if (0 == strcmp(name, val_name)) {
2740 break;
2741 }
2742 }
2743 if (NULL == name) {
2744 SECFILE_LOG(secfile, entry_section(pentry),
2745 "Entry \"%s\": no match for \"%s\".",
2746 entry_name(pentry), val_name);
2747 return defval;
2748 }
2749 value |= 1 << val;
2750 str = p;
2751 } while (NULL != p);
2752 } else {
2753 for (val = 0; (name = name_fn(data, val)); val++) {
2754 if (0 == strcmp(name, str)) {
2755 value = val;
2756 break;
2757 }
2758 }
2759 if (NULL == name) {
2760 SECFILE_LOG(secfile, entry_section(pentry),
2761 "Entry \"%s\": no match for \"%s\".",
2762 entry_name(pentry), str);
2763 return defval;
2764 }
2765 }
2766
2767 return value;
2768}
2769
2770/**********************************************************************/
2774 int *secfile_lookup_enum_vec_data(const struct section_file *secfile,
2775 size_t *dim, bool bitwise,
2776 secfile_enum_name_data_fn_t name_fn,
2777 secfile_data_t data, const char *path, ...)
2778{
2779 char fullpath[MAX_LEN_SECPATH];
2780 size_t i = 0;
2781 int *vec;
2782 va_list args;
2783
2784 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2785 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2786 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
2787
2788 va_start(args, path);
2789 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2790 va_end(args);
2791
2792 /* Check size. */
2793 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2794 i++;
2795 }
2796 *dim = i;
2797
2798 if (0 == i) {
2799 /* Doesn't exist. */
2800 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2801 return NULL;
2802 }
2803
2804 vec = fc_malloc(i * sizeof(int));
2805 for (i = 0; i < *dim; i++) {
2806 if (!secfile_lookup_enum_data(secfile, vec + i, bitwise, name_fn, data,
2807 "%s,%d", fullpath, (int) i)) {
2808 SECFILE_LOG(secfile, NULL,
2809 "An error occurred when looking up to \"%s,%d\" entry.",
2810 fullpath, (int) i);
2811 free(vec);
2812 *dim = 0;
2813 return NULL;
2814 }
2815 }
2816
2817 return vec;
2818}
2819
2820/**********************************************************************/
2823 struct section *secfile_section_by_name(const struct section_file *secfile,
2824 const char *name)
2825{
2826 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2827
2828 section_list_iterate(secfile->sections, psection) {
2829 if (0 == strcmp(section_name(psection), name)) {
2830 return psection;
2831 }
2832 } section_list_iterate_end;
2833
2834 return NULL;
2835}
2836
2837/**********************************************************************/
2840 struct section *secfile_section_lookup(const struct section_file *secfile,
2841 const char *path, ...)
2842{
2843 char fullpath[MAX_LEN_SECPATH];
2844 va_list args;
2845
2846 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2847
2848 va_start(args, path);
2849 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2850 va_end(args);
2851
2852 return secfile_section_by_name(secfile, fullpath);
2853}
2854
2855/**********************************************************************/
2859const struct section_list *
2860secfile_sections(const struct section_file *secfile)
2861{
2862 return (NULL != secfile ? secfile->sections : NULL);
2863}
2864
2865/**********************************************************************/
2870struct section_list *
2871secfile_sections_by_name_prefix(const struct section_file *secfile,
2872 const char *prefix)
2873{
2874 struct section_list *matches = NULL;
2875 size_t len;
2876
2877 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2878 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, NULL);
2879
2880 len = strlen(prefix);
2881 if (0 == len) {
2882 return NULL;
2883 }
2884
2885 section_list_iterate(secfile->sections, psection) {
2886 if (!fc_strncmp(section_name(psection), prefix, len)) {
2887 if (NULL == matches) {
2888 matches = section_list_new();
2889 }
2890 section_list_append(matches, psection);
2891 }
2892 } section_list_iterate_end;
2893
2894 return matches;
2895}
2896
2897/**********************************************************************/
2900 bool secfile_section_prefix_present(const struct section_file *secfile,
2901 const char *prefix)
2902{
2903 size_t len;
2904
2905 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2906 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, FALSE);
2907
2908 len = strlen(prefix);
2909 if (0 == len) {
2910 return FALSE;
2911 }
2912
2913 section_list_iterate(secfile->sections, psection) {
2914 if (!fc_strncmp(section_name(psection), prefix, len)) {
2915 return TRUE;
2916 }
2917 } section_list_iterate_end;
2918
2919 return FALSE;
2920}
2921
2922/**********************************************************************/
2925 struct section *secfile_section_new(struct section_file *secfile,
2926 const char *name)
2927{
2928 struct section *psection;
2929
2930 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2931
2932 if (NULL == name || '\0' == name[0]) {
2933 SECFILE_LOG(secfile, NULL, "Cannot create a section without name.");
2934 return NULL;
2935 }
2936
2937 if (!is_secfile_entry_name_valid(name)) {
2938 SECFILE_LOG(secfile, NULL, "\"%s\" is not a valid section name.",
2939 name);
2940 return NULL;
2941 }
2942
2943 if (NULL != secfile_section_by_name(secfile, name)) {
2944 /* We cannot duplicate sections in any case! Not even if one is
2945 * include -section and the other not. */
2946 SECFILE_LOG(secfile, NULL, "Section \"%s\" already exists.", name);
2947 return NULL;
2948 }
2949
2950 psection = fc_malloc(sizeof(struct section));
2951 psection->special = EST_NORMAL;
2952 psection->name = fc_strdup(name);
2953 psection->entries = entry_list_new_full(entry_destroy);
2954
2955 /* Append to secfile. */
2956 psection->secfile = secfile;
2957 section_list_append(secfile->sections, psection);
2958
2959 if (NULL != secfile->hash.sections) {
2960 section_hash_insert(secfile->hash.sections, psection->name, psection);
2961 }
2962
2963 return psection;
2964}
2965
2966/**********************************************************************/
2969 void section_destroy(struct section *psection)
2970{
2971 struct section_file *secfile;
2972
2973 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2974
2975 section_clear_all(psection);
2976
2977 if ((secfile = psection->secfile)) {
2978 /* Detach from secfile. */
2979 if (section_list_remove(secfile->sections, psection)) {
2980 /* This has called section_destroy() already then. */
2981 return;
2982 }
2983 if (NULL != secfile->hash.sections) {
2984 section_hash_remove(secfile->hash.sections, psection->name);
2985 }
2986 }
2987
2988 entry_list_destroy(psection->entries);
2989 free(psection->name);
2990 free(psection);
2991}
2992
2993/**********************************************************************/
2996 void section_clear_all(struct section *psection)
2997{
2998 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2999
3000 /* This include the removing of the hash datas. */
3001 entry_list_clear(psection->entries);
3002
3003 if (0 < entry_list_size(psection->entries)) {
3004 SECFILE_LOG(psection->secfile, psection,
3005 "After clearing all, %d entries are still remaining.",
3006 entry_list_size(psection->entries));
3007 }
3008}
3009
3010/**********************************************************************/
3013 bool section_set_name(struct section *psection, const char *name)
3014{
3015 struct section_file *secfile;
3016 struct section *pother;
3017
3018 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, FALSE);
3019 secfile = psection->secfile;
3020 SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, NULL != secfile, FALSE);
3021
3022 if (NULL == name || '\0' == name[0]) {
3023 SECFILE_LOG(secfile, psection, "No new name for section \"%s\".",
3024 psection->name);
3025 return FALSE;
3026 }
3027
3028 if (!is_secfile_entry_name_valid(name)) {
3029 SECFILE_LOG(secfile, psection,
3030 "\"%s\" is not a valid section name for section \"%s\".",
3031 name, psection->name);
3032 return FALSE;
3033 }
3034
3035 if ((pother = secfile_section_by_name(secfile, name))
3036 && pother != psection) {
3037 /* We cannot duplicate sections in any case! */
3038 SECFILE_LOG(secfile, psection, "Section \"%s\" already exists.", name);
3039 return FALSE;
3040 }
3041
3042 /* Remove old references in the hash tables. */
3043 if (NULL != secfile->hash.sections) {
3044 section_hash_remove(secfile->hash.sections, psection->name);
3045 }
3046 if (NULL != secfile->hash.entries) {
3047 entry_list_iterate(psection->entries, pentry) {
3048 secfile_hash_delete(secfile, pentry);
3049 } entry_list_iterate_end;
3050 }
3051
3052 /* Really rename. */
3053 free(psection->name);
3054 psection->name = fc_strdup(name);
3055
3056 /* Reinsert new references into the hash tables. */
3057 if (NULL != secfile->hash.sections) {
3058 section_hash_insert(secfile->hash.sections, psection->name, psection);
3059 }
3060 if (NULL != secfile->hash.entries) {
3061 entry_list_iterate(psection->entries, pentry) {
3062 secfile_hash_insert(secfile, pentry);
3063 } entry_list_iterate_end;
3064 }
3065
3066 return TRUE;
3067}
3068
3069/**********************************************************************/
3073 const struct entry_list *section_entries(const struct section *psection)
3074{
3075 return (NULL != psection ? psection->entries : NULL);
3076}
3077
3078/**********************************************************************/
3081 struct entry *section_entry_by_name(const struct section *psection,
3082 const char *name)
3083{
3084 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
3085
3086 entry_list_iterate(psection->entries, pentry) {
3087 if (0 == strcmp(entry_name(pentry), name)) {
3088 entry_use(pentry);
3089 return pentry;
3090 }
3091 } entry_list_iterate_end;
3092
3093 return NULL;
3094}
3095
3096/**********************************************************************/
3099 struct entry *section_entry_lookup(const struct section *psection,
3100 const char *path, ...)
3101{
3102 char fullpath[MAX_LEN_SECPATH];
3103 struct entry *pentry;
3104 va_list args;
3105
3106 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
3107
3108 va_start(args, path);
3109 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
3110 va_end(args);
3111
3112 if ((pentry = section_entry_by_name(psection, fullpath))) {
3113 return pentry;
3114 }
3115
3116 /* Try with full path. */
3117 if ((pentry = secfile_entry_by_path(psection->secfile, fullpath))
3118 && psection == entry_section(pentry)) {
3119 /* Ensured this is really owned by this section. */
3120 return pentry;
3121 }
3122
3123 return NULL;
3124}
3125
3126/**********************************************************************/
3129 static struct entry *entry_new(struct section *psection, const char *name)
3130{
3131 struct section_file *secfile;
3132 struct entry *pentry;
3133 bool long_comment = !strcmp("#", name);
3134
3135 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
3136
3137 secfile = psection->secfile;
3138 if (NULL == name || '\0' == name[0]) {
3139 SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
3140 return NULL;
3141 }
3142
3143 if (!is_secfile_entry_name_valid(name) && !long_comment) {
3144 SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
3145 name);
3146 return NULL;
3147 }
3148
3149 if (!secfile->allow_duplicates
3150 && NULL != section_entry_by_name(psection, name)) {
3151 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3152 return NULL;
3153 }
3154
3155 pentry = fc_malloc(sizeof(struct entry));
3156 if (long_comment) {
3157 pentry->name = NULL;
3158 } else {
3159 pentry->name = fc_strdup(name);
3160 }
3161 pentry->type = -1; /* Invalid case. */
3162 pentry->used = 0;
3163 pentry->comment = NULL;
3164
3165 /* Append to section. */
3166 pentry->psection = psection;
3167 entry_list_append(psection->entries, pentry);
3168
3169 /* Notify secfile. */
3170 secfile->num_entries++;
3171 secfile_hash_insert(secfile, pentry);
3172
3173 return pentry;
3174}
3175
3176/**********************************************************************/
3179 struct entry *section_entry_int_new(struct section *psection,
3180 const char *name, int value)
3181{
3182 struct entry *pentry = entry_new(psection, name);
3183
3184 if (NULL != pentry) {
3185 pentry->type = ENTRY_INT;
3186 pentry->integer.value = value;
3187 }
3188
3189 return pentry;
3190}
3191
3192/**********************************************************************/
3195 struct entry *section_entry_bool_new(struct section *psection,
3196 const char *name, bool value)
3197{
3198 struct entry *pentry = entry_new(psection, name);
3199
3200 if (NULL != pentry) {
3201 pentry->type = ENTRY_BOOL;
3202 pentry->boolean.value = value;
3203 }
3204
3205 return pentry;
3206}
3207
3208/**********************************************************************/
3211 struct entry *section_entry_float_new(struct section *psection,
3212 const char *name, float value)
3213{
3214 struct entry *pentry = entry_new(psection, name);
3215
3216 if (NULL != pentry) {
3217 pentry->type = ENTRY_FLOAT;
3218 pentry->floating.value = value;
3219 }
3220
3221 return pentry;
3222}
3223
3224/**********************************************************************/
3227 struct entry *section_entry_str_new(struct section *psection,
3228 const char *name, const char *value,
3229 bool escaped)
3230{
3231 struct entry *pentry = entry_new(psection, name);
3232
3233 if (NULL != pentry) {
3234 pentry->type = ENTRY_STR;
3235 pentry->string.value = fc_strdup(NULL != value ? value : "");
3236 pentry->string.escaped = escaped;
3237 pentry->string.raw = FALSE;
3238 pentry->string.gt_marking = FALSE;
3239 }
3240
3241 return pentry;
3242}
3243
3244/**********************************************************************/
3247 static struct entry *section_entry_filereference_new(struct section *psection,
3248 const char *name,
3249 const char *value)
3250{
3251 struct entry *pentry = entry_new(psection, name);
3252
3253 if (NULL != pentry) {
3254 pentry->type = ENTRY_FILEREFERENCE;
3255 pentry->string.value = fc_strdup(NULL != value ? value : "");
3256 }
3257
3258 return pentry;
3259}
3260
3261/**********************************************************************/
3264 static struct entry *section_entry_comment_new(struct section *psection,
3265 const char *comment)
3266{
3267 struct entry *pentry = entry_new(psection, "#");
3268
3269 if (NULL != pentry) {
3270 pentry->type = ENTRY_LONG_COMMENT;
3271 pentry->comment = fc_strdup(NULL != comment ? comment : "");
3272 }
3273
3274 return pentry;
3275}
3276
3277/**********************************************************************/
3280 void entry_destroy(struct entry *pentry)
3281{
3282 struct section_file *secfile;
3283 struct section *psection;
3284
3285 if (NULL == pentry) {
3286 return;
3287 }
3288
3289 if ((psection = pentry->psection)) {
3290 /* Detach from section. */
3291 if (entry_list_remove(psection->entries, pentry)) {
3292 /* This has called entry_destroy() already then. */
3293 return;
3294 }
3295 if ((secfile = psection->secfile)) {
3296 /* Detach from secfile. */
3297 secfile->num_entries--;
3298 secfile_hash_delete(secfile, pentry);
3299 }
3300 }
3301
3302 /* Specific type free. */
3303 switch (pentry->type) {
3304 case ENTRY_BOOL:
3305 case ENTRY_INT:
3306 case ENTRY_FLOAT:
3307 case ENTRY_LONG_COMMENT:
3308 break;
3309
3310 case ENTRY_STR:
3311 case ENTRY_FILEREFERENCE:
3312 free(pentry->string.value);
3313 break;
3314
3315 case ENTRY_ILLEGAL:
3316 fc_assert(pentry->type != ENTRY_ILLEGAL);
3317 break;
3318 }
3319
3320 /* Common free. */
3321 free(pentry->name);
3322 if (NULL != pentry->comment) {
3323 free(pentry->comment);
3324 }
3325 free(pentry);
3326}
3327
3328/**********************************************************************/
3331 struct section *entry_section(const struct entry *pentry)
3332{
3333 return (NULL != pentry ? pentry->psection : NULL);
3334}
3335
3336/**********************************************************************/
3339 enum entry_type entry_type_get(const struct entry *pentry)
3340{
3341 return (NULL != pentry ? pentry->type : ENTRY_ILLEGAL);
3342}
3343
3344/**********************************************************************/
3347 int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3348{
3349 return fc_snprintf(buf, buf_len, "%s.%s",
3350 section_name(entry_section(pentry)),
3351 entry_name(pentry));
3352}
3353
3354/**********************************************************************/
3357 const char *entry_name(const struct entry *pentry)
3358{
3359 return (NULL != pentry ? pentry->name : NULL);
3360}
3361
3362/**********************************************************************/
3365 bool entry_set_name(struct entry *pentry, const char *name)
3366{
3367 struct section *psection;
3368 struct section_file *secfile;
3369
3370 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3371 psection = pentry->psection;
3372 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != psection, FALSE);
3373 secfile = psection->secfile;
3374 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != secfile, FALSE);
3375
3376 if (NULL == name || '\0' == name[0]) {
3377 SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3378 pentry->name);
3379 return FALSE;
3380 }
3381
3382 if (!is_secfile_entry_name_valid(name)) {
3383 SECFILE_LOG(secfile, psection,
3384 "\"%s\" is not a valid entry name for entry \"%s\".",
3385 name, pentry->name);
3386 return FALSE;
3387 }
3388
3389 if (!secfile->allow_duplicates) {
3390 struct entry *pother = section_entry_by_name(psection, name);
3391
3392 if (NULL != pother && pother != pentry) {
3393 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3394 return FALSE;
3395 }
3396 }
3397
3398 /* Remove from hash table the old path. */
3399 secfile_hash_delete(secfile, pentry);
3400
3401 /* Really rename the entry. */
3402 free(pentry->name);
3403 pentry->name = fc_strdup(name);
3404
3405 /* Insert into hash table the new path. */
3406 secfile_hash_insert(secfile, pentry);
3407 return TRUE;
3408}
3409
3410/**********************************************************************/
3413 const char *entry_comment(const struct entry *pentry)
3414{
3415 return (NULL != pentry ? pentry->comment : NULL);
3416}
3417
3418/**********************************************************************/
3421 void entry_set_comment(struct entry *pentry, const char *comment)
3422{
3423 if (NULL == pentry) {
3424 return;
3425 }
3426
3427 if (NULL != pentry->comment) {
3428 free(pentry->comment);
3429 }
3430
3431 pentry->comment = (NULL != comment ? fc_strdup(comment) : NULL);
3432}
3433
3434/**********************************************************************/
3437 static inline bool entry_used(const struct entry *pentry)
3438{
3439 return (0 < pentry->used);
3440}
3441
3442/**********************************************************************/
3445 static inline void entry_use(struct entry *pentry)
3446{
3447 pentry->used++;
3448}
3449
3450/**********************************************************************/
3454 bool entry_bool_get(const struct entry *pentry, bool *value)
3455{
3456 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3457
3458 if (ENTRY_INT == pentry->type
3459 && (pentry->integer.value == 0
3460 || pentry->integer.value == 1)
3461 && NULL != pentry->psection
3462 && NULL != pentry->psection->secfile
3463 && pentry->psection->secfile->allow_digital_boolean) {
3464 *value = (0 != pentry->integer.value);
3465 return TRUE;
3466 }
3467
3468 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection != NULL
3469 ? pentry->psection->secfile : NULL,
3470 pentry->psection,
3471 ENTRY_BOOL == pentry->type, FALSE);
3472
3473 if (NULL != value) {
3474 *value = pentry->boolean.value;
3475 }
3476 return TRUE;
3477}
3478
3479/**********************************************************************/
3482 bool entry_bool_set(struct entry *pentry, bool value)
3483{
3484 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3485 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3486 ENTRY_BOOL == pentry->type, FALSE);
3487
3488 pentry->boolean.value = value;
3489 return TRUE;
3490}
3491
3492/**********************************************************************/
3495 bool entry_float_get(const struct entry *pentry, float *value)
3496{
3497 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3498 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3499 ENTRY_FLOAT == pentry->type, FALSE);
3500
3501 if (NULL != value) {
3502 *value = pentry->floating.value;
3503 }
3504
3505 return TRUE;
3506}
3507
3508/**********************************************************************/
3511 bool entry_float_set(struct entry *pentry, float value)
3512{
3513 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3514 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3515 ENTRY_FLOAT == pentry->type, FALSE);
3516
3517 pentry->floating.value = value;
3518
3519 return TRUE;
3520}
3521
3522/**********************************************************************/
3525 bool entry_int_get(const struct entry *pentry, int *value)
3526{
3527 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3528 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3529 ENTRY_INT == pentry->type, FALSE);
3530
3531 if (NULL != value) {
3532 *value = pentry->integer.value;
3533 }
3534 return TRUE;
3535}
3536
3537/**********************************************************************/
3540 bool entry_int_set(struct entry *pentry, int value)
3541{
3542 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3543 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3544 ENTRY_INT == pentry->type, FALSE);
3545
3546 pentry->integer.value = value;
3547 return TRUE;
3548}
3549
3550/**********************************************************************/
3553 bool entry_str_get(const struct entry *pentry, const char **value)
3554{
3555 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3556 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3557 ENTRY_STR == pentry->type, FALSE);
3558
3559 if (NULL != value) {
3560 *value = pentry->string.value;
3561 }
3562 return TRUE;
3563}
3564
3565/**********************************************************************/
3568 bool entry_str_set(struct entry *pentry, const char *value)
3569{
3570 char *old_val;
3571
3572 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3573 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3574 ENTRY_STR == pentry->type, FALSE);
3575
3576 /* We free() old value only after we've placed the new one, to
3577 * support secfile_replace_str_vec() calls that want to keep some of
3578 * the entries from the old vector in the new one. We don't want
3579 * to lose the entry in between. */
3580 old_val = pentry->string.value;
3581 pentry->string.value = fc_strdup(NULL != value ? value : "");
3582 free(old_val);
3583 return TRUE;
3584}
3585
3586/**********************************************************************/
3589 bool entry_str_escaped(const struct entry *pentry)
3590{
3591 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3592 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3593 ENTRY_STR == pentry->type, FALSE);
3594
3595 return pentry->string.escaped;
3596}
3597
3598/**********************************************************************/
3601 bool entry_str_set_escaped(struct entry *pentry, bool escaped)
3602{
3603 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3604 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3605 ENTRY_STR == pentry->type, FALSE);
3606
3607 pentry->string.escaped = escaped;
3608 return TRUE;
3609}
3610
3611/**********************************************************************/
3614 bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
3615{
3616 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3617 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection->secfile, pentry->psection,
3618 ENTRY_STR == pentry->type, FALSE);
3619
3620 pentry->string.gt_marking = gt_marking;
3621
3622 return TRUE;
3623}
3624
3625/**********************************************************************/
3628 static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
3629{
3630 static char buf[8192];
3631 char *dot = NULL;
3632 int i;
3633
3634 switch (pentry->type) {
3635 case ENTRY_BOOL:
3636 fz_fprintf(fs, "%s", pentry->boolean.value ? "TRUE" : "FALSE");
3637 break;
3638 case ENTRY_INT:
3639 fz_fprintf(fs, "%d", pentry->integer.value);
3640 break;
3641 case ENTRY_FLOAT:
3642 snprintf(buf, sizeof(buf), "%f", pentry->floating.value);
3643 for (i = 0; buf[i] != '\0' ; i++) {
3644 if (buf[i] == '.') {
3645 dot = &(buf[i]);
3646 break;
3647 }
3648 }
3649 if (dot == NULL) {
3650 /* There's no '.' so it would seem like a integer value when loaded.
3651 * Force it not to look like an integer by adding ".0" */
3652 fz_fprintf(fs, "%s.0", buf);
3653 } else {
3654 fz_fprintf(fs, "%s", buf);
3655 }
3656 break;
3657 case ENTRY_STR:
3658 if (pentry->string.escaped) {
3659 make_escapes(pentry->string.value, buf, sizeof(buf));
3660 if (pentry->string.gt_marking) {
3661 fz_fprintf(fs, "_(\"%s\")", buf);
3662 } else {
3663 fz_fprintf(fs, "\"%s\"", buf);
3664 }
3665 } else if (pentry->string.raw) {
3666 fz_fprintf(fs, "%s", pentry->string.value);
3667 } else {
3668 fz_fprintf(fs, "$%s$", pentry->string.value);
3669 }
3670 break;
3671 case ENTRY_FILEREFERENCE:
3672 fz_fprintf(fs, "*%s*", pentry->string.value);
3673 break;
3674 case ENTRY_LONG_COMMENT:
3675 fz_fprintf(fs, "%s\n", pentry->comment);
3676 break;
3677 case ENTRY_ILLEGAL:
3678 fc_assert(pentry->type != ENTRY_ILLEGAL);
3679 break;
3680 }
3681}
3682
3683/**********************************************************************/
3686 static void entry_from_inf_token(struct section *psection, const char *name,
3687 const char *tok, struct inputfile *inf)
3688{
3689 if (!entry_from_token(psection, name, tok)) {
3690 log_error("%s", inf_log_str(inf, "Entry value not recognized: %s", tok));
3691 }
3692}
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:2937
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:3129
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:2490
entry_set_comment
void entry_set_comment(struct entry *pentry, const char *comment)
Definition registry_ini.c:3421
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:3454
section_destroy
void section_destroy(struct section *psection)
Definition registry_ini.c:2969
secfile_lookup_float
bool secfile_lookup_float(const struct section_file *secfile, float *fval, const char *path,...)
Definition registry_ini.c:2122
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:3347
secfile_lookup_int
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
Definition registry_ini.c:1975
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:3247
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:1831
entry_set_name
bool entry_set_name(struct entry *pentry, const char *name)
Definition registry_ini.c:3365
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:2609
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:3589
section_entry_int_new
struct entry * section_entry_int_new(struct section *psection, const char *name, int value)
Definition registry_ini.c:3179
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:3331
section_entry_comment_new
static struct entry * section_entry_comment_new(struct section *psection, const char *comment)
Definition registry_ini.c:3264
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:2871
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:2691
section_entries
const struct entry_list * section_entries(const struct section *psection)
Definition registry_ini.c:3073
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:3482
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:3628
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:3686
entry_float_get
bool entry_float_get(const struct entry *pentry, float *value)
Definition registry_ini.c:3495
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:2239
entry_str_set_escaped
bool entry_str_set_escaped(struct entry *pentry, bool escaped)
Definition registry_ini.c:3601
entry_name
const char * entry_name(const struct entry *pentry)
Definition registry_ini.c:3357
secfile_entry_lookup
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:1857
entry_str_get
bool entry_str_get(const struct entry *pentry, const char **value)
Definition registry_ini.c:3553
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:3614
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:2175
entry_destroy
void entry_destroy(struct entry *pentry)
Definition registry_ini.c:3280
entry_used
static bool entry_used(const struct entry *pentry)
Definition registry_ini.c:3437
section_clear_all
void section_clear_all(struct section *psection)
Definition registry_ini.c:2996
secfile_lookup_int_vec
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Definition registry_ini.c:2077
entry_float_set
bool entry_float_set(struct entry *pentry, float value)
Definition registry_ini.c:3511
secfile_lookup_float_default
float secfile_lookup_float_default(const struct section_file *secfile, float def, const char *path,...)
Definition registry_ini.c:2147
secfile_lookup_bool_vec
bool * secfile_lookup_bool_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Definition registry_ini.c:1930
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:2328
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:1900
entry_int_set
bool entry_int_set(struct entry *pentry, int value)
Definition registry_ini.c:3540
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:3081
secfile_sections
const struct section_list * secfile_sections(const struct section_file *secfile)
Definition registry_ini.c:2860
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:3013
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:3227
section_entry_float_new
struct entry * section_entry_float_new(struct section *psection, const char *name, float value)
Definition registry_ini.c:3211
secfile_lookup_int_default
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Definition registry_ini.c:2000
section_entry_lookup
struct entry * section_entry_lookup(const struct section *psection, const char *path,...)
Definition registry_ini.c:3099
entry_int_get
bool entry_int_get(const struct entry *pentry, int *value)
Definition registry_ini.c:3525
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:2554
entry_use
static void entry_use(struct entry *pentry)
Definition registry_ini.c:3445
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:2774
section_entry_bool_new
struct entry * section_entry_bool_new(struct section *psection, const char *name, bool value)
Definition registry_ini.c:3195
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:2285
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:2925
entry_comment
const char * entry_comment(const struct entry *pentry)
Definition registry_ini.c:3413
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:1784
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:2823
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:2371
secfile_section_lookup
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:2840
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:2205
secfile_section_prefix_present
bool secfile_section_prefix_present(const struct section_file *secfile, const char *prefix)
Definition registry_ini.c:2900
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:3568
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:2425
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:1740
secfile_lookup_bool
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
Definition registry_ini.c:1875
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:2030
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:3339
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:1101
interpret_tilde
void interpret_tilde(char *buf, size_t buf_size, const char *filename)
Definition shared.c:1717
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:893
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