Feature #1903 ยป 1903.patch
| utility/registry_ini.c | ||
|---|---|---|
|
the idea with this file is to create something similar to the ms-windows
|
||
|
.ini files functions.
|
||
|
however the interface is nice. ie:
|
||
|
secfile_lookup_str(file, "player%d.unit%d.name", plrno, unitno);
|
||
|
secfile_lookup_str(file, "player%d.unit%d.name", plrno, unitno);
|
||
|
***************************************************************************/
|
||
|
/**************************************************************************
|
||
| ... | ... | |
|
#include <fc_config.h>
|
||
|
#endif
|
||
|
#include <ctype.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
| ... | ... | |
|
#include "shared.h"
|
||
|
#include "support.h"
|
||
|
/* common */
|
||
|
#include "fc_types.h"
|
||
|
#include "registry_ini.h"
|
||
|
#define MAX_LEN_SECPATH 1024
|
||
| ... | ... | |
|
return (num ? fc_isalnum(c) : fc_isalpha(c)) || c == '_';
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Utility routine used in word_wrap_helptext()
|
||
|
returns whether it's OK to insert a line break before the passed in char,
|
||
|
most non-alphanumeric are OK, test high bit to rule out UTF-8.
|
||
|
**************************************************************************/
|
||
|
static bool is_delim(char ch) {
|
||
|
if (isalnum(ch) || ch & 0x80) {
|
||
|
return FALSE;
|
||
|
} else {
|
||
|
return (ch != '%' && ch != '.' && ch != ',' && ch != '?'
|
||
|
&& ch != '!' && ch != ';' && ch != ':' && ch != ')');
|
||
|
}
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Utility routine used in word_wrap_helptext()
|
||
|
starting at a location in a string, find the offsets of the next 2
|
||
|
delims, and return those offset values. Return value -1 means not found.
|
||
|
**************************************************************************/
|
||
|
static void find_next_delims(char *start_ptr,
|
||
|
int *delim1_offset, int *delim2_offset) {
|
||
|
char *p = start_ptr;
|
||
|
*delim1_offset = -1;
|
||
|
*delim2_offset = -1;
|
||
|
while (*p && !is_delim(*p)) {
|
||
|
p++;
|
||
|
}
|
||
|
if (*p) {
|
||
|
*delim1_offset = p - start_ptr;
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
p++;
|
||
|
while (*p && !is_delim(*p)) {
|
||
|
p++;
|
||
|
}
|
||
|
if (*p) {
|
||
|
*delim2_offset = p - start_ptr;
|
||
|
}
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Utility routine used in secfile_save() when writing out helptext strings.
|
||
|
When a helptext string has "\n\" followed by a newline, that gets lost
|
||
|
when it's read in. This re-inserts the "\n\" so the output will look
|
||
|
the same.
|
||
|
Also tries to keep output lines to be shorter than LINE_BREAK chars, by
|
||
|
inserting new lines as needed.
|
||
|
Assumes the struct entry is type ENTRY_STR.
|
||
|
**************************************************************************/
|
||
|
static void word_wrap_helptext(struct entry *pentry, int indent) {
|
||
|
static char new_buf[8192];
|
||
|
char *new_buf_ptr = new_buf;
|
||
|
char *buf_ptr = pentry->string.value;
|
||
|
char *end_new_buf_ptr;
|
||
|
int width = LINE_BREAK - indent;
|
||
|
size_t str_length;
|
||
|
bool is_finished = FALSE;
|
||
|
char *break_ptr, *p;
|
||
|
int num_undone;
|
||
|
int delim1_offset, delim2_offset;
|
||
|
int looked_at;
|
||
|
char *old_val;
|
||
|
fc_assert(pentry->type == ENTRY_STR);
|
||
|
/* look for newline chars */
|
||
|
while (*buf_ptr) {
|
||
|
if (*buf_ptr == '\n') {
|
||
|
/* found a newline char, insert "\n\" */
|
||
|
*new_buf_ptr++ = '\\';
|
||
|
*new_buf_ptr++ = 'n';
|
||
|
*new_buf_ptr++ = '\\';
|
||
|
*new_buf_ptr++ = *buf_ptr++;
|
||
|
}
|
||
|
*new_buf_ptr++ = *buf_ptr++;
|
||
|
}
|
||
|
*new_buf_ptr = 0;
|
||
|
buf_ptr = new_buf;
|
||
|
/* do word wrapping */
|
||
|
str_length = strlen(new_buf);
|
||
|
end_new_buf_ptr = new_buf + str_length;
|
||
|
p = new_buf;
|
||
|
num_undone = str_length;
|
||
|
looked_at = 0;
|
||
|
while (! is_finished) {
|
||
|
if (num_undone > width) {
|
||
|
find_next_delims(p, &delim1_offset, &delim2_offset);
|
||
|
if (delim1_offset == -1) {
|
||
|
is_finished = TRUE;
|
||
|
} else {
|
||
|
if (looked_at + delim1_offset < width
|
||
|
&& (looked_at + delim2_offset >= width || delim2_offset == -1)) {
|
||
|
break_ptr = p + delim1_offset;
|
||
|
/* found where we want to word wrap */
|
||
|
/* insert '\' and newline char into new_buf at break_ptr */
|
||
|
/* first, move to make room */
|
||
|
p = end_new_buf_ptr;
|
||
|
while (p >= break_ptr) {
|
||
|
*(p + 2) = *p;
|
||
|
p--;
|
||
|
}
|
||
|
*break_ptr++ = '\\';
|
||
|
*break_ptr++ = '\n';
|
||
|
end_new_buf_ptr += 2;
|
||
|
/* update for next time thru loop */
|
||
|
num_undone = end_new_buf_ptr - break_ptr;
|
||
|
looked_at = 0;
|
||
|
p = break_ptr + 1;
|
||
|
width = LINE_BREAK;
|
||
|
} else {
|
||
|
/* still looking, update for next time thru loop */
|
||
|
p += delim1_offset + 1;
|
||
|
looked_at += delim1_offset + 1;
|
||
|
}
|
||
|
/* if now pointing at a new line, update for next time thru loop */
|
||
|
if (*p == '\n') {
|
||
|
looked_at = 0;
|
||
|
width = LINE_BREAK;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
is_finished = TRUE;
|
||
|
}
|
||
|
}
|
||
|
/* We free() old value only after we've placed the new one, to
|
||
|
* support secfile_replace_str_vec() calls that want to keep some of
|
||
|
* the entries from the old vector in the new one. We don't want
|
||
|
* to lose the entry in between. */
|
||
|
old_val = pentry->string.value;
|
||
|
pentry->string.value = fc_strdup(buf_ptr);
|
||
|
free(old_val);
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Utility routine used in secfile_save() when writing out strings.
|
||
|
Assumes the struct entry is type ENTRY_STR.
|
||
|
**************************************************************************/
|
||
|
static size_t entry_str_length(struct entry *pentry) {
|
||
|
size_t len;
|
||
|
fc_assert(pentry->type == ENTRY_STR);
|
||
|
/* + 2 for the enclosing " chars */
|
||
|
len = strlen(pentry->string.value) + 2;
|
||
|
if (pentry->string.gt_marking) {
|
||
|
len +=3; /* + 3 for the initial "_(" and terminating ")" */
|
||
|
}
|
||
|
return len;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Save the previously filled in section_file to disk.
|
||
| ... | ... | |
|
if (pentry->type == ENTRY_LONG_COMMENT) {
|
||
|
entry_to_file(pentry, fs);
|
||
|
} else {
|
||
|
/* these vars are only used for ENTRY_STR's */
|
||
|
bool need_new_line = FALSE;
|
||
|
int col, indent, next_len;
|
||
|
/* Classic entry. */
|
||
|
col_entry_name = entry_name(pentry);
|
||
|
fz_fprintf(fs, "%s=", col_entry_name);
|
||
|
indent = fz_fprintf(fs, "%s=", col_entry_name);
|
||
|
col = indent;
|
||
|
/* for ENTRY_STR's, wrap long lines */
|
||
|
if (pentry->type == ENTRY_STR) {
|
||
|
if (!strcmp(col_entry_name, "helptext")
|
||
|
|| !strcmp(col_entry_name, "summary")) {
|
||
|
/* helptext - do word wrap, always put next on new line */
|
||
|
word_wrap_helptext(pentry, indent);
|
||
|
need_new_line = TRUE;
|
||
|
col = indent;
|
||
|
} else {
|
||
|
/* not helptext - track the col position */
|
||
|
/* + 1 for the comma */
|
||
|
next_len = entry_str_length(pentry) + 1;
|
||
|
col += next_len;
|
||
|
}
|
||
|
}
|
||
|
entry_to_file(pentry, fs);
|
||
|
/* Check for vector. */
|
||
| ... | ... | |
|
if (0 != strcmp(pentry_name, entry_name(col_pentry))) {
|
||
|
break;
|
||
|
}
|
||
|
fz_fprintf(fs, ",");
|
||
|
col++;
|
||
|
/* for ENTRY_STR's, wrap long lines */
|
||
|
if (pentry->type == ENTRY_STR) {
|
||
|
if (!strcmp(col_entry_name, "helptext")) {
|
||
|
/* helptext - do word wrap, always put next on new line */
|
||
|
word_wrap_helptext(col_pentry, indent);
|
||
|
need_new_line = TRUE;
|
||
|
} else {
|
||
|
/* not helptext - track the col position and
|
||
|
check if we will need a new line */
|
||
|
/* + 1 for the comma */
|
||
|
next_len = entry_str_length(col_pentry) + 1;
|
||
|
if (col + next_len > LINE_BREAK) {
|
||
|
need_new_line = TRUE;
|
||
|
}
|
||
|
}
|
||
|
if (need_new_line) {
|
||
|
fz_fprintf(fs, "\n%*s", indent, " ");
|
||
|
need_new_line = FALSE;
|
||
|
col = indent + next_len;
|
||
|
} else {
|
||
|
col += next_len;
|
||
|
}
|
||
|
}
|
||
|
entry_to_file(col_pentry, fs);
|
||
|
ent_iter = col_iter;
|
||
|
}
|
||
| ... | ... | |
|
} section_list_iterate_end;
|
||
|
if (0 != fz_ferror(fs)) {
|
||
|
SECFILE_LOG(secfile, NULL, "Error before closing %s: %s",
|
||
|
SECFILE_LOG(secfile, NULL, "Error before closing %s: %s",
|
||
|
real_filename, fz_strerror(fs));
|
||
|
fz_fclose(fs);
|
||
|
return FALSE;
|
||
| ... | ... | |
|
}
|
||
|
/**********************************************************************//**
|
||
|
Insert 'dim' boolean entries at 'path,0', 'path,1' etc. Returns
|
||
|
Insert 'dim' boolean entries at 'path,0', 'path,1' etc. Returns
|
||
|
the number of entries inserted or replaced.
|
||
|
**************************************************************************/
|
||
|
size_t secfile_insert_bool_vec_full(struct section_file *secfile,
|
||
| ... | ... | |
|
return TRUE;
|
||
|
}
|
||
|
/************************************************************************//**
|
||
|
Copies a string and convert the following characters:
|
||
|
- '\"' to "\\\"".
|
||
|
****************************************************************************/
|
||
|
static void make_escapes_quotes(const char *str, char *buf, size_t buf_len)
|
||
|
{
|
||
|
char *dest = buf;
|
||
|
/* Sometimes we insert a character, so keep
|
||
|
* place for '\0' and an extra character. */
|
||
|
const char *max = buf + buf_len - 1;
|
||
|
while (*str != '\0' && dest < max) {
|
||
|
if (*str == '\"') {
|
||
|
*dest++ = '\\';
|
||
|
max--;
|
||
|
}
|
||
|
*dest++ = *str++;
|
||
|
}
|
||
|
*dest = 0;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Push an entry into a file stream.
|
||
|
**************************************************************************/
|
||
| ... | ... | |
|
break;
|
||
|
case ENTRY_STR:
|
||
|
if (pentry->string.escaped) {
|
||
|
make_escapes(pentry->string.value, buf, sizeof(buf));
|
||
|
make_escapes_quotes(pentry->string.value, buf, sizeof(buf));
|
||
|
if (pentry->string.gt_marking) {
|
||
|
fz_fprintf(fs, "_(\"%s\")", buf);
|
||
|
} else {
|
||
| utility/support.c | ||
|---|---|---|
|
return ret;
|
||
|
}
|
||
|
/************************************************************************//**
|
||
|
Copies a string and convert the following characters:
|
||
|
- '\n' to "\\n".
|
||
|
- '\\' to "\\\\".
|
||
|
- '\"' to "\\\"".
|
||
|
See also remove_escapes().
|
||
|
****************************************************************************/
|
||
|
void make_escapes(const char *str, char *buf, size_t buf_len)
|
||
|
{
|
||
|
char *dest = buf;
|
||
|
/* Sometimes we insert 2 characters at once ('\n' -> "\\n"), so keep
|
||
|
* place for '\0' and an extra character. */
|
||
|
const char *const max = buf + buf_len - 2;
|
||
|
while (*str != '\0' && dest < max) {
|
||
|
switch (*str) {
|
||
|
case '\n':
|
||
|
*dest++ = '\\';
|
||
|
*dest++ = 'n';
|
||
|
str++;
|
||
|
break;
|
||
|
case '\\':
|
||
|
case '\"':
|
||
|
*dest++ = '\\';
|
||
|
fc__fallthrough;
|
||
|
default:
|
||
|
*dest++ = *str++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
*dest = 0;
|
||
|
}
|
||
|
/************************************************************************//**
|
||
|
Copies a string. Backslash followed by a genuine newline always
|
||
|
removes the newline.
|
||
| ... | ... | |
|
- '\n' -> newline translation.
|
||
|
- Other '\?' sequences (any character '?') are just passed
|
||
|
through with the '\' removed (eg, includes '\\', '\"').
|
||
|
See also make_escapes().
|
||
|
****************************************************************************/
|
||
|
void remove_escapes(const char *str, bool full_escapes,
|
||
|
char *buf, size_t buf_len)
|
||
| utility/support.h | ||
|---|---|---|
|
#endif /* WORDS_BIGENDIAN */
|
||
|
}
|
||
|
void make_escapes(const char *str, char *buf, size_t buf_len);
|
||
|
void remove_escapes(const char *str, bool full_escapes,
|
||
|
char *buf, size_t buf_len);
|
||