OpenTTD Source
20240919-master-gdf0233f4c2
|
Go to the documentation of this file.
10 #include "../stdafx.h"
11 #include "../string_func.h"
12 #include "../strings_type.h"
13 #include "../misc/getoptdata.h"
14 #include "../ini_type.h"
15 #include "../core/mem_func.hpp"
16 #include "../error_func.h"
20 #include "../safeguards.h"
29 fmt::print(stderr,
"settingsgen: FATAL: {}\n", msg);
50 size_t Add(
const char *text,
size_t length)
55 this->
size += store_size;
65 if (fwrite(this->
data, 1, this->
size, out_fp) != this->
size) {
66 FatalError(
"Cannot write output");
102 void Add(
const char *text,
size_t length = 0)
104 if (length == 0) length = strlen(text);
108 length -= stored_size;
114 size_t stored_size = block.
Add(text, length);
115 length -= stored_size;
127 out_data.Write(out_fp);
139 return num_blocks > 0 && this->
output_buffer[num_blocks - 1].HasRoom();
164 if (!in.has_value())
return in;
166 fseek(*in, 0L, SEEK_END);
168 fseek(*in, 0L, SEEK_SET);
173 void ReportFileError(
const char *
const pre,
const char *
const buffer,
const char *
const post)
override
175 FatalError(
"{}{}{}", pre, buffer, post);
198 if (!item.
name.empty()) {
216 if (item ==
nullptr && defaults !=
nullptr) item = defaults->
GetItem(name);
217 if (item ==
nullptr || !item->
value.has_value())
return nullptr;
218 return item->
value->c_str();
230 static const int MAX_VAR_LENGTH = 64;
233 static const auto pp_lines = {
"if",
"ifdef",
"ifndef"};
235 for (
const auto &name : pp_lines) {
236 const char *condition =
FindItemValue(name, grp, default_grp);
237 if (condition !=
nullptr) {
241 output.
Add(condition);
248 const char *txt = item->
value->c_str();
249 while (*txt !=
'\0') {
263 char variable[MAX_VAR_LENGTH];
265 while (i < MAX_VAR_LENGTH - 1) {
266 if (!(txt[i] ==
'_' || (txt[i] >=
'a' && txt[i] <=
'z') || (txt[i] >=
'0' && txt[i] <=
'9')))
break;
267 variable[i] = txt[i];
275 const char *valitem =
FindItemValue(variable, grp, default_grp);
276 if (valitem !=
nullptr) output.
Add(valitem);
283 output.
Add(
"#endif\n");
299 if (templates_grp ==
nullptr)
return;
304 if (std::find(std::begin(special_group_names), std::end(special_group_names), grp.
name) != std::end(special_group_names))
continue;
307 if (template_item ==
nullptr || !template_item->
value.has_value()) {
308 FatalError(
"Cannot find template {}", grp.
name);
312 if (validation_grp !=
nullptr) {
314 if (validation_item !=
nullptr && validation_item->
value.has_value()) {
328 if (fname ==
nullptr)
return;
331 if (!in_fp.has_value()) {
332 FatalError(
"Cannot open file {} for copying", fname);
338 length = fread(buffer, 1,
lengthof(buffer), *in_fp);
339 if (fwrite(buffer, 1, length, out_fp) != length) {
340 FatalError(
"Cannot copy file");
342 }
while (length ==
lengthof(buffer));
354 if (!f2.has_value())
return false;
357 if (!f1.has_value()) {
358 FatalError(
"can't open {}", n1);
365 l1 = fread(b1, 1,
sizeof(b1), *f1);
366 l2 = fread(b2, 1,
sizeof(b2), *f2);
368 if (l1 != l2 || memcmp(b1, b2, l1) != 0) {
378 { .
type =
ODF_NO_VALUE, .id =
'h', .shortname =
'h', .longname =
"--help" },
380 { .type =
ODF_HAS_VALUE, .id =
'o', .shortname =
'o', .longname =
"--output" },
381 { .type =
ODF_HAS_VALUE, .id =
'b', .shortname =
'b', .longname =
"--before" },
382 { .type =
ODF_HAS_VALUE, .id =
'a', .shortname =
'a', .longname =
"--after" },
422 int CDECL
main(
int argc,
char *argv[])
424 const char *output_file =
nullptr;
425 const char *before_file =
nullptr;
426 const char *after_file =
nullptr;
435 fmt::print(
"settingsgen\n"
436 "Usage: settingsgen [options] ini-file...\n"
438 " -h, -?, --help Print this help message and exit\n"
439 " -b FILE, --before FILE Copy FILE before all settings\n"
440 " -a FILE, --after FILE Copy FILE after all settings\n"
441 " -o FILE, --output FILE Write output to FILE\n");
445 output_file = mgo.
opt;
449 after_file = mgo.
opt;
453 before_file = mgo.
opt;
457 fmt::print(stderr,
"Invalid arguments\n");
468 if (output_file ==
nullptr) {
474 static const char *
const tmp_output =
"tmp2.xxx";
477 if (!fp.has_value()) {
478 FatalError(
"Cannot open file {}", tmp_output);
486 std::error_code error_code;
489 std::filesystem::remove(tmp_output, error_code);
492 std::filesystem::rename(tmp_output, output_file, error_code);
493 if (error_code) FatalError(
"rename({}, {}) failed: {}", tmp_output, output_file, error_code.message());
505 std::optional<FileHandle>
FileHandle::Open(
const std::string &filename,
const std::string &mode)
507 auto f = fopen(filename.c_str(), mode.c_str());
508 if (f ==
nullptr)
return std::nullopt;
static void ProcessIniFile(const char *fname)
Process a single INI file.
static bool CompareFiles(const char *n1, const char *n2)
Compare two files for identity.
const char * opt
Option value, if available (else nullptr).
void Write(FILE *out_fp) const
Write all stored output to the output stream.
ArgumentSpan arguments
Remaining command line arguments.
static void DumpGroup(const IniLoadFile &ifile, const char *const group_name)
Dump a IGT_SEQUENCE group into _stored_output.
char data[OUTPUT_BLOCK_SIZE]
Stored data.
void Clear()
Prepare buffer for use.
static const char * DEFAULTS_GROUP_NAME
Name of the group containing default values for the template variables.
A single "line" in an ini file.
A group within an ini file.
void FatalErrorI(const std::string &msg)
Report a fatal error.
OutputStore _post_amble_output
Similar to _stored_output, but for the post amble.
bool BufferHasRoom() const
Does the buffer have room without adding a new OutputBuffer block?
OutputStore _stored_output
Temporary storage of the output, until all processing is done.
std::list< IniItem > items
all items in the group
static std::optional< FileHandle > Open(const std::string &filename, const std::string &mode)
Open an RAII file handle if possible.
size_t size
Number of bytes stored in data.
const IniGroupNameList seq_group_names
list of group names that are sequences.
const IniGroupNameList list_group_names
list of group names that are lists
Ini file that only supports loading.
@ ODF_HAS_VALUE
An option with a value.
static const char * POSTAMBLE_GROUP_NAME
Name of the group containing the post amble.
void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
const IniItem * GetItem(std::string_view name) const
Get the item with the given name.
void Clear()
Clear the temporary storage.
@ ODF_NO_VALUE
A plain option (no value attached to it).
static const size_t OUTPUT_BLOCK_SIZE
Block size of the buffer in OutputBuffer.
std::optional< std::string > value
The value of this item.
bool HasRoom() const
Does the block have room for more data?
std::optional< FileHandle > OpenFile(const std::string &filename, Subdirectory, size_t *size) override
Open the INI file.
OutputBufferVector output_buffer
Vector of blocks containing the stored output.
#define lengthof(array)
Return the length of an fixed size array.
IniGroupType type
type of group
Data storage for parsing command line options.
Derived class for loading INI files without going through Fio stuff.
void Write(FILE *out_fp) const
Dump buffer to the output stream.
Temporarily store output.
std::vector< OutputBuffer > OutputBufferVector
Vector type for output buffers.
SettingsIniFile(const IniGroupNameList &list_group_names={}, const IniGroupNameList &seq_group_names={})
Construct a new ini loader.
static const OptionData _opts[]
Options of settingsgen.
static const char * PREAMBLE_GROUP_NAME
Name of the group containing the pre amble.
size_t Add(const char *text, size_t length)
Add text to the output buffer.
static const char * VALIDATION_GROUP_NAME
Name of the group containing the validation statements.
int CDECL main(int argc, char *argv[])
And the main program (what else?)
std::string name
name of group
IniLoadFile(const IniGroupNameList &list_group_names={}, const IniGroupNameList &seq_group_names={})
Construct a new in-memory Ini file representation.
@ NO_DIRECTORY
A path without any base directory.
@ IGT_SEQUENCE
A list of uninterpreted lines, terminated by the next group block.
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
OptionDataType type
The type of option.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
int GetOpt()
Find the next option.
std::list< IniGroup > groups
all groups in the ini
std::string name
The name of this item.
void Add(const char *text, size_t length=0)
Add text to the output storage.
Output buffer for a block of data.
void LoadFromDisk(const std::string &filename, Subdirectory subdir)
Load the Ini file's data from the disk.
static void DumpSections(const IniLoadFile &ifile)
Output all non-special sections through the template / template variable expansion system.
void ReportFileError(const char *const pre, const char *const buffer, const char *const post) override
Report an error about the file contents.
static const char * TEMPLATES_GROUP_NAME
Name of the group containing the templates.
static void AppendFile(const char *fname, FILE *out_fp)
Append a file to the output stream.
static void DumpLine(const IniItem *item, const IniGroup *grp, const IniGroup *default_grp, OutputStore &output)
Parse a single entry via a template and output this.
static const char * FindItemValue(const char *name, const IniGroup *grp, const IniGroup *defaults)
Find the value of a template variable.