12 #include "../stdafx.h" 13 #include "../string_func.h" 14 #include "../strings_type.h" 15 #include "../misc/getoptdata.h" 16 #include "../ini_type.h" 17 #include "../core/smallvec_type.hpp" 21 #if !defined(_WIN32) || defined(__CYGWIN__) 26 #include "../safeguards.h" 33 void NORETURN CDECL
error(
const char *s, ...)
40 fprintf(stderr,
"FATAL: %s\n", buf);
61 size_t Add(
const char *text,
size_t length)
66 this->
size += store_size;
76 if (fwrite(this->
data, 1, this->
size, out_fp) != this->
size) {
77 fprintf(stderr,
"Error: Cannot write output\n");
105 this->output_buffer.clear();
113 void Add(
const char *text,
size_t length = 0)
115 if (length == 0) length = strlen(text);
117 if (length > 0 && this->BufferHasRoom()) {
118 size_t stored_size = this->output_buffer[this->output_buffer.size() - 1].Add(text, length);
119 length -= stored_size;
123 this->output_buffer.emplace_back();
126 size_t stored_size = block.
Add(text, length);
127 length -= stored_size;
139 out_data.Write(out_fp);
150 size_t num_blocks = this->output_buffer.size();
151 return num_blocks > 0 && this->output_buffer[num_blocks - 1].HasRoom();
166 SettingsIniFile(
const char *
const *list_group_names =
nullptr,
const char *
const *seq_group_names =
nullptr) :
175 FILE *in = fopen(filename,
"rb");
176 if (in ==
nullptr)
return nullptr;
178 fseek(in, 0L, SEEK_END);
181 fseek(in, 0L, SEEK_SET);
185 virtual void ReportFileError(
const char *
const pre,
const char *
const buffer,
const char *
const post)
187 error(
"%s%s%s", pre, buffer, post);
223 _stored_output.
Add(item->name);
224 _stored_output.
Add(
"\n", 1);
240 if (item ==
nullptr && defaults !=
nullptr) item = defaults->
GetItem(name,
false);
241 if (item ==
nullptr || item->
value ==
nullptr)
return nullptr;
251 static const int MAX_VAR_LENGTH = 64;
256 if (templates_grp ==
nullptr)
return;
260 const char *
const *sgn;
261 for (sgn = special_group_names; *sgn !=
nullptr; sgn++)
if (strcmp(grp->name, *sgn) == 0)
break;
262 if (*sgn !=
nullptr)
continue;
264 IniItem *template_item = templates_grp->
GetItem(grp->name,
false);
265 if (template_item ==
nullptr || template_item->
value ==
nullptr) {
266 fprintf(stderr,
"settingsgen: Warning: Cannot find template %s\n", grp->name);
271 static const char *
const pp_lines[] = {
"if",
"ifdef",
"ifndef",
nullptr};
273 for (
const char *
const *name = pp_lines; *name !=
nullptr; name++) {
274 const char *condition =
FindItemValue(*name, grp, default_grp);
275 if (condition !=
nullptr) {
276 _stored_output.
Add(
"#", 1);
277 _stored_output.
Add(*name);
278 _stored_output.
Add(
" ", 1);
279 _stored_output.
Add(condition);
280 _stored_output.
Add(
"\n", 1);
286 const char *txt = template_item->
value;
287 while (*txt !=
'\0') {
289 _stored_output.
Add(txt, 1);
295 _stored_output.
Add(txt, 1);
301 char variable[MAX_VAR_LENGTH];
303 while (i < MAX_VAR_LENGTH - 1) {
304 if (!(txt[i] ==
'_' || (txt[i] >=
'a' && txt[i] <=
'z') || (txt[i] >=
'0' && txt[i] <=
'9')))
break;
305 variable[i] = txt[i];
313 const char *valitem =
FindItemValue(variable, grp, default_grp);
314 if (valitem !=
nullptr) _stored_output.
Add(valitem);
316 _stored_output.
Add(
"$", 1);
319 _stored_output.
Add(
"\n", 1);
321 _stored_output.
Add(
"#endif\n");
332 static void CopyFile(
const char *fname, FILE *out_fp)
334 if (fname ==
nullptr)
return;
336 FILE *in_fp = fopen(fname,
"r");
337 if (in_fp ==
nullptr) {
338 fprintf(stderr,
"settingsgen: Warning: Cannot open file %s for copying\n", fname);
345 length = fread(buffer, 1,
lengthof(buffer), in_fp);
346 if (fwrite(buffer, 1, length, out_fp) != length) {
347 fprintf(stderr,
"Error: Cannot copy file\n");
350 }
while (length ==
lengthof(buffer));
363 FILE *f2 = fopen(n2,
"rb");
364 if (f2 ==
nullptr)
return false;
366 FILE *f1 = fopen(n1,
"rb");
369 error(
"can't open %s", n1);
376 l1 = fread(b1, 1,
sizeof(b1), f1);
377 l2 = fread(b2, 1,
sizeof(b2), f2);
379 if (l1 != l2 || memcmp(b1, b2, l1) != 0) {
436 int CDECL
main(
int argc,
char *argv[])
438 const char *output_file =
nullptr;
439 const char *before_file =
nullptr;
440 const char *after_file =
nullptr;
453 puts(
"settingsgen - $Revision$\n" 454 "Usage: settingsgen [options] ini-file...\n" 456 " -v, --version Print version information and exit\n" 457 " -h, -?, --help Print this help message and exit\n" 458 " -b FILE, --before FILE Copy FILE before all settings\n" 459 " -a FILE, --after FILE Copy FILE after all settings\n" 460 " -o FILE, --output FILE Write output to FILE\n");
464 output_file = mgo.
opt;
468 after_file = mgo.
opt;
472 before_file = mgo.
opt;
476 fprintf(stderr,
"Invalid arguments\n");
481 _stored_output.
Clear();
486 if (output_file ==
nullptr) {
488 _stored_output.
Write(stdout);
491 static const char *
const tmp_output =
"tmp2.xxx";
493 FILE *fp = fopen(tmp_output,
"w");
495 fprintf(stderr,
"settingsgen: Warning: Cannot open file %s\n", tmp_output);
499 _stored_output.
Write(fp);
511 if (rename(tmp_output, output_file) == -1)
error(
"rename() failed");
A group within an ini file.
static void ProcessIniFile(const char *fname)
Process a single INI file.
static void CopyFile(const char *fname, FILE *out_fp)
Copy a file to the output.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
A plain option (no value attached to it).
int CDECL main(int argc, char *argv[])
And the main program (what else?)
char ** argv
Remaining command line arguments.
void Write(FILE *out_fp) const
Dump buffer to the output stream.
IniItem * item
the first item in the group
#define GETOPT_VALUE(shortname, longname)
Short option with value.
int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap)
Safer implementation of vsnprintf; same as vsnprintf except:
size_t Add(const char *text, size_t length)
Add text to the output buffer.
void Write(FILE *out_fp) const
Write all stored output to the output stream.
#define lastof(x)
Get the last element of an fixed size array.
IniGroup * GetGroup(const char *name, size_t len=0, bool create_new=true)
Get the group with the given name.
IniItem * next
The next item in this group.
static const size_t OUTPUT_BLOCK_SIZE
Block size of the buffer in OutputBuffer.
bool HasRoom() const
Does the block have room for more data?
static void DumpGroup(IniLoadFile *ifile, const char *const group_name)
Dump a IGT_SEQUENCE group into _stored_output.
static const char * FindItemValue(const char *name, IniGroup *grp, IniGroup *defaults)
Find the value of a template variable.
A single "line" in an ini file.
std::vector< OutputBuffer > OutputBufferVector
Vector type for output buffers.
void Clear()
Prepare buffer for use.
IniGroup * group
the first group in the ini
static bool CompareFiles(const char *n1, const char *n2)
Compare two files for identity.
IniGroupType type
type of group
#define GETOPT_GENERAL(id, shortname, longname, flags)
General macro for creating an option.
void LoadFromDisk(const char *filename, Subdirectory subdir)
Load the Ini file's data from the disk.
A path without any base directory.
bool BufferHasRoom() const
Does the buffer have room without adding a new OutputBuffer block?
void Clear()
Clear the temporary storage.
Temporarily store output.
static const OptionData _opts[]
Options of settingsgen.
#define GETOPT_END()
Option terminator.
char * value
The value of this item.
void Add(const char *text, size_t length=0)
Add text to the output storage.
char * opt
Option value, if available (else nullptr).
static const char * TEMPLATES_GROUP_NAME
Name of the group containing the templates.
#define GETOPT_NOVAL(shortname, longname)
Short option without value.
char data[OUTPUT_BLOCK_SIZE]
Stored data.
#define lengthof(x)
Return the length of an fixed size array.
static T min(const T a, const T b)
Returns the minimum of two values.
Output buffer for a block of data.
OutputStore _stored_output
Temporary storage of the output, until all processing is done.
static void DumpSections(IniLoadFile *ifile)
Output all non-special sections through the template / template variable expansion system...
static void MemCpyT(T *destination, const T *source, size_t num=1)
Type-safe version of memcpy().
OutputBufferVector output_buffer
Vector of blocks containing the stored output.
static IniLoadFile * LoadIniFile(const char *filename)
Load the INI file.
A list of uninterpreted lines, terminated by the next group block.
Data storage for parsing command line options.
size_t size
Number of bytes stored in data.
virtual void ReportFileError(const char *const pre, const char *const buffer, const char *const post)
Report an error about the file contents.
IniItem * GetItem(const char *name, bool create)
Get the item with the given name, and if it doesn't exist and create is true it creates a new item...
static const char * POSTAMBLE_GROUP_NAME
Name of the group containing the post amble.
virtual FILE * OpenFile(const char *filename, Subdirectory subdir, size_t *size)
Open the INI file.
void NORETURN CDECL error(const char *s,...)
Report a fatal error.
int GetOpt()
Find the next option.
static const char * DEFAULTS_GROUP_NAME
Name of the group containing default values for the template variables.
IniGroup * next
the next group within this file
int numleft
Number of arguments left in argv.
static const char * PREAMBLE_GROUP_NAME
Name of the group containing the pre amble.
Ini file that only supports loading.
SettingsIniFile(const char *const *list_group_names=nullptr, const char *const *seq_group_names=nullptr)
Construct a new ini loader.
Derived class for loading INI files without going through Fio stuff.