Project

General

Profile

Feature #1903 ยป 1903.patch

Dean Brown, 01/13/2026 02:35 AM

View differences:

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);
    (1-1/1)