Freeciv21
Develop your civilization from humble roots to a global empire
inputfile.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 
66 #include <cstdarg>
67 // Qt
68 #include <QLoggingCategory>
69 
70 // KArchive
71 #include <KFilterDev>
72 
73 // utility
74 #include "fcintl.h"
75 #include "log.h"
76 
77 #include "inputfile.h"
78 
79 #define INF_MAGIC (0xabdc0132) // arbitrary
80 
81 struct inputfile {
82  unsigned int magic; // memory check
83  QString filename; // filename as passed to fopen
84  QIODevice *fp; // read from this
85  QTextStream *stream; // handles encoding
86  QString cur_line; // data from current line
87  unsigned int cur_line_pos; // position in current line
88  unsigned int line_num; // line number from file in cur_line
89  QString partial; /* used in accumulating multi-line strings;
90  used only in get_token_value, but put
91  here so it gets freed when file closed */
92  QString token; // data returned to user
93  datafilename_fn_t datafn; /* function like datafilename(); use a
94  function pointer just to keep this
95  inputfile module "generic" */
96  bool in_string; /* set when reading multi-line strings,
97  to know not to handle *include at start
98  of line as include mechanism */
99  int string_start_line; /* when in_string is true, this is the
100  start line of current string */
101  struct inputfile *included_from; /* nullptr for toplevel file, otherwise
102  points back to files which this one
103  has been included from */
104 };
105 
106 // A function to get a specific token type:
107 typedef QString (*get_token_fn_t)(struct inputfile *inf);
108 
109 static QString get_token_section_name(struct inputfile *inf);
110 static QString get_token_entry_name(struct inputfile *inf);
111 static QString get_token_eol(struct inputfile *inf);
112 static QString get_token_table_start(struct inputfile *inf);
113 static QString get_token_table_end(struct inputfile *inf);
114 static QString get_token_comma(struct inputfile *inf);
115 static QString get_token_value(struct inputfile *inf);
116 
117 static struct {
118  const char *name;
120 } tok_tab[INF_TOK_LAST] = {
121  {"section_name", get_token_section_name},
122  {"entry_name", get_token_entry_name},
123  {"end_of_line", get_token_eol},
124  {"table_start", get_token_table_start},
125  {"table_end", get_token_table_end},
126  {"comma", get_token_comma},
127  {"value", get_token_value},
128 };
129 
130 static bool read_a_line(struct inputfile *inf);
131 
132 Q_LOGGING_CATEGORY(inf_category, "freeciv.inputfile")
133 
134 
137 template <class Char> static bool is_comment(Char c)
138 {
139  return (c == '#' || c == ';');
140 }
141 
146 static void init_zeros(struct inputfile *inf)
147 {
148  fc_assert_ret(nullptr != inf);
149  inf->magic = INF_MAGIC;
150  inf->filename.clear();
151  inf->fp = nullptr;
152  inf->stream = nullptr;
153  inf->datafn = nullptr;
154  inf->included_from = nullptr;
155  inf->line_num = inf->cur_line_pos = 0;
156  inf->in_string = false;
157  inf->string_start_line = 0;
158  inf->cur_line.clear();
159  inf->token.clear();
160  inf->partial.clear();
161  inf->partial.reserve(200);
162 }
163 
167 static bool inf_sanity_check(struct inputfile *inf)
168 {
169  fc_assert_ret_val(nullptr != inf, false);
170  fc_assert_ret_val(INF_MAGIC == inf->magic, false);
171  fc_assert_ret_val(nullptr != inf->fp, false);
172  fc_assert_ret_val(false == inf->in_string || true == inf->in_string,
173  false);
174 
175 #ifdef FREECIV_DEBUG
176  fc_assert_ret_val(0 <= inf->string_start_line, false);
177  if (inf->included_from && !inf_sanity_check(inf->included_from)) {
178  return false;
179  }
180 #endif // FREECIV_DEBUG
181 
182  return true;
183 }
184 
189 static QString inf_filename(struct inputfile *inf)
190 {
191  if (inf->filename.isEmpty()) {
192  return QStringLiteral("(anonymous)");
193  } else {
194  return inf->filename;
195  }
196 }
197 
202 struct inputfile *inf_from_file(const QString &filename,
204 {
205  struct inputfile *inf;
206 
207  fc_assert_ret_val(!filename.isEmpty(), nullptr);
208  fc_assert_ret_val(0 < filename.length(), nullptr);
209  auto *fp = new KFilterDev(filename);
210  fp->open(QIODevice::ReadOnly);
211  if (!fp->isOpen()) {
212  delete fp;
213  return nullptr;
214  }
215  qCDebug(inf_category) << "opened" << filename << "ok";
216  inf = inf_from_stream(fp, datafn);
217  inf->filename = filename;
218  return inf;
219 }
220 
225 struct inputfile *inf_from_stream(QIODevice *stream,
227 {
228  struct inputfile *inf;
229 
230  fc_assert_ret_val(nullptr != stream, nullptr);
231  inf = new inputfile;
232  init_zeros(inf);
233 
234  inf->filename.clear();
235  inf->fp = stream;
236  inf->stream = new QTextStream(stream);
237  inf->stream->setCodec("UTF-8");
238  inf->stream->setAutoDetectUnicode(true); // Allow UTF-16 and UTF-32
239  inf->datafn = datafn;
240 
241  qCDebug(inf_category) << "opened" << inf_filename(inf) << "ok";
242  return inf;
243 }
244 
251 static void inf_close_partial(struct inputfile *inf)
252 {
254 
255  qCDebug(inf_category) << "sub-closing" << inf_filename(inf);
256 
257  // No way to determine whether a generic QIODevice has error'ed :(
258  bool error = false;
259  if (dynamic_cast<KFilterDev *>(inf->fp)) {
260  error = dynamic_cast<KFilterDev *>(inf->fp)->error() != 0;
261  }
262  if (error) {
263  qCCritical(inf_category) << "Error before closing" << inf_filename(inf)
264  << ":" << inf->fp->errorString();
265  }
266  delete inf->stream;
267  inf->stream = nullptr;
268 
269  delete inf->fp;
270  inf->fp = nullptr;
271 
272  // assign zeros for safety if accidentally re-use etc:
273  init_zeros(inf);
274  inf->magic = ~INF_MAGIC;
275 
276  qCDebug(inf_category) << "sub-closed ok";
277 }
278 
285 void inf_close(struct inputfile *inf)
286 {
288 
289  qCDebug(inf_category) << "closing" << inf_filename(inf);
290  if (inf->included_from) {
291  inf_close(inf->included_from);
292  }
293  inf_close_partial(inf);
294  delete inf;
295  qCDebug(inf_category) << "closed ok";
296 }
297 
301 static bool have_line(struct inputfile *inf)
302 {
303  fc_assert_ret_val(inf_sanity_check(inf), false);
304 
305  return !inf->cur_line.isEmpty();
306 }
307 
311 static bool at_eol(struct inputfile *inf)
312 {
314  fc_assert_ret_val(inf->cur_line_pos <= inf->cur_line.length(), true);
315 
316  // - 1 because of the trailing newline character.
317  return inf->cur_line_pos >= inf->cur_line.length() - 1;
318 }
319 
323 bool inf_at_eof(struct inputfile *inf)
324 {
326 
327  return inf->included_from == nullptr && inf->stream->atEnd()
328  && inf->cur_line_pos >= inf->cur_line.length();
329 }
330 
339 static bool check_include(struct inputfile *inf)
340 {
341  struct inputfile *new_inf, temp;
342 
343  fc_assert_ret_val(inf_sanity_check(inf), false);
344  if (inf->in_string || inf->cur_line_pos > 0) {
345  return false;
346  }
347 
348  QString include_prefix = QStringLiteral("*include");
349  if (!inf->cur_line.startsWith(include_prefix)) {
350  return false;
351  }
352 
353  // From here, the include-line must be well formed
354  // Skip any whitespace
355  for (inf->cur_line_pos = include_prefix.length();
356  inf->cur_line_pos < inf->cur_line.length(); ++inf->cur_line_pos) {
357  if (!inf->cur_line[inf->cur_line_pos].isSpace()) {
358  break;
359  }
360  }
361 
362  // Check that we've got the opening ", and not EOL
363  if (inf->cur_line_pos >= inf->cur_line.length()
364  || inf->cur_line[inf->cur_line_pos] != '\"') {
365  qCCritical(inf_category,
366  "Did not find opening doublequote for '*include' line");
367  return false;
368  }
369 
370  // First char after the "
371  auto start = inf->cur_line_pos + 1;
372 
373  // Find the closing "
374  auto end = inf->cur_line.indexOf('\"', start);
375  if (end < 0) {
376  qCCritical(inf_category,
377  "Did not find closing doublequote for '*include' line");
378  return false;
379  }
380 
381  auto name = inf->cur_line.mid(start, end - start);
382 
383  // Check that the rest of line is well-formed
384  for (int i = end + 1; i < inf->cur_line.length(); ++i) {
385  auto c = inf->cur_line[i];
386  if (is_comment(c)) {
387  // Ignore the rest of the line
388  break;
389  } else if (!c.isSpace()) {
390  qCCritical(inf_category, "Junk after filename for '*include' line");
391  return false;
392  }
393  }
394 
395  inf->cur_line_pos = inf->cur_line.length() - 1;
396  auto full_name = inf->datafn(name);
397  if (full_name.isEmpty()) {
398  qCCritical(inf_category) << "Could not find included file: " << name;
399  return false;
400  }
401 
402  // Avoid recursion (first filename may not have the same path, but will at
403  // east stop infinite recursion)
404  {
405  struct inputfile *inc = inf;
406  do {
407  if (full_name == inc->filename) {
408  qCCritical(inf_category)
409  << "Recursion trap on '*include' for" << full_name;
410  return false;
411  }
412  } while ((inc = inc->included_from));
413  }
414 
415  new_inf = inf_from_file(qUtf8Printable(full_name), inf->datafn);
416 
417  /* Swap things around so that memory pointed to by inf (user pointer,
418  and pointer in calling functions) contains the new inputfile,
419  and newly allocated memory for new_inf contains the old inputfile.
420  This is pretty scary, lets hope it works...
421  */
422  temp = *new_inf;
423  *new_inf = *inf;
424  *inf = temp;
425  inf->included_from = new_inf;
426  return true;
427 }
428 
433 static bool stop_reading(inputfile *inf)
434 {
435  if (inf->included_from == nullptr) {
436  return false;
437  }
438 
439  qCDebug(inf_category) << "*include end:" << inf->filename;
440  // Pop the include, and get next line from file above instead.
441  struct inputfile *inc = inf->included_from;
442  inf_close_partial(inf);
443  // So the user pointer in still valid (and inf pointers in calling
444  // functions)
445  *inf = std::move(*inc);
446  delete inc;
447  qCDebug(inf_category) << "back to:" << inf->filename;
448  return read_a_line(inf);
449 }
450 
457 static bool read_a_line(struct inputfile *inf)
458 {
459  fc_assert_ret_val(inf_sanity_check(inf), false);
460 
461  // eof
462  if (inf->stream->atEnd() && inf->cur_line_pos >= inf->cur_line.length()) {
463  return stop_reading(inf);
464  }
465 
466  // Read a full line. Only ASCII line separators are valid.
467  // First get the data. Proper error handling makes this terrible...
468  QString line;
469  const auto ok = inf->stream->readLineInto(&inf->cur_line, 0);
470  if (!ok && !inf->fp->atEnd()) {
471  // TRANS: Error reading <file>: <reason>
472  qCCritical(inf_category) << QString::fromUtf8(_("Error reading %1: %2"))
473  .arg(inf->filename)
474  .arg(inf->fp->errorString());
475  return stop_reading(inf);
476  }
477 
478  // Normal behavior
479  inf->cur_line += '\n'; // The parsing code needs a termination character.
480  inf->cur_line_pos = 0;
481  inf->line_num++;
482 
483  if (check_include(inf)) {
484  return read_a_line(inf);
485  }
486  return true;
487 }
488 
494 QString inf_log_str(struct inputfile *inf, const char *message, ...)
495 {
496  fc_assert_ret_val(inf_sanity_check(inf), nullptr);
497 
498  QString str;
499 
500  if (message) {
501  va_list args;
502  va_start(args, message);
503  str = QString::vasprintf(message, args);
504  va_end(args);
505  }
506 
507  str += QStringLiteral("\n");
508  str += QStringLiteral(" file \"%1\", line %2, pos %3")
509  .arg(inf_filename(inf))
510  .arg(inf->line_num)
511  .arg(inf->cur_line_pos);
512  if (inf_at_eof(inf)) {
513  str += QStringLiteral(", EOF");
514  }
515 
516  if (!inf->cur_line.isEmpty()) {
517  str += QStringLiteral("\n looking at: '%1'")
518  .arg(inf->cur_line.mid(inf->cur_line_pos));
519  }
520  if (inf->in_string) {
521  str += QStringLiteral("\n processing string starting at line %1")
522  .arg(inf->string_start_line);
523  }
524  while ((inf = inf->included_from)) { // local pointer assignment
525  str += QStringLiteral("\n included from file \"%1\", line %2")
526  .arg(inf_filename(inf))
527  .arg(inf->line_num);
528  }
529 
530  return str;
531 }
532 
536 QString inf_token(struct inputfile *inf, enum inf_token_type type)
537 {
538  fc_assert_ret_val(inf_sanity_check(inf), nullptr);
539  fc_assert_ret_val(INF_TOK_FIRST <= type && INF_TOK_LAST > type, nullptr);
540 
541  auto name = tok_tab[type].name ? tok_tab[type].name : "(unnamed)";
542  auto func = tok_tab[type].func;
543 
544  QString s;
545  if (func) {
546  while (!have_line(inf) && read_a_line(inf)) {
547  // Nothing.
548  }
549  if (have_line(inf)) {
550  s = func(inf);
551  }
552  } else {
553  qCCritical(inf_category)
554  << "token type" << type << "(" << name << ") not supported yet";
555  }
556  return s;
557 }
558 
563 int inf_discard_tokens(struct inputfile *inf, enum inf_token_type type)
564 {
565  int count = 0;
566 
567  while (!inf_token(inf, type).isEmpty()) {
568  count++;
569  }
570 
571  return count;
572 }
573 
579 static QString get_token_section_name(struct inputfile *inf)
580 {
581  fc_assert_ret_val(have_line(inf), "");
582 
583  auto start = inf->cur_line_pos;
584  if (start >= inf->cur_line.length() || inf->cur_line[start] != '[') {
585  return "";
586  }
587  ++start; // Skip the [
588  auto end = inf->cur_line.indexOf(']', start);
589  if (end < 0) {
590  return "";
591  }
592 
593  // Extract the name
594  inf->token = inf->cur_line.mid(start, end - start);
595  inf->cur_line_pos = end + 1;
596  return inf->token;
597 }
598 
603 static QString get_token_entry_name(struct inputfile *inf)
604 {
605  fc_assert_ret_val(have_line(inf), "");
606 
607  // Skip whitespace
608  auto i = inf->cur_line_pos;
609  for (; i < inf->cur_line.length(); ++i) {
610  if (!inf->cur_line[i].isSpace()) {
611  break;
612  }
613  }
614  if (i >= inf->cur_line.length()) {
615  return "";
616  }
617  auto start = i;
618 
619  // Find the end of the name
620  for (; i < inf->cur_line.length(); ++i) {
621  auto c = inf->cur_line[i];
622  if (c.isSpace() || c == '=') {
623  break;
624  }
625  }
626  if (i >= inf->cur_line.length()) {
627  return "";
628  }
629  auto end = i;
630 
631  // Find the equal sign
632  auto eq = inf->cur_line.indexOf('=', end);
633  if (eq < 0) {
634  return "";
635  }
636 
637  // Check that we didn't eat a comment in the middle
638  auto ref = inf->cur_line.midRef(inf->cur_line_pos, eq - inf->cur_line_pos);
639  if (ref.contains(';') || ref.contains('#')) {
640  return "";
641  }
642 
643  inf->cur_line_pos = eq + 1;
644  inf->token = inf->cur_line.mid(start, end - start);
645 
646  return inf->token;
647 }
648 
653 static QString get_token_eol(struct inputfile *inf)
654 {
655  fc_assert_ret_val(have_line(inf), "");
656 
657  if (!at_eol(inf)) {
658  auto it = inf->cur_line.cbegin() + inf->cur_line_pos;
659  for (; it < inf->cur_line.cend() && it->isSpace(); ++it) {
660  // Skip
661  }
662  if (it != inf->cur_line.cend() && !is_comment(*it)) {
663  return "";
664  }
665  }
666 
667  // finished with this line: say that we don't have it any more
668  inf->cur_line.clear();
669  inf->cur_line_pos = 0;
670 
671  inf->token = QStringLiteral(" ");
672  return inf->token;
673 }
674 
679 static QString get_token_white_char(struct inputfile *inf, char target)
680 {
681  fc_assert_ret_val(have_line(inf), nullptr);
682 
683  // Skip whitespace
684  auto it = inf->cur_line.cbegin() + inf->cur_line_pos;
685  for (; it != inf->cur_line.cend() && it->isSpace(); ++it) {
686  // Skip
687  }
688  if (it == inf->cur_line.cend() || *it != target) {
689  return "";
690  }
691 
692  inf->cur_line_pos = it - inf->cur_line.cbegin() + 1;
693  inf->token = target;
694  return inf->token;
695 }
696 
700 static QString get_token_table_start(struct inputfile *inf)
701 {
702  return get_token_white_char(inf, '{');
703 }
704 
708 static QString get_token_table_end(struct inputfile *inf)
709 {
710  return get_token_white_char(inf, '}');
711 }
712 
716 static QString get_token_comma(struct inputfile *inf)
717 {
718  return get_token_white_char(inf, ',');
719 }
720 
724 static QString get_token_value(struct inputfile *inf)
725 {
726  fc_assert_ret_val(have_line(inf), nullptr);
727 
728  auto begin = inf->cur_line.cbegin();
729  auto end = inf->cur_line.cend();
730 
731  // Skip whitespace
732  auto c = begin + inf->cur_line_pos;
733  for (; c != end && c->isSpace(); ++c) {
734  // Skip
735  }
736  if (c == end) {
737  return "";
738  }
739 
740  // Advance
741  inf->cur_line_pos = c - begin;
742 
743  if (*c == '-' || *c == '+' || c->isDigit()) {
744  // A number
745  auto start = c++;
746  for (; c != end && c->isDigit(); ++c) {
747  // Take
748  }
749  if (*c == '.') {
750  // Float maybe
751  c++;
752  for (; c != end && c->isDigit(); ++c) {
753  // Take
754  }
755  }
756  // check that the trailing stuff is ok
757  if (!(c == end || *c == ',' || c->isSpace() || is_comment(*c))) {
758  return "";
759  }
760 
761  inf->token = inf->cur_line.mid(start - begin, c - start);
762  inf->cur_line_pos = c - begin;
763 
764  return inf->token;
765  }
766 
767  // Allow gettext marker
768  bool has_i18n_marking = false;
769  if (*c == '_' && *(c + 1) == '(') {
770  has_i18n_marking = true;
771  c += 2;
772  while (c != end && c->isSpace()) {
773  c++;
774  }
775  if (c == end) {
776  return nullptr;
777  }
778  }
779 
780  auto border_character = *c;
781  if (border_character == '*') {
782  // File included as string
783  auto first = c - begin + 1; // Switch to indexes
784 
785  // Find the closing *
786  auto last = inf->cur_line.indexOf('*', first);
787  if (last < 0) {
788  return "";
789  }
790  // Check that the trailing stuff is ok
791  c += last - first + 2;
792  if (!(c == end || *c == ',' || c->isSpace() || is_comment(*c))) {
793  return "";
794  }
795 
796  // File name without *
797  auto name = inf->cur_line.mid(first, last - first);
798  auto rfname = inf->datafn(name);
799  if (rfname == nullptr) {
800 
801  qCCritical(inf_category, _("Cannot find stringfile \"%s\"."),
802  qUtf8Printable(name));
803  return "";
804  }
805  auto fp = new KFilterDev(rfname);
806  fp->open(QIODevice::ReadOnly);
807  if (!fp->isOpen()) {
808  qCCritical(inf_category, _("Cannot open stringfile \"%s\"."),
809  qUtf8Printable(rfname));
810  delete fp;
811  return "";
812  }
813  qCDebug(inf_category) << "Stringfile" << name << "opened ok";
814 
815  inf->token = QStringLiteral("*"); // Mark as a string read from a file
816  inf->token += QString::fromUtf8(fp->readAll());
817 
818  delete fp;
819  fp = nullptr;
820 
821  inf->cur_line_pos = c + 1 - begin;
822 
823  return inf->token;
824  } else if (border_character != '\"' && border_character != '\''
825  && border_character != '$') {
826  // A one-word string: maybe FALSE or TRUE.
827  auto start = c;
828  for (; c->isLetterOrNumber(); ++c) {
829  // Skip
830  }
831  // check that the trailing stuff is ok:
832  if (!(c == end || *c == ',' || c->isSpace() || is_comment(*c))) {
833  return nullptr;
834  }
835 
836  inf->cur_line_pos = c - begin;
837  inf->token = inf->cur_line.mid(start - begin, c - start);
838 
839  return inf->token;
840  }
841 
842  /* From here, we know we have a string, we just have to find the
843  trailing (un-escaped) double-quote. We read in extra lines if
844  necessary to find it. If we _don't_ find the end-of-string
845  (that is, we come to end-of-file), we return nullptr, but we
846  leave the file in at_eof, and don't try to back-up to the
847  current point. (That would be more difficult, and probably
848  not necessary: at that point we probably have a malformed
849  string/file.)
850 
851  As we read extra lines, the string value from previous
852  lines is placed in partial.
853  */
854 
855  // prepare for possibly multi-line string:
856  inf->string_start_line = inf->line_num;
857  inf->in_string = true;
858  inf->partial.clear();
859 
860  auto start = c++; /* start includes the initial \", to
861  * distinguish from a number */
862  for (;;) {
863  while (c != end && *c != border_character) {
864  /* skip over escaped chars, including backslash-doublequote,
865  * and backslash-backslash: */
866  if (*c == '\\' && (c + 1) != end) {
867  c++;
868  }
869  c++;
870  }
871 
872  if (*c == border_character) {
873  // Found end of string
874  break;
875  }
876 
877  inf->partial += QString(start);
878 
879  if (!read_a_line(inf)) {
880  // shouldn't happen
881  qCCritical(inf_category,
882  "Bad return for multi-line string from read_a_line");
883  return "";
884  }
885  begin = inf->cur_line.cbegin();
886  end = inf->cur_line.cend();
887  c = start = begin;
888  }
889 
890  // found end of string
891  inf->cur_line_pos = c + 1 - begin;
892  inf->token = inf->partial + inf->cur_line.mid(start - begin, c - start);
893 
894  // check gettext tag at end:
895  if (has_i18n_marking) {
896  if (*++c == ')') {
897  inf->cur_line_pos++;
898  } else {
899  qCWarning(inf_category, "Missing end of i18n string marking");
900  }
901  }
902  inf->in_string = false;
903  return inf->token;
904 }
#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
static struct @0 tok_tab[INF_TOK_LAST]
static bool stop_reading(inputfile *inf)
Stops reading the passed file.
Definition: inputfile.cpp:433
QString(* get_token_fn_t)(struct inputfile *inf)
Definition: inputfile.cpp:107
static QString get_token_white_char(struct inputfile *inf, char target)
Get a flag token of a single character, with optional preceeding whitespace.
Definition: inputfile.cpp:679
static QString get_token_eol(struct inputfile *inf)
If inputfile is at end-of-line, frees current line, and returns " ".
Definition: inputfile.cpp:653
static QString inf_filename(struct inputfile *inf)
Return the filename the inputfile was loaded as, or "(anonymous)" if this inputfile was loaded from a...
Definition: inputfile.cpp:189
static QString get_token_entry_name(struct inputfile *inf)
Returns next entry name from inputfile.
Definition: inputfile.cpp:603
QString inf_token(struct inputfile *inf, enum inf_token_type type)
Returns token of given type from given inputfile.
Definition: inputfile.cpp:536
static bool inf_sanity_check(struct inputfile *inf)
Check sensible values for an opened inputfile.
Definition: inputfile.cpp:167
static QString get_token_table_end(struct inputfile *inf)
Get flag token for table end, or nullptr if that is not next token.
Definition: inputfile.cpp:708
bool inf_at_eof(struct inputfile *inf)
Return TRUE if current pos is at end of file.
Definition: inputfile.cpp:323
static bool have_line(struct inputfile *inf)
Return TRUE if have data for current line.
Definition: inputfile.cpp:301
static QString get_token_section_name(struct inputfile *inf)
Returns section name in current position of inputfile.
Definition: inputfile.cpp:579
static void init_zeros(struct inputfile *inf)
Set values to zeros; should have free'd/closed everything before this if appropriate.
Definition: inputfile.cpp:146
static bool at_eol(struct inputfile *inf)
Return TRUE if current pos is at end of current line.
Definition: inputfile.cpp:311
const char * name
Definition: inputfile.cpp:118
static bool is_comment(Char c)
Return true if c is a 'comment' character: '#' or ';'.
Definition: inputfile.cpp:137
void inf_close(struct inputfile *inf)
Close the file and free associated memory, included any partially recursed included files,...
Definition: inputfile.cpp:285
#define INF_MAGIC
A low-level object for reading a registry-format file.
Definition: inputfile.cpp:79
static bool check_include(struct inputfile *inf)
Check for an include command, which is an isolated line with: include "filename" If a file is include...
Definition: inputfile.cpp:339
static QString get_token_value(struct inputfile *inf)
This one is more complicated; note that it may read in multiple lines.
Definition: inputfile.cpp:724
static bool read_a_line(struct inputfile *inf)
Read a new line into cur_line.
Definition: inputfile.cpp:457
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
static QString get_token_comma(struct inputfile *inf)
Get flag token comma, or nullptr if that is not next token.
Definition: inputfile.cpp:716
get_token_fn_t func
Definition: inputfile.cpp:119
static QString get_token_table_start(struct inputfile *inf)
Get flag token for table start, or nullptr if that is not next token.
Definition: inputfile.cpp:700
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
static void inf_close_partial(struct inputfile *inf)
Close the file and free associated memory, but don't recurse included_from files, and don't free the ...
Definition: inputfile.cpp:251
inf_token_type
Definition: inputfile.h:36
@ INF_TOK_LAST
Definition: inputfile.h:44
QString(*)(const QString &filename) datafilename_fn_t
Definition: inputfile.h:27
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
QTextStream * stream
Definition: inputfile.cpp:85
int string_start_line
Definition: inputfile.cpp:99
unsigned int magic
Definition: inputfile.cpp:82
QString cur_line
Definition: inputfile.cpp:86
QString partial
Definition: inputfile.cpp:89
unsigned int line_num
Definition: inputfile.cpp:88
unsigned int cur_line_pos
Definition: inputfile.cpp:87
QString filename
Definition: inputfile.cpp:83
struct inputfile * included_from
Definition: inputfile.cpp:101
bool in_string
Definition: inputfile.cpp:96
datafilename_fn_t datafn
Definition: inputfile.cpp:93
QString token
Definition: inputfile.cpp:92
QIODevice * fp
Definition: inputfile.cpp:84
Q_LOGGING_CATEGORY(tileset_category, "freeciv.tileset")
Functions for handling the tilespec files which describe the files and contents of tilesets.