Feature #406 ยป 0052-inputfile.-ch-Improve-coding-style.patch
utility/inputfile.c | ||
---|---|---|
original author: David Pfitzner <dwp@mso.anu.edu.au>
|
||
This module implements an object which is useful for reading/parsing
|
||
a file in the registry format of registry.c. It takes care of the
|
||
a file in the registry format of registry.c. It takes care of the
|
||
low-level file-reading details, and provides functions to return
|
||
specific "tokens" from the file. Probably this should really use
|
||
specific "tokens" from the file. Probably this should really use
|
||
higher-level tools... (flex/lex bison/yacc?)
|
||
When the user tries to read a token, we return a (const char*)
|
||
pointing to some data if the token was found, or NULL otherwise.
|
||
The data pointed to should not be modified. The retuned pointer
|
||
is valid _only_ until another inputfile is performed. (So should
|
||
pointing to some data if the token was found, or nullptr otherwise.
|
||
The data pointed to should not be modified. The retuned pointer
|
||
is valid _only_ until another inputfile is performed. (So should
|
||
be used immediately, or fc_strdup-ed etc.)
|
||
|
||
The tokens recognised are as follows:
|
||
(Single quotes are delimiters used here, but are not part of the
|
||
actual tokens/strings.)
|
||
... | ... | |
section_name: '[foo]'
|
||
returned token: 'foo'
|
||
|
||
entry_name: 'foo =' (optional whitespace allowed before '=')
|
||
returned token: 'foo'
|
||
|
||
end_of_line: newline, or optional '#' or ';' (comment characters)
|
||
followed by any other chars, then newline.
|
||
returned token: should not be used except to check non-NULL.
|
||
|
||
table_start: '{'
|
||
returned token: should not be used except to check non-NULL.
|
||
|
||
table_end: '}'
|
||
returned token: should not be used except to check non-NULL.
|
||
comma: literal ','
|
||
returned token: should not be used except to check non-NULL.
|
||
|
||
returned token: should not be used except to check non-nullptr.
|
||
table_start: '{'
|
||
returned token: should not be used except to check non-nullptr.
|
||
table_end: '}'
|
||
returned token: should not be used except to check non-nullptr.
|
||
comma: literal ','
|
||
returned token: should not be used except to check non-nullptr.
|
||
value: a signed integer, or a double-quoted string, or a
|
||
gettext-marked double quoted string. Strings _may_ contain
|
||
raw embedded newlines, and escaped doublequotes, or \.
|
||
eg: '123', '-999', '"foo"', '_("foo")'
|
||
gettext-marked double quoted string. Strings _may_ contain
|
||
raw embedded newlines, and escaped doublequotes, or \.
|
||
eg: '123', '-999', '"foo"', '_("foo")'
|
||
returned token: string containing number, for numeric, or string
|
||
starting at first doublequote for strings, but ommiting
|
||
trailing double-quote. Note this does _not_ translate
|
||
escaped doublequotes etc back to normal.
|
||
trailing double-quote. Note this does _not_ translate
|
||
escaped doublequotes etc back to normal.
|
||
***********************************************************************/
|
||
... | ... | |
#include "ioz.h"
|
||
#include "log.h"
|
||
#include "mem.h"
|
||
#include "shared.h" /* TRUE, FALSE */
|
||
#include "shared.h" /* TRUE, FALSE */
|
||
#include "support.h"
|
||
#include "inputfile.h"
|
||
... | ... | |
#define INF_DEBUG_FOUND FALSE
|
||
#define INF_DEBUG_NOT_FOUND FALSE
|
||
#define INF_MAGIC (0xabdc0132) /* arbitrary */
|
||
#define INF_MAGIC (0xabdc0132) /* Arbitrary */
|
||
struct inputfile {
|
||
unsigned int magic; /* memory check */
|
||
char *filename; /* filename as passed to fopen */
|
||
fz_FILE *fp; /* read from this */
|
||
bool at_eof; /* flag for end-of-file */
|
||
struct astring cur_line; /* data from current line */
|
||
unsigned int cur_line_pos; /* position in current line */
|
||
unsigned int line_num; /* line number from file in cur_line */
|
||
struct astring token; /* data returned to user */
|
||
struct astring partial; /* used in accumulating multi-line strings;
|
||
used only in get_token_value, but put
|
||
here so it gets freed when file closed */
|
||
datafilename_fn_t datafn; /* function like datafilename(); use a
|
||
function pointer just to keep this
|
||
inputfile module "generic" */
|
||
bool in_string; /* set when reading multi-line strings,
|
||
to know not to handle *include at start
|
||
of line as include mechanism */
|
||
int string_start_line; /* when in_string is true, this is the
|
||
start line of current string */
|
||
struct inputfile *included_from; /* NULL for toplevel file, otherwise
|
||
points back to files which this one
|
||
has been included from */
|
||
unsigned int magic; /* Memory check */
|
||
char *filename; /* Filename as passed to fopen */
|
||
fz_FILE *fp; /* Read from this */
|
||
bool at_eof; /* Flag for end-of-file */
|
||
struct astring cur_line; /* Data from current line */
|
||
unsigned int cur_line_pos; /* Position in current line */
|
||
unsigned int line_num; /* Line number from file in cur_line */
|
||
struct astring token; /* Data returned to user */
|
||
struct astring partial; /* Used in accumulating multi-line strings;
|
||
used only in get_token_value, but put
|
||
here so it gets freed when file closed */
|
||
datafilename_fn_t datafn; /* Function like datafilename(); use a
|
||
function pointer just to keep this
|
||
inputfile module "generic" */
|
||
bool in_string; /* Set when reading multi-line strings,
|
||
to know not to handle *include at start
|
||
of line as include mechanism */
|
||
int string_start_line; /* When in_string is true, this is the
|
||
start line of current string */
|
||
struct inputfile *included_from; /* nullptr for toplevel file, otherwise
|
||
points back to files which this one
|
||
has been included from */
|
||
};
|
||
/* A function to get a specific token type: */
|
||
... | ... | |
***********************************************************************/
|
||
static void init_zeros(struct inputfile *inf)
|
||
{
|
||
fc_assert_ret(NULL != inf);
|
||
fc_assert_ret(inf != nullptr);
|
||
inf->magic = INF_MAGIC;
|
||
inf->filename = NULL;
|
||
inf->fp = NULL;
|
||
inf->datafn = NULL;
|
||
inf->included_from = NULL;
|
||
inf->filename = nullptr;
|
||
inf->fp = nullptr;
|
||
inf->datafn = nullptr;
|
||
inf->included_from = nullptr;
|
||
inf->line_num = inf->cur_line_pos = 0;
|
||
inf->at_eof = inf->in_string = FALSE;
|
||
inf->string_start_line = 0;
|
||
... | ... | |
***********************************************************************/
|
||
static bool inf_sanity_check(struct inputfile *inf)
|
||
{
|
||
fc_assert_ret_val(NULL != inf, FALSE);
|
||
fc_assert_ret_val(inf != nullptr, FALSE);
|
||
fc_assert_ret_val(INF_MAGIC == inf->magic, FALSE);
|
||
fc_assert_ret_val(NULL != inf->fp, FALSE);
|
||
fc_assert_ret_val(inf->fp != nullptr, FALSE);
|
||
fc_assert_ret_val(!inf->at_eof
|
||
|| inf->at_eof, FALSE);
|
||
fc_assert_ret_val(!inf->in_string
|
||
... | ... | |
/*******************************************************************//**
|
||
Open the file, and return an allocated, initialized structure.
|
||
Returns NULL if the file could not be opened.
|
||
Returns nullptr if the file could not be opened.
|
||
***********************************************************************/
|
||
struct inputfile *inf_from_file(const char *filename,
|
||
datafilename_fn_t datafn)
|
||
... | ... | |
struct inputfile *inf;
|
||
fz_FILE *fp;
|
||
fc_assert_ret_val(NULL != filename, NULL);
|
||
fc_assert_ret_val(0 < strlen(filename), NULL);
|
||
fc_assert_ret_val(filename != nullptr, nullptr);
|
||
fc_assert_ret_val(0 < strlen(filename), nullptr);
|
||
fp = fz_from_file(filename, "r", -1, 0);
|
||
if (!fp) {
|
||
return NULL;
|
||
if (fp == nullptr) {
|
||
return nullptr;
|
||
}
|
||
log_debug("inputfile: opened \"%s\" ok", filename);
|
||
inf = inf_from_stream(fp, datafn);
|
||
inf->filename = fc_strdup(filename);
|
||
return inf;
|
||
}
|
||
/*******************************************************************//**
|
||
Open the stream, and return an allocated, initialized structure.
|
||
Returns NULL if the file could not be opened.
|
||
Returns nullptr if the file could not be opened.
|
||
***********************************************************************/
|
||
struct inputfile *inf_from_stream(fz_FILE *stream, datafilename_fn_t datafn)
|
||
{
|
||
struct inputfile *inf;
|
||
fc_assert_ret_val(NULL != stream, NULL);
|
||
fc_assert_ret_val(stream != nullptr, nullptr);
|
||
inf = fc_malloc(sizeof(*inf));
|
||
init_zeros(inf);
|
||
inf->filename = NULL;
|
||
inf->filename = nullptr;
|
||
inf->fp = stream;
|
||
inf->datafn = datafn;
|
||
log_debug("inputfile: opened \"%s\" ok", inf_filename(inf));
|
||
return inf;
|
||
}
|
||
/*******************************************************************//**
|
||
Close the file and free associated memory, but don't recurse
|
||
included_from files, and don't free the actual memory where
|
||
the inf record is stored (ie, the memory where the users pointer
|
||
points to). This is used when closing an included file.
|
||
points to). This is used when closing an included file.
|
||
***********************************************************************/
|
||
static void inf_close_partial(struct inputfile *inf)
|
||
{
|
||
... | ... | |
log_error("Error before closing %s: %s", inf_filename(inf),
|
||
fz_strerror(inf->fp));
|
||
fz_fclose(inf->fp);
|
||
inf->fp = NULL;
|
||
}
|
||
else if (fz_fclose(inf->fp) != 0) {
|
||
inf->fp = nullptr;
|
||
} else if (fz_fclose(inf->fp) != 0) {
|
||
log_error("Error closing %s", inf_filename(inf));
|
||
}
|
||
if (inf->filename) {
|
||
free(inf->filename);
|
||
}
|
||
inf->filename = NULL;
|
||
inf->filename = nullptr;
|
||
astr_free(&inf->cur_line);
|
||
astr_free(&inf->token);
|
||
astr_free(&inf->partial);
|
||
... | ... | |
if (inf->included_from) {
|
||
inf_close(inf->included_from);
|
||
/* Stop anything from recursing to already closed including file */
|
||
inf->included_from = NULL;
|
||
inf->included_from = nullptr;
|
||
}
|
||
inf_close_partial(inf);
|
||
free(inf);
|
||
... | ... | |
bare_name_start = c;
|
||
while (*c != '\0' && *c != '\"') c++;
|
||
if (*c != '\"') {
|
||
inf_log(inf, LOG_ERROR,
|
||
inf_log(inf, LOG_ERROR,
|
||
"Did not find closing doublequote for '*include' line");
|
||
return FALSE;
|
||
}
|
||
... | ... | |
bare_name[bare_name_len - 1] = '\0';
|
||
inf->cur_line_pos = c - astr_str(&inf->cur_line);
|
||
/* check rest of line is well-formed: */
|
||
/* Check rest of line is well-formed: */
|
||
while (*c != '\0' && fc_isspace(*c) && !is_comment(*c)) {
|
||
c++;
|
||
}
|
||
... | ... | |
}
|
||
free(bare_name);
|
||
/* avoid recursion: (first filename may not have the same path,
|
||
/* Avoid recursion: (First filename may not have the same path,
|
||
* but will at least stop infinite recursion) */
|
||
{
|
||
struct inputfile *inc = inf;
|
||
... | ... | |
*new_inf = *inf;
|
||
*inf = temp;
|
||
inf->included_from = new_inf;
|
||
return TRUE;
|
||
}
|
||
... | ... | |
return FALSE;
|
||
}
|
||
/* abbreviation: */
|
||
/* Abbreviation: */
|
||
line = &inf->cur_line;
|
||
/* minimum initial line length: */
|
||
/* Minimum initial line length: */
|
||
astr_reserve(line, 80);
|
||
astr_clear(line);
|
||
pos = 0;
|
||
... | ... | |
/* Pop the include, and get next line from file above instead. */
|
||
struct inputfile *inc = inf->included_from;
|
||
inf_close_partial(inf);
|
||
*inf = *inc; /* so the user pointer in still valid
|
||
*inf = *inc; /* So the user pointer in still valid
|
||
* (and inf pointers in calling functions) */
|
||
free(inc);
|
||
return read_a_line(inf);
|
||
... | ... | |
/*******************************************************************//**
|
||
Return a detailed log message, including information on current line
|
||
number etc. Message can be NULL: then just logs information on where
|
||
number etc. Message can be nullptr: then just logs information on where
|
||
we are in the file.
|
||
***********************************************************************/
|
||
char *inf_log_str(struct inputfile *inf, const char *message, ...)
|
||
... | ... | |
"\n processing string starting at line %d",
|
||
inf->string_start_line);
|
||
}
|
||
while ((inf = inf->included_from)) { /* local pointer assignment */
|
||
while ((inf = inf->included_from)) { /* Local pointer assignment */
|
||
cat_snprintf(str, sizeof(str), "\n included from file \"%s\", line %d",
|
||
inf_filename(inf), inf->line_num);
|
||
}
|
||
... | ... | |
get_token_fn_t func;
|
||
if (!inf_sanity_check(inf)) {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
fc_assert_ret_val(INF_TOK_FIRST <= type && INF_TOK_LAST > type, NULL);
|
||
fc_assert_ret_val(INF_TOK_FIRST <= type && INF_TOK_LAST > type,
|
||
nullptr);
|
||
name = tok_tab[type].name ? tok_tab[type].name : "(unnamed)";
|
||
func = tok_tab[type].func;
|
||
if (!func) {
|
||
log_error("token type %d (%s) not supported yet", type, name);
|
||
c = NULL;
|
||
c = nullptr;
|
||
} else {
|
||
while (!have_line(inf) && read_a_line(inf)) {
|
||
/* Nothing. */
|
||
}
|
||
if (!have_line(inf)) {
|
||
c = NULL;
|
||
c = nullptr;
|
||
} else {
|
||
c = func(inf);
|
||
}
|
||
... | ... | |
}
|
||
/*******************************************************************//**
|
||
Returns section name in current position of inputfile. Returns NULL
|
||
Returns section name in current position of inputfile. Returns nullptr
|
||
if there is no section name on that position. Sets inputfile position
|
||
after section name.
|
||
***********************************************************************/
|
||
... | ... | |
{
|
||
const char *c, *start;
|
||
fc_assert_ret_val(have_line(inf), NULL);
|
||
fc_assert_ret_val(have_line(inf), nullptr);
|
||
c = astr_str(&inf->cur_line) + inf->cur_line_pos;
|
||
if (*c++ != '[') {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
start = c;
|
||
while (*c != '\0' && *c != ']') {
|
||
c++;
|
||
}
|
||
if (*c != ']') {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
*((char *) c) = '\0'; /* Tricky. */
|
||
astr_set(&inf->token, "%s", start);
|
||
*((char *) c) = ']'; /* Revert. */
|
||
inf->cur_line_pos = c + 1 - astr_str(&inf->cur_line);
|
||
return astr_str(&inf->token);
|
||
}
|
||
... | ... | |
const char *c, *start, *end;
|
||
char trailing;
|
||
fc_assert_ret_val(have_line(inf), NULL);
|
||
fc_assert_ret_val(have_line(inf), nullptr);
|
||
c = astr_str(&inf->cur_line) + inf->cur_line_pos;
|
||
while (*c != '\0' && fc_isspace(*c)) {
|
||
c++;
|
||
}
|
||
if (*c == '\0') {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
start = c;
|
||
while (*c != '\0' && !fc_isspace(*c) && *c != '=' && !is_comment(*c)) {
|
||
c++;
|
||
}
|
||
if (!(*c != '\0' && (fc_isspace(*c) || *c == '='))) {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
end = c;
|
||
while (*c != '\0' && *c != '=' && !is_comment(*c)) {
|
||
c++;
|
||
}
|
||
if (*c != '=') {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
trailing = *end;
|
||
*((char *) end) = '\0'; /* Tricky. */
|
||
astr_set(&inf->token, "%s", start);
|
||
*((char *) end) = trailing; /* Revert. */
|
||
inf->cur_line_pos = c + 1 - astr_str(&inf->cur_line);
|
||
return astr_str(&inf->token);
|
||
}
|
||
/*******************************************************************//**
|
||
If inputfile is at end-of-line, frees current line, and returns " ".
|
||
If there is still something on that line, returns NULL.
|
||
If there is still something on that line, returns nullptr.
|
||
***********************************************************************/
|
||
static const char *get_token_eol(struct inputfile *inf)
|
||
{
|
||
const char *c;
|
||
fc_assert_ret_val(have_line(inf), NULL);
|
||
fc_assert_ret_val(have_line(inf), nullptr);
|
||
if (!at_eol(inf)) {
|
||
c = astr_str(&inf->cur_line) + inf->cur_line_pos;
|
||
... | ... | |
c++;
|
||
}
|
||
if (*c != '\0' && !is_comment(*c)) {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
}
|
||
/* finished with this line: say that we don't have it any more: */
|
||
/* Finished with this line: say that we don't have it any more: */
|
||
astr_clear(&inf->cur_line);
|
||
inf->cur_line_pos = 0;
|
||
astr_set(&inf->token, " ");
|
||
return astr_str(&inf->token);
|
||
}
|
||
... | ... | |
{
|
||
const char *c;
|
||
fc_assert_ret_val(have_line(inf), NULL);
|
||
fc_assert_ret_val(have_line(inf), nullptr);
|
||
c = astr_str(&inf->cur_line) + inf->cur_line_pos;
|
||
while (*c != '\0' && fc_isspace(*c)) {
|
||
c++;
|
||
}
|
||
if (*c != target) {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
inf->cur_line_pos = c + 1 - astr_str(&inf->cur_line);
|
||
astr_set(&inf->token, "%c", target);
|
||
return astr_str(&inf->token);
|
||
}
|
||
/*******************************************************************//**
|
||
Get flag token for table start, or NULL if that is not next token.
|
||
Get flag token for table start, or nullptr if that is not next token.
|
||
***********************************************************************/
|
||
static const char *get_token_table_start(struct inputfile *inf)
|
||
{
|
||
... | ... | |
}
|
||
/*******************************************************************//**
|
||
Get flag token for table end, or NULL if that is not next token.
|
||
Get flag token for table end, or nullptr if that is not next token.
|
||
***********************************************************************/
|
||
static const char *get_token_table_end(struct inputfile *inf)
|
||
{
|
||
... | ... | |
}
|
||
/*******************************************************************//**
|
||
Get flag token comma, or NULL if that is not next token.
|
||
Get flag token comma, or nullptr if that is not next token.
|
||
***********************************************************************/
|
||
static const char *get_token_comma(struct inputfile *inf)
|
||
{
|
||
... | ... | |
bool has_i18n_marking = FALSE;
|
||
char border_character = '\"';
|
||
fc_assert_ret_val(have_line(inf), NULL);
|
||
fc_assert_ret_val(have_line(inf), nullptr);
|
||
c = astr_str(&inf->cur_line) + inf->cur_line_pos;
|
||
while (*c != '\0' && fc_isspace(*c)) {
|
||
c++;
|
||
}
|
||
if (*c == '\0') {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
if (*c == '-' || *c == '+' || fc_isdigit(*c)) {
|
||
/* a number: */
|
||
/* A number: */
|
||
start = c++;
|
||
while (*c != '\0' && fc_isdigit(*c)) {
|
||
c++;
|
||
... | ... | |
c++;
|
||
}
|
||
}
|
||
/* check that the trailing stuff is ok: */
|
||
/* Check that the trailing stuff is ok: */
|
||
if (!(*c == '\0' || *c == ',' || fc_isspace(*c) || is_comment(*c))) {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
/* If its a comma, we don't want to obliterate it permanently,
|
||
* so remember it: */
|
||
... | ... | |
return astr_str(&inf->token);
|
||
}
|
||
/* allow gettext marker: */
|
||
/* Allow gettext marker: */
|
||
if (*c == '_' && *(c + 1) == '(') {
|
||
has_i18n_marking = TRUE;
|
||
c += 2;
|
||
... | ... | |
c++;
|
||
}
|
||
if (*c == '\0') {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
}
|
||
... | ... | |
start = c;
|
||
while (*c != '*') {
|
||
if (*c == '\0' || *c == '\n') {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
c++;
|
||
}
|
||
c++;
|
||
/* check that the trailing stuff is ok: */
|
||
/* Check that the trailing stuff is ok: */
|
||
if (!(*c == '\0' || *c == ',' || fc_isspace(*c) || is_comment(*c))) {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
/* We don't want to obliterate ending '*' permanently,
|
||
* so remember it: */
|
||
... | ... | |
*((char *) (c - 1)) = '\0'; /* Tricky. */
|
||
rfname = fileinfoname(get_data_dirs(), start);
|
||
if (rfname == NULL) {
|
||
inf_log(inf, LOG_ERROR,
|
||
if (rfname == nullptr) {
|
||
inf_log(inf, LOG_ERROR,
|
||
_("Cannot find stringfile \"%s\"."), start);
|
||
*((char *) c) = trailing; /* Revert. */
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
*((char *) c) = trailing; /* Revert. */
|
||
fp = fz_from_file(rfname, "r", -1, 0);
|
||
if (!fp) {
|
||
inf_log(inf, LOG_ERROR,
|
||
_("Cannot open stringfile \"%s\"."), rfname);
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
log_debug("Stringfile \"%s\" opened ok", start);
|
||
*((char *) (c - 1)) = trailing; /* Revert. */
|
||
... | ... | |
ret = fz_fgets((char *) astr_str(&inf->token) + pos,
|
||
astr_capacity(&inf->token) - pos, fp);
|
||
if (ret == NULL) {
|
||
if (ret == nullptr) {
|
||
eof = TRUE;
|
||
} else {
|
||
pos = astr_len(&inf->token);
|
||
... | ... | |
return astr_str(&inf->token);
|
||
} else if (border_character != '\"'
|
||
&& border_character != '\''
|
||
&& border_character != '$') {
|
||
&& border_character != '\''
|
||
&& border_character != '$') {
|
||
/* A one-word string: maybe FALSE or TRUE. */
|
||
start = c;
|
||
while (fc_isalnum(*c)) {
|
||
c++;
|
||
}
|
||
/* check that the trailing stuff is ok: */
|
||
/* Check that the trailing stuff is ok: */
|
||
if (!(*c == '\0' || *c == ',' || fc_isspace(*c) || is_comment(*c))) {
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
/* If its a comma, we don't want to obliterate it permanently,
|
||
* so remember it: */
|
||
... | ... | |
astr_set(&inf->token, "%s", start);
|
||
*((char *) c) = trailing; /* Revert. */
|
||
return astr_str(&inf->token);
|
||
}
|
||
/* From here, we know we have a string, we just have to find the
|
||
trailing (un-escaped) double-quote. We read in extra lines if
|
||
necessary to find it. If we _don't_ find the end-of-string
|
||
(that is, we come to end-of-file), we return NULL, but we
|
||
trailing (un-escaped) double-quote. We read in extra lines if
|
||
necessary to find it. If we _don't_ find the end-of-string
|
||
(that is, we come to end-of-file), we return nullptr, but we
|
||
leave the file in at_eof, and don't try to back-up to the
|
||
current point. (That would be more difficult, and probably
|
||
current point. (That would be more difficult, and probably
|
||
not necessary: at that point we probably have a malformed
|
||
string/file.)
|
||
... | ... | |
lines is placed in partial.
|
||
*/
|
||
/* prepare for possibly multi-line string: */
|
||
/* Prepare for possibly multi-line string: */
|
||
inf->string_start_line = inf->line_num;
|
||
inf->in_string = TRUE;
|
||
partial = &inf->partial; /* abbreviation */
|
||
partial = &inf->partial; /* Abbreviation */
|
||
astr_clear(partial);
|
||
start = c++; /* start includes the initial \", to
|
||
start = c++; /* Atart includes the initial \", to
|
||
* distinguish from a number */
|
||
for (;;) {
|
||
while (*c != '\0' && *c != border_character) {
|
||
/* skip over escaped chars, including backslash-doublequote,
|
||
/* Skip over escaped chars, including backslash-doublequote,
|
||
* and backslash-backslash: */
|
||
if (*c == '\\' && *(c + 1) != '\0') {
|
||
c++;
|
||
... | ... | |
astr_add(partial, "%s\n", start);
|
||
if (!read_a_line(inf)) {
|
||
/* shouldn't happen */
|
||
inf_log(inf, LOG_ERROR,
|
||
/* Shouldn't happen */
|
||
inf_log(inf, LOG_ERROR,
|
||
"Bad return for multi-line string from read_a_line");
|
||
return NULL;
|
||
return nullptr;
|
||
}
|
||
c = start = astr_str(&inf->cur_line);
|
||
}
|
||
/* found end of string */
|
||
/* Found end of string */
|
||
trailing = *c;
|
||
*((char *) c) = '\0'; /* Tricky. */
|
||
... | ... | |
*((char *) c) = trailing; /* Revert. */
|
||
/* check gettext tag at end: */
|
||
/* Check gettext tag at end: */
|
||
if (has_i18n_marking) {
|
||
if (*++c == ')') {
|
||
inf->cur_line_pos++;
|
||
... | ... | |
}
|
||
}
|
||
inf->in_string = FALSE;
|
||
return astr_str(&inf->token);
|
||
}
|
utility/inputfile.h | ||
---|---|---|
/**********************************************************************
|
||
/***********************************************************************
|
||
Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
... | ... | |
GNU General Public License for more details.
|
||
***********************************************************************/
|
||
/**********************************************************************
|
||
/***********************************************************************
|
||
A low-level object for reading a registry-format file.
|
||
See comments in inputfile.c
|
||
***********************************************************************/
|
||
... | ... | |
}
|
||
#endif /* __cplusplus */
|
||
#endif /* FC__INPUTFILE_H */
|
||
#endif /* FC__INPUTFILE_H */
|