Freeciv-3.1
Loading...
Searching...
No Matches
registry_ini.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14/**************************************************************************
15 the idea with this file is to create something similar to the ms-windows
16 .ini files functions.
17 however the interface is nice. ie:
18 secfile_lookup_str(file, "player%d.unit%d.name", plrno, unitno);
19***************************************************************************/
20
21/**************************************************************************
22 Description of the file format:
23 (This is based on a format by the original authors, with
24 various incremental extensions. --dwp)
25
26 - Whitespace lines are ignored, as are lines where the first
27 non-whitespace character is ';' (comment lines).
28 Optionally '#' can also be used for comments.
29
30 - A line of the form:
31 *include "filename"
32 includes the named file at that point. (The '*' must be the
33 first character on the line.) The file is found by looking in
34 FREECIV_DATA_PATH. Non-infinite recursive includes are allowed.
35
36 - A line with "[name]" labels the start of a section with
37 that name; one of these must be the first non-comment line in
38 the file. Any spaces within the brackets are included in the
39 name, but this feature (?) should probably not be used...
40
41 - Within a section, lines have one of the following forms:
42 subname = "stringvalue"
43 subname = -digits
44 subname = digits
45 subname = TRUE
46 sunname = FALSE
47 for a value with given name and string, negative integer, and
48 positive integer values, respectively. These entries are
49 referenced in the following functions as "sectionname.subname".
50 The section name should not contain any dots ('.'); the subname
51 can, but they have no particular significance. There can be
52 optional whitespace before and/or after the equals sign.
53 You can put a newline after (but not before) the equals sign.
54
55 Backslash is an escape character in strings (double-quoted strings
56 only, not names); recognised escapes are \n, \\, and \".
57 (Any other <char> is just treated as <char>.)
58
59 - Gettext markings: You can surround strings like so:
60 foo = _("stringvalue")
61 The registry just ignores these extra markings, but this is
62 useful for marking strings for translations via gettext tools.
63
64 - Multiline strings: Strings can have embedded newlines, eg:
65 foo = _("
66 This is a string
67 over multiple lines
68 ")
69 This is equivalent to:
70 foo = _("\nThis is a string\nover multiple lines\n")
71 Note that if you misplace the trailing doublequote you can
72 easily end up with strange errors reading the file...
73
74 - Strings read from a file: A file can be read as a string value:
75 foo = *filename.txt*
76
77 - Vector format: An entry can have multiple values separated
78 by commas, eg:
79 foo = 10, 11, "x"
80 These are accessed by names "foo", "foo,1" and "foo,2"
81 (with section prefix as above). So the above is equivalent to:
82 foo = 10
83 foo,1 = 11
84 foo,2 = "x"
85 As in the example, in principle you can mix integers and strings,
86 but the calling program will probably require elements to be the
87 same type. Note that the first element of a vector is not "foo,0",
88 in order that the name of the first element is the same whether or
89 not there are subsequent elements. However as a convenience, if
90 you try to lookup "foo,0" then you get back "foo". (So you should
91 never have "foo,0" as a real name in the datafile.)
92
93 - Tabular format: The lines:
94 foo = { "bar", "baz", "bax"
95 "wow", 10, -5
96 "cool", "str"
97 "hmm", 314, 99, 33, 11
98 }
99 are equivalent to the following:
100 foo0.bar = "wow"
101 foo0.baz = 10
102 foo0.bax = -5
103 foo1.bar = "cool"
104 foo1.baz = "str"
105 foo2.bar = "hmm"
106 foo2.baz = 314
107 foo2.bax = 99
108 foo2.bax,1 = 33
109 foo2.bax,2 = 11
110 The first line specifies the base name and the column names, and the
111 subsequent lines have data. Again it is possible to mix string and
112 integer values in a column, and have either more or less values
113 in a row than there are column headings, but the code which uses
114 this information (via the registry) may set more stringent conditions.
115 If a row has more entries than column headings, the last column is
116 treated as a vector (as above). You can optionally put a newline
117 after '=' and/or after '{'.
118
119 The equivalence above between the new and old formats is fairly
120 direct: internally, data is converted to the old format.
121 In principle it could be a good idea to represent the data
122 as a table (2-d array) internally, but the current method
123 seems sufficient and relatively simple...
124
125 There is a limited ability to save data in tabular:
126 So long as the section_file is constructed in an expected way,
127 tabular data (with no missing or extra values) can be saved
128 in tabular form. (See section_file_save().)
129
130 - Multiline vectors: if the last non-comment non-whitespace
131 character in a line is a comma, the line is considered to
132 continue on to the next line. Eg:
133 foo = 10,
134 11,
135 "x"
136 This is equivalent to the original "vector format" example above.
137 Such multi-lines can occur for column headings, vectors, or
138 table rows, again with some potential for strange errors...
139
140***************************************************************************/
141
142/**************************************************************************
143 Hashing registry lookups: (by dwp)
144 - Have a hash table direct to entries, bypassing sections division.
145 - For convenience, store the key (the full section+entry name)
146 in the hash table (some memory overhead).
147 - The number of entries is fixed when the hash table is built.
148 - Now uses hash.c
149**************************************************************************/
150
151#ifdef HAVE_CONFIG_H
152#include <fc_config.h>
153#endif
154
155#include <stdarg.h>
156#include <stdlib.h>
157#include <string.h>
158
159/* utility */
160#include "astring.h"
161#include "bugs.h"
162#include "deprecations.h"
163#include "fcintl.h"
164#include "inputfile.h"
165#include "ioz.h"
166#include "log.h"
167#include "mem.h"
168#include "registry.h"
169#include "section_file.h"
170#include "shared.h"
171#include "support.h"
172
173#include "registry_ini.h"
174
175#define MAX_LEN_SECPATH 1024
176
177/* Set to FALSE for old-style savefiles. */
178#define SAVE_TABLES TRUE
179
180#define SPECVEC_TAG astring
181#include "specvec.h"
182
183static inline bool entry_used(const struct entry *pentry);
184static inline void entry_use(struct entry *pentry);
185
186static void entry_to_file(const struct entry *pentry, fz_FILE *fs);
187static void entry_from_inf_token(struct section *psection, const char *name,
188 const char *tok, struct inputfile *file);
189
190/* An 'entry' is a string, integer, boolean or string vector;
191 * See enum entry_type in registry.h.
192 */
193struct entry {
194 struct section *psection; /* Parent section. */
195 char *name; /* Name, not including section prefix. */
196 enum entry_type type; /* The type of the entry. */
197 int used; /* Number of times entry looked up. */
198 char *comment; /* Comment, may be NULL. */
199
200 union {
201 /* ENTRY_BOOL */
202 struct {
203 bool value;
204 } boolean;
205 /* ENTRY_INT */
206 struct {
207 int value;
208 } integer;
209 /* ENTRY_FLOAT */
210 struct {
211 float value;
212 } floating;
213 /* ENTRY_STR */
214 struct {
215 char *value; /* Malloced string. */
216 bool escaped; /* " or $. Usually TRUE */
217 bool raw; /* Do not add anything. */
218 bool gt_marking; /* Save with gettext marking. */
219 } string;
220 };
221};
222
224 const char *name, const char *value);
225
226/**********************************************************************/
229static const char *datafilename(const char *filename)
230{
231 return fileinfoname(get_data_dirs(), filename);
232}
233
234/**********************************************************************/
237static bool is_secfile_entry_name_valid(const char *name)
238{
239 static const char *const allowed = "_.,-[]";
240
241 while ('\0' != *name) {
242 if (!fc_isalnum(*name) && NULL == strchr(allowed, *name)) {
243 return FALSE;
244 }
245 name++;
246 }
247 return TRUE;
248}
249
250/**********************************************************************/
253static bool secfile_hash_insert(struct section_file *secfile,
254 struct entry *pentry)
255{
256 char buf[256];
257 struct entry *hentry;
258
259 if (NULL == secfile->hash.entries) {
260 /* Consider as success if this secfile doesn't have built the entries
261 * hash table. */
262 return TRUE;
263 }
264
265 entry_path(pentry, buf, sizeof(buf));
266 if (entry_hash_replace_full(secfile->hash.entries, buf, pentry,
267 NULL, &hentry)) {
268 entry_use(hentry);
269 if (!secfile->allow_duplicates) {
270 SECFILE_LOG(secfile, entry_section(hentry),
271 "Tried to insert same value twice: %s", buf);
272 return FALSE;
273 }
274 }
275
276 return TRUE;
277}
278
279/**********************************************************************/
282static bool secfile_hash_delete(struct section_file *secfile,
283 struct entry *pentry)
284{
285 char buf[256];
286
287 if (NULL == secfile->hash.entries) {
288 /* Consider as success if this secfile doesn't have built the entries
289 * hash table. */
290 return TRUE;
291 }
292
293 entry_path(pentry, buf, sizeof(buf));
294 return entry_hash_remove(secfile->hash.entries, buf);
295}
296
297/**********************************************************************/
301 const char *filename,
302 const char *section,
303 bool allow_duplicates)
304{
305 struct section_file *secfile;
306 struct section *psection = NULL;
307 struct section *single_section = NULL;
308 bool table_state = FALSE; /* TRUE when within tabular format. */
309 int table_lineno = 0; /* Row number in tabular, 0 top data row. */
310 const char *tok;
311 int i;
312 struct astring base_name = ASTRING_INIT; /* for table or single entry */
313 struct astring field_name = ASTRING_INIT;
314 struct astring_vector columns; /* astrings for column headings */
315 bool found_my_section = FALSE;
316 bool error = FALSE;
317
318 if (!inf) {
319 return NULL;
320 }
321
322 /* Assign the real value later, to speed up the creation of new entries. */
323 secfile = secfile_new(TRUE);
324 if (filename) {
325 secfile->name = fc_strdup(filename);
326 } else {
327 secfile->name = NULL;
328 }
329
330 astring_vector_init(&columns);
331
332 if (filename) {
333 log_verbose("Reading registry from \"%s\"", filename);
334 } else {
335 log_verbose("Reading registry");
336 }
337
338 while (!inf_at_eof(inf)) {
339 if (inf_token(inf, INF_TOK_EOL)) {
340 continue;
341 }
342 if (inf_at_eof(inf)) {
343 /* may only realise at eof after trying to read eol above */
344 break;
345 }
347 if (tok) {
348 if (found_my_section) {
349 /* This shortcut will stop any further loading after the requested
350 * section has been loaded (i.e., at the start of a new section).
351 * This is needed to make the behavior useful, since the whole
352 * purpose is to short-cut further loading of the file. However
353 * normally a section may be split up, and that will no longer
354 * work here because it will be short-cut. */
355 SECFILE_LOG(secfile, psection, "%s",
356 inf_log_str(inf, "Found requested section; finishing"));
357 goto END;
358 }
359 if (table_state) {
360 SECFILE_LOG(secfile, psection, "%s",
361 inf_log_str(inf, "New section during table"));
362 error = TRUE;
363 goto END;
364 }
365 /* Check if we already have a section with this name.
366 (Could ignore this and have a duplicate sections internally,
367 but then secfile_get_secnames_prefix would return duplicates.)
368 Duplicate section in input are likely to be useful for includes.
369 */
370 psection = secfile_section_by_name(secfile, tok);
371 if (!psection) {
372 if (!section || strcmp(tok, section) == 0) {
373 psection = secfile_section_new(secfile, tok);
374 if (section) {
375 single_section = psection;
376 found_my_section = TRUE;
377 }
378 }
379 }
380 if (!inf_token(inf, INF_TOK_EOL)) {
381 SECFILE_LOG(secfile, psection, "%s",
382 inf_log_str(inf, "Expected end of line"));
383 error = TRUE;
384 goto END;
385 }
386 continue;
387 }
388 if (inf_token(inf, INF_TOK_TABLE_END)) {
389 if (!table_state) {
390 SECFILE_LOG(secfile, psection, "%s",
391 inf_log_str(inf, "Misplaced \"}\""));
392 error = TRUE;
393 goto END;
394 }
395 if (!inf_token(inf, INF_TOK_EOL)) {
396 SECFILE_LOG(secfile, psection, "%s",
397 inf_log_str(inf, "Expected end of line"));
398 error = TRUE;
399 goto END;
400 }
401 table_state = FALSE;
402 continue;
403 }
404 if (table_state) {
405 i = -1;
406 do {
407 int num_columns = astring_vector_size(&columns);
408
409 i++;
410
411 if (i < num_columns) {
412 astr_set(&field_name, "%s%d.%s", astr_str(&base_name),
413 table_lineno, astr_str(&columns.p[i]));
414 } else {
415 astr_set(&field_name, "%s%d.%s,%d", astr_str(&base_name),
416 table_lineno, astr_str(&columns.p[num_columns - 1]),
417 (int) (i - num_columns + 1));
418 }
419
420 inf_discard_tokens(inf, INF_TOK_EOL); /* Allow newlines */
421 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
422 SECFILE_LOG(secfile, psection, "%s",
423 inf_log_str(inf, "Expected value for %s",
424 astr_str(&field_name)));
425 error = TRUE;
426 goto END;
427 }
428
429 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
430 } while (inf_token(inf, INF_TOK_COMMA));
431
432 if (!inf_token(inf, INF_TOK_EOL)) {
433 SECFILE_LOG(secfile, psection, "%s",
434 inf_log_str(inf, "Expected end of line or comma"));
435 error = TRUE;
436 goto END;
437 }
438 table_lineno++;
439 continue;
440 }
441
442 if (!(tok = inf_token(inf, INF_TOK_ENTRY_NAME))) {
443 SECFILE_LOG(secfile, psection, "%s",
444 inf_log_str(inf, "Expected entry name"));
445 error = TRUE;
446 goto END;
447 }
448
449 /* need to store tok before next calls: */
450 astr_set(&base_name, "%s", tok);
451
452 inf_discard_tokens(inf, INF_TOK_EOL); /* allow newlines */
453
454 if (inf_token(inf, INF_TOK_TABLE_START)) {
455 i = -1;
456 do {
457 i++;
458 inf_discard_tokens(inf, INF_TOK_EOL); /* Allow newlines */
459 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
460 SECFILE_LOG(secfile, psection, "%s",
461 inf_log_str(inf, "Expected column header %s,%d",
462 astr_str(&base_name), i));
463 error = TRUE;
464 goto END;
465 }
466 if (tok[0] != '\"') {
467 SECFILE_LOG(secfile, psection, "%s",
468 inf_log_str(inf, "Table column header non-string"));
469 error = TRUE;
470 goto END;
471 }
472 { /* Expand columns: */
473 int j, n_prev;
474
475 n_prev = astring_vector_size(&columns);
476 for (j = i + 1; j < n_prev; j++) {
477 astr_free(&columns.p[j]);
478 }
479 astring_vector_reserve(&columns, i + 1);
480 for (j = n_prev; j < i + 1; j++) {
481 astr_init(&columns.p[j]);
482 }
483 }
484 astr_set(&columns.p[i], "%s", tok + 1);
485
486 } while (inf_token(inf, INF_TOK_COMMA));
487
488 if (!inf_token(inf, INF_TOK_EOL)) {
489 SECFILE_LOG(secfile, psection, "%s",
490 inf_log_str(inf, "Expected end of line or comma"));
491 error = TRUE;
492 goto END;
493 }
494 table_state = TRUE;
495 table_lineno = 0;
496 continue;
497 }
498 /* ordinary value: */
499 i = -1;
500 do {
501 i++;
502 inf_discard_tokens(inf, INF_TOK_EOL); /* Allow newlines */
503 if (!(tok = inf_token(inf, INF_TOK_VALUE))) {
504 if (i == 0) {
505 SECFILE_LOG(secfile, psection, "%s",
506 inf_log_str(inf, "Expected value for %s",
507 astr_str(&base_name)));
508 } else {
509 SECFILE_LOG(secfile, psection, "%s",
510 inf_log_str(inf, "Expected value for %s,%d",
511 astr_str(&base_name), i));
512 }
513 error = TRUE;
514 goto END;
515 }
516 if (i == 0) {
517 entry_from_inf_token(psection, astr_str(&base_name), tok, inf);
518 } else {
519 astr_set(&field_name, "%s,%d", astr_str(&base_name), i);
520 entry_from_inf_token(psection, astr_str(&field_name), tok, inf);
521 }
522 } while (inf_token(inf, INF_TOK_COMMA));
523 if (!inf_token(inf, INF_TOK_EOL)) {
524 SECFILE_LOG(secfile, psection, "%s",
525 inf_log_str(inf, "Expected end of line or comma"));
526 error = TRUE;
527 goto END;
528 }
529 }
530
531 if (table_state) {
532 SECFILE_LOG(secfile, psection,
533 "Finished registry before end of table");
534 error = TRUE;
535 }
536
537END:
538 inf_close(inf);
539 astr_free(&base_name);
540 astr_free(&field_name);
541 for (i = 0; i < astring_vector_size(&columns); i++) {
542 astr_free(&columns.p[i]);
543 }
544 astring_vector_free(&columns);
545
546 if (section != NULL) {
547 if (!found_my_section) {
548 secfile_destroy(secfile);
549 return NULL;
550 }
551
552 /* Build the entry hash table with single section information */
553 secfile->allow_duplicates = allow_duplicates;
554 entry_list_iterate(section_entries(single_section), pentry) {
555 if (!secfile_hash_insert(secfile, pentry)) {
556 secfile_destroy(secfile);
557 return NULL;
558 }
560
561 return secfile;
562 }
563
564 if (!error) {
565 /* Build the entry hash table. */
566 secfile->allow_duplicates = allow_duplicates;
567 secfile->hash.entries = entry_hash_new_nentries(secfile->num_entries);
568
569 section_list_iterate(secfile->sections, hashing_section) {
570 entry_list_iterate(section_entries(hashing_section), pentry) {
571 if (!secfile_hash_insert(secfile, pentry)) {
572 error = TRUE;
573 break;
574 }
576 if (error) {
577 break;
578 }
580 }
581 if (error) {
582 secfile_destroy(secfile);
583 return NULL;
584 } else {
585 return secfile;
586 }
587}
588
589/**********************************************************************/
593struct section_file *secfile_load_section(const char *filename,
594 const char *section,
595 bool allow_duplicates)
596{
597 char real_filename[1024];
598
599 interpret_tilde(real_filename, sizeof(real_filename), filename);
601 filename, section, allow_duplicates);
602}
603
604/**********************************************************************/
608 bool allow_duplicates)
609{
611 NULL, NULL, allow_duplicates);
612}
613
614/**********************************************************************/
617static bool is_legal_table_entry_name(char c, bool num)
618{
619 return (num ? fc_isalnum(c) : fc_isalpha(c)) || c == '_';
620}
621
622/**********************************************************************/
641bool secfile_save(const struct section_file *secfile, const char *filename,
642 int compression_level, enum fz_method compression_method)
643{
644 char real_filename[1024];
645 char pentry_name[128];
646 const char *col_entry_name;
647 fz_FILE *fs;
648 const struct entry_list_link *ent_iter, *save_iter, *col_iter;
649 struct entry *pentry, *col_pentry;
650 int i;
651
652 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
653
654 if (NULL == filename) {
655 filename = secfile->name;
656 }
657
658 interpret_tilde(real_filename, sizeof(real_filename), filename);
659 fs = fz_from_file(real_filename, "w",
660 compression_method, compression_level);
661
662 if (!fs) {
663 SECFILE_LOG(secfile, NULL, _("Could not open %s for writing"), real_filename);
664
665 return FALSE;
666 }
667
669 if (psection->special == EST_INCLUDE) {
670 for (ent_iter = entry_list_head(section_entries(psection));
671 ent_iter && (pentry = entry_list_link_data(ent_iter));
672 ent_iter = entry_list_link_next(ent_iter)) {
673
674 fc_assert(!strcmp(entry_name(pentry), "file"));
675
676 fz_fprintf(fs, "*include ");
677 entry_to_file(pentry, fs);
678 fz_fprintf(fs, "\n");
679 }
680 } else if (psection->special == EST_COMMENT) {
681 for (ent_iter = entry_list_head(section_entries(psection));
682 ent_iter && (pentry = entry_list_link_data(ent_iter));
683 ent_iter = entry_list_link_next(ent_iter)) {
684
685 fc_assert(!strcmp(entry_name(pentry), "comment"));
686
687 entry_to_file(pentry, fs);
688 fz_fprintf(fs, "\n");
689 }
690 } else {
691 fz_fprintf(fs, "\n[%s]\n", section_name(psection));
692
693 /* Following doesn't use entry_list_iterate() because we want to do
694 * tricky things with the iterators...
695 */
696 for (ent_iter = entry_list_head(section_entries(psection));
697 ent_iter && (pentry = entry_list_link_data(ent_iter));
698 ent_iter = entry_list_link_next(ent_iter)) {
699 const char *comment;
700
701 /* Tables: break out of this loop if this is a non-table
702 * entry (pentry and ent_iter unchanged) or after table (pentry
703 * and ent_iter suitably updated, pentry possibly NULL).
704 * After each table, loop again in case the next entry
705 * is another table.
706 */
707 for (;;) {
708 char *c, *first, base[64];
709 int offset, irow, icol, ncol;
710
711 /* Example: for first table name of "xyz0.blah":
712 * first points to the original string pentry->name
713 * base contains "xyz";
714 * offset = 5 (so first+offset gives "blah")
715 * note strlen(base) = offset - 2
716 */
717
718 if (!SAVE_TABLES) {
719 break;
720 }
721
722 sz_strlcpy(pentry_name, entry_name(pentry));
723 c = first = pentry_name;
724 if (*c == '\0' || !is_legal_table_entry_name(*c, FALSE)) {
725 break;
726 }
727 for (; *c != '\0' && is_legal_table_entry_name(*c, FALSE); c++) {
728 /* nothing */
729 }
730 if (0 != strncmp(c, "0.", 2)) {
731 break;
732 }
733 c += 2;
734 if (*c == '\0' || !is_legal_table_entry_name(*c, TRUE)) {
735 break;
736 }
737
738 offset = c - first;
739 first[offset - 2] = '\0';
740 sz_strlcpy(base, first);
741 first[offset - 2] = '0';
742 fz_fprintf(fs, "%s={", base);
743
744 /* Save an iterator at this first entry, which we can later use
745 * to repeatedly iterate over column names:
746 */
747 save_iter = ent_iter;
748
749 /* write the column names, and calculate ncol: */
750 ncol = 0;
751 col_iter = save_iter;
752 for (; (col_pentry = entry_list_link_data(col_iter));
753 col_iter = entry_list_link_next(col_iter)) {
754 col_entry_name = entry_name(col_pentry);
755 if (strncmp(col_entry_name, first, offset) != 0) {
756 break;
757 }
758 fz_fprintf(fs, "%s\"%s\"", (ncol == 0 ? "" : ","),
759 col_entry_name + offset);
760 ncol++;
761 }
762 fz_fprintf(fs, "\n");
763
764 /* Iterate over rows and columns, incrementing ent_iter as we go,
765 * and writing values to the table. Have a separate iterator
766 * to the column names to check they all match.
767 */
768 irow = icol = 0;
769 col_iter = save_iter;
770 for (;;) {
771 char expect[128]; /* pentry->name we're expecting */
772
773 pentry = entry_list_link_data(ent_iter);
774 col_pentry = entry_list_link_data(col_iter);
775
776 fc_snprintf(expect, sizeof(expect), "%s%d.%s",
777 base, irow, entry_name(col_pentry) + offset);
778
779 /* break out of tabular if doesn't match: */
780 if ((!pentry) || (strcmp(entry_name(pentry), expect) != 0)) {
781 if (icol != 0) {
782 /* If the second or later row of a table is missing some
783 * entries that the first row had, we drop out of the tabular
784 * format. This is inefficient so we print a warning message;
785 * the calling code probably needs to be fixed so that it can
786 * use the more efficient tabular format.
787 *
788 * FIXME: If the first row is missing some entries that the
789 * second or later row has, then we'll drop out of tabular
790 * format without an error message. */
791 bugreport_request("In file %s, there is no entry in the registry for\n"
792 "%s.%s (or the entries are out of order). This means\n"
793 "a less efficient non-tabular format will be used.\n"
794 "To avoid this make sure all rows of a table are\n"
795 "filled out with an entry for every column.",
796 real_filename, section_name(psection), expect);
797 fz_fprintf(fs, "\n");
798 }
799 fz_fprintf(fs, "}\n");
800 break;
801 }
802
803 if (icol > 0) {
804 fz_fprintf(fs, ",");
805 }
806 entry_to_file(pentry, fs);
807
808 ent_iter = entry_list_link_next(ent_iter);
809 col_iter = entry_list_link_next(col_iter);
810
811 icol++;
812 if (icol == ncol) {
813 fz_fprintf(fs, "\n");
814 irow++;
815 icol = 0;
816 col_iter = save_iter;
817 }
818 }
819 if (!pentry) {
820 break;
821 }
822 }
823 if (!pentry) {
824 break;
825 }
826
827 /* Classic entry. */
828 col_entry_name = entry_name(pentry);
829 fz_fprintf(fs, "%s=", col_entry_name);
830 entry_to_file(pentry, fs);
831
832 /* Check for vector. */
833 for (i = 1;; i++) {
834 col_iter = entry_list_link_next(ent_iter);
835 col_pentry = entry_list_link_data(col_iter);
836 if (NULL == col_pentry) {
837 break;
838 }
839 fc_snprintf(pentry_name, sizeof(pentry_name),
840 "%s,%d", col_entry_name, i);
841 if (0 != strcmp(pentry_name, entry_name(col_pentry))) {
842 break;
843 }
844 fz_fprintf(fs, ",");
845 entry_to_file(col_pentry, fs);
846 ent_iter = col_iter;
847 }
848
849 comment = entry_comment(pentry);
850 if (comment) {
851 fz_fprintf(fs, " # %s\n", comment);
852 } else {
853 fz_fprintf(fs, "\n");
854 }
855 }
856 }
858
859 if (0 != fz_ferror(fs)) {
860 SECFILE_LOG(secfile, NULL, "Error before closing %s: %s",
861 real_filename, fz_strerror(fs));
862 fz_fclose(fs);
863 return FALSE;
864 }
865 if (0 != fz_fclose(fs)) {
866 SECFILE_LOG(secfile, NULL, "Error closing %s", real_filename);
867 return FALSE;
868 }
869
870 return TRUE;
871}
872
873/**********************************************************************/
880void secfile_check_unused(const struct section_file *secfile)
881{
882 bool any = FALSE;
883
886 if (!entry_used(pentry)) {
887 if (!any && secfile->name) {
888 log_verbose("Unused entries in file %s:", secfile->name);
889 any = TRUE;
890 }
892 log_deprecation_always("%s: unused entry: %s.%s",
893 secfile->name != NULL ? secfile->name : "nameless",
895 } else {
896#ifdef FREECIV_TESTMATIC
897 log_testmatic("%s: unused entry: %s.%s",
898 secfile->name != NULL ? secfile->name : "nameless",
900#else /* FREECIV_TESTMATIC */
901 log_verbose(" unused entry: %s.%s",
903#endif /* FREECIV_TESTMATIC */
904 }
905 }
908}
909
910/**********************************************************************/
916const char *secfile_name(const struct section_file *secfile)
917{
918 if (NULL == secfile) {
919 return "NULL";
920 } else if (secfile->name) {
921 return secfile->name;
922 } else {
923 return "(anonymous)";
924 }
925}
926
927/**********************************************************************/
931 const char *path,
932 const char **pent_name)
933{
934 char fullpath[MAX_LEN_SECPATH];
935 char *ent_name;
936 struct section *psection;
937
938 sz_strlcpy(fullpath, path);
939
940 ent_name = strchr(fullpath, '.');
941 if (!ent_name) {
942 SECFILE_LOG(secfile, NULL,
943 "Section and entry names must be separated by a dot.");
944 return NULL;
945 }
946
947 /* Separates section and entry names. */
948 *ent_name = '\0';
949 *pent_name = path + (ent_name - fullpath) + 1;
950 psection = secfile_section_by_name(secfile, fullpath);
951 if (psection) {
952 return psection;
953 } else {
954 return secfile_section_new(secfile, fullpath);
955 }
956}
957
958/**********************************************************************/
962 bool value, const char *comment,
963 bool allow_replace,
964 const char *path, ...)
965{
966 char fullpath[MAX_LEN_SECPATH];
967 const char *ent_name;
968 struct section *psection;
969 struct entry *pentry = NULL;
970 va_list args;
971
972 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
973
974 va_start(args, path);
975 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
976 va_end(args);
977
978 psection = secfile_insert_base(secfile, fullpath, &ent_name);
979 if (!psection) {
980 return NULL;
981 }
982
983 if (allow_replace) {
984 pentry = section_entry_by_name(psection, ent_name);
985 if (NULL != pentry) {
986 if (ENTRY_BOOL == entry_type_get(pentry)) {
987 if (!entry_bool_set(pentry, value)) {
988 return NULL;
989 }
990 } else {
991 entry_destroy(pentry);
992 pentry = NULL;
993 }
994 }
995 }
996
997 if (NULL == pentry) {
998 pentry = section_entry_bool_new(psection, ent_name, value);
999 }
1000
1001 if (NULL != pentry && NULL != comment) {
1002 entry_set_comment(pentry, comment);
1003 }
1004
1005 return pentry;
1006}
1007
1008/**********************************************************************/
1013 const bool *values, size_t dim,
1014 const char *comment, bool allow_replace,
1015 const char *path, ...)
1016{
1017 char fullpath[MAX_LEN_SECPATH];
1018 size_t i, ret = 0;
1019 va_list args;
1020
1021 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1022
1023 va_start(args, path);
1024 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1025 va_end(args);
1026
1027 /* NB: 'path,0' is actually 'path'. See comment in the head
1028 * of the file. */
1029 if (dim > 0
1030 && NULL != secfile_insert_bool_full(secfile, values[0], comment,
1031 allow_replace, "%s", fullpath)) {
1032 ret++;
1033 }
1034 for (i = 1; i < dim; i++) {
1035 if (NULL != secfile_insert_bool_full(secfile, values[i], comment,
1036 allow_replace, "%s,%d",
1037 fullpath, (int) i)) {
1038 ret++;
1039 }
1040 }
1041
1042 return ret;
1043}
1044
1045/**********************************************************************/
1049 int value, const char *comment,
1050 bool allow_replace,
1051 const char *path, ...)
1052{
1053 char fullpath[MAX_LEN_SECPATH];
1054 const char *ent_name;
1055 struct section *psection;
1056 struct entry *pentry = NULL;
1057 va_list args;
1058
1059 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1060
1061 va_start(args, path);
1062 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1063 va_end(args);
1064
1065 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1066 if (!psection) {
1067 return NULL;
1068 }
1069
1070 if (allow_replace) {
1071 pentry = section_entry_by_name(psection, ent_name);
1072 if (NULL != pentry) {
1073 if (ENTRY_INT == entry_type_get(pentry)) {
1074 if (!entry_int_set(pentry, value)) {
1075 return NULL;
1076 }
1077 } else {
1078 entry_destroy(pentry);
1079 pentry = NULL;
1080 }
1081 }
1082 }
1083
1084 if (NULL == pentry) {
1085 pentry = section_entry_int_new(psection, ent_name, value);
1086 }
1087
1088 if (NULL != pentry && NULL != comment) {
1089 entry_set_comment(pentry, comment);
1090 }
1091
1092 return pentry;
1093}
1094
1095/**********************************************************************/
1100 const int *values, size_t dim,
1101 const char *comment, bool allow_replace,
1102 const char *path, ...)
1103{
1104 char fullpath[MAX_LEN_SECPATH];
1105 size_t i, ret = 0;
1106 va_list args;
1107
1108 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1109
1110 va_start(args, path);
1111 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1112 va_end(args);
1113
1114 /* NB: 'path,0' is actually 'path'. See comment in the head
1115 * of the file. */
1116 if (dim > 0
1117 && NULL != secfile_insert_int_full(secfile, values[0], comment,
1118 allow_replace, "%s", fullpath)) {
1119 ret++;
1120 }
1121 for (i = 1; i < dim; i++) {
1122 if (NULL != secfile_insert_int_full(secfile, values[i], comment,
1123 allow_replace, "%s,%d",
1124 fullpath, (int) i)) {
1125 ret++;
1126 }
1127 }
1128
1129 return ret;
1130}
1131
1132/**********************************************************************/
1136 float value, const char *comment,
1137 bool allow_replace,
1138 const char *path, ...)
1139{
1140 char fullpath[MAX_LEN_SECPATH];
1141 const char *ent_name;
1142 struct section *psection;
1143 struct entry *pentry = NULL;
1144 va_list args;
1145
1146 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1147
1148 va_start(args, path);
1149 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1150 va_end(args);
1151
1152 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1153 if (!psection) {
1154 return NULL;
1155 }
1156
1157 if (allow_replace) {
1158 pentry = section_entry_by_name(psection, ent_name);
1159 if (NULL != pentry) {
1160 if (ENTRY_FLOAT == entry_type_get(pentry)) {
1161 if (!entry_float_set(pentry, value)) {
1162 return NULL;
1163 }
1164 } else {
1165 entry_destroy(pentry);
1166 pentry = NULL;
1167 }
1168 }
1169 }
1170
1171 if (NULL == pentry) {
1172 pentry = section_entry_float_new(psection, ent_name, value);
1173 }
1174
1175 if (NULL != pentry && NULL != comment) {
1176 entry_set_comment(pentry, comment);
1177 }
1178
1179 return pentry;
1180}
1181
1182/**********************************************************************/
1186 const char *filename)
1187{
1188 struct section *psection;
1189 char buffer[200];
1190
1191 fc_snprintf(buffer, sizeof(buffer), "include_%u", secfile->num_includes++);
1192
1193 fc_assert_ret_val(secfile_section_by_name(secfile, buffer) == NULL, NULL);
1194
1195 /* Create include section. */
1196 psection = secfile_section_new(secfile, buffer);
1197 psection->special = EST_INCLUDE;
1198
1199 /* Then add string entry "file" to it. */
1200 secfile_insert_str_full(secfile, filename, NULL, FALSE, FALSE,
1201 EST_INCLUDE, "%s.file", buffer);
1202
1203 return psection;
1204}
1205
1206/**********************************************************************/
1210 const char *comment)
1211{
1212 struct section *psection;
1213 char buffer[200];
1214
1215 fc_snprintf(buffer, sizeof(buffer), "long_comment_%u", secfile->num_long_comments++);
1216
1217 fc_assert_ret_val(secfile_section_by_name(secfile, buffer) == NULL, NULL);
1218
1219 /* Create long comment section. */
1220 psection = secfile_section_new(secfile, buffer);
1221 psection->special = EST_COMMENT;
1222
1223 /* Then add string entry "comment" to it. */
1224 secfile_insert_str_full(secfile, comment, NULL, FALSE, TRUE,
1225 EST_COMMENT, "%s.comment", buffer);
1226
1227 return psection;
1228}
1229
1230/**********************************************************************/
1234 const char *str,
1235 const char *comment,
1236 bool allow_replace,
1237 bool no_escape,
1238 enum entry_special_type stype,
1239 const char *path, ...)
1240{
1241 char fullpath[MAX_LEN_SECPATH];
1242 const char *ent_name;
1243 struct section *psection;
1244 struct entry *pentry = NULL;
1245 va_list args;
1246
1247 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1248
1249 va_start(args, path);
1250 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1251 va_end(args);
1252
1253 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1254 if (!psection) {
1255 return NULL;
1256 }
1257
1258 if (psection->special != stype) {
1259 log_error("Tried to insert wrong type of entry to section");
1260 return NULL;
1261 }
1262
1263 if (allow_replace) {
1264 pentry = section_entry_by_name(psection, ent_name);
1265 if (NULL != pentry) {
1266 if (ENTRY_STR == entry_type_get(pentry)) {
1267 if (!entry_str_set(pentry, str)) {
1268 return NULL;
1269 }
1270 } else {
1271 entry_destroy(pentry);
1272 pentry = NULL;
1273 }
1274 }
1275 }
1276
1277 if (NULL == pentry) {
1278 pentry = section_entry_str_new(psection, ent_name, str, !no_escape);
1279 }
1280
1281 if (NULL != pentry && NULL != comment) {
1282 entry_set_comment(pentry, comment);
1283 }
1284
1285 if (stype == EST_COMMENT) {
1286 pentry->string.raw = TRUE;
1287 }
1288
1289 return pentry;
1290}
1291
1292/**********************************************************************/
1297 const char *const *strings, size_t dim,
1298 const char *comment, bool allow_replace,
1299 bool no_escape, const char *path, ...)
1300{
1301 char fullpath[MAX_LEN_SECPATH];
1302 size_t i, ret = 0;
1303 va_list args;
1304
1305 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1306
1307 va_start(args, path);
1308 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1309 va_end(args);
1310
1311 /* NB: 'path,0' is actually 'path'. See comment in the head
1312 * of the file. */
1313 if (dim > 0
1314 && NULL != secfile_insert_str_full(secfile, strings[0], comment,
1315 allow_replace, no_escape, FALSE,
1316 "%s", fullpath)) {
1317 ret++;
1318 }
1319 for (i = 1; i < dim; i++) {
1320 if (NULL != secfile_insert_str_full(secfile, strings[i], comment,
1321 allow_replace, no_escape, FALSE,
1322 "%s,%d", fullpath, (int) i)) {
1323 ret++;
1324 }
1325 }
1326
1327 return ret;
1328}
1329
1330/**********************************************************************/
1334 const char *filename,
1335 const char *path, ...)
1336{
1337 char fullpath[MAX_LEN_SECPATH];
1338 const char *ent_name;
1339 struct section *psection;
1340 struct entry *pentry = NULL;
1341 va_list args;
1342
1343 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1344
1345 va_start(args, path);
1346 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1347 va_end(args);
1348
1349 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1350 if (!psection) {
1351 return NULL;
1352 }
1353
1354 if (psection->special != EST_NORMAL) {
1355 log_error("Tried to insert normal entry to different kind of section");
1356 return NULL;
1357 }
1358
1359 if (NULL == pentry) {
1360 pentry = section_entry_filereference_new(psection, ent_name, filename);
1361 }
1362
1363 return pentry;
1364}
1365
1366/**********************************************************************/
1370 int enumerator,
1371 secfile_enum_name_fn_t name_fn,
1372 const char *comment,
1373 bool allow_replace,
1374 const char *path, ...)
1375{
1376 char fullpath[MAX_LEN_SECPATH];
1377 const char *str;
1378 const char *ent_name;
1379 struct section *psection;
1380 struct entry *pentry = NULL;
1381 va_list args;
1382
1383 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1384 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1385 str = name_fn(enumerator);
1386 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != str, NULL);
1387
1388 va_start(args, path);
1389 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1390 va_end(args);
1391
1392 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1393 if (!psection) {
1394 return NULL;
1395 }
1396
1397 if (allow_replace) {
1398 pentry = section_entry_by_name(psection, ent_name);
1399 if (NULL != pentry) {
1400 if (ENTRY_STR == entry_type_get(pentry)) {
1401 if (!entry_str_set(pentry, str)) {
1402 return NULL;
1403 }
1404 } else {
1405 entry_destroy(pentry);
1406 pentry = NULL;
1407 }
1408 }
1409 }
1410
1411 if (NULL == pentry) {
1412 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1413 }
1414
1415 if (NULL != pentry && NULL != comment) {
1416 entry_set_comment(pentry, comment);
1417 }
1418
1419 return pentry;
1420}
1421
1422/**********************************************************************/
1427 const int *enumurators, size_t dim,
1428 secfile_enum_name_fn_t name_fn,
1429 const char *comment,
1430 bool allow_replace,
1431 const char *path, ...)
1432{
1433 char fullpath[MAX_LEN_SECPATH];
1434 size_t i, ret = 0;
1435 va_list args;
1436
1437 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1438 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1439
1440 va_start(args, path);
1441 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1442 va_end(args);
1443
1444 /* NB: 'path,0' is actually 'path'. See comment in the head
1445 * of the file. */
1446 if (dim > 0
1447 && NULL != secfile_insert_plain_enum_full(secfile, enumurators[0],
1448 name_fn, comment,
1449 allow_replace, "%s",
1450 fullpath)) {
1451 ret++;
1452 }
1453 for (i = 1; i < dim; i++) {
1454 if (NULL != secfile_insert_plain_enum_full(secfile, enumurators[i],
1455 name_fn, comment,
1456 allow_replace, "%s,%d",
1457 fullpath, (int) i)) {
1458 ret++;
1459 }
1460 }
1461
1462 return ret;
1463}
1464
1465/**********************************************************************/
1469 int bitwise_val,
1471 name_fn,
1473 begin_fn,
1475 end_fn,
1477 next_fn,
1478 const char *comment,
1479 bool allow_replace,
1480 const char *path, ...)
1481{
1482 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1483 const char *ent_name;
1484 struct section *psection;
1485 struct entry *pentry = NULL;
1486 va_list args;
1487 int i;
1488
1489 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1490 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1491 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, NULL);
1492 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, NULL);
1493 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, NULL);
1494
1495 /* Compute a string containing all the values separated by '|'. */
1496 str[0] = '\0'; /* Insert at least an empty string. */
1497 if (0 != bitwise_val) {
1498 for (i = begin_fn(); i != end_fn(); i = next_fn(i)) {
1499 if (i & bitwise_val) {
1500 if ('\0' == str[0]) {
1501 sz_strlcpy(str, name_fn(i));
1502 } else {
1503 cat_snprintf(str, sizeof(str), "|%s", name_fn(i));
1504 }
1505 }
1506 }
1507 }
1508
1509 va_start(args, path);
1510 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1511 va_end(args);
1512
1513 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1514 if (!psection) {
1515 return NULL;
1516 }
1517
1518 if (allow_replace) {
1519 pentry = section_entry_by_name(psection, ent_name);
1520 if (NULL != pentry) {
1521 if (ENTRY_STR == entry_type_get(pentry)) {
1522 if (!entry_str_set(pentry, str)) {
1523 return NULL;
1524 }
1525 } else {
1526 entry_destroy(pentry);
1527 pentry = NULL;
1528 }
1529 }
1530 }
1531
1532 if (NULL == pentry) {
1533 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1534 }
1535
1536 if (NULL != pentry && NULL != comment) {
1537 entry_set_comment(pentry, comment);
1538 }
1539
1540 return pentry;
1541}
1542
1543/**********************************************************************/
1548 const int *bitwise_vals,
1549 size_t dim,
1550 secfile_enum_name_fn_t name_fn,
1551 secfile_enum_iter_fn_t begin_fn,
1553 secfile_enum_next_fn_t next_fn,
1554 const char *comment,
1555 bool allow_replace,
1556 const char *path, ...)
1557{
1558 char fullpath[MAX_LEN_SECPATH];
1559 size_t i, ret = 0;
1560 va_list args;
1561
1562 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1563 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1564 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != begin_fn, 0);
1565 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != end_fn, 0);
1566 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != next_fn, 0);
1567
1568 va_start(args, path);
1569 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1570 va_end(args);
1571
1572 /* NB: 'path,0' is actually 'path'. See comment in the head
1573 * of the file. */
1574 if (dim > 0
1575 && NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[0],
1576 name_fn, begin_fn, end_fn,
1577 next_fn, comment,
1578 allow_replace, "%s",
1579 fullpath)) {
1580 ret++;
1581 }
1582 for (i = 1; i < dim; i++) {
1583 if (NULL != secfile_insert_bitwise_enum_full(secfile, bitwise_vals[i],
1584 name_fn, begin_fn, end_fn,
1585 next_fn, comment,
1586 allow_replace, "%s,%d",
1587 fullpath, (int) i)) {
1588 ret++;
1589 }
1590 }
1591
1592 return ret;
1593}
1594
1595/**********************************************************************/
1600 int value, bool bitwise,
1602 secfile_data_t data,
1603 const char *comment,
1604 bool allow_replace,
1605 const char *path, ...)
1606{
1607 char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1608 const char *ent_name, *val_name;
1609 struct section *psection;
1610 struct entry *pentry = NULL;
1611 va_list args;
1612 int i;
1613
1614 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1615 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
1616
1617 if (bitwise) {
1618 /* Compute a string containing all the values separated by '|'. */
1619 str[0] = '\0'; /* Insert at least an empty string. */
1620 if (0 != value) {
1621 for (i = 0; (val_name = name_fn(data, i)); i++) {
1622 if ((1 << i) & value) {
1623 if ('\0' == str[0]) {
1624 sz_strlcpy(str, val_name);
1625 } else {
1626 cat_snprintf(str, sizeof(str), "|%s", val_name);
1627 }
1628 }
1629 }
1630 }
1631 } else {
1632 if (!(val_name = name_fn(data, value))) {
1633 SECFILE_LOG(secfile, NULL, "Value %d not supported.", value);
1634 return NULL;
1635 }
1636 sz_strlcpy(str, val_name);
1637 }
1638
1639 va_start(args, path);
1640 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1641 va_end(args);
1642
1643 psection = secfile_insert_base(secfile, fullpath, &ent_name);
1644 if (!psection) {
1645 return NULL;
1646 }
1647
1648 if (allow_replace) {
1649 pentry = section_entry_by_name(psection, ent_name);
1650 if (NULL != pentry) {
1651 if (ENTRY_STR == entry_type_get(pentry)) {
1652 if (!entry_str_set(pentry, str)) {
1653 return NULL;
1654 }
1655 } else {
1656 entry_destroy(pentry);
1657 pentry = NULL;
1658 }
1659 }
1660 }
1661
1662 if (NULL == pentry) {
1663 pentry = section_entry_str_new(psection, ent_name, str, TRUE);
1664 }
1665
1666 if (NULL != pentry && NULL != comment) {
1667 entry_set_comment(pentry, comment);
1668 }
1669
1670 return pentry;
1671}
1672
1673/**********************************************************************/
1678 const int *values, size_t dim,
1679 bool bitwise,
1681 secfile_data_t data,
1682 const char *comment,
1683 bool allow_replace,
1684 const char *path, ...)
1685{
1686 char fullpath[MAX_LEN_SECPATH];
1687 size_t i, ret = 0;
1688 va_list args;
1689
1690 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, 0);
1691 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, 0);
1692
1693 va_start(args, path);
1694 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1695 va_end(args);
1696
1697 /* NB: 'path,0' is actually 'path'. See comment in the head
1698 * of the file. */
1699 if (dim > 0
1700 && NULL != secfile_insert_enum_data_full(secfile, values[0], bitwise,
1701 name_fn, data, comment,
1702 allow_replace, "%s",
1703 fullpath)) {
1704 ret++;
1705 }
1706 for (i = 1; i < dim; i++) {
1707 if (NULL != secfile_insert_enum_data_full(secfile, values[i], bitwise,
1708 name_fn, data, comment,
1709 allow_replace, "%s,%d",
1710 fullpath, (int) i)) {
1711 ret++;
1712 }
1713 }
1714
1715 return ret;
1716}
1717
1718/**********************************************************************/
1721struct entry *secfile_entry_by_path(const struct section_file *secfile,
1722 const char *path)
1723{
1724 char fullpath[MAX_LEN_SECPATH];
1725 char *ent_name;
1726 size_t len;
1727 struct section *psection;
1728
1729 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1730
1731 sz_strlcpy(fullpath, path);
1732
1733 /* treat "sec.foo,0" as "sec.foo": */
1734 len = strlen(fullpath);
1735 if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1736 fullpath[len - 2] = '\0';
1737 }
1738
1739 if (NULL != secfile->hash.entries) {
1740 struct entry *pentry;
1741
1742 if (entry_hash_lookup(secfile->hash.entries, fullpath, &pentry)) {
1743 entry_use(pentry);
1744 }
1745 return pentry;
1746 }
1747
1748 /* I dont like strtok.
1749 * - Me neither! */
1750 ent_name = strchr(fullpath, '.');
1751 if (!ent_name) {
1752 return NULL;
1753 }
1754
1755 /* Separates section and entry names. */
1756 *ent_name++ = '\0';
1757 psection = secfile_section_by_name(secfile, fullpath);
1758 if (psection) {
1759 return section_entry_by_name(psection, ent_name);
1760 } else {
1761 return NULL;
1762 }
1763}
1764
1765/**********************************************************************/
1769 const char *path, ...)
1770{
1771 char fullpath[MAX_LEN_SECPATH];
1772 va_list args;
1773 struct entry *pentry;
1774
1775 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1776
1777 va_start(args, path);
1778 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1779 va_end(args);
1780
1781 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1782 SECFILE_LOG(secfile, NULL, "Path %s does not exists.", fullpath);
1783 return FALSE;
1784 }
1785
1786 entry_destroy(pentry);
1787
1788 return TRUE;
1789}
1790
1791/**********************************************************************/
1794struct entry *secfile_entry_lookup(const struct section_file *secfile,
1795 const char *path, ...)
1796{
1797 char fullpath[MAX_LEN_SECPATH];
1798 va_list args;
1799
1800 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1801
1802 va_start(args, path);
1803 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1804 va_end(args);
1805
1806 return secfile_entry_by_path(secfile, fullpath);
1807}
1808
1809/**********************************************************************/
1812bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1813 const char *path, ...)
1814{
1815 char fullpath[MAX_LEN_SECPATH];
1816 const struct entry *pentry;
1817 va_list args;
1818
1819 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1820
1821 va_start(args, path);
1822 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1823 va_end(args);
1824
1825 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1826 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1827 return FALSE;
1828 }
1829
1830 return entry_bool_get(pentry, bval);
1831}
1832
1833/**********************************************************************/
1838 bool def, const char *path, ...)
1839{
1840 char fullpath[MAX_LEN_SECPATH];
1841 const struct entry *pentry;
1842 bool bval;
1843 va_list args;
1844
1845 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1846
1847 va_start(args, path);
1848 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1849 va_end(args);
1850
1851 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1852 return def;
1853 }
1854
1855 if (entry_bool_get(pentry, &bval)) {
1856 return bval;
1857 }
1858
1859 return def;
1860}
1861
1862/**********************************************************************/
1867bool *secfile_lookup_bool_vec(const struct section_file *secfile,
1868 size_t *dim, const char *path, ...)
1869{
1870 char fullpath[MAX_LEN_SECPATH];
1871 size_t i = 0;
1872 bool *vec;
1873 va_list args;
1874
1875 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
1876 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
1877
1878 va_start(args, path);
1879 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1880 va_end(args);
1881
1882 /* Check size. */
1883 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
1884 i++;
1885 }
1886 *dim = i;
1887
1888 if (0 == i) {
1889 /* Doesn't exist. */
1890 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1891 return NULL;
1892 }
1893
1894 vec = fc_malloc(i * sizeof(bool));
1895 for (i = 0; i < *dim; i++) {
1896 if (!secfile_lookup_bool(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
1897 SECFILE_LOG(secfile, NULL,
1898 "An error occurred when looking up to \"%s,%d\" entry.",
1899 fullpath, (int) i);
1900 free(vec);
1901 *dim = 0;
1902 return NULL;
1903 }
1904 }
1905
1906 return vec;
1907}
1908
1909/**********************************************************************/
1912bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1913 const char *path, ...)
1914{
1915 char fullpath[MAX_LEN_SECPATH];
1916 const struct entry *pentry;
1917 va_list args;
1918
1919 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
1920
1921 va_start(args, path);
1922 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1923 va_end(args);
1924
1925 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1926 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
1927 return FALSE;
1928 }
1929
1930 return entry_int_get(pentry, ival);
1931}
1932
1933/**********************************************************************/
1937int secfile_lookup_int_default(const struct section_file *secfile, int def,
1938 const char *path, ...)
1939{
1940 char fullpath[MAX_LEN_SECPATH];
1941 const struct entry *pentry;
1942 int ival;
1943 va_list args;
1944
1945 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
1946
1947 va_start(args, path);
1948 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1949 va_end(args);
1950
1951 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1952 return def;
1953 }
1954
1955 if (entry_int_get(pentry, &ival)) {
1956 return ival;
1957 }
1958
1959 return def;
1960}
1961
1962/**********************************************************************/
1968 int defval, int minval, int maxval,
1969 const char *path, ...)
1970{
1971 char fullpath[MAX_LEN_SECPATH];
1972 const struct entry *pentry;
1973 int value;
1974 va_list args;
1975
1976 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
1977
1978 va_start(args, path);
1979 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1980 va_end(args);
1981
1982 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1983 return defval;
1984 }
1985
1986 if (!entry_int_get(pentry, &value)) {
1987 return defval;
1988 }
1989
1990 if (value < minval) {
1991 SECFILE_LOG(secfile, entry_section(pentry),
1992 "\"%s\" should be in the interval [%d, %d] but is %d;"
1993 "using the minimal value.",
1994 fullpath, minval, maxval, value);
1995 value = minval;
1996 }
1997
1998 if (value > maxval) {
1999 SECFILE_LOG(secfile, entry_section(pentry),
2000 "\"%s\" should be in the interval [%d, %d] but is %d;"
2001 "using the maximal value.",
2002 fullpath, minval, maxval, value);
2003 value = maxval;
2004 }
2005
2006 return value;
2007}
2008
2009/**********************************************************************/
2014int *secfile_lookup_int_vec(const struct section_file *secfile,
2015 size_t *dim, const char *path, ...)
2016{
2017 char fullpath[MAX_LEN_SECPATH];
2018 size_t i = 0;
2019 int *vec;
2020 va_list args;
2021
2022 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2023 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2024
2025 va_start(args, path);
2026 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2027 va_end(args);
2028
2029 /* Check size. */
2030 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2031 i++;
2032 }
2033 *dim = i;
2034
2035 if (0 == i) {
2036 /* Doesn't exist. */
2037 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2038 return NULL;
2039 }
2040
2041 vec = fc_malloc(i * sizeof(int));
2042 for (i = 0; i < *dim; i++) {
2043 if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath, (int) i)) {
2044 SECFILE_LOG(secfile, NULL,
2045 "An error occurred when looking up to \"%s,%d\" entry.",
2046 fullpath, (int) i);
2047 free(vec);
2048 *dim = 0;
2049 return NULL;
2050 }
2051 }
2052
2053 return vec;
2054}
2055
2056/**********************************************************************/
2059bool secfile_lookup_float(const struct section_file *secfile, float *fval,
2060 const char *path, ...)
2061{
2062 char fullpath[MAX_LEN_SECPATH];
2063 const struct entry *pentry;
2064 va_list args;
2065
2066 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2067
2068 va_start(args, path);
2069 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2070 va_end(args);
2071
2072 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2073 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2074 return FALSE;
2075 }
2076
2077 return entry_float_get(pentry, fval);
2078}
2079
2080/**********************************************************************/
2084float secfile_lookup_float_default(const struct section_file *secfile,
2085 float def, const char *path, ...)
2086{
2087 char fullpath[MAX_LEN_SECPATH];
2088 const struct entry *pentry;
2089 float fval;
2090 va_list args;
2091
2092 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2093
2094 va_start(args, path);
2095 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2096 va_end(args);
2097
2098 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2099 return def;
2100 }
2101
2102 if (entry_float_get(pentry, &fval)) {
2103 return fval;
2104 }
2105
2106 return def;
2107}
2108
2109/**********************************************************************/
2112const char *secfile_lookup_str(const struct section_file *secfile,
2113 const char *path, ...)
2114{
2115 char fullpath[MAX_LEN_SECPATH];
2116 const struct entry *pentry;
2117 const char *str;
2118 va_list args;
2119
2120 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2121
2122 va_start(args, path);
2123 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2124 va_end(args);
2125
2126 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2127 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2128 return NULL;
2129 }
2130
2131 if (entry_str_get(pentry, &str)) {
2132 return str;
2133 }
2134
2135 return NULL;
2136}
2137
2138/**********************************************************************/
2142const char *secfile_lookup_str_default(const struct section_file *secfile,
2143 const char *def,
2144 const char *path, ...)
2145{
2146 char fullpath[MAX_LEN_SECPATH];
2147 const struct entry *pentry;
2148 const char *str;
2149 va_list args;
2150
2151 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, def);
2152
2153 va_start(args, path);
2154 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2155 va_end(args);
2156
2157 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2158 return def;
2159 }
2160
2161 if (entry_str_get(pentry, &str)) {
2162 return str;
2163 }
2164
2165 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't have a string.", fullpath);
2166
2167 return def;
2168}
2169
2170/**********************************************************************/
2176const char **secfile_lookup_str_vec(const struct section_file *secfile,
2177 size_t *dim, const char *path, ...)
2178{
2179 char fullpath[MAX_LEN_SECPATH];
2180 size_t i = 0;
2181 const char **vec;
2182 va_list args;
2183
2184 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2185 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2186
2187 va_start(args, path);
2188 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2189 va_end(args);
2190
2191 /* Check size. */
2192 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2193 i++;
2194 }
2195 *dim = i;
2196
2197 if (0 == i) {
2198 /* Doesn't exist. */
2199 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2200 return NULL;
2201 }
2202
2203 vec = fc_malloc(i * sizeof(const char *));
2204 for (i = 0; i < *dim; i++) {
2205 if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d",
2206 fullpath, (int) i))) {
2207 SECFILE_LOG(secfile, NULL,
2208 "An error occurred when looking up to \"%s,%d\" entry.",
2209 fullpath, (int) i);
2210 free(vec);
2211 *dim = 0;
2212 return NULL;
2213 }
2214 }
2215
2216 return vec;
2217}
2218
2219/**********************************************************************/
2223 int *penumerator,
2224 secfile_enum_is_valid_fn_t is_valid_fn,
2225 secfile_enum_by_name_fn_t by_name_fn,
2226 const char *path, ...)
2227{
2228 char fullpath[MAX_LEN_SECPATH];
2229 const struct entry *pentry;
2230 const char *str;
2231 va_list args;
2232
2233 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2234 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2235 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2236 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2237
2238 va_start(args, path);
2239 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2240 va_end(args);
2241
2242 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2243 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2244 return FALSE;
2245 }
2246
2247 if (!entry_str_get(pentry, &str)) {
2248 return FALSE;
2249 }
2250
2251 *penumerator = by_name_fn(str, strcmp);
2252 if (is_valid_fn(*penumerator)) {
2253 return TRUE;
2254 }
2255
2256 SECFILE_LOG(secfile, entry_section(pentry),
2257 "Entry \"%s\": no match for \"%s\".",
2258 entry_name(pentry), str);
2259 return FALSE;
2260}
2261
2262/**********************************************************************/
2266 *secfile, int defval,
2268 is_valid_fn,
2270 by_name_fn,
2271 const char *path, ...)
2272{
2273 char fullpath[MAX_LEN_SECPATH];
2274 const struct entry *pentry;
2275 const char *str;
2276 int val;
2277 va_list args;
2278
2279 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2280 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2281 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2282
2283 va_start(args, path);
2284 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2285 va_end(args);
2286
2287 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2288 return defval;
2289 }
2290
2291 if (!entry_str_get(pentry, &str)) {
2292 return defval;
2293 }
2294
2295 val = by_name_fn(str, strcmp);
2296 if (is_valid_fn(val)) {
2297 return val;
2298 } else {
2299 return defval;
2300 }
2301}
2302
2303/**********************************************************************/
2309 size_t *dim,
2311 is_valid_fn,
2313 by_name_fn,
2314 const char *path, ...)
2315{
2316 char fullpath[MAX_LEN_SECPATH];
2317 size_t i = 0;
2318 int *vec;
2319 va_list args;
2320
2321 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2322 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2323 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2324 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2325
2326 va_start(args, path);
2327 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2328 va_end(args);
2329
2330 /* Check size. */
2331 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2332 i++;
2333 }
2334 *dim = i;
2335
2336 if (0 == i) {
2337 /* Doesn't exist. */
2338 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2339 return NULL;
2340 }
2341
2342 vec = fc_malloc(i * sizeof(int));
2343 for (i = 0; i < *dim; i++) {
2344 if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2345 by_name_fn, "%s,%d",
2346 fullpath, (int) i)) {
2347 SECFILE_LOG(secfile, NULL,
2348 "An error occurred when looking up to \"%s,%d\" entry.",
2349 fullpath, (int) i);
2350 free(vec);
2351 *dim = 0;
2352 return NULL;
2353 }
2354 }
2355
2356 return vec;
2357}
2358
2359/**********************************************************************/
2363 int *penumerator,
2364 secfile_enum_is_valid_fn_t is_valid_fn,
2365 secfile_enum_by_name_fn_t by_name_fn,
2366 const char *path, ...)
2367{
2368 char fullpath[MAX_LEN_SECPATH];
2369 const struct entry *pentry;
2370 const char *str, *p;
2371 char val_name[MAX_LEN_SECPATH];
2372 int val;
2373 va_list args;
2374
2375 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2376 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != penumerator, FALSE);
2377 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, FALSE);
2378 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, FALSE);
2379
2380 va_start(args, path);
2381 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2382 va_end(args);
2383
2384 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2385 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2386 return FALSE;
2387 }
2388
2389 if (!entry_str_get(pentry, &str)) {
2390 return FALSE;
2391 }
2392
2393 *penumerator = 0;
2394 if ('\0' == str[0]) {
2395 /* Empty string = no value. */
2396 return TRUE;
2397 }
2398
2399 /* Value names are separated by '|'. */
2400 do {
2401 p = strchr(str, '|');
2402 if (NULL != p) {
2403 p++;
2404 fc_strlcpy(val_name, str, p - str);
2405 } else {
2406 /* Last segment, full copy. */
2407 sz_strlcpy(val_name, str);
2408 }
2410 val = by_name_fn(val_name, strcmp);
2411 if (!is_valid_fn(val)) {
2412 SECFILE_LOG(secfile, entry_section(pentry),
2413 "Entry \"%s\": no match for \"%s\".",
2414 entry_name(pentry), val_name);
2415 return FALSE;
2416 }
2417 *penumerator |= val;
2418 str = p;
2419 } while (NULL != p);
2420
2421 return TRUE;
2422}
2423
2424/**********************************************************************/
2428 *secfile, int defval,
2430 is_valid_fn,
2432 by_name_fn,
2433 const char *path, ...)
2434{
2435 char fullpath[MAX_LEN_SECPATH];
2436 const struct entry *pentry;
2437 const char *str, *p;
2438 char val_name[MAX_LEN_SECPATH];
2439 int val, full_val;
2440 va_list args;
2441
2442 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2443 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, defval);
2444 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, defval);
2445
2446 va_start(args, path);
2447 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2448 va_end(args);
2449
2450 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2451 return defval;
2452 }
2453
2454 if (!entry_str_get(pentry, &str)) {
2455 return defval;
2456 }
2457
2458 if ('\0' == str[0]) {
2459 /* Empty string = no value. */
2460 return 0;
2461 }
2462
2463 /* Value names are separated by '|'. */
2464 full_val = 0;
2465 do {
2466 p = strchr(str, '|');
2467 if (NULL != p) {
2468 p++;
2469 fc_strlcpy(val_name, str, p - str);
2470 } else {
2471 /* Last segment, full copy. */
2472 sz_strlcpy(val_name, str);
2473 }
2475 val = by_name_fn(val_name, strcmp);
2476 if (!is_valid_fn(val)) {
2477 return defval;
2478 }
2479 full_val |= val;
2480 str = p;
2481 } while (NULL != p);
2482
2483 return full_val;
2484}
2485
2486/**********************************************************************/
2492 size_t *dim,
2494 is_valid_fn,
2496 by_name_fn,
2497 const char *path, ...)
2498{
2499 char fullpath[MAX_LEN_SECPATH];
2500 size_t i = 0;
2501 int *vec;
2502 va_list args;
2503
2504 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2505 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2506 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != is_valid_fn, NULL);
2507 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != by_name_fn, NULL);
2508
2509 va_start(args, path);
2510 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2511 va_end(args);
2512
2513 /* Check size. */
2514 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2515 i++;
2516 }
2517 *dim = i;
2518
2519 if (0 == i) {
2520 /* Doesn't exist. */
2521 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2522 return NULL;
2523 }
2524
2525 vec = fc_malloc(i * sizeof(int));
2526 for (i = 0; i < *dim; i++) {
2527 if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2528 by_name_fn, "%s,%d",
2529 fullpath, (int) i)) {
2530 SECFILE_LOG(secfile, NULL,
2531 "An error occurred when looking up to \"%s,%d\" entry.",
2532 fullpath, (int) i);
2533 free(vec);
2534 *dim = 0;
2535
2536 return NULL;
2537 }
2538 }
2539
2540 return vec;
2541}
2542
2543/**********************************************************************/
2546bool secfile_lookup_enum_data(const struct section_file *secfile,
2547 int *pvalue, bool bitwise,
2549 secfile_data_t data, const char *path, ...)
2550{
2551 char fullpath[MAX_LEN_SECPATH];
2552 const struct entry *pentry;
2553 const char *str, *p, *name;
2554 char val_name[MAX_LEN_SECPATH];
2555 int val;
2556 va_list args;
2557
2558 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, FALSE);
2559 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != pvalue, FALSE);
2560 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, FALSE);
2561
2562 va_start(args, path);
2563 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2564 va_end(args);
2565
2566 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2567 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2568 return FALSE;
2569 }
2570
2571 if (!entry_str_get(pentry, &str)) {
2572 return FALSE;
2573 }
2574
2575 if (bitwise) {
2576 *pvalue = 0;
2577 if ('\0' == str[0]) {
2578 /* Empty string = no value. */
2579 return TRUE;
2580 }
2581
2582 /* Value names are separated by '|'. */
2583 do {
2584 p = strchr(str, '|');
2585 if (NULL != p) {
2586 p++;
2587 fc_strlcpy(val_name, str, p - str);
2588 } else {
2589 /* Last segment, full copy. */
2590 sz_strlcpy(val_name, str);
2591 }
2593 for (val = 0; (name = name_fn(data, val)); val++) {
2594 if (0 == fc_strcasecmp(name, val_name)) {
2595 break;
2596 }
2597 }
2598 if (NULL == name) {
2599 SECFILE_LOG(secfile, entry_section(pentry),
2600 "Entry \"%s\": no match for \"%s\".",
2601 entry_name(pentry), val_name);
2602 return FALSE;
2603 }
2604 *pvalue |= 1 << val;
2605 str = p;
2606 } while (NULL != p);
2607 } else {
2608 for (val = 0; (name = name_fn(data, val)); val++) {
2609 if (0 == fc_strcasecmp(name, str)) {
2610 *pvalue = val;
2611 break;
2612 }
2613 }
2614 if (NULL == name) {
2615 SECFILE_LOG(secfile, entry_section(pentry),
2616 "Entry \"%s\": no match for \"%s\".",
2617 entry_name(pentry), str);
2618 return FALSE;
2619 }
2620 }
2621
2622 return TRUE;
2623}
2624
2625/**********************************************************************/
2629 int defval, bool bitwise,
2631 secfile_data_t data,
2632 const char *path, ...)
2633{
2634 char fullpath[MAX_LEN_SECPATH];
2635 const struct entry *pentry;
2636 const char *str, *p, *name;
2637 char val_name[MAX_LEN_SECPATH];
2638 int value, val;
2639 va_list args;
2640
2641 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, defval);
2642 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, defval);
2643
2644 va_start(args, path);
2645 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2646 va_end(args);
2647
2648 if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2649 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2650 return defval;
2651 }
2652
2653 if (!entry_str_get(pentry, &str)) {
2654 return defval;
2655 }
2656
2657 value = 0;
2658 if (bitwise) {
2659 if ('\0' == str[0]) {
2660 /* Empty string = no value. */
2661 return value;
2662 }
2663
2664 /* Value names are separated by '|'. */
2665 do {
2666 p = strchr(str, '|');
2667 if (NULL != p) {
2668 p++;
2669 fc_strlcpy(val_name, str, p - str);
2670 } else {
2671 /* Last segment, full copy. */
2672 sz_strlcpy(val_name, str);
2673 }
2675 for (val = 0; (name = name_fn(data, val)); val++) {
2676 if (0 == strcmp(name, val_name)) {
2677 break;
2678 }
2679 }
2680 if (NULL == name) {
2681 SECFILE_LOG(secfile, entry_section(pentry),
2682 "Entry \"%s\": no match for \"%s\".",
2683 entry_name(pentry), val_name);
2684 return defval;
2685 }
2686 value |= 1 << val;
2687 str = p;
2688 } while (NULL != p);
2689 } else {
2690 for (val = 0; (name = name_fn(data, val)); val++) {
2691 if (0 == strcmp(name, str)) {
2692 value = val;
2693 break;
2694 }
2695 }
2696 if (NULL == name) {
2697 SECFILE_LOG(secfile, entry_section(pentry),
2698 "Entry \"%s\": no match for \"%s\".",
2699 entry_name(pentry), str);
2700 return defval;
2701 }
2702 }
2703
2704 return value;
2705}
2706
2707/**********************************************************************/
2712 size_t *dim, bool bitwise,
2714 secfile_data_t data, const char *path, ...)
2715{
2716 char fullpath[MAX_LEN_SECPATH];
2717 size_t i = 0;
2718 int *vec;
2719 va_list args;
2720
2721 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2722 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != dim, NULL);
2723 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != name_fn, NULL);
2724
2725 va_start(args, path);
2726 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2727 va_end(args);
2728
2729 /* Check size. */
2730 while (NULL != secfile_entry_lookup(secfile, "%s,%d", fullpath, (int) i)) {
2731 i++;
2732 }
2733 *dim = i;
2734
2735 if (0 == i) {
2736 /* Doesn't exist. */
2737 SECFILE_LOG(secfile, NULL, "\"%s\" entry doesn't exist.", fullpath);
2738 return NULL;
2739 }
2740
2741 vec = fc_malloc(i * sizeof(int));
2742 for (i = 0; i < *dim; i++) {
2743 if (!secfile_lookup_enum_data(secfile, vec + i, bitwise, name_fn, data,
2744 "%s,%d", fullpath, (int) i)) {
2745 SECFILE_LOG(secfile, NULL,
2746 "An error occurred when looking up to \"%s,%d\" entry.",
2747 fullpath, (int) i);
2748 free(vec);
2749 *dim = 0;
2750 return NULL;
2751 }
2752 }
2753
2754 return vec;
2755}
2756
2757/**********************************************************************/
2761 const char *name)
2762{
2763 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2764
2766 if (0 == strcmp(section_name(psection), name)) {
2767 return psection;
2768 }
2770
2771 return NULL;
2772}
2773
2774/**********************************************************************/
2778 const char *path, ...)
2779{
2780 char fullpath[MAX_LEN_SECPATH];
2781 va_list args;
2782
2783 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2784
2785 va_start(args, path);
2786 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2787 va_end(args);
2788
2789 return secfile_section_by_name(secfile, fullpath);
2790}
2791
2792/**********************************************************************/
2796const struct section_list *
2797secfile_sections(const struct section_file *secfile)
2798{
2799 return (NULL != secfile ? secfile->sections : NULL);
2800}
2801
2802/**********************************************************************/
2807struct section_list *
2809 const char *prefix)
2810{
2811 struct section_list *matches = NULL;
2812 size_t len;
2813
2814 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2815 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != prefix, NULL);
2816
2817 len = strlen(prefix);
2818 if (0 == len) {
2819 return NULL;
2820 }
2821
2822 section_list_iterate(secfile->sections, psection) {
2823 if (0 == strncmp(section_name(psection), prefix, len)) {
2824 if (NULL == matches) {
2825 matches = section_list_new();
2826 }
2827 section_list_append(matches, psection);
2828 }
2830
2831 return matches;
2832}
2833
2834/**********************************************************************/
2838 const char *name)
2839{
2840 struct section *psection;
2841
2842 SECFILE_RETURN_VAL_IF_FAIL(secfile, NULL, NULL != secfile, NULL);
2843
2844 if (NULL == name || '\0' == name[0]) {
2845 SECFILE_LOG(secfile, NULL, "Cannot create a section without name.");
2846 return NULL;
2847 }
2848
2850 SECFILE_LOG(secfile, NULL, "\"%s\" is not a valid section name.",
2851 name);
2852 return NULL;
2853 }
2854
2855 if (NULL != secfile_section_by_name(secfile, name)) {
2856 /* We cannot duplicate sections in any case! Not even if one is
2857 * include -section and the other not. */
2858 SECFILE_LOG(secfile, NULL, "Section \"%s\" already exists.", name);
2859 return NULL;
2860 }
2861
2862 psection = fc_malloc(sizeof(struct section));
2863 psection->special = EST_NORMAL;
2864 psection->name = fc_strdup(name);
2865 psection->entries = entry_list_new_full(entry_destroy);
2866
2867 /* Append to secfile. */
2868 psection->secfile = secfile;
2869 section_list_append(secfile->sections, psection);
2870
2871 if (NULL != secfile->hash.sections) {
2872 section_hash_insert(secfile->hash.sections, psection->name, psection);
2873 }
2874
2875 return psection;
2876}
2877
2878/**********************************************************************/
2881void section_destroy(struct section *psection)
2882{
2883 struct section_file *secfile;
2884
2885 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2886
2887 section_clear_all(psection);
2888
2889 if ((secfile = psection->secfile)) {
2890 /* Detach from secfile. */
2891 if (section_list_remove(secfile->sections, psection)) {
2892 /* This has called section_destroy() already then. */
2893 return;
2894 }
2895 if (NULL != secfile->hash.sections) {
2896 section_hash_remove(secfile->hash.sections, psection->name);
2897 }
2898 }
2899
2900 entry_list_destroy(psection->entries);
2901 free(psection->name);
2902 free(psection);
2903}
2904
2905/**********************************************************************/
2908void section_clear_all(struct section *psection)
2909{
2910 SECFILE_RETURN_IF_FAIL(NULL, psection, NULL != psection);
2911
2912 /* This include the removing of the hash data. */
2913 entry_list_clear(psection->entries);
2914
2915 if (0 < entry_list_size(psection->entries)) {
2916 SECFILE_LOG(psection->secfile, psection,
2917 "After clearing all, %d entries are still remaining.",
2918 entry_list_size(psection->entries));
2919 }
2920}
2921
2922/**********************************************************************/
2925bool section_set_name(struct section *psection, const char *name)
2926{
2927 struct section_file *secfile;
2928 struct section *pother;
2929
2930 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, FALSE);
2931 secfile = psection->secfile;
2932 SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, NULL != secfile, FALSE);
2933
2934 if (NULL == name || '\0' == name[0]) {
2935 SECFILE_LOG(secfile, psection, "No new name for section \"%s\".",
2936 psection->name);
2937 return FALSE;
2938 }
2939
2941 SECFILE_LOG(secfile, psection,
2942 "\"%s\" is not a valid section name for section \"%s\".",
2943 name, psection->name);
2944 return FALSE;
2945 }
2946
2947 if ((pother = secfile_section_by_name(secfile, name))
2948 && pother != psection) {
2949 /* We cannot duplicate sections in any case! */
2950 SECFILE_LOG(secfile, psection, "Section \"%s\" already exists.", name);
2951 return FALSE;
2952 }
2953
2954 /* Remove old references in the hash tables. */
2955 if (NULL != secfile->hash.sections) {
2956 section_hash_remove(secfile->hash.sections, psection->name);
2957 }
2958 if (NULL != secfile->hash.entries) {
2959 entry_list_iterate(psection->entries, pentry) {
2962 }
2963
2964 /* Really rename. */
2965 free(psection->name);
2966 psection->name = fc_strdup(name);
2967
2968 /* Reinsert new references into the hash tables. */
2969 if (NULL != secfile->hash.sections) {
2970 section_hash_insert(secfile->hash.sections, psection->name, psection);
2971 }
2972 if (NULL != secfile->hash.entries) {
2973 entry_list_iterate(psection->entries, pentry) {
2976 }
2977
2978 return TRUE;
2979}
2980
2981/**********************************************************************/
2985const struct entry_list *section_entries(const struct section *psection)
2986{
2987 return (NULL != psection ? psection->entries : NULL);
2988}
2989
2990/**********************************************************************/
2994 const char *name)
2995{
2996 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
2997
2999 if (0 == strcmp(entry_name(pentry), name)) {
3000 entry_use(pentry);
3001 return pentry;
3002 }
3004
3005 return NULL;
3006}
3007
3008/**********************************************************************/
3012 const char *path, ...)
3013{
3014 char fullpath[MAX_LEN_SECPATH];
3015 struct entry *pentry;
3016 va_list args;
3017
3018 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
3019
3020 va_start(args, path);
3021 fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
3022 va_end(args);
3023
3024 if ((pentry = section_entry_by_name(psection, fullpath))) {
3025 return pentry;
3026 }
3027
3028 /* Try with full path. */
3029 if ((pentry = secfile_entry_by_path(psection->secfile, fullpath))
3030 && psection == entry_section(pentry)) {
3031 /* Ensured this is really owned by this section. */
3032 return pentry;
3033 }
3034
3035 return NULL;
3036}
3037
3038/**********************************************************************/
3041static struct entry *entry_new(struct section *psection, const char *name)
3042{
3043 struct section_file *secfile;
3044 struct entry *pentry;
3045
3046 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != psection, NULL);
3047
3048 secfile = psection->secfile;
3049 if (NULL == name || '\0' == name[0]) {
3050 SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
3051 return NULL;
3052 }
3053
3055 SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
3056 name);
3057 return NULL;
3058 }
3059
3060 if (!secfile->allow_duplicates
3061 && NULL != section_entry_by_name(psection, name)) {
3062 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3063 return NULL;
3064 }
3065
3066 pentry = fc_malloc(sizeof(struct entry));
3067 pentry->name = fc_strdup(name);
3068 pentry->type = -1; /* Invalid case. */
3069 pentry->used = 0;
3070 pentry->comment = NULL;
3071
3072 /* Append to section. */
3073 pentry->psection = psection;
3074 entry_list_append(psection->entries, pentry);
3075
3076 /* Notify secfile. */
3077 secfile->num_entries++;
3078 secfile_hash_insert(secfile, pentry);
3079
3080 return pentry;
3081}
3082
3083/**********************************************************************/
3087 const char *name, int value)
3088{
3089 struct entry *pentry = entry_new(psection, name);
3090
3091 if (NULL != pentry) {
3092 pentry->type = ENTRY_INT;
3093 pentry->integer.value = value;
3094 }
3095
3096 return pentry;
3097}
3098
3099/**********************************************************************/
3103 const char *name, bool value)
3104{
3105 struct entry *pentry = entry_new(psection, name);
3106
3107 if (NULL != pentry) {
3108 pentry->type = ENTRY_BOOL;
3109 pentry->boolean.value = value;
3110 }
3111
3112 return pentry;
3113}
3114
3115/**********************************************************************/
3119 const char *name, float value)
3120{
3121 struct entry *pentry = entry_new(psection, name);
3122
3123 if (NULL != pentry) {
3124 pentry->type = ENTRY_FLOAT;
3125 pentry->floating.value = value;
3126 }
3127
3128 return pentry;
3129}
3130
3131/**********************************************************************/
3135 const char *name, const char *value,
3136 bool escaped)
3137{
3138 struct entry *pentry = entry_new(psection, name);
3139
3140 if (NULL != pentry) {
3141 pentry->type = ENTRY_STR;
3142 pentry->string.value = fc_strdup(NULL != value ? value : "");
3143 pentry->string.escaped = escaped;
3144 pentry->string.raw = FALSE;
3145 pentry->string.gt_marking = FALSE;
3146 }
3147
3148 return pentry;
3149}
3150
3151/**********************************************************************/
3155 const char *name, const char *value)
3156{
3157 struct entry *pentry = entry_new(psection, name);
3158
3159 if (NULL != pentry) {
3160 pentry->type = ENTRY_FILEREFERENCE;
3161 pentry->string.value = fc_strdup(NULL != value ? value : "");
3162 }
3163
3164 return pentry;
3165}
3166
3167/**********************************************************************/
3170void entry_destroy(struct entry *pentry)
3171{
3172 struct section_file *secfile;
3173 struct section *psection;
3174
3175 if (NULL == pentry) {
3176 return;
3177 }
3178
3179 if ((psection = pentry->psection)) {
3180 /* Detach from section. */
3181 if (entry_list_remove(psection->entries, pentry)) {
3182 /* This has called entry_destroy() already then. */
3183 return;
3184 }
3185 if ((secfile = psection->secfile)) {
3186 /* Detach from secfile. */
3189 }
3190 }
3191
3192 /* Specific type free. */
3193 switch (pentry->type) {
3194 case ENTRY_BOOL:
3195 case ENTRY_INT:
3196 case ENTRY_FLOAT:
3197 break;
3198
3199 case ENTRY_STR:
3201 free(pentry->string.value);
3202 break;
3203
3204 case ENTRY_ILLEGAL:
3205 fc_assert(pentry->type != ENTRY_ILLEGAL);
3206 break;
3207 }
3208
3209 /* Common free. */
3210 free(pentry->name);
3211 if (NULL != pentry->comment) {
3212 free(pentry->comment);
3213 }
3214 free(pentry);
3215}
3216
3217/**********************************************************************/
3220struct section *entry_section(const struct entry *pentry)
3221{
3222 return (NULL != pentry ? pentry->psection : NULL);
3223}
3224
3225/**********************************************************************/
3228enum entry_type entry_type_get(const struct entry *pentry)
3229{
3230 return (NULL != pentry ? pentry->type : ENTRY_ILLEGAL);
3231}
3232
3233/**********************************************************************/
3236int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3237{
3238 return fc_snprintf(buf, buf_len, "%s.%s",
3239 section_name(entry_section(pentry)),
3240 entry_name(pentry));
3241}
3242
3243/**********************************************************************/
3246const char *entry_name(const struct entry *pentry)
3247{
3248 return (NULL != pentry ? pentry->name : NULL);
3249}
3250
3251/**********************************************************************/
3254bool entry_set_name(struct entry *pentry, const char *name)
3255{
3256 struct section *psection;
3257 struct section_file *secfile;
3258
3259 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3260 psection = pentry->psection;
3261 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != psection, FALSE);
3262 secfile = psection->secfile;
3263 SECFILE_RETURN_VAL_IF_FAIL(NULL, psection, NULL != secfile, FALSE);
3264
3265 if (NULL == name || '\0' == name[0]) {
3266 SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3267 pentry->name);
3268 return FALSE;
3269 }
3270
3272 SECFILE_LOG(secfile, psection,
3273 "\"%s\" is not a valid entry name for entry \"%s\".",
3274 name, pentry->name);
3275 return FALSE;
3276 }
3277
3278 if (!secfile->allow_duplicates) {
3279 struct entry *pother = section_entry_by_name(psection, name);
3280
3281 if (NULL != pother && pother != pentry) {
3282 SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3283 return FALSE;
3284 }
3285 }
3286
3287 /* Remove from hash table the old path. */
3288 secfile_hash_delete(secfile, pentry);
3289
3290 /* Really rename the entry. */
3291 free(pentry->name);
3292 pentry->name = fc_strdup(name);
3293
3294 /* Insert into hash table the new path. */
3295 secfile_hash_insert(secfile, pentry);
3296 return TRUE;
3297}
3298
3299/**********************************************************************/
3302const char *entry_comment(const struct entry *pentry)
3303{
3304 return (NULL != pentry ? pentry->comment : NULL);
3305}
3306
3307/**********************************************************************/
3310void entry_set_comment(struct entry *pentry, const char *comment)
3311{
3312 if (NULL == pentry) {
3313 return;
3314 }
3315
3316 if (NULL != pentry->comment) {
3317 free(pentry->comment);
3318 }
3319
3320 pentry->comment = (NULL != comment ? fc_strdup(comment) : NULL);
3321}
3322
3323/**********************************************************************/
3326static inline bool entry_used(const struct entry *pentry)
3327{
3328 return (0 < pentry->used);
3329}
3330
3331/**********************************************************************/
3334static inline void entry_use(struct entry *pentry)
3335{
3336 pentry->used++;
3337}
3338
3339/**********************************************************************/
3343bool entry_bool_get(const struct entry *pentry, bool *value)
3344{
3345 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3346
3347 if (ENTRY_INT == pentry->type
3348 && (pentry->integer.value == 0
3349 || pentry->integer.value == 1)
3350 && NULL != pentry->psection
3351 && NULL != pentry->psection->secfile
3352 && pentry->psection->secfile->allow_digital_boolean) {
3353 *value = (0 != pentry->integer.value);
3354 return TRUE;
3355 }
3356
3357 SECFILE_RETURN_VAL_IF_FAIL(pentry->psection != NULL
3358 ? pentry->psection->secfile : NULL,
3359 pentry->psection,
3360 ENTRY_BOOL == pentry->type, FALSE);
3361
3362 if (NULL != value) {
3363 *value = pentry->boolean.value;
3364 }
3365 return TRUE;
3366}
3367
3368/**********************************************************************/
3371bool entry_bool_set(struct entry *pentry, bool value)
3372{
3373 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3375 ENTRY_BOOL == pentry->type, FALSE);
3376
3377 pentry->boolean.value = value;
3378 return TRUE;
3379}
3380
3381/**********************************************************************/
3384bool entry_float_get(const struct entry *pentry, float *value)
3385{
3386 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3388 ENTRY_FLOAT == pentry->type, FALSE);
3389
3390 if (NULL != value) {
3391 *value = pentry->floating.value;
3392 }
3393
3394 return TRUE;
3395}
3396
3397/**********************************************************************/
3400bool entry_float_set(struct entry *pentry, float value)
3401{
3402 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3404 ENTRY_FLOAT == pentry->type, FALSE);
3405
3406 pentry->floating.value = value;
3407
3408 return TRUE;
3409}
3410
3411/**********************************************************************/
3414bool entry_int_get(const struct entry *pentry, int *value)
3415{
3416 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3418 ENTRY_INT == pentry->type, FALSE);
3419
3420 if (NULL != value) {
3421 *value = pentry->integer.value;
3422 }
3423 return TRUE;
3424}
3425
3426/**********************************************************************/
3429bool entry_int_set(struct entry *pentry, int value)
3430{
3431 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3433 ENTRY_INT == pentry->type, FALSE);
3434
3435 pentry->integer.value = value;
3436 return TRUE;
3437}
3438
3439/**********************************************************************/
3442bool entry_str_get(const struct entry *pentry, const char **value)
3443{
3444 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3446 ENTRY_STR == pentry->type, FALSE);
3447
3448 if (NULL != value) {
3449 *value = pentry->string.value;
3450 }
3451 return TRUE;
3452}
3453
3454/**********************************************************************/
3457bool entry_str_set(struct entry *pentry, const char *value)
3458{
3459 char *old_val;
3460
3461 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3463 ENTRY_STR == pentry->type, FALSE);
3464
3465 /* We free() old value only after we've placed the new one, to
3466 * support secfile_replace_str_vec() calls that want to keep some of
3467 * the entries from the old vector in the new one. We don't want
3468 * to lose the entry in between. */
3469 old_val = pentry->string.value;
3470 pentry->string.value = fc_strdup(NULL != value ? value : "");
3471 free(old_val);
3472 return TRUE;
3473}
3474
3475/**********************************************************************/
3478bool entry_str_escaped(const struct entry *pentry)
3479{
3480 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3482 ENTRY_STR == pentry->type, FALSE);
3483
3484 return pentry->string.escaped;
3485}
3486
3487/**********************************************************************/
3490bool entry_str_set_escaped(struct entry *pentry, bool escaped)
3491{
3492 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3494 ENTRY_STR == pentry->type, FALSE);
3495
3496 pentry->string.escaped = escaped;
3497 return TRUE;
3498}
3499
3500/**********************************************************************/
3504{
3505 SECFILE_RETURN_VAL_IF_FAIL(NULL, NULL, NULL != pentry, FALSE);
3507 ENTRY_STR == pentry->type, FALSE);
3508
3509 pentry->string.gt_marking = gt_marking;
3510
3511 return TRUE;
3512}
3513
3514/**********************************************************************/
3517static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
3518{
3519 static char buf[8192];
3520 char *dot = NULL;
3521 int i;
3522
3523 switch (pentry->type) {
3524 case ENTRY_BOOL:
3525 fz_fprintf(fs, "%s", pentry->boolean.value ? "TRUE" : "FALSE");
3526 break;
3527 case ENTRY_INT:
3528 fz_fprintf(fs, "%d", pentry->integer.value);
3529 break;
3530 case ENTRY_FLOAT:
3531 snprintf(buf, sizeof(buf), "%f", pentry->floating.value);
3532 for (i = 0; buf[i] != '\0' ; i++) {
3533 if (buf[i] == '.') {
3534 dot = &(buf[i]);
3535 break;
3536 }
3537 }
3538 if (dot == NULL) {
3539 /* There's no '.' so it would seem like a integer value when loaded.
3540 * Force it not to look like an integer by adding ".0" */
3541 fz_fprintf(fs, "%s.0", buf);
3542 } else {
3543 fz_fprintf(fs, "%s", buf);
3544 }
3545 break;
3546 case ENTRY_STR:
3547 if (pentry->string.escaped) {
3548 make_escapes(pentry->string.value, buf, sizeof(buf));
3549 if (pentry->string.gt_marking) {
3550 fz_fprintf(fs, "_(\"%s\")", buf);
3551 } else {
3552 fz_fprintf(fs, "\"%s\"", buf);
3553 }
3554 } else if (pentry->string.raw) {
3555 fz_fprintf(fs, "%s", pentry->string.value);
3556 } else {
3557 fz_fprintf(fs, "$%s$", pentry->string.value);
3558 }
3559 break;
3561 fz_fprintf(fs, "*%s*", pentry->string.value);
3562 break;
3563 case ENTRY_ILLEGAL:
3564 fc_assert(pentry->type != ENTRY_ILLEGAL);
3565 break;
3566 }
3567}
3568
3569/**********************************************************************/
3572static void entry_from_inf_token(struct section *psection, const char *name,
3573 const char *tok, struct inputfile *inf)
3574{
3575 if (!entry_from_token(psection, name, tok)) {
3576 log_error("%s", inf_log_str(inf, "Entry value not recognized: %s", tok));
3577 }
3578}
void astr_free(struct astring *astr)
Definition astring.c:153
void astr_set(struct astring *astr, const char *format,...)
Definition astring.c:267
void astr_init(struct astring *astr)
Definition astring.c:144
#define str
Definition astring.c:76
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
void bugreport_request(const char *reason_format,...)
Definition bugs.c:31
bool are_deprecation_warnings_enabled(void)
#define log_deprecation_always(message,...)
static void base(QVariant data1, QVariant data2)
Definition dialogs.cpp:2840
#define _(String)
Definition fcintl.h:67
char * inf_log_str(struct inputfile *inf, const char *message,...)
Definition inputfile.c:567
bool inf_at_eof(struct inputfile *inf)
Definition inputfile.c:346
struct inputfile * inf_from_file(const char *filename, datafilename_fn_t datafn)
Definition inputfile.c:219
struct inputfile * inf_from_stream(fz_FILE *stream, datafilename_fn_t datafn)
Definition inputfile.c:241
const char * name
Definition inputfile.c:127
void inf_close(struct inputfile *inf)
Definition inputfile.c:300
int inf_discard_tokens(struct inputfile *inf, enum inf_token_type type)
Definition inputfile.c:645
const char * inf_token(struct inputfile *inf, enum inf_token_type type)
Definition inputfile.c:607
@ INF_TOK_EOL
Definition inputfile.h:45
@ INF_TOK_COMMA
Definition inputfile.h:48
@ INF_TOK_TABLE_END
Definition inputfile.h:47
@ INF_TOK_VALUE
Definition inputfile.h:49
@ INF_TOK_TABLE_START
Definition inputfile.h:46
@ INF_TOK_ENTRY_NAME
Definition inputfile.h:44
@ INF_TOK_SECTION_NAME
Definition inputfile.h:43
int fz_fprintf(fz_FILE *fp, const char *format,...)
Definition ioz.c:971
fz_FILE * fz_from_file(const char *filename, const char *in_mode, enum fz_method method, int compress_level)
Definition ioz.c:230
const char * fz_strerror(fz_FILE *fp)
Definition ioz.c:1157
int fz_fclose(fz_FILE *fp)
Definition ioz.c:571
int fz_ferror(fz_FILE *fp)
Definition ioz.c:1099
fz_method
Definition ioz.h:36
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define log_error(message,...)
Definition log.h:103
#define log_testmatic(message,...)
Definition log.h:123
#define fc_strdup(str)
Definition mem.h:43
#define fc_malloc(sz)
Definition mem.h:34
int len
Definition packhand.c:125
struct section_file * secfile_new(bool allow_duplicates)
const char * section_name(const struct section *psection)
void secfile_destroy(struct section_file *secfile)
static struct entry * entry_new(struct section *psection, const char *name)
int secfile_lookup_bitwise_enum_default_full(const struct section_file *secfile, int defval, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
void entry_set_comment(struct entry *pentry, const char *comment)
size_t secfile_insert_bool_vec_full(struct section_file *secfile, const bool *values, size_t dim, const char *comment, bool allow_replace, const char *path,...)
bool entry_bool_get(const struct entry *pentry, bool *value)
void section_destroy(struct section *psection)
bool secfile_lookup_float(const struct section_file *secfile, float *fval, const char *path,...)
void secfile_check_unused(const struct section_file *secfile)
int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
struct section * secfile_insert_long_comment(struct section_file *secfile, const char *comment)
static struct entry * section_entry_filereference_new(struct section *psection, const char *name, const char *value)
#define MAX_LEN_SECPATH
bool secfile_entry_delete(struct section_file *secfile, const char *path,...)
bool entry_set_name(struct entry *pentry, const char *name)
bool secfile_lookup_enum_data(const struct section_file *secfile, int *pvalue, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *path,...)
static bool secfile_hash_insert(struct section_file *secfile, struct entry *pentry)
bool entry_str_escaped(const struct entry *pentry)
struct entry * section_entry_int_new(struct section *psection, const char *name, int value)
struct entry * secfile_insert_bool_full(struct section_file *secfile, bool value, const char *comment, bool allow_replace, const char *path,...)
struct entry * secfile_insert_int_full(struct section_file *secfile, int value, const char *comment, bool allow_replace, const char *path,...)
struct section * entry_section(const struct entry *pentry)
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
int secfile_lookup_enum_default_data(const struct section_file *secfile, int defval, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *path,...)
const struct entry_list * section_entries(const struct section *psection)
struct section_file * secfile_load_section(const char *filename, const char *section, bool allow_duplicates)
bool entry_bool_set(struct entry *pentry, bool value)
struct section_file * secfile_from_stream(fz_FILE *stream, bool allow_duplicates)
size_t secfile_insert_bitwise_enum_vec_full(struct section_file *secfile, const int *bitwise_vals, size_t dim, secfile_enum_name_fn_t name_fn, secfile_enum_iter_fn_t begin_fn, secfile_enum_iter_fn_t end_fn, secfile_enum_next_fn_t next_fn, const char *comment, bool allow_replace, const char *path,...)
static void entry_to_file(const struct entry *pentry, fz_FILE *fs)
static void entry_from_inf_token(struct section *psection, const char *name, const char *tok, struct inputfile *file)
bool entry_float_get(const struct entry *pentry, float *value)
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
bool entry_str_set_escaped(struct entry *pentry, bool escaped)
const char * entry_name(const struct entry *pentry)
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
bool entry_str_get(const struct entry *pentry, const char **value)
struct entry * secfile_insert_enum_data_full(struct section_file *secfile, int value, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *comment, bool allow_replace, const char *path,...)
bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
#define SAVE_TABLES
size_t secfile_insert_int_vec_full(struct section_file *secfile, const int *values, size_t dim, const char *comment, bool allow_replace, const char *path,...)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
void entry_destroy(struct entry *pentry)
static bool entry_used(const struct entry *pentry)
void section_clear_all(struct section *psection)
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
bool entry_float_set(struct entry *pentry, float value)
float secfile_lookup_float_default(const struct section_file *secfile, float def, const char *path,...)
bool * secfile_lookup_bool_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
int secfile_lookup_plain_enum_default_full(const struct section_file *secfile, int defval, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
size_t secfile_insert_str_vec_full(struct section_file *secfile, const char *const *strings, size_t dim, const char *comment, bool allow_replace, bool no_escape, const char *path,...)
size_t secfile_insert_plain_enum_vec_full(struct section_file *secfile, const int *enumurators, size_t dim, secfile_enum_name_fn_t name_fn, const char *comment, bool allow_replace, const char *path,...)
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
struct entry * secfile_insert_float_full(struct section_file *secfile, float value, const char *comment, bool allow_replace, const char *path,...)
struct section * secfile_insert_include(struct section_file *secfile, const char *filename)
struct entry * secfile_insert_plain_enum_full(struct section_file *secfile, int enumerator, secfile_enum_name_fn_t name_fn, const char *comment, bool allow_replace, const char *path,...)
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
bool entry_int_set(struct entry *pentry, int value)
static bool is_secfile_entry_name_valid(const char *name)
struct entry * section_entry_by_name(const struct section *psection, const char *name)
const struct section_list * secfile_sections(const struct section_file *secfile)
struct entry * secfile_insert_filereference(struct section_file *secfile, const char *filename, const char *path,...)
bool section_set_name(struct section *psection, const char *name)
struct entry * section_entry_str_new(struct section *psection, const char *name, const char *value, bool escaped)
struct entry * section_entry_float_new(struct section *psection, const char *name, float value)
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
struct entry * section_entry_lookup(const struct section *psection, const char *path,...)
bool entry_int_get(const struct entry *pentry, int *value)
int * secfile_lookup_bitwise_enum_vec_full(const struct section_file *secfile, size_t *dim, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
static void entry_use(struct entry *pentry)
int * secfile_lookup_enum_vec_data(const struct section_file *secfile, size_t *dim, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *path,...)
struct entry * section_entry_bool_new(struct section *psection, const char *name, bool value)
bool secfile_lookup_plain_enum_full(const struct section_file *secfile, int *penumerator, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
const char * secfile_name(const struct section_file *secfile)
struct section * secfile_section_new(struct section_file *secfile, const char *name)
const char * entry_comment(const struct entry *pentry)
static bool secfile_hash_delete(struct section_file *secfile, struct entry *pentry)
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
static struct section_file * secfile_from_input_file(struct inputfile *inf, const char *filename, const char *section, bool allow_duplicates)
struct section * secfile_section_by_name(const struct section_file *secfile, const char *name)
struct entry * secfile_insert_bitwise_enum_full(struct section_file *secfile, int bitwise_val, secfile_enum_name_fn_t name_fn, secfile_enum_iter_fn_t begin_fn, secfile_enum_iter_fn_t end_fn, secfile_enum_next_fn_t next_fn, const char *comment, bool allow_replace, const char *path,...)
struct entry * secfile_insert_str_full(struct section_file *secfile, const char *str, const char *comment, bool allow_replace, bool no_escape, enum entry_special_type stype, const char *path,...)
int * secfile_lookup_plain_enum_vec_full(const struct section_file *secfile, size_t *dim, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
static bool is_legal_table_entry_name(char c, bool num)
bool entry_str_set(struct entry *pentry, const char *value)
bool secfile_lookup_bitwise_enum_full(const struct section_file *secfile, int *penumerator, secfile_enum_is_valid_fn_t is_valid_fn, secfile_enum_by_name_fn_t by_name_fn, const char *path,...)
size_t secfile_insert_enum_vec_data_full(struct section_file *secfile, const int *values, size_t dim, bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data, const char *comment, bool allow_replace, const char *path,...)
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
static const char * datafilename(const char *filename)
int secfile_lookup_int_def_min_max(const struct section_file *secfile, int defval, int minval, int maxval, const char *path,...)
static struct section * secfile_insert_base(struct section_file *secfile, const char *path, const char **pent_name)
enum entry_type entry_type_get(const struct entry *pentry)
int(* secfile_enum_iter_fn_t)(void)
const char *(* secfile_enum_name_data_fn_t)(secfile_data_t data, int enumerator)
entry_type
@ ENTRY_FILEREFERENCE
@ ENTRY_INT
@ ENTRY_FLOAT
@ ENTRY_STR
@ ENTRY_ILLEGAL
@ ENTRY_BOOL
#define section_list_iterate(seclist, psection)
#define entry_list_iterate_end
bool(* secfile_enum_is_valid_fn_t)(int enumerator)
entry_special_type
@ EST_COMMENT
@ EST_NORMAL
@ EST_INCLUDE
const char *(* secfile_enum_name_fn_t)(int enumerator)
#define section_list_iterate_end
#define entry_list_iterate(entlist, pentry)
int(* secfile_enum_by_name_fn_t)(const char *enum_name, int(*strcmp_fn)(const char *, const char *))
int(* secfile_enum_next_fn_t)(int enumerator)
const void * secfile_data_t
bool entry_from_token(struct section *psection, const char *name, const char *tok)
#define SECFILE_LOG(secfile, psection, format,...)
#define SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, condition, value)
#define SECFILE_RETURN_IF_FAIL(secfile, psection, condition)
const char * fileinfoname(const struct strvec *dirs, const char *filename)
Definition shared.c:1094
void interpret_tilde(char *buf, size_t buf_size, const char *filename)
Definition shared.c:1711
void remove_leading_trailing_spaces(char *s)
Definition shared.c:443
const struct strvec * get_data_dirs(void)
Definition shared.c:886
enum entry_type type
struct entry::@2::@6 floating
int value
struct entry::@2::@7 string
bool gt_marking
char * value
bool raw
struct section * psection
struct entry::@2::@4 boolean
float value
bool escaped
bool value
char * comment
struct entry::@2::@5 integer
char * name
struct entry_hash * entries
struct section_file::@8 hash
struct section_list * sections
bool allow_digital_boolean
bool allow_duplicates
unsigned int num_includes
unsigned int num_long_comments
size_t num_entries
struct entry_list * entries
char * name
enum entry_special_type special
struct section_file * secfile
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
bool fc_isalpha(char c)
Definition support.c:1216
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
void make_escapes(const char *str, char *buf, size_t buf_len)
Definition support.c:297
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
int cat_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:995
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:896
bool fc_isalnum(char c)
Definition support.c:1205
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47