Freeciv21
Develop your civilization from humble roots to a global empire
registry_ini.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
157 // KArchive
158 #include <KFilterDev>
159 
160 // utility
161 #include "bugs.h"
162 #include "deprecations.h"
163 #include "fcintl.h"
164 #include "inputfile.h"
165 #include "log.h"
166 #include "registry.h"
167 #include "section_file.h"
168 #include "shared.h"
169 #include "support.h"
170 
171 #include "registry_ini.h"
172 
173 #define MAX_LEN_SECPATH 1024
174 
175 // Set to FALSE for old-style savefiles.
176 #define SAVE_TABLES true
177 
178 static inline bool entry_used(const struct entry *pentry);
179 static inline void entry_use(struct entry *pentry);
180 
181 static bool entry_to_file(const struct entry *pentry, QIODevice *fs);
182 static void entry_from_inf_token(struct section *psection,
183  const QString &name, const QString &tok,
184  struct inputfile *file);
185 
186 /* An 'entry' is a string, integer, boolean or string vector;
187  * See enum entry_type in registry.h.
188  */
189 struct entry {
190  struct section *psection; // Parent section.
191  char *name; // Name, not including section prefix.
192  enum entry_type type; // The type of the entry.
193  int used; // Number of times entry looked up.
194  char *comment; // Comment, may be nullptr.
195 
196  union {
197  // ENTRY_BOOL
198  struct {
199  bool value;
201  // ENTRY_INT
202  struct {
203  int value;
205  // ENTRY_FLOAT
206  struct {
207  float value;
209  // ENTRY_STR
210  struct {
211  char *value; // Malloced string.
212  bool escaped; // " or $. Usually TRUE
213  bool raw; // Do not add anything.
214  bool gt_marking; // Save with gettext marking.
216  };
217 };
218 
219 static struct entry *
221  const char *value);
222 
226 static QString datafilename(const QString &filename)
227 {
228  return fileinfoname(get_data_dirs(), qUtf8Printable(filename));
229 }
230 
234 static bool is_secfile_entry_name_valid(const QString &name)
235 {
236  static const auto allowed = QStringLiteral("_.,-[]");
237 
238  for (const auto &c : name) {
239  if (!c.isLetterOrNumber() && !allowed.contains(c)) {
240  return false;
241  }
242  }
243  return true;
244 }
245 
249 static bool secfile_hash_insert(struct section_file *secfile,
250  struct entry *pentry)
251 {
252  char buf[256];
253  struct entry *hentry;
254 
255  if (nullptr == secfile->hash.entries) {
256  /* Consider as success if this secfile doesn't have built the entries
257  * hash table. */
258  return true;
259  }
260 
261  entry_path(pentry, buf, sizeof(buf));
262 
263  hentry = secfile->hash.entries->value(buf, nullptr);
264  if (hentry) {
265  entry_use(hentry);
266  if (!secfile->allow_duplicates) {
267  SECFILE_LOG(secfile, entry_section(hentry),
268  "Tried to insert same value twice: %s", buf);
269  return false;
270  }
271  }
272  secfile->hash.entries->insert(buf, pentry);
273  return true;
274 }
275 
279 static bool secfile_hash_delete(struct section_file *secfile,
280  struct entry *pentry)
281 {
282  char buf[256];
283 
284  if (nullptr == secfile->hash.entries) {
285  /* Consider as success if this secfile doesn't have built the entries
286  * hash table. */
287  return true;
288  }
289 
290  entry_path(pentry, buf, sizeof(buf));
291  secfile->hash.entries->remove(buf);
292  return true;
293 }
294 
298 static struct section_file *secfile_from_input_file(struct inputfile *inf,
299  const QString &filename,
300  const QString &section,
301  bool allow_duplicates)
302 {
303  struct section_file *secfile;
304  struct section *psection = nullptr;
305  struct section *single_section = nullptr;
306  bool table_state = false; // TRUE when within tabular format.
307  int table_lineno = 0; // Row number in tabular, 0 top data row.
308  QString tok;
309  int i;
310  QString base_name; // for table or single entry
311  QString field_name;
312  QVector<QString> columns; // qstrings for column headings
313  bool found_my_section = false;
314  bool error = false;
315 
316  if (!inf) {
317  return nullptr;
318  }
319 
320  // Assign the real value later, to speed up the creation of new entries.
321  secfile = secfile_new(true);
322  if (!filename.isEmpty()) {
323  secfile->name = fc_strdup(qUtf8Printable(filename));
324  } else {
325  secfile->name = nullptr;
326  }
327 
328  if (!filename.isEmpty()) {
329  qDebug("Reading registry from \"%s\"", qUtf8Printable(filename));
330  } else {
331  qDebug("Reading registry");
332  }
333 
334  while (!inf_at_eof(inf)) {
335  if (!inf_token(inf, INF_TOK_EOL).isEmpty()) {
336  continue;
337  }
338  if (inf_at_eof(inf)) {
339  // may only realise at eof after trying to read eol above
340  break;
341  }
342  tok = inf_token(inf, INF_TOK_SECTION_NAME);
343  if (!tok.isEmpty()) {
344  if (found_my_section) {
345  /* This shortcut will stop any further loading after the requested
346  * section has been loaded (i.e., at the start of a new section).
347  * This is needed to make the behavior useful, since the whole
348  * purpose is to short-cut further loading of the file. However
349  * normally a section may be split up, and that will no longer
350  * work here because it will be short-cut. */
351  SECFILE_LOG(secfile, psection, "%s",
352  qUtf8Printable(inf_log_str(
353  inf, "Found requested section; finishing")));
354  goto END;
355  }
356  if (table_state) {
357  SECFILE_LOG(
358  secfile, psection, "%s",
359  qUtf8Printable(inf_log_str(inf, "New section during table")));
360  error = true;
361  goto END;
362  }
363  /* Check if we already have a section with this name.
364  (Could ignore this and have a duplicate sections internally,
365  but then secfile_get_secnames_prefix would return duplicates.)
366  Duplicate section in input are likely to be useful for includes.
367  */
368  psection = secfile_section_by_name(secfile, tok);
369  if (!psection) {
370  if (section.isEmpty() || tok == section) {
371  psection = secfile_section_new(secfile, tok);
372  if (!section.isEmpty()) {
373  single_section = psection;
374  found_my_section = true;
375  }
376  }
377  }
378  if (inf_token(inf, INF_TOK_EOL).isEmpty()) {
379  SECFILE_LOG(
380  secfile, psection, "%s",
381  qUtf8Printable(inf_log_str(inf, "Expected end of line")));
382  error = true;
383  goto END;
384  }
385  continue;
386  }
387  if (!inf_token(inf, INF_TOK_TABLE_END).isEmpty()) {
388  if (!table_state) {
389  SECFILE_LOG(secfile, psection, "%s",
390  qUtf8Printable(inf_log_str(inf, "Misplaced \"}\"")));
391  error = true;
392  goto END;
393  }
394  if (inf_token(inf, INF_TOK_EOL).isEmpty()) {
395  SECFILE_LOG(
396  secfile, psection, "%s",
397  qUtf8Printable(inf_log_str(inf, "Expected end of line")));
398  error = true;
399  goto END;
400  }
401  columns.clear();
402  table_state = false;
403  continue;
404  }
405  if (table_state) {
406  i = -1;
407  do {
408  int num_columns = columns.size();
409 
410  i++;
411  inf_discard_tokens(inf, INF_TOK_EOL); // allow newlines
412  if ((tok = inf_token(inf, INF_TOK_VALUE)).isEmpty()) {
413  SECFILE_LOG(secfile, psection, "%s",
414  qUtf8Printable(inf_log_str(inf, "Expected value")));
415  error = true;
416  goto END;
417  }
418 
419  if (i < num_columns) {
420  field_name = QStringLiteral("%1%2.%3").arg(
421  base_name, QString::number(table_lineno), columns.at(i));
422  } else {
423  field_name = QStringLiteral("%1%2.%3,%4")
424  .arg(base_name, QString::number(table_lineno),
425  columns.at(num_columns - 1),
426  QString::number((i - num_columns + 1)));
427  }
428  entry_from_inf_token(psection, field_name, tok, inf);
429  } while (!inf_token(inf, INF_TOK_COMMA).isEmpty());
430 
431  if (inf_token(inf, INF_TOK_EOL).isEmpty()) {
432  SECFILE_LOG(
433  secfile, psection, "%s",
434  qUtf8Printable(inf_log_str(inf, "Expected end of line")));
435  error = true;
436  goto END;
437  }
438  table_lineno++;
439  continue;
440  }
441 
442  if ((tok = inf_token(inf, INF_TOK_ENTRY_NAME)).isEmpty()) {
443  SECFILE_LOG(secfile, psection, "%s",
444  qUtf8Printable(inf_log_str(inf, "Expected entry name")));
445  error = true;
446  goto END;
447  }
448 
449  // need to store tok before next calls:
450  base_name = tok;
451 
452  inf_discard_tokens(inf, INF_TOK_EOL); // allow newlines
453 
454  if (!inf_token(inf, INF_TOK_TABLE_START).isEmpty()) {
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)).isEmpty()) {
460  SECFILE_LOG(secfile, psection, "%s",
461  qUtf8Printable(inf_log_str(inf, "Expected value")));
462  error = true;
463  goto END;
464  }
465  if (tok[0] != '\"') {
466  SECFILE_LOG(secfile, psection, "%s",
467  qUtf8Printable(inf_log_str(
468  inf, "Table column header non-string")));
469  error = true;
470  goto END;
471  }
472  columns.append(tok.mid(1));
473  } while (!inf_token(inf, INF_TOK_COMMA).isEmpty());
474 
475  if (inf_token(inf, INF_TOK_EOL).isEmpty()) {
476  SECFILE_LOG(
477  secfile, psection, "%s",
478  qUtf8Printable(inf_log_str(inf, "Expected end of line")));
479  error = true;
480  goto END;
481  }
482  table_state = true;
483  table_lineno = 0;
484  continue;
485  }
486  // ordinary value:
487  i = -1;
488  do {
489  i++;
490  inf_discard_tokens(inf, INF_TOK_EOL); // allow newlines
491  if ((tok = inf_token(inf, INF_TOK_VALUE)).isEmpty()) {
492  SECFILE_LOG(secfile, psection, "%s",
493  qUtf8Printable(inf_log_str(inf, "Expected value")));
494  error = true;
495  goto END;
496  }
497  if (i == 0) {
498  entry_from_inf_token(psection, qUtf8Printable(base_name), tok, inf);
499  } else {
500  field_name =
501  QStringLiteral("%1,%2").arg(base_name, QString::number(i));
502  entry_from_inf_token(psection, qUtf8Printable(field_name), tok, inf);
503  }
504  } while (!inf_token(inf, INF_TOK_COMMA).isEmpty());
505  if (inf_token(inf, INF_TOK_EOL).isEmpty()) {
506  SECFILE_LOG(secfile, psection, "%s",
507  qUtf8Printable(inf_log_str(inf, "Expected end of line")));
508  error = true;
509  goto END;
510  }
511  }
512 
513  if (table_state) {
514  SECFILE_LOG(secfile, psection, "Finished registry before end of table");
515  error = true;
516  }
517 
518 END:
519  inf_close(inf);
520 
521  if (section != nullptr) {
522  if (!found_my_section) {
524  return nullptr;
525  }
526 
527  // Build the entry hash table with single section information
528  secfile->allow_duplicates = allow_duplicates;
529  entry_list_iterate(section_entries(single_section), pentry)
530  {
531  if (!secfile_hash_insert(secfile, pentry)) {
533  return nullptr;
534  }
535  }
537 
538  return secfile;
539  }
540 
541  if (!error) {
542  // Build the entry hash table.
543  secfile->allow_duplicates = allow_duplicates;
545  section_list_iterate(secfile->sections, hashing_section)
546  {
547  entry_list_iterate(section_entries(hashing_section), pentry)
548  {
549  if (!secfile_hash_insert(secfile, pentry)) {
550  error = true;
551  break;
552  }
553  }
555  if (error) {
556  break;
557  }
558  }
560  }
561  if (error) {
563  return nullptr;
564  } else {
565  return secfile;
566  }
567 }
568 
573 struct section_file *secfile_load_section(const QString &filename,
574  const QString &section,
575  bool allow_duplicates)
576 {
577  const auto real_filename = interpret_tilde(filename);
578  return secfile_from_input_file(inf_from_file(real_filename, datafilename),
579  filename, section, allow_duplicates);
580 }
581 
585 struct section_file *secfile_from_stream(QIODevice *stream,
586  bool allow_duplicates)
587 {
589  nullptr, nullptr, allow_duplicates);
590 }
591 
595 static bool is_legal_table_entry_name(char c, bool num)
596 {
597  return (num ? QChar::isLetterOrNumber(c) : QChar::isLetter(c)) || c == '_';
598 }
599 
614 bool secfile_save(const struct section_file *secfile, QString filename)
615 {
616  char pentry_name[128];
617  const char *col_entry_name;
618  const struct entry_list_link *ent_iter, *save_iter, *col_iter;
619  struct entry *pentry, *col_pentry;
620  int i;
621 
622  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, false);
623 
624  if (filename.isEmpty()) {
625  filename = secfile->name;
626  }
627 
628  auto real_filename = interpret_tilde(filename);
629  auto fs = std::make_unique<KFilterDev>(real_filename);
630  fs->open(QIODevice::WriteOnly);
631 
632  if (!fs->isOpen()) {
633  SECFILE_LOG(secfile, nullptr, _("Could not open %s for writing"),
634  qUtf8Printable((real_filename)));
635  return false;
636  }
637 
639  {
640  if (psection->special == EST_INCLUDE) {
641  for (ent_iter = entry_list_head(section_entries(psection));
642  ent_iter && (pentry = entry_list_link_data(ent_iter));
643  ent_iter = entry_list_link_next(ent_iter)) {
644  fc_assert(!strcmp(entry_name(pentry), "file"));
645 
646  fc_assert_ret_val(fs->write("*include ") > 0, false);
647  fc_assert_ret_val(entry_to_file(pentry, fs.get()), false);
648  fc_assert_ret_val(fs->write("\n") > 0, false);
649  }
650  } else if (psection->special == EST_COMMENT) {
651  for (ent_iter = entry_list_head(section_entries(psection));
652  ent_iter && (pentry = entry_list_link_data(ent_iter));
653  ent_iter = entry_list_link_next(ent_iter)) {
654  fc_assert(!strcmp(entry_name(pentry), "comment"));
655 
656  fc_assert_ret_val(entry_to_file(pentry, fs.get()), false);
657  fc_assert_ret_val(fs->write("\n") > 0, false);
658  }
659  } else {
660  fc_assert_ret_val(fs->write("\n[") > 0, false);
661  fc_assert_ret_val(fs->write(section_name(psection)) > 0, false);
662  fc_assert_ret_val(fs->write("]\n") > 0, false);
663 
664  /* Following doesn't use entry_list_iterate() because we want to do
665  * tricky things with the iterators...
666  */
667  for (ent_iter = entry_list_head(section_entries(psection));
668  ent_iter && (pentry = entry_list_link_data(ent_iter));
669  ent_iter = entry_list_link_next(ent_iter)) {
670  const char *comment;
671 
672  /* Tables: break out of this loop if this is a non-table
673  * entry (pentry and ent_iter unchanged) or after table (pentry
674  * and ent_iter suitably updated, pentry possibly nullptr).
675  * After each table, loop again in case the next entry
676  * is another table.
677  */
678  for (;;) {
679  char *c, *first, base[64];
680  int offset, irow, icol, ncol;
681 
682  /* Example: for first table name of "xyz0.blah":
683  * first points to the original string pentry->name
684  * base contains "xyz";
685  * offset = 5 (so first+offset gives "blah")
686  * note qstrlen(base) = offset - 2
687  */
688 
689  if (!SAVE_TABLES) {
690  break;
691  }
692 
693  sz_strlcpy(pentry_name, entry_name(pentry));
694  c = first = pentry_name;
695  if (*c == '\0' || !is_legal_table_entry_name(*c, false)) {
696  break;
697  }
698  for (; *c != '\0' && is_legal_table_entry_name(*c, false); c++) {
699  // nothing
700  }
701  if (0 != strncmp(c, "0.", 2)) {
702  break;
703  }
704  c += 2;
705  if (*c == '\0' || !is_legal_table_entry_name(*c, true)) {
706  break;
707  }
708 
709  offset = c - first;
710  first[offset - 2] = '\0';
711  sz_strlcpy(base, first);
712  first[offset - 2] = '0';
713  fc_assert_ret_val(fs->write(base) > 0, false);
714  fc_assert_ret_val(fs->write("={") > 0, false);
715 
716  /* Save an iterator at this first entry, which we can later use
717  * to repeatedly iterate over column names:
718  */
719  save_iter = ent_iter;
720 
721  // write the column names, and calculate ncol:
722  ncol = 0;
723  col_iter = save_iter;
724  for (; (col_pentry = entry_list_link_data(col_iter));
725  col_iter = entry_list_link_next(col_iter)) {
726  col_entry_name = entry_name(col_pentry);
727  if (strncmp(col_entry_name, first, offset) != 0) {
728  break;
729  }
730  fc_assert_ret_val(fs->write(ncol == 0 ? "\"" : ",\"") > 0,
731  false);
732  fc_assert_ret_val(fs->write(col_entry_name + offset) > 0, false);
733  fc_assert_ret_val(fs->write("\"") > 0, false);
734  ncol++;
735  }
736  fc_assert_ret_val(fs->write("\n") > 0, false);
737 
738  /* Iterate over rows and columns, incrementing ent_iter as we go,
739  * and writing values to the table. Have a separate iterator
740  * to the column names to check they all match.
741  */
742  irow = icol = 0;
743  col_iter = save_iter;
744  for (;;) {
745  char expect[128]; // pentry->name we're expecting
746 
747  pentry = entry_list_link_data(ent_iter);
748  col_pentry = entry_list_link_data(col_iter);
749 
750  fc_snprintf(expect, sizeof(expect), "%s%d.%s", base, irow,
751  entry_name(col_pentry) + offset);
752 
753  // break out of tabular if doesn't match:
754  if ((!pentry) || (strcmp(entry_name(pentry), expect) != 0)) {
755  if (icol != 0) {
756  /* If the second or later row of a table is missing some
757  * entries that the first row had, we drop out of the tabular
758  * format. This is inefficient so we print a warning
759  * message; the calling code probably needs to be fixed so
760  * that it can use the more efficient tabular format.
761  *
762  * FIXME: If the first row is missing some entries that the
763  * second or later row has, then we'll drop out of tabular
764  * format without an error message. */
765  qCCritical(
766  bugs_category,
767  "In file %s, there is no entry in the registry for\n"
768  "%s.%s (or the entries are out of order). This means\n"
769  "a less efficient non-tabular format will be used.\n"
770  "To avoid this make sure all rows of a table are\n"
771  "filled out with an entry for every column.",
772  qUtf8Printable(real_filename), section_name(psection),
773  expect);
774  fc_assert_ret_val(fs->write("\n") > 0, false);
775  }
776  fc_assert_ret_val(fs->write("}\n") > 0, false);
777  break;
778  }
779 
780  if (icol > 0) {
781  fc_assert_ret_val(fs->write(",") > 0, false);
782  }
783  fc_assert_ret_val(entry_to_file(pentry, fs.get()), false);
784 
785  ent_iter = entry_list_link_next(ent_iter);
786  col_iter = entry_list_link_next(col_iter);
787 
788  icol++;
789  if (icol == ncol) {
790  fc_assert_ret_val(fs->write("\n") > 0, false);
791  irow++;
792  icol = 0;
793  col_iter = save_iter;
794  }
795  }
796  if (!pentry) {
797  break;
798  }
799  }
800  if (!pentry) {
801  break;
802  }
803 
804  // Classic entry.
805  col_entry_name = entry_name(pentry);
806  fc_assert_ret_val(fs->write(col_entry_name), false);
807  fc_assert_ret_val(fs->write("="), false);
808  fc_assert_ret_val(entry_to_file(pentry, fs.get()), false);
809 
810  // Check for vector.
811  for (i = 1;; i++) {
812  col_iter = entry_list_link_next(ent_iter);
813  col_pentry = entry_list_link_data(col_iter);
814  if (nullptr == col_pentry) {
815  break;
816  }
817  fc_snprintf(pentry_name, sizeof(pentry_name), "%s,%d",
818  col_entry_name, i);
819  if (0 != strcmp(pentry_name, entry_name(col_pentry))) {
820  break;
821  }
822  fc_assert_ret_val(fs->write(",") > 0, false);
823  fc_assert_ret_val(entry_to_file(col_pentry, fs.get()), false);
824  ent_iter = col_iter;
825  }
826 
827  comment = entry_comment(pentry);
828  if (comment) {
829  fc_assert_ret_val(fs->write(" # ") > 0, false);
830  fc_assert_ret_val(fs->write(comment) > 0, false);
831  fc_assert_ret_val(fs->write("\n") > 0, false);
832  } else {
833  fc_assert_ret_val(fs->write("\n") > 0, false);
834  }
835  }
836  }
837  }
839 
840  if (fs->error() != 0) {
841  SECFILE_LOG(secfile, nullptr, "Error before closing %s: %s",
842  qUtf8Printable(real_filename),
843  qUtf8Printable(fs->errorString()));
844  return false;
845  }
846 
847  return true;
848 }
849 
857 void secfile_check_unused(const struct section_file *secfile)
858 {
859  bool any = false;
860 
862  {
864  {
865  if (!entry_used(pentry)) {
866  if (!any && secfile->name) {
867  qDebug("Unused entries in file %s:", secfile->name);
868  any = true;
869  }
870  qCWarning(deprecations_category, "%s: unused entry: %s.%s",
871  secfile->name != nullptr ? secfile->name : "nameless",
872  section_name(psection), entry_name(pentry));
873  }
874  }
876  }
878 }
879 
886 const char *secfile_name(const struct section_file *secfile)
887 {
888  if (nullptr == secfile) {
889  return "nullptr";
890  } else if (secfile->name) {
891  return secfile->name;
892  } else {
893  return "(anonymous)";
894  }
895 }
896 
901  const char *path,
902  const char **pent_name)
903 {
904  char fullpath[MAX_LEN_SECPATH];
905  char *ent_name;
906  struct section *psection;
907 
908  sz_strlcpy(fullpath, path);
909 
910  ent_name = strchr(fullpath, '.');
911  if (!ent_name) {
912  SECFILE_LOG(secfile, nullptr,
913  "Section and entry names must be separated by a dot.");
914  return nullptr;
915  }
916 
917  // Separates section and entry names.
918  *ent_name = '\0';
919  *pent_name = path + (ent_name - fullpath) + 1;
920  psection = secfile_section_by_name(secfile, fullpath);
921  if (psection) {
922  return psection;
923  } else {
924  return secfile_section_new(secfile, fullpath);
925  }
926 }
927 
932  bool value, const char *comment,
933  bool allow_replace, const char *path,
934  ...)
935 {
936  char fullpath[MAX_LEN_SECPATH];
937  const char *ent_name;
938  struct section *psection;
939  struct entry *pentry = nullptr;
940  va_list args;
941 
942  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
943 
944  va_start(args, path);
945  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
946  va_end(args);
947 
948  psection = secfile_insert_base(secfile, fullpath, &ent_name);
949  if (!psection) {
950  return nullptr;
951  }
952 
953  if (allow_replace) {
954  pentry = section_entry_by_name(psection, ent_name);
955  if (nullptr != pentry) {
956  if (ENTRY_BOOL == entry_type_get(pentry)) {
957  if (!entry_bool_set(pentry, value)) {
958  return nullptr;
959  }
960  } else {
961  entry_destroy(pentry);
962  pentry = nullptr;
963  }
964  }
965  }
966 
967  if (nullptr == pentry) {
968  pentry = section_entry_bool_new(psection, ent_name, value);
969  }
970 
971  if (nullptr != pentry && nullptr != comment) {
972  entry_set_comment(pentry, comment);
973  }
974 
975  return pentry;
976 }
977 
983  const bool *values, size_t dim,
984  const char *comment, bool allow_replace,
985  const char *path, ...)
986 {
987  char fullpath[MAX_LEN_SECPATH];
988  size_t i, ret = 0;
989  va_list args;
990 
991  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, 0);
992 
993  va_start(args, path);
994  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
995  va_end(args);
996 
997  /* NB: 'path,0' is actually 'path'. See comment in the head
998  * of the file. */
999  if (dim > 0
1000  && nullptr
1001  != secfile_insert_bool_full(secfile, values[0], comment,
1002  allow_replace, "%s", fullpath)) {
1003  ret++;
1004  }
1005  for (i = 1; i < dim; i++) {
1006  if (nullptr
1007  != secfile_insert_bool_full(secfile, values[i], comment,
1008  allow_replace, "%s,%d", fullpath,
1009  static_cast<int>(i))) {
1010  ret++;
1011  }
1012  }
1013 
1014  return ret;
1015 }
1016 
1021  int value, const char *comment,
1022  bool allow_replace, const char *path,
1023  ...)
1024 {
1025  char fullpath[MAX_LEN_SECPATH];
1026  const char *ent_name;
1027  struct section *psection;
1028  struct entry *pentry = nullptr;
1029  va_list args;
1030 
1031  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1032 
1033  va_start(args, path);
1034  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1035  va_end(args);
1036 
1037  psection = secfile_insert_base(secfile, fullpath, &ent_name);
1038  if (!psection) {
1039  return nullptr;
1040  }
1041 
1042  if (allow_replace) {
1043  pentry = section_entry_by_name(psection, ent_name);
1044  if (nullptr != pentry) {
1045  if (ENTRY_INT == entry_type_get(pentry)) {
1046  if (!entry_int_set(pentry, value)) {
1047  return nullptr;
1048  }
1049  } else {
1050  entry_destroy(pentry);
1051  pentry = nullptr;
1052  }
1053  }
1054  }
1055 
1056  if (nullptr == pentry) {
1057  pentry = section_entry_int_new(psection, ent_name, value);
1058  }
1059 
1060  if (nullptr != pentry && nullptr != comment) {
1061  entry_set_comment(pentry, comment);
1062  }
1063 
1064  return pentry;
1065 }
1066 
1072  const int *values, size_t dim,
1073  const char *comment, bool allow_replace,
1074  const char *path, ...)
1075 {
1076  char fullpath[MAX_LEN_SECPATH];
1077  size_t i, ret = 0;
1078  va_list args;
1079 
1080  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, 0);
1081 
1082  va_start(args, path);
1083  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1084  va_end(args);
1085 
1086  /* NB: 'path,0' is actually 'path'. See comment in the head
1087  * of the file. */
1088  if (dim > 0
1089  && nullptr
1090  != secfile_insert_int_full(secfile, values[0], comment,
1091  allow_replace, "%s", fullpath)) {
1092  ret++;
1093  }
1094  for (i = 1; i < dim; i++) {
1095  if (nullptr
1096  != secfile_insert_int_full(secfile, values[i], comment,
1097  allow_replace, "%s,%d", fullpath,
1098  static_cast<int>(i))) {
1099  ret++;
1100  }
1101  }
1102 
1103  return ret;
1104 }
1105 
1110  float value, const char *comment,
1111  bool allow_replace, const char *path,
1112  ...)
1113 {
1114  char fullpath[MAX_LEN_SECPATH];
1115  const char *ent_name;
1116  struct section *psection;
1117  struct entry *pentry = nullptr;
1118  va_list args;
1119 
1120  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1121 
1122  va_start(args, path);
1123  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1124  va_end(args);
1125 
1126  psection = secfile_insert_base(secfile, fullpath, &ent_name);
1127  if (!psection) {
1128  return nullptr;
1129  }
1130 
1131  if (allow_replace) {
1132  pentry = section_entry_by_name(psection, ent_name);
1133  if (nullptr != pentry) {
1134  if (ENTRY_FLOAT == entry_type_get(pentry)) {
1135  if (!entry_float_set(pentry, value)) {
1136  return nullptr;
1137  }
1138  } else {
1139  entry_destroy(pentry);
1140  pentry = nullptr;
1141  }
1142  }
1143  }
1144 
1145  if (nullptr == pentry) {
1146  pentry = section_entry_float_new(psection, ent_name, value);
1147  }
1148 
1149  if (nullptr != pentry && nullptr != comment) {
1150  entry_set_comment(pentry, comment);
1151  }
1152 
1153  return pentry;
1154 }
1155 
1160  const char *filename)
1161 {
1162  struct section *psection;
1163  char buffer[200];
1164 
1165  fc_snprintf(buffer, sizeof(buffer), "include_%u", secfile->num_includes++);
1166 
1168  nullptr);
1169 
1170  // Create include section.
1171  psection = secfile_section_new(secfile, buffer);
1172  psection->special = EST_INCLUDE;
1173 
1174  // Then add string entry "file" to it.
1175  secfile_insert_str_full(secfile, filename, nullptr, false, false,
1176  EST_INCLUDE, "%s.file", buffer);
1177 
1178  return psection;
1179 }
1180 
1185  const char *comment)
1186 {
1187  struct section *psection;
1188  char buffer[200];
1189 
1190  fc_snprintf(buffer, sizeof(buffer), "long_comment_%u",
1192 
1194  nullptr);
1195 
1196  // Create long comment section.
1197  psection = secfile_section_new(secfile, buffer);
1198  psection->special = EST_COMMENT;
1199 
1200  // Then add string entry "comment" to it.
1201  secfile_insert_str_full(secfile, comment, nullptr, false, true,
1202  EST_COMMENT, "%s.comment", buffer);
1203 
1204  return psection;
1205 }
1206 
1211  const char *str, const char *comment,
1212  bool allow_replace, bool no_escape,
1213  enum entry_special_type stype,
1214  const char *path, ...)
1215 {
1216  char fullpath[MAX_LEN_SECPATH];
1217  const char *ent_name;
1218  struct section *psection;
1219  struct entry *pentry = nullptr;
1220  va_list args;
1221 
1222  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1223 
1224  va_start(args, path);
1225  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1226  va_end(args);
1227 
1228  psection = secfile_insert_base(secfile, fullpath, &ent_name);
1229  if (!psection) {
1230  return nullptr;
1231  }
1232 
1233  if (psection->special != stype) {
1234  qCritical("Tried to insert wrong type of entry to section");
1235  return nullptr;
1236  }
1237 
1238  if (allow_replace) {
1239  pentry = section_entry_by_name(psection, ent_name);
1240  if (nullptr != pentry) {
1241  if (ENTRY_STR == entry_type_get(pentry)) {
1242  if (!entry_str_set(pentry, str)) {
1243  return nullptr;
1244  }
1245  } else {
1246  entry_destroy(pentry);
1247  pentry = nullptr;
1248  }
1249  }
1250  }
1251 
1252  if (nullptr == pentry) {
1253  pentry = section_entry_str_new(psection, ent_name, str, !no_escape);
1254  }
1255 
1256  if (nullptr != pentry && nullptr != comment) {
1257  entry_set_comment(pentry, comment);
1258  }
1259 
1260  if (pentry != nullptr && stype == EST_COMMENT) {
1261  pentry->string.raw = true;
1262  }
1263 
1264  return pentry;
1265 }
1266 
1272  const char *const *strings, size_t dim,
1273  const char *comment, bool allow_replace,
1274  bool no_escape, const char *path, ...)
1275 {
1276  char fullpath[MAX_LEN_SECPATH];
1277  size_t i, ret = 0;
1278  va_list args;
1279 
1280  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, 0);
1281 
1282  va_start(args, path);
1283  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1284  va_end(args);
1285 
1286  /* NB: 'path,0' is actually 'path'. See comment in the head
1287  * of the file. */
1288  if (dim > 0
1289  && nullptr
1290  != secfile_insert_str_full(secfile, strings[0], comment,
1291  allow_replace, no_escape, EST_NORMAL,
1292  "%s", fullpath)) {
1293  ret++;
1294  }
1295  for (i = 1; i < dim; i++) {
1296  if (nullptr
1297  != secfile_insert_str_full(secfile, strings[i], comment,
1298  allow_replace, no_escape, EST_NORMAL,
1299  "%s,%d", fullpath, static_cast<int>(i))) {
1300  ret++;
1301  }
1302  }
1303 
1304  return ret;
1305 }
1306 
1312  const QVector<QString> &strings,
1313  size_t dim, const char *comment,
1314  bool allow_replace, bool no_escape,
1315  const char *path, ...)
1316 {
1317  char fullpath[MAX_LEN_SECPATH];
1318  size_t i, ret = 0;
1319  va_list args;
1320 
1321  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, 0);
1322 
1323  va_start(args, path);
1324  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1325  va_end(args);
1326 
1327  /* NB: 'path,0' is actually 'path'. See comment in the head
1328  * of the file. */
1329  if (dim > 0 && !strings.isEmpty()
1330  && nullptr
1331  != secfile_insert_str_full(secfile, qUtf8Printable(strings[0]),
1332  comment, allow_replace, no_escape,
1333  EST_NORMAL, "%s", fullpath)) {
1334  ret++;
1335  }
1336  for (i = 1; i < dim && i < strings.size(); i++) {
1337  if (nullptr
1339  secfile, qUtf8Printable(strings[i]), comment, allow_replace,
1340  no_escape, EST_NORMAL, "%s,%d", fullpath, static_cast<int>(i))) {
1341  ret++;
1342  }
1343  }
1344 
1345  return ret;
1346 }
1347 
1352  const char *filename,
1353  const char *path, ...)
1354 {
1355  char fullpath[MAX_LEN_SECPATH];
1356  const char *ent_name;
1357  struct section *psection;
1358  struct entry *pentry = nullptr;
1359  va_list args;
1360 
1361  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1362 
1363  va_start(args, path);
1364  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1365  va_end(args);
1366 
1367  psection = secfile_insert_base(secfile, fullpath, &ent_name);
1368  if (!psection) {
1369  return nullptr;
1370  }
1371 
1372  if (psection->special != EST_NORMAL) {
1373  qCritical("Tried to insert normal entry to different kind of section");
1374  return nullptr;
1375  }
1376 
1377  if (nullptr == pentry) {
1378  pentry = section_entry_filereference_new(psection, ent_name, filename);
1379  }
1380 
1381  return pentry;
1382 }
1383 
1388  int enumerator,
1389  secfile_enum_name_fn_t name_fn,
1390  const char *comment,
1391  bool allow_replace,
1392  const char *path, ...)
1393 {
1394  char fullpath[MAX_LEN_SECPATH];
1395  const char *str;
1396  const char *ent_name;
1397  struct section *psection;
1398  struct entry *pentry = nullptr;
1399  va_list args;
1400 
1401  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1402  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, nullptr);
1403  str = name_fn(enumerator);
1404  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != str, nullptr);
1405 
1406  va_start(args, path);
1407  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1408  va_end(args);
1409 
1410  psection = secfile_insert_base(secfile, fullpath, &ent_name);
1411  if (!psection) {
1412  return nullptr;
1413  }
1414 
1415  if (allow_replace) {
1416  pentry = section_entry_by_name(psection, ent_name);
1417  if (nullptr != pentry) {
1418  if (ENTRY_STR == entry_type_get(pentry)) {
1419  if (!entry_str_set(pentry, str)) {
1420  return nullptr;
1421  }
1422  } else {
1423  entry_destroy(pentry);
1424  pentry = nullptr;
1425  }
1426  }
1427  }
1428 
1429  if (nullptr == pentry) {
1430  pentry = section_entry_str_new(psection, ent_name, str, true);
1431  }
1432 
1433  if (nullptr != pentry && nullptr != comment) {
1434  entry_set_comment(pentry, comment);
1435  }
1436 
1437  return pentry;
1438 }
1439 
1445  const int *enumurators, size_t dim,
1446  secfile_enum_name_fn_t name_fn,
1447  const char *comment,
1448  bool allow_replace,
1449  const char *path, ...)
1450 {
1451  char fullpath[MAX_LEN_SECPATH];
1452  size_t i, ret = 0;
1453  va_list args;
1454 
1455  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, 0);
1456  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, 0);
1457 
1458  va_start(args, path);
1459  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1460  va_end(args);
1461 
1462  /* NB: 'path,0' is actually 'path'. See comment in the head
1463  * of the file. */
1464  if (dim > 0
1465  && nullptr
1467  secfile, enumurators[0], name_fn, comment, allow_replace,
1468  "%s", fullpath)) {
1469  ret++;
1470  }
1471  for (i = 1; i < dim; i++) {
1472  if (nullptr
1473  != secfile_insert_plain_enum_full(secfile, enumurators[i], name_fn,
1474  comment, allow_replace, "%s,%d",
1475  fullpath, static_cast<int>(i))) {
1476  ret++;
1477  }
1478  }
1479 
1480  return ret;
1481 }
1482 
1487  struct section_file *secfile, int bitwise_val,
1490  const char *comment, bool allow_replace, const char *path, ...)
1491 {
1492  char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1493  const char *ent_name;
1494  struct section *psection;
1495  struct entry *pentry = nullptr;
1496  va_list args;
1497  int i;
1498 
1499  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1500  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, nullptr);
1501  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != begin_fn, nullptr);
1502  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != end_fn, nullptr);
1503  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != next_fn, nullptr);
1504 
1505  // Compute a string containing all the values separated by '|'.
1506  str[0] = '\0'; // Insert at least an empty string.
1507  if (0 != bitwise_val) {
1508  for (i = begin_fn(); i != end_fn(); i = next_fn(i)) {
1509  if (i & bitwise_val) {
1510  if ('\0' == str[0]) {
1511  sz_strlcpy(str, name_fn(i));
1512  } else {
1513  cat_snprintf(str, sizeof(str), "|%s", name_fn(i));
1514  }
1515  }
1516  }
1517  }
1518 
1519  va_start(args, path);
1520  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1521  va_end(args);
1522 
1523  psection = secfile_insert_base(secfile, fullpath, &ent_name);
1524  if (!psection) {
1525  return nullptr;
1526  }
1527 
1528  if (allow_replace) {
1529  pentry = section_entry_by_name(psection, ent_name);
1530  if (nullptr != pentry) {
1531  if (ENTRY_STR == entry_type_get(pentry)) {
1532  if (!entry_str_set(pentry, str)) {
1533  return nullptr;
1534  }
1535  } else {
1536  entry_destroy(pentry);
1537  pentry = nullptr;
1538  }
1539  }
1540  }
1541 
1542  if (nullptr == pentry) {
1543  pentry = section_entry_str_new(psection, ent_name, str, true);
1544  }
1545 
1546  if (nullptr != pentry && nullptr != comment) {
1547  entry_set_comment(pentry, comment);
1548  }
1549 
1550  return pentry;
1551 }
1552 
1558  struct section_file *secfile, const int *bitwise_vals, size_t dim,
1561  const char *comment, bool allow_replace, const char *path, ...)
1562 {
1563  char fullpath[MAX_LEN_SECPATH];
1564  size_t i, ret = 0;
1565  va_list args;
1566 
1567  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, 0);
1568  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, 0);
1569  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != begin_fn, 0);
1570  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != end_fn, 0);
1571  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != next_fn, 0);
1572 
1573  va_start(args, path);
1574  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1575  va_end(args);
1576 
1577  /* NB: 'path,0' is actually 'path'. See comment in the head
1578  * of the file. */
1579  if (dim > 0
1580  && nullptr
1582  secfile, bitwise_vals[0], name_fn, begin_fn, end_fn,
1583  next_fn, comment, allow_replace, "%s", fullpath)) {
1584  ret++;
1585  }
1586  for (i = 1; i < dim; i++) {
1587  if (nullptr
1589  secfile, bitwise_vals[i], name_fn, begin_fn, end_fn, next_fn,
1590  comment, allow_replace, "%s,%d", fullpath,
1591  static_cast<int>(i))) {
1592  ret++;
1593  }
1594  }
1595 
1596  return ret;
1597 }
1598 
1604  struct section_file *secfile, int value, bool bitwise,
1606  const char *comment, bool allow_replace, const char *path, ...)
1607 {
1608  char fullpath[MAX_LEN_SECPATH], str[MAX_LEN_SECPATH];
1609  const char *ent_name, *val_name;
1610  struct section *psection;
1611  struct entry *pentry = nullptr;
1612  va_list args;
1613  int i;
1614 
1615  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1616  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, nullptr);
1617 
1618  if (bitwise) {
1619  // Compute a string containing all the values separated by '|'.
1620  str[0] = '\0'; // Insert at least an empty string.
1621  if (0 != value) {
1622  for (i = 0; (val_name = name_fn(data, i)); i++) {
1623  if ((1 << i) & value) {
1624  if ('\0' == str[0]) {
1625  sz_strlcpy(str, val_name);
1626  } else {
1627  cat_snprintf(str, sizeof(str), "|%s", val_name);
1628  }
1629  }
1630  }
1631  }
1632  } else {
1633  if (!(val_name = name_fn(data, value))) {
1634  SECFILE_LOG(secfile, nullptr, "Value %d not supported.", value);
1635  return nullptr;
1636  }
1637  sz_strlcpy(str, val_name);
1638  }
1639 
1640  va_start(args, path);
1641  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1642  va_end(args);
1643 
1644  psection = secfile_insert_base(secfile, fullpath, &ent_name);
1645  if (!psection) {
1646  return nullptr;
1647  }
1648 
1649  if (allow_replace) {
1650  pentry = section_entry_by_name(psection, ent_name);
1651  if (nullptr != pentry) {
1652  if (ENTRY_STR == entry_type_get(pentry)) {
1653  if (!entry_str_set(pentry, str)) {
1654  return nullptr;
1655  }
1656  } else {
1657  entry_destroy(pentry);
1658  pentry = nullptr;
1659  }
1660  }
1661  }
1662 
1663  if (nullptr == pentry) {
1664  pentry = section_entry_str_new(psection, ent_name, str, true);
1665  }
1666 
1667  if (nullptr != pentry && nullptr != comment) {
1668  entry_set_comment(pentry, comment);
1669  }
1670 
1671  return pentry;
1672 }
1673 
1679  struct section_file *secfile, const int *values, size_t dim,
1680  bool bitwise, secfile_enum_name_data_fn_t name_fn, secfile_data_t data,
1681  const char *comment, bool allow_replace, const char *path, ...)
1682 {
1683  char fullpath[MAX_LEN_SECPATH];
1684  size_t i, ret = 0;
1685  va_list args;
1686 
1687  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, 0);
1688  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, 0);
1689 
1690  va_start(args, path);
1691  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1692  va_end(args);
1693 
1694  /* NB: 'path,0' is actually 'path'. See comment in the head
1695  * of the file. */
1696  if (dim > 0
1697  && nullptr
1699  secfile, values[0], bitwise, name_fn, data, comment,
1700  allow_replace, "%s", fullpath)) {
1701  ret++;
1702  }
1703  for (i = 1; i < dim; i++) {
1704  if (nullptr
1706  secfile, values[i], bitwise, name_fn, data, comment,
1707  allow_replace, "%s,%d", fullpath, static_cast<int>(i))) {
1708  ret++;
1709  }
1710  }
1711 
1712  return ret;
1713 }
1714 
1718 struct entry *secfile_entry_by_path(const struct section_file *secfile,
1719  const char *path)
1720 {
1721  char fullpath[MAX_LEN_SECPATH];
1722  char *ent_name;
1723  size_t len;
1724  struct section *psection;
1725 
1726  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1727 
1728  sz_strlcpy(fullpath, path);
1729 
1730  // treat "sec.foo,0" as "sec.foo":
1731  len = qstrlen(fullpath);
1732  if (len > 2 && fullpath[len - 2] == ',' && fullpath[len - 1] == '0') {
1733  fullpath[len - 2] = '\0';
1734  }
1735 
1736  if (nullptr != secfile->hash.entries) {
1737  struct entry *pentry = secfile->hash.entries->value(fullpath, nullptr);
1738 
1739  if (pentry) {
1740  entry_use(pentry);
1741  }
1742  return pentry;
1743  }
1744 
1745  /* I dont like strtok.
1746  * - Me neither! */
1747  ent_name = strchr(fullpath, '.');
1748  if (!ent_name) {
1749  return nullptr;
1750  }
1751 
1752  // Separates section and entry names.
1753  *ent_name++ = '\0';
1754  psection = secfile_section_by_name(secfile, fullpath);
1755  if (psection) {
1756  return section_entry_by_name(psection, ent_name);
1757  } else {
1758  return nullptr;
1759  }
1760 }
1761 
1765 bool secfile_entry_delete(struct section_file *secfile, const char *path,
1766  ...)
1767 {
1768  char fullpath[MAX_LEN_SECPATH];
1769  va_list args;
1770  struct entry *pentry;
1771 
1772  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, false);
1773 
1774  va_start(args, path);
1775  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1776  va_end(args);
1777 
1778  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1779  SECFILE_LOG(secfile, nullptr, "Path %s does not exists.", fullpath);
1780  return false;
1781  }
1782 
1783  entry_destroy(pentry);
1784 
1785  return true;
1786 }
1787 
1791 struct entry *secfile_entry_lookup(const struct section_file *secfile,
1792  const char *path, ...)
1793 {
1794  char fullpath[MAX_LEN_SECPATH];
1795  va_list args;
1796 
1797  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1798 
1799  va_start(args, path);
1800  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1801  va_end(args);
1802 
1803  return secfile_entry_by_path(secfile, fullpath);
1804 }
1805 
1809 bool secfile_lookup_bool(const struct section_file *secfile, bool *bval,
1810  const char *path, ...)
1811 {
1812  char fullpath[MAX_LEN_SECPATH];
1813  const struct entry *pentry;
1814  va_list args;
1815 
1816  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, false);
1817 
1818  va_start(args, path);
1819  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1820  va_end(args);
1821 
1822  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1823  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
1824  return false;
1825  }
1826 
1827  return entry_bool_get(pentry, bval);
1828 }
1829 
1834 bool secfile_lookup_bool_default(const struct section_file *secfile,
1835  bool def, const char *path, ...)
1836 {
1837  char fullpath[MAX_LEN_SECPATH];
1838  const struct entry *pentry;
1839  bool bval;
1840  va_list args;
1841 
1842  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, def);
1843 
1844  va_start(args, path);
1845  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1846  va_end(args);
1847 
1848  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1849  return def;
1850  }
1851 
1852  if (entry_bool_get(pentry, &bval)) {
1853  return bval;
1854  }
1855 
1856  return def;
1857 }
1858 
1862 bool secfile_lookup_int(const struct section_file *secfile, int *ival,
1863  const char *path, ...)
1864 {
1865  char fullpath[MAX_LEN_SECPATH];
1866  const struct entry *pentry;
1867  va_list args;
1868 
1869  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, false);
1870 
1871  va_start(args, path);
1872  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1873  va_end(args);
1874 
1875  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1876  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
1877  return false;
1878  }
1879 
1880  return entry_int_get(pentry, ival);
1881 }
1882 
1887 int secfile_lookup_int_default(const struct section_file *secfile, int def,
1888  const char *path, ...)
1889 {
1890  char fullpath[MAX_LEN_SECPATH];
1891  const struct entry *pentry;
1892  int ival;
1893  va_list args;
1894 
1895  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, def);
1896 
1897  va_start(args, path);
1898  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1899  va_end(args);
1900 
1901  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1902  return def;
1903  }
1904 
1905  if (entry_int_get(pentry, &ival)) {
1906  return ival;
1907  }
1908 
1909  return def;
1910 }
1911 
1918  int defval, int minval, int maxval,
1919  const char *path, ...)
1920 {
1921  char fullpath[MAX_LEN_SECPATH];
1922  const struct entry *pentry;
1923  int value;
1924  va_list args;
1925 
1926  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, defval);
1927 
1928  va_start(args, path);
1929  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1930  va_end(args);
1931 
1932  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
1933  return defval;
1934  }
1935 
1936  if (!entry_int_get(pentry, &value)) {
1937  return defval;
1938  }
1939 
1940  if (value < minval) {
1941  SECFILE_LOG(secfile, entry_section(pentry),
1942  "\"%s\" should be in the interval [%d, %d] but is %d;"
1943  "using the minimal value.",
1944  fullpath, minval, maxval, value);
1945  value = minval;
1946  }
1947 
1948  if (value > maxval) {
1949  SECFILE_LOG(secfile, entry_section(pentry),
1950  "\"%s\" should be in the interval [%d, %d] but is %d;"
1951  "using the maximal value.",
1952  fullpath, minval, maxval, value);
1953  value = maxval;
1954  }
1955 
1956  return value;
1957 }
1958 
1964 int *secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim,
1965  const char *path, ...)
1966 {
1967  char fullpath[MAX_LEN_SECPATH];
1968  size_t i = 0;
1969  int *vec;
1970  va_list args;
1971 
1972  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
1973  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != dim, nullptr);
1974 
1975  va_start(args, path);
1976  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
1977  va_end(args);
1978 
1979  // Check size.
1980  while (nullptr
1981  != secfile_entry_lookup(secfile, "%s,%d", fullpath,
1982  static_cast<int>(i))) {
1983  i++;
1984  }
1985  *dim = i;
1986 
1987  if (0 == i) {
1988  // Doesn't exist.
1989  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
1990  return nullptr;
1991  }
1992 
1993  vec = new int[i];
1994  for (i = 0; i < *dim; i++) {
1995  if (!secfile_lookup_int(secfile, vec + i, "%s,%d", fullpath,
1996  static_cast<int>(i))) {
1997  SECFILE_LOG(secfile, nullptr,
1998  "An error occurred when looking up to \"%s,%d\" entry.",
1999  fullpath, (int) i);
2000  delete[] vec;
2001  *dim = 0;
2002  return nullptr;
2003  }
2004  }
2005 
2006  return vec;
2007 }
2008 
2012 const char *secfile_lookup_str(const struct section_file *secfile,
2013  const char *path, ...)
2014 {
2015  char fullpath[MAX_LEN_SECPATH];
2016  const struct entry *pentry;
2017  const char *str;
2018  va_list args;
2019 
2020  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2021 
2022  va_start(args, path);
2023  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2024  va_end(args);
2025 
2026  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2027  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2028  return nullptr;
2029  }
2030 
2031  if (entry_str_get(pentry, &str)) {
2032  return str;
2033  }
2034 
2035  return nullptr;
2036 }
2037 
2042 const char *secfile_lookup_str_default(const struct section_file *secfile,
2043  const char *def, const char *path,
2044  ...)
2045 {
2046  char fullpath[MAX_LEN_SECPATH];
2047  const struct entry *pentry;
2048  const char *str;
2049  va_list args;
2050 
2051  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, def);
2052 
2053  va_start(args, path);
2054  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2055  va_end(args);
2056 
2057  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2058  return def;
2059  }
2060 
2061  if (entry_str_get(pentry, &str)) {
2062  return str;
2063  }
2064 
2065  return def;
2066 }
2067 
2074 const char **secfile_lookup_str_vec(const struct section_file *secfile,
2075  size_t *dim, const char *path, ...)
2076 {
2077  char fullpath[MAX_LEN_SECPATH];
2078  size_t i = 0;
2079  const char **vec;
2080  va_list args;
2081 
2082  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2083  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != dim, nullptr);
2084 
2085  va_start(args, path);
2086  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2087  va_end(args);
2088 
2089  // Check size.
2090  while (nullptr
2091  != secfile_entry_lookup(secfile, "%s,%d", fullpath,
2092  static_cast<int>(i))) {
2093  i++;
2094  }
2095  *dim = i;
2096 
2097  if (0 == i) {
2098  // Doesn't exist.
2099  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2100  return nullptr;
2101  }
2102 
2103  vec = new const char *[i];
2104  for (i = 0; i < *dim; i++) {
2105  if (!(vec[i] = secfile_lookup_str(secfile, "%s,%d", fullpath,
2106  static_cast<int>(i)))) {
2107  SECFILE_LOG(secfile, nullptr,
2108  "An error occurred when looking up to \"%s,%d\" entry.",
2109  fullpath, (int) i);
2110  delete[] vec;
2111  *dim = 0;
2112  return nullptr;
2113  }
2114  }
2115 
2116  return vec;
2117 }
2118 
2123  int *penumerator,
2124  secfile_enum_is_valid_fn_t is_valid_fn,
2125  secfile_enum_by_name_fn_t by_name_fn,
2126  const char *path, ...)
2127 {
2128  char fullpath[MAX_LEN_SECPATH];
2129  const struct entry *pentry;
2130  const char *str;
2131  va_list args;
2132 
2133  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, false);
2134  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != penumerator,
2135  false);
2136  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != is_valid_fn,
2137  false);
2138  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != by_name_fn, false);
2139 
2140  va_start(args, path);
2141  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2142  va_end(args);
2143 
2144  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2145  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2146  return false;
2147  }
2148 
2149  if (!entry_str_get(pentry, &str)) {
2150  return false;
2151  }
2152 
2153  *penumerator = by_name_fn(str, strcmp);
2154  if (is_valid_fn(*penumerator)) {
2155  return true;
2156  }
2157 
2158  SECFILE_LOG(secfile, entry_section(pentry),
2159  "Entry \"%s\": no match for \"%s\".", entry_name(pentry), str);
2160  return false;
2161 }
2162 
2167  const struct section_file *secfile, int defval,
2168  secfile_enum_is_valid_fn_t is_valid_fn,
2169  secfile_enum_by_name_fn_t by_name_fn, const char *path, ...)
2170 {
2171  char fullpath[MAX_LEN_SECPATH];
2172  const struct entry *pentry;
2173  const char *str;
2174  int val;
2175  va_list args;
2176 
2177  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, defval);
2178  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != is_valid_fn,
2179  defval);
2180  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != by_name_fn,
2181  defval);
2182 
2183  va_start(args, path);
2184  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2185  va_end(args);
2186 
2187  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2188  return defval;
2189  }
2190 
2191  if (!entry_str_get(pentry, &str)) {
2192  return defval;
2193  }
2194 
2195  val = by_name_fn(str, strcmp);
2196  if (is_valid_fn(val)) {
2197  return val;
2198  } else {
2199  return defval;
2200  }
2201 }
2202 
2209  const struct section_file *secfile, size_t *dim,
2210  secfile_enum_is_valid_fn_t is_valid_fn,
2211  secfile_enum_by_name_fn_t by_name_fn, const char *path, ...)
2212 {
2213  char fullpath[MAX_LEN_SECPATH];
2214  size_t i = 0;
2215  int *vec;
2216  va_list args;
2217 
2218  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2219  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != dim, nullptr);
2220  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != is_valid_fn,
2221  nullptr);
2222  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != by_name_fn,
2223  nullptr);
2224 
2225  va_start(args, path);
2226  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2227  va_end(args);
2228 
2229  // Check size.
2230  while (nullptr
2231  != secfile_entry_lookup(secfile, "%s,%d", fullpath,
2232  static_cast<int>(i))) {
2233  i++;
2234  }
2235  *dim = i;
2236 
2237  if (0 == i) {
2238  // Doesn't exist.
2239  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2240  return nullptr;
2241  }
2242 
2243  vec = new int[i];
2244  for (i = 0; i < *dim; i++) {
2245  if (!secfile_lookup_plain_enum_full(secfile, vec + i, is_valid_fn,
2246  by_name_fn, "%s,%d", fullpath,
2247  static_cast<int>(i))) {
2248  SECFILE_LOG(secfile, nullptr,
2249  "An error occurred when looking up to \"%s,%d\" entry.",
2250  fullpath, (int) i);
2251  delete[] vec;
2252  *dim = 0;
2253  return nullptr;
2254  }
2255  }
2256 
2257  return vec;
2258 }
2259 
2264  int *penumerator,
2265  secfile_enum_is_valid_fn_t is_valid_fn,
2266  secfile_enum_by_name_fn_t by_name_fn,
2267  const char *path, ...)
2268 {
2269  char fullpath[MAX_LEN_SECPATH];
2270  const struct entry *pentry;
2271  const char *str, *p;
2272  char val_name[MAX_LEN_SECPATH];
2273  int val;
2274  va_list args;
2275 
2276  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, false);
2277  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != penumerator,
2278  false);
2279  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != is_valid_fn,
2280  false);
2281  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != by_name_fn, false);
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  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2289  return false;
2290  }
2291 
2292  if (!entry_str_get(pentry, &str)) {
2293  return false;
2294  }
2295 
2296  *penumerator = 0;
2297  if ('\0' == str[0]) {
2298  // Empty string = no value.
2299  return true;
2300  }
2301 
2302  // Value names are separated by '|'.
2303  do {
2304  p = strchr(str, '|');
2305  if (nullptr != p) {
2306  p++;
2307  fc_strlcpy(val_name, str, p - str);
2308  } else {
2309  // Last segment, full copy.
2310  sz_strlcpy(val_name, str);
2311  }
2313  val = by_name_fn(val_name, strcmp);
2314  if (!is_valid_fn(val)) {
2315  SECFILE_LOG(secfile, entry_section(pentry),
2316  "Entry \"%s\": no match for \"%s\".", entry_name(pentry),
2317  val_name);
2318  return false;
2319  }
2320  *penumerator |= val;
2321  str = p;
2322  } while (nullptr != p);
2323 
2324  return true;
2325 }
2326 
2331  const struct section_file *secfile, int defval,
2332  secfile_enum_is_valid_fn_t is_valid_fn,
2333  secfile_enum_by_name_fn_t by_name_fn, const char *path, ...)
2334 {
2335  char fullpath[MAX_LEN_SECPATH];
2336  const struct entry *pentry;
2337  const char *str, *p;
2338  char val_name[MAX_LEN_SECPATH];
2339  int val, full_val;
2340  va_list args;
2341 
2342  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, defval);
2343  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != is_valid_fn,
2344  defval);
2345  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != by_name_fn,
2346  defval);
2347 
2348  va_start(args, path);
2349  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2350  va_end(args);
2351 
2352  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2353  return defval;
2354  }
2355 
2356  if (!entry_str_get(pentry, &str)) {
2357  return defval;
2358  }
2359 
2360  if ('\0' == str[0]) {
2361  // Empty string = no value.
2362  return 0;
2363  }
2364 
2365  // Value names are separated by '|'.
2366  full_val = 0;
2367  do {
2368  p = strchr(str, '|');
2369  if (nullptr != p) {
2370  p++;
2371  fc_strlcpy(val_name, str, p - str);
2372  } else {
2373  // Last segment, full copy.
2374  sz_strlcpy(val_name, str);
2375  }
2377  val = by_name_fn(val_name, strcmp);
2378  if (!is_valid_fn(val)) {
2379  return defval;
2380  }
2381  full_val |= val;
2382  str = p;
2383  } while (nullptr != p);
2384 
2385  return full_val;
2386 }
2387 
2394  const struct section_file *secfile, size_t *dim,
2395  secfile_enum_is_valid_fn_t is_valid_fn,
2396  secfile_enum_by_name_fn_t by_name_fn, const char *path, ...)
2397 {
2398  char fullpath[MAX_LEN_SECPATH];
2399  size_t i = 0;
2400  int *vec;
2401  va_list args;
2402 
2403  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2404  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != dim, nullptr);
2405  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != is_valid_fn,
2406  nullptr);
2407  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != by_name_fn,
2408  nullptr);
2409 
2410  va_start(args, path);
2411  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2412  va_end(args);
2413 
2414  // Check size.
2415  while (nullptr
2416  != secfile_entry_lookup(secfile, "%s,%d", fullpath,
2417  static_cast<int>(i))) {
2418  i++;
2419  }
2420  *dim = i;
2421 
2422  if (0 == i) {
2423  // Doesn't exist.
2424  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2425  return nullptr;
2426  }
2427 
2428  vec = new int[i];
2429  for (i = 0; i < *dim; i++) {
2430  if (!secfile_lookup_bitwise_enum_full(secfile, vec + i, is_valid_fn,
2431  by_name_fn, "%s,%d", fullpath,
2432  static_cast<int>(i))) {
2433  SECFILE_LOG(secfile, nullptr,
2434  "An error occurred when looking up to \"%s,%d\" entry.",
2435  fullpath, (int) i);
2436  delete[] vec;
2437  *dim = 0;
2438 
2439  return nullptr;
2440  }
2441  }
2442 
2443  return vec;
2444 }
2445 
2449 bool secfile_lookup_enum_data(const struct section_file *secfile,
2450  int *pvalue, bool bitwise,
2452  secfile_data_t data, const char *path, ...)
2453 {
2454  char fullpath[MAX_LEN_SECPATH];
2455  const struct entry *pentry;
2456  const char *str, *p, *name;
2457  char val_name[MAX_LEN_SECPATH];
2458  int val;
2459  va_list args;
2460 
2461  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, false);
2462  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != pvalue, false);
2463  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, false);
2464 
2465  va_start(args, path);
2466  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2467  va_end(args);
2468 
2469  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2470  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2471  return false;
2472  }
2473 
2474  if (!entry_str_get(pentry, &str)) {
2475  return false;
2476  }
2477 
2478  if (bitwise) {
2479  *pvalue = 0;
2480  if ('\0' == str[0]) {
2481  // Empty string = no value.
2482  return true;
2483  }
2484 
2485  // Value names are separated by '|'.
2486  do {
2487  p = strchr(str, '|');
2488  if (nullptr != p) {
2489  p++;
2490  fc_strlcpy(val_name, str, p - str);
2491  } else {
2492  // Last segment, full copy.
2493  sz_strlcpy(val_name, str);
2494  }
2496  for (val = 0; (name = name_fn(data, val)); val++) {
2497  if (0 == fc_strcasecmp(name, val_name)) {
2498  break;
2499  }
2500  }
2501  if (nullptr == name) {
2502  SECFILE_LOG(secfile, entry_section(pentry),
2503  "Entry \"%s\": no match for \"%s\".", entry_name(pentry),
2504  val_name);
2505  return false;
2506  }
2507  *pvalue |= 1 << val;
2508  str = p;
2509  } while (nullptr != p);
2510  } else {
2511  for (val = 0; (name = name_fn(data, val)); val++) {
2512  if (0 == fc_strcasecmp(name, str)) {
2513  *pvalue = val;
2514  break;
2515  }
2516  }
2517  if (nullptr == name) {
2518  SECFILE_LOG(secfile, entry_section(pentry),
2519  "Entry \"%s\": no match for \"%s\".", entry_name(pentry),
2520  str);
2521  return false;
2522  }
2523  }
2524 
2525  return true;
2526 }
2527 
2532  int defval, bool bitwise,
2534  secfile_data_t data, const char *path,
2535  ...)
2536 {
2537  char fullpath[MAX_LEN_SECPATH];
2538  const struct entry *pentry;
2539  const char *str, *p, *name;
2540  char val_name[MAX_LEN_SECPATH];
2541  int value, val;
2542  va_list args;
2543 
2544  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, defval);
2545  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != name_fn, defval);
2546 
2547  va_start(args, path);
2548  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2549  va_end(args);
2550 
2551  if (!(pentry = secfile_entry_by_path(secfile, fullpath))) {
2552  SECFILE_LOG(secfile, nullptr, "\"%s\" entry doesn't exist.", fullpath);
2553  return defval;
2554  }
2555 
2556  if (!entry_str_get(pentry, &str)) {
2557  return defval;
2558  }
2559 
2560  value = 0;
2561  if (bitwise) {
2562  if ('\0' == str[0]) {
2563  // Empty string = no value.
2564  return value;
2565  }
2566 
2567  // Value names are separated by '|'.
2568  do {
2569  p = strchr(str, '|');
2570  if (nullptr != p) {
2571  p++;
2572  fc_strlcpy(val_name, str, p - str);
2573  } else {
2574  // Last segment, full copy.
2575  sz_strlcpy(val_name, str);
2576  }
2578  for (val = 0; (name = name_fn(data, val)); val++) {
2579  if (0 == strcmp(name, val_name)) {
2580  break;
2581  }
2582  }
2583  if (nullptr == name) {
2584  SECFILE_LOG(secfile, entry_section(pentry),
2585  "Entry \"%s\": no match for \"%s\".", entry_name(pentry),
2586  val_name);
2587  return defval;
2588  }
2589  value |= 1 << val;
2590  str = p;
2591  } while (nullptr != p);
2592  } else {
2593  for (val = 0; (name = name_fn(data, val)); val++) {
2594  if (0 == strcmp(name, str)) {
2595  value = val;
2596  break;
2597  }
2598  }
2599  if (nullptr == name) {
2600  SECFILE_LOG(secfile, entry_section(pentry),
2601  "Entry \"%s\": no match for \"%s\".", entry_name(pentry),
2602  str);
2603  return defval;
2604  }
2605  }
2606 
2607  return value;
2608 }
2609 
2614  const QString &name)
2615 {
2616  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2617 
2619  {
2620  if (section_name(psection) == name) {
2621  return psection;
2622  }
2623  }
2625 
2626  return nullptr;
2627 }
2628 
2633  const char *path, ...)
2634 {
2635  char fullpath[MAX_LEN_SECPATH];
2636  va_list args;
2637 
2638  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2639 
2640  va_start(args, path);
2641  fc_vsnprintf(fullpath, sizeof(fullpath), path, args);
2642  va_end(args);
2643 
2644  return secfile_section_by_name(secfile, fullpath);
2645 }
2646 
2651 const struct section_list *
2652 secfile_sections(const struct section_file *secfile)
2653 {
2654  return (nullptr != secfile ? secfile->sections : nullptr);
2655 }
2656 
2662 struct section_list *
2664  const char *prefix)
2665 {
2666  struct section_list *matches = nullptr;
2667  size_t len;
2668 
2669  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2670  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != prefix, nullptr);
2671 
2672  len = qstrlen(prefix);
2673  if (0 == len) {
2674  return nullptr;
2675  }
2676 
2677  section_list_iterate(secfile->sections, psection)
2678  {
2679  if (0 == strncmp(section_name(psection), prefix, len)) {
2680  if (nullptr == matches) {
2681  matches = section_list_new();
2682  }
2683  section_list_append(matches, psection);
2684  }
2685  }
2687 
2688  return matches;
2689 }
2690 
2695  const QString &name)
2696 {
2697  struct section *psection;
2698 
2699  SECFILE_RETURN_VAL_IF_FAIL(secfile, nullptr, nullptr != secfile, nullptr);
2700 
2701  if (nullptr == name || '\0' == name[0]) {
2702  SECFILE_LOG(secfile, nullptr, "Cannot create a section without name.");
2703  return nullptr;
2704  }
2705 
2707  SECFILE_LOG(secfile, nullptr, "\"%s\" is not a valid section name.",
2708  qUtf8Printable(name));
2709  return nullptr;
2710  }
2711 
2712  if (nullptr != secfile_section_by_name(secfile, name)) {
2713  /* We cannot duplicate sections in any case! Not even if one is
2714  * include -section and the other not. */
2715  SECFILE_LOG(secfile, nullptr, "Section \"%s\" already exists.",
2716  qUtf8Printable(name));
2717  return nullptr;
2718  }
2719 
2720  psection = new section;
2721  psection->special = EST_NORMAL;
2722  psection->name = qstrdup(qUtf8Printable(name));
2723  psection->entries = entry_list_new_full(entry_destroy);
2724 
2725  // Append to secfile.
2726  psection->secfile = secfile;
2727  section_list_append(secfile->sections, psection);
2728 
2729  if (nullptr != secfile->hash.sections) {
2730  secfile->hash.sections->insert(psection->name, psection);
2731  }
2732 
2733  return psection;
2734 }
2735 
2739 void section_destroy(struct section *psection)
2740 {
2741  struct section_file *secfile;
2742 
2743  SECFILE_RETURN_IF_FAIL(nullptr, psection, nullptr != psection);
2744 
2745  section_clear_all(psection);
2746 
2747  if ((secfile = psection->secfile)) {
2748  // Detach from secfile.
2749  if (section_list_remove(secfile->sections, psection)) {
2750  // This has called section_destroy() already then.
2751  return;
2752  }
2753  if (nullptr != secfile->hash.sections) {
2754  secfile->hash.sections->remove(psection->name);
2755  }
2756  }
2757 
2758  entry_list_destroy(psection->entries);
2759  delete[] psection->name;
2760  delete psection;
2761 }
2762 
2766 void section_clear_all(struct section *psection)
2767 {
2768  SECFILE_RETURN_IF_FAIL(nullptr, psection, nullptr != psection);
2769 
2770  // This include the removing of the hash datas.
2771  entry_list_clear(psection->entries);
2772 
2773  if (0 < entry_list_size(psection->entries)) {
2774  SECFILE_LOG(psection->secfile, psection,
2775  "After clearing all, %d entries are still remaining.",
2776  entry_list_size(psection->entries));
2777  }
2778 }
2779 
2784 const struct entry_list *section_entries(const struct section *psection)
2785 {
2786  return (nullptr != psection ? psection->entries : nullptr);
2787 }
2788 
2793  const QString &name)
2794 {
2795  SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, nullptr != psection,
2796  nullptr);
2797 
2799  {
2800  if (entry_name(pentry) == name) {
2801  entry_use(pentry);
2802  return pentry;
2803  }
2804  }
2806 
2807  return nullptr;
2808 }
2809 
2813 static entry *entry_new(struct section *psection, const QString &name)
2814 {
2815  struct section_file *secfile;
2816  struct entry *pentry;
2817 
2818  SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, nullptr != psection,
2819  nullptr);
2820 
2821  secfile = psection->secfile;
2822  if (nullptr == name || '\0' == name[0]) {
2823  SECFILE_LOG(secfile, psection, "Cannot create an entry without name.");
2824  return nullptr;
2825  }
2826 
2828  SECFILE_LOG(secfile, psection, "\"%s\" is not a valid entry name.",
2829  qUtf8Printable(name));
2830  return nullptr;
2831  }
2832 
2833  if (!secfile->allow_duplicates
2834  && nullptr != section_entry_by_name(psection, name)) {
2835  SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.",
2836  qUtf8Printable(name));
2837  return nullptr;
2838  }
2839 
2840  pentry = new entry;
2841  pentry->name = qstrdup(qUtf8Printable(name));
2842  pentry->type = ENTRY_ILLEGAL; // Invalid case
2843  pentry->used = 0;
2844  pentry->comment = nullptr;
2845 
2846  // Append to section.
2847  pentry->psection = psection;
2848  entry_list_append(psection->entries, pentry);
2849 
2850  // Notify secfile.
2851  secfile->num_entries++;
2852  secfile_hash_insert(secfile, pentry);
2853 
2854  return pentry;
2855 }
2856 
2861  const QString &name, int value)
2862 {
2863  struct entry *pentry = entry_new(psection, name);
2864 
2865  if (nullptr != pentry) {
2866  pentry->type = ENTRY_INT;
2867  pentry->integer.value = value;
2868  }
2869 
2870  return pentry;
2871 }
2872 
2877  const QString &name, bool value)
2878 {
2879  struct entry *pentry = entry_new(psection, name);
2880 
2881  if (nullptr != pentry) {
2882  pentry->type = ENTRY_BOOL;
2883  pentry->boolean.value = value;
2884  }
2885 
2886  return pentry;
2887 }
2888 
2893  const QString &name, float value)
2894 {
2895  struct entry *pentry = entry_new(psection, name);
2896 
2897  if (nullptr != pentry) {
2898  pentry->type = ENTRY_FLOAT;
2899  pentry->floating.value = value;
2900  }
2901 
2902  return pentry;
2903 }
2904 
2909  const QString &name,
2910  const QString &value, bool escaped)
2911 {
2912  struct entry *pentry = entry_new(psection, name);
2913 
2914  if (nullptr != pentry) {
2915  pentry->type = ENTRY_STR;
2916  pentry->string.value = qstrdup(qUtf8Printable(value));
2917  pentry->string.escaped = escaped;
2918  pentry->string.raw = false;
2919  pentry->string.gt_marking = false;
2920  }
2921 
2922  return pentry;
2923 }
2924 
2928 static struct entry *
2930  const char *value)
2931 {
2932  struct entry *pentry = entry_new(psection, name);
2933 
2934  if (nullptr != pentry) {
2935  pentry->type = ENTRY_FILEREFERENCE;
2936  pentry->string.value = fc_strdup(nullptr != value ? value : "");
2937  }
2938 
2939  return pentry;
2940 }
2941 
2945 void entry_destroy(struct entry *pentry)
2946 {
2947  struct section_file *secfile;
2948  struct section *psection;
2949 
2950  if (nullptr == pentry) {
2951  return;
2952  }
2953 
2954  if ((psection = pentry->psection)) {
2955  // Detach from section.
2956  if (entry_list_remove(psection->entries, pentry)) {
2957  // This has called entry_destroy() already then.
2958  return;
2959  }
2960  if ((secfile = psection->secfile)) {
2961  // Detach from secfile.
2962  secfile->num_entries--;
2963  secfile_hash_delete(secfile, pentry);
2964  }
2965  }
2966 
2967  // Specific type free.
2968  switch (pentry->type) {
2969  case ENTRY_BOOL:
2970  case ENTRY_INT:
2971  case ENTRY_FLOAT:
2972  break;
2973 
2974  case ENTRY_STR:
2975  case ENTRY_FILEREFERENCE:
2976  delete[] pentry->string.value;
2977  break;
2978 
2979  case ENTRY_ILLEGAL:
2980  fc_assert(pentry->type != ENTRY_ILLEGAL);
2981  break;
2982  }
2983 
2984  // Common free.
2985  delete[] pentry->name;
2986  delete[] pentry->comment;
2987  delete pentry;
2988  pentry = nullptr;
2989 }
2990 
2994 struct section *entry_section(const struct entry *pentry)
2995 {
2996  return (nullptr != pentry ? pentry->psection : nullptr);
2997 }
2998 
3002 enum entry_type entry_type_get(const struct entry *pentry)
3003 {
3004  return (nullptr != pentry ? pentry->type : ENTRY_ILLEGAL);
3005 }
3006 
3010 int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
3011 {
3012  return fc_snprintf(buf, buf_len, "%s.%s",
3013  section_name(entry_section(pentry)),
3014  entry_name(pentry));
3015 }
3016 
3020 const char *entry_name(const struct entry *pentry)
3021 {
3022  return (nullptr != pentry ? pentry->name : nullptr);
3023 }
3024 
3028 bool entry_set_name(struct entry *pentry, const char *name)
3029 {
3030  struct section *psection;
3031  struct section_file *secfile;
3032 
3033  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3034  psection = pentry->psection;
3035  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != psection, false);
3036  secfile = psection->secfile;
3037  SECFILE_RETURN_VAL_IF_FAIL(nullptr, psection, nullptr != secfile, false);
3038 
3039  if (nullptr == name || '\0' == name[0]) {
3040  SECFILE_LOG(secfile, psection, "No new name for entry \"%s\".",
3041  pentry->name);
3042  return false;
3043  }
3044 
3046  SECFILE_LOG(secfile, psection,
3047  "\"%s\" is not a valid entry name for entry \"%s\".", name,
3048  pentry->name);
3049  return false;
3050  }
3051 
3052  if (!secfile->allow_duplicates) {
3053  struct entry *pother = section_entry_by_name(psection, name);
3054 
3055  if (nullptr != pother && pother != pentry) {
3056  SECFILE_LOG(secfile, psection, "Entry \"%s\" already exists.", name);
3057  return false;
3058  }
3059  }
3060 
3061  // Remove from hash table the old path.
3062  secfile_hash_delete(secfile, pentry);
3063 
3064  // Really rename the entry.
3065  free(pentry->name);
3066  pentry->name = fc_strdup(name);
3067 
3068  // Insert into hash table the new path.
3069  secfile_hash_insert(secfile, pentry);
3070  return true;
3071 }
3072 
3076 const char *entry_comment(const struct entry *pentry)
3077 {
3078  return (nullptr != pentry ? pentry->comment : nullptr);
3079 }
3080 
3084 void entry_set_comment(struct entry *pentry, const QString &comment)
3085 {
3086  if (nullptr == pentry) {
3087  return;
3088  }
3089 
3090  pentry->comment =
3091  (!comment.isEmpty() ? fc_strdup(qUtf8Printable(comment)) : nullptr);
3092 }
3093 
3097 static inline bool entry_used(const struct entry *pentry)
3098 {
3099  return (0 < pentry->used);
3100 }
3101 
3105 static inline void entry_use(struct entry *pentry) { pentry->used++; }
3106 
3111 bool entry_bool_get(const struct entry *pentry, bool *value)
3112 {
3113  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3114 
3115  if (ENTRY_INT == pentry->type
3116  && (pentry->integer.value == 0 || pentry->integer.value == 1)
3117  && nullptr != pentry->psection->secfile
3118  && pentry->psection->secfile->allow_digital_boolean) {
3119  *value = (0 != pentry->integer.value);
3120  return true;
3121  }
3122 
3124  pentry->psection->secfile, pentry->psection,
3125  pentry->psection != nullptr && ENTRY_BOOL == pentry->type, false);
3126 
3127  if (nullptr != value) {
3128  *value = pentry->boolean.value;
3129  }
3130  return true;
3131 }
3132 
3136 bool entry_bool_set(struct entry *pentry, bool value)
3137 {
3138  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3140  ENTRY_BOOL == pentry->type, false);
3141 
3142  pentry->boolean.value = value;
3143  return true;
3144 }
3145 
3149 bool entry_float_get(const struct entry *pentry, float *value)
3150 {
3151  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3153  ENTRY_FLOAT == pentry->type, false);
3154 
3155  if (nullptr != value) {
3156  *value = pentry->floating.value;
3157  }
3158 
3159  return true;
3160 }
3161 
3165 bool entry_float_set(struct entry *pentry, float value)
3166 {
3167  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3169  ENTRY_FLOAT == pentry->type, false);
3170 
3171  pentry->floating.value = value;
3172 
3173  return true;
3174 }
3175 
3179 bool entry_int_get(const struct entry *pentry, int *value)
3180 {
3181  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3183  ENTRY_INT == pentry->type, false);
3184 
3185  if (nullptr != value) {
3186  *value = pentry->integer.value;
3187  }
3188  return true;
3189 }
3190 
3194 bool entry_int_set(struct entry *pentry, int value)
3195 {
3196  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3198  ENTRY_INT == pentry->type, false);
3199 
3200  pentry->integer.value = value;
3201  return true;
3202 }
3203 
3207 bool entry_str_get(const struct entry *pentry, const char **value)
3208 {
3209  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3211  ENTRY_STR == pentry->type, false);
3212 
3213  if (nullptr != value) {
3214  *value = pentry->string.value;
3215  }
3216  return true;
3217 }
3218 
3222 bool entry_str_set(struct entry *pentry, const char *value)
3223 {
3224  char *old_val;
3225 
3226  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3228  ENTRY_STR == pentry->type, false);
3229 
3230  /* We free() old value only after we've placed the new one, to
3231  * support secfile_replace_str_vec() calls that want to keep some of
3232  * the entries from the old vector in the new one. We don't want
3233  * to lose the entry in between. */
3234  old_val = pentry->string.value;
3235  pentry->string.value = fc_strdup(nullptr != value ? value : "");
3236  free(old_val);
3237  return true;
3238 }
3239 
3243 bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
3244 {
3245  SECFILE_RETURN_VAL_IF_FAIL(nullptr, nullptr, nullptr != pentry, false);
3247  ENTRY_STR == pentry->type, false);
3248 
3249  pentry->string.gt_marking = gt_marking;
3250 
3251  return true;
3252 }
3253 
3257 static bool entry_to_file(const struct entry *pentry, QIODevice *fs)
3258 {
3259  static char buf[8192];
3260 
3261  switch (pentry->type) {
3262  case ENTRY_BOOL:
3264  fs->write(pentry->boolean.value ? "TRUE" : "FALSE") > 0, false);
3265  break;
3266  case ENTRY_INT: {
3267  auto number = QString::number(pentry->integer.value);
3268  fc_assert_ret_val(fs->write(number.toUtf8()) > 0, false);
3269  } break;
3270  case ENTRY_FLOAT: {
3271  auto number = QString::number(pentry->floating.value, 'f');
3272  if (!number.contains('.')) {
3273  number += QStringLiteral(".0");
3274  }
3275  fc_assert_ret_val(fs->write(number.toUtf8()) > 0, false);
3276  } break;
3277  case ENTRY_STR:
3278  if (pentry->string.escaped) {
3279  make_escapes(pentry->string.value, buf, sizeof(buf));
3280  if (pentry->string.gt_marking) {
3281  fc_assert_ret_val(fs->write("_(\"" + QByteArray(buf) + "\")") > 0,
3282  false);
3283  } else {
3284  fc_assert_ret_val(fs->write("\"" + QByteArray(buf) + "\"") > 0,
3285  false);
3286  }
3287  } else if (pentry->string.raw) {
3288  fc_assert_ret_val(fs->write(pentry->string.value) > 0, false);
3289  } else {
3291  fs->write("$" + QByteArray(pentry->string.value) + "$") > 0,
3292  false);
3293  }
3294  break;
3295  case ENTRY_FILEREFERENCE:
3297  fs->write("*" + QByteArray(pentry->string.value) + "*") > 0, false);
3298  break;
3299  case ENTRY_ILLEGAL:
3300  fc_assert(pentry->type != ENTRY_ILLEGAL);
3301  return false;
3302  }
3303 
3304  return true;
3305 }
3306 
3311  const QString &name, const QString &tok,
3312  struct inputfile *inf)
3313 {
3314  if (!entry_from_token(psection, name, tok)) {
3315  qCritical("%s", qUtf8Printable(
3316  inf_log_str(inf, "Entry value not recognized: %s",
3317  qUtf8Printable(tok))));
3318  }
3319 }
static void base(QVariant data1, QVariant data2)
Action "Build Base" for choice dialog.
Definition: dialogs.cpp:2393
#define _(String)
Definition: fcintl.h:50
struct inputfile * inf_from_stream(QIODevice *stream, datafilename_fn_t datafn)
Open the stream, and return an allocated, initialized structure.
Definition: inputfile.cpp:225
QString inf_token(struct inputfile *inf, enum inf_token_type type)
Returns token of given type from given inputfile.
Definition: inputfile.cpp:536
bool inf_at_eof(struct inputfile *inf)
Return TRUE if current pos is at end of file.
Definition: inputfile.cpp:323
const char * name
Definition: inputfile.cpp:118
void inf_close(struct inputfile *inf)
Close the file and free associated memory, included any partially recursed included files,...
Definition: inputfile.cpp:285
int inf_discard_tokens(struct inputfile *inf, enum inf_token_type type)
Read as many tokens of specified type as possible, discarding the results; returns number of such tok...
Definition: inputfile.cpp:563
QString inf_log_str(struct inputfile *inf, const char *message,...)
Return a detailed log message, including information on current line number etc.
Definition: inputfile.cpp:494
struct inputfile * inf_from_file(const QString &filename, datafilename_fn_t datafn)
Open the file, and return an allocated, initialized structure.
Definition: inputfile.cpp:202
@ INF_TOK_EOL
Definition: inputfile.h:39
@ INF_TOK_COMMA
Definition: inputfile.h:42
@ INF_TOK_TABLE_END
Definition: inputfile.h:41
@ INF_TOK_VALUE
Definition: inputfile.h:43
@ INF_TOK_TABLE_START
Definition: inputfile.h:40
@ INF_TOK_ENTRY_NAME
Definition: inputfile.h:38
@ INF_TOK_SECTION_NAME
Definition: inputfile.h:37
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
int len
Definition: packhand.cpp:127
struct section_file * secfile_new(bool allow_duplicates)
Create a new empty section file.
const char * section_name(const struct section *psection)
Returns the section name.
void secfile_destroy(struct section_file *secfile)
Free a section file.
bool secfile_save(const struct section_file *secfile, QString filename)
Save the previously filled in section_file to disk.
const char * entry_comment(const struct entry *pentry)
Returns the comment associated to this entry.
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,...)
Lookup an enumerator value in the secfile.
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,...)
Insert 'dim' boolean entries at 'path,0', 'path,1' etc.
struct entry * secfile_insert_int_full(struct section_file *secfile, int value, const char *comment, bool allow_replace, const char *path,...)
Insert a integer entry.
bool entry_bool_get(const struct entry *pentry, bool *value)
Gets an boolean value.
void section_destroy(struct section *psection)
Remove this section from the secfile.
struct section * entry_section(const struct entry *pentry)
Returns the parent section of this entry.
void secfile_check_unused(const struct section_file *secfile)
Print log messages for any entries in the file which have not been looked up – ie,...
int entry_path(const struct entry *pentry, char *buf, size_t buf_len)
Build the entry path.
bool secfile_lookup_int(const struct section_file *secfile, int *ival, const char *path,...)
Lookup a integer value in the secfile.
static struct section * secfile_insert_base(struct section_file *secfile, const char *path, const char **pent_name)
Seperates the section and entry names.
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,...)
Insert a bitwise value entry.
struct section_file * secfile_from_stream(QIODevice *stream, bool allow_duplicates)
Create a section file from a stream.
static struct entry * section_entry_filereference_new(struct section *psection, const char *name, const char *value)
Returns a new entry of type ENTRY_FILEREFERENCE.
struct entry * secfile_insert_filereference(struct section_file *secfile, const char *filename, const char *path,...)
Insert a read-from-a-file string entry.
#define MAX_LEN_SECPATH
struct entry * section_entry_str_new(struct section *psection, const QString &name, const QString &value, bool escaped)
Returns a new entry of type ENTRY_STR.
struct entry * secfile_entry_lookup(const struct section_file *secfile, const char *path,...)
Returns the entry at "fullpath" or nullptr if not matched.
bool secfile_entry_delete(struct section_file *secfile, const char *path,...)
Delete an entry.
bool entry_set_name(struct entry *pentry, const char *name)
Sets the name of the entry.
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,...)
Lookup a value saved as string in the secfile.
static bool secfile_hash_insert(struct section_file *secfile, struct entry *pentry)
Insert an entry into the hash table.
int * secfile_lookup_int_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Lookup a integer vector in the secfile.
const char * entry_name(const struct entry *pentry)
Returns the name of this entry.
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,...)
Lookup a value saved as string in the secfile.
bool entry_bool_set(struct entry *pentry, bool value)
Sets an boolean value.
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Lookup a string value in the secfile.
const char ** secfile_lookup_str_vec(const struct section_file *secfile, size_t *dim, const char *path,...)
Lookup a string vector in the secfile.
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,...)
Insert 'dim' string entries at 'path,0', 'path,1' etc.
bool entry_float_get(const struct entry *pentry, float *value)
Gets an floating value.
bool entry_str_get(const struct entry *pentry, const char **value)
Gets an string 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,...)
Insert an enumerator value entry that we only have a name accessor function.
bool entry_str_set_gt_marking(struct entry *pentry, bool gt_marking)
Sets if the string should get gettext marking.
static entry * entry_new(struct section *psection, const QString &name)
Returns a new entry.
#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,...)
Insert 'dim' integer entries at 'path,0', 'path,1' etc.
void entry_destroy(struct entry *pentry)
Entry structure destructor.
static bool entry_used(const struct entry *pentry)
Returns TRUE if this entry has been used.
void section_clear_all(struct section *psection)
Remove all entries.
const char * secfile_name(const struct section_file *secfile)
Return the filename the section file was loaded as, or "(anonymous)" if this sectionfile was created ...
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,...)
Insert a string entry.
bool entry_float_set(struct entry *pentry, float value)
Sets an floating value.
struct section * secfile_section_by_name(const struct section_file *secfile, const QString &name)
Returns the first section matching the name.
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,...)
Lookup an enumerator value in the secfile.
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,...)
Insert 'dim' string entries at 'path,0', 'path,1' etc.
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,...)
Insert 'dim' string entries at 'path,0', 'path,1' etc.
static struct section_file * secfile_from_input_file(struct inputfile *inf, const QString &filename, const QString &section, bool allow_duplicates)
Base function to load a section file.
struct section_file * secfile_load_section(const QString &filename, const QString &section, bool allow_duplicates)
Create a section file from a file, read only one particular section.
bool secfile_lookup_bool_default(const struct section_file *secfile, bool def, const char *path,...)
Lookup a boolean value in the secfile.
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,...)
Lookup a enumerator vector in the secfile.
struct section * secfile_insert_long_comment(struct section_file *secfile, const char *comment)
Insert a long comment entry.
bool entry_int_set(struct entry *pentry, int value)
Sets an integer value.
const char * secfile_lookup_str_default(const struct section_file *secfile, const char *def, const char *path,...)
Lookup a string value in the secfile.
struct entry * secfile_entry_by_path(const struct section_file *secfile, const char *path)
Returns the entry by the name or nullptr if not matched.
static bool entry_to_file(const struct entry *pentry, QIODevice *fs)
Push an entry into a file stream.
struct entry * secfile_insert_float_full(struct section_file *secfile, float value, const char *comment, bool allow_replace, const char *path,...)
Insert a floating entry.
static QString datafilename(const QString &filename)
Simplification of fileinfoname().
int secfile_lookup_int_default(const struct section_file *secfile, int def, const char *path,...)
Lookup a integer value in the secfile.
struct entry * section_entry_by_name(const struct section *psection, const QString &name)
Returns the first entry matching the name.
bool entry_int_get(const struct entry *pentry, int *value)
Gets an integer value.
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,...)
Insert a enumerator entry.
static void entry_use(struct entry *pentry)
Increase the used count.
static bool is_secfile_entry_name_valid(const QString &name)
Ensure name is correct to use it as section or entry name.
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,...)
Lookup an enumerator value in the secfile.
static void entry_from_inf_token(struct section *psection, const QString &name, const QString &tok, struct inputfile *file)
Creates a new entry from the token.
static bool secfile_hash_delete(struct section_file *secfile, struct entry *pentry)
Delete an entry from the hash table.
struct entry * secfile_insert_bool_full(struct section_file *secfile, bool value, const char *comment, bool allow_replace, const char *path,...)
Insert a boolean entry.
const struct section_list * secfile_sections(const struct section_file *secfile)
Returns the list of sections.
struct section * secfile_insert_include(struct section_file *secfile, const char *filename)
Insert a include entry.
static bool is_legal_table_entry_name(char c, bool num)
Returns TRUE iff the character is legal in a table entry name.
bool entry_str_set(struct entry *pentry, const char *value)
Sets an string value.
struct section * secfile_section_new(struct section_file *secfile, const QString &name)
Create a new section in the secfile.
struct section * secfile_section_lookup(const struct section_file *secfile, const char *path,...)
Find a section by path.
struct entry * section_entry_int_new(struct section *psection, const QString &name, int value)
Returns a new entry of type ENTRY_INT.
struct entry * section_entry_bool_new(struct section *psection, const QString &name, bool value)
Returns a new entry of type ENTRY_BOOL.
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,...)
Lookup a bitwise enumerator value in the secfile.
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,...)
Insert 'dim' entries at 'path,0', 'path,1' etc.
struct section_list * secfile_sections_by_name_prefix(const struct section_file *secfile, const char *prefix)
Returns the list of sections which match the name prefix.
const struct entry_list * section_entries(const struct section *psection)
Returns a list containing all the entries.
void entry_set_comment(struct entry *pentry, const QString &comment)
Sets a comment for the entry.
bool secfile_lookup_bool(const struct section_file *secfile, bool *bval, const char *path,...)
Lookup a boolean value in the secfile.
struct entry * section_entry_float_new(struct section *psection, const QString &name, float value)
Returns a new entry of type ENTRY_FLOAT.
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,...)
Lookup a enumerator vector in the secfile.
int secfile_lookup_int_def_min_max(const struct section_file *secfile, int defval, int minval, int maxval, const char *path,...)
Lookup a integer value in the secfile.
enum entry_type entry_type_get(const struct entry *pentry)
Returns the type of this entry or ENTRY_ILLEGAL or error.
entry_type
Definition: registry_ini.h:533
@ ENTRY_FILEREFERENCE
Definition: registry_ini.h:538
@ ENTRY_INT
Definition: registry_ini.h:535
@ ENTRY_FLOAT
Definition: registry_ini.h:536
@ ENTRY_STR
Definition: registry_ini.h:537
@ ENTRY_ILLEGAL
Definition: registry_ini.h:539
@ ENTRY_BOOL
Definition: registry_ini.h:534
#define section_list_iterate(seclist, psection)
Definition: registry_ini.h:46
#define entry_list_iterate_end
Definition: registry_ini.h:58
bool(* secfile_enum_is_valid_fn_t)(int enumerator)
Definition: registry_ini.h:33
entry_special_type
Definition: registry_ini.h:71
@ EST_COMMENT
Definition: registry_ini.h:71
@ EST_NORMAL
Definition: registry_ini.h:71
@ EST_INCLUDE
Definition: registry_ini.h:71
#define section_list_iterate_end
Definition: registry_ini.h:48
#define entry_list_iterate(entlist, pentry)
Definition: registry_ini.h:56
int(* secfile_enum_by_name_fn_t)(const char *enum_name, int(*strcmp_fn)(const char *, const char *))
Definition: registry_ini.h:35
const char *(* secfile_enum_name_fn_t)(int enumerator)
Definition: registry_ini.h:34
int(* secfile_enum_iter_fn_t)()
Definition: registry_ini.h:38
const char *(* secfile_enum_name_data_fn_t)(secfile_data_t data, int enumerator)
Definition: registry_ini.h:40
int(* secfile_enum_next_fn_t)(int enumerator)
Definition: registry_ini.h:39
const void * secfile_data_t
Definition: registry_ini.h:28
bool entry_from_token(struct section *psection, const QString &name, const QString &tok)
Add entry to section from token.
#define SECFILE_LOG(secfile, psection, format,...)
Definition: section_file.h:58
#define SECFILE_RETURN_VAL_IF_FAIL(secfile, psection, condition, value)
Definition: section_file.h:66
#define SECFILE_RETURN_IF_FAIL(secfile, psection, condition)
Definition: section_file.h:61
const QStringList & get_data_dirs()
Returns a list of data directory paths, in the order in which they should be searched.
Definition: shared.cpp:533
QString interpret_tilde(const QString &filename)
Interpret ~ in filename as home dir.
Definition: shared.cpp:1100
QString fileinfoname(const QStringList &dirs, const QString &filename)
Returns a filename to access the specified file from a directory by searching all specified directori...
Definition: shared.cpp:661
void remove_leading_trailing_spaces(char *s)
Removes leading and trailing spaces in string pointed to by 's'.
Definition: shared.cpp:353
struct entry::@1::@3 boolean
enum entry_type type
struct entry::@1::@5 floating
bool gt_marking
char * value
bool raw
struct section * psection
float value
bool escaped
struct entry::@1::@6 string
bool value
char * comment
char * name
struct entry::@1::@4 integer
struct section_file::@7 hash
QMultiHash< QString, struct entry * > * entries
Definition: section_file.h:49
struct section_list * sections
Definition: section_file.h:44
bool allow_digital_boolean
Definition: section_file.h:46
bool allow_duplicates
Definition: section_file.h:45
unsigned int num_includes
Definition: section_file.h:42
unsigned int num_long_comments
Definition: section_file.h:43
size_t num_entries
Definition: section_file.h:38
struct entry_list * entries
Definition: section_file.h:32
char * name
Definition: section_file.h:31
enum entry_special_type special
Definition: section_file.h:30
struct section_file * secfile
Definition: section_file.h:29
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
size_t fc_strlcpy(char *dest, const char *src, size_t n)
fc_strlcpy() provides utf-8 version of (non-standard) function strlcpy() It is intended as more user-...
Definition: support.cpp:412
void make_escapes(const char *str, char *buf, size_t buf_len)
Copies a string and convert the following characters:
Definition: support.cpp:114
int fc_strcasecmp(const char *str0, const char *str1)
Compare strings like strcmp(), but ignoring case.
Definition: support.cpp:89
int cat_snprintf(char *str, size_t n, const char *format,...)
cat_snprintf is like a combination of fc_snprintf and fc_strlcat; it does snprintf to the end of an e...
Definition: support.cpp:564
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition: support.cpp:512
#define sz_strlcpy(dest, src)
Definition: support.h:140
#define fc_strdup(str)
Definition: support.h:111