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(WIN64)) || defined(__CYGWIN__) 33 #include "../safeguards.h" 40 void NORETURN CDECL
error(
const char *s, ...)
47 fprintf(stderr,
"FATAL: %s\n", buf);
68 int Add(
const char *text,
int length)
71 assert(store_size >= 0);
74 this->
size += store_size;
84 if (fwrite(this->
data, 1, this->
size, out_fp) != (
size_t)this->
size) {
85 fprintf(stderr,
"Error: Cannot write output\n");
113 this->output_buffer.Clear();
121 void Add(
const char *text,
int length = 0)
123 if (length == 0) length = strlen(text);
125 if (length > 0 && this->BufferHasRoom()) {
126 int stored_size = this->output_buffer[this->output_buffer.Length() - 1].Add(text, length);
127 length -= stored_size;
133 int stored_size = block->
Add(text, length);
134 length -= stored_size;
145 for (
const OutputBuffer *out_data = this->output_buffer.Begin(); out_data != this->output_buffer.End(); out_data++) {
146 out_data->Write(out_fp);
157 uint num_blocks = this->output_buffer.Length();
158 return num_blocks > 0 && this->output_buffer[num_blocks - 1].HasRoom();
173 SettingsIniFile(
const char *
const *list_group_names = NULL,
const char *
const *seq_group_names = NULL) :
182 FILE *in = fopen(filename,
"rb");
183 if (in == NULL)
return NULL;
185 fseek(in, 0L, SEEK_END);
188 fseek(in, 0L, SEEK_SET);
192 virtual void ReportFileError(
const char *
const pre,
const char *
const buffer,
const char *
const post)
194 error(
"%s%s%s", pre, buffer, post);
231 _stored_output.
Add(item->name);
232 _stored_output.
Add(
"\n", 1);
248 if (item == NULL && defaults != NULL) item = defaults->
GetItem(name,
false);
249 if (item == NULL || item->
value == NULL)
return NULL;
259 static const int MAX_VAR_LENGTH = 64;
264 if (templates_grp == NULL)
return;
268 const char *
const *sgn;
269 for (sgn = special_group_names; *sgn != NULL; sgn++)
if (strcmp(grp->name, *sgn) == 0)
break;
270 if (*sgn != NULL)
continue;
272 IniItem *template_item = templates_grp->
GetItem(grp->name,
false);
273 if (template_item == NULL || template_item->
value == NULL) {
274 fprintf(stderr,
"settingsgen: Warning: Cannot find template %s\n", grp->name);
279 static const char *
const pp_lines[] = {
"if",
"ifdef",
"ifndef", NULL};
281 for (
const char *
const *name = pp_lines; *name != NULL; name++) {
282 const char *condition =
FindItemValue(*name, grp, default_grp);
283 if (condition != NULL) {
284 _stored_output.
Add(
"#", 1);
285 _stored_output.
Add(*name);
286 _stored_output.
Add(
" ", 1);
287 _stored_output.
Add(condition);
288 _stored_output.
Add(
"\n", 1);
294 const char *txt = template_item->
value;
295 while (*txt !=
'\0') {
297 _stored_output.
Add(txt, 1);
303 _stored_output.
Add(txt, 1);
309 char variable[MAX_VAR_LENGTH];
311 while (i < MAX_VAR_LENGTH - 1) {
312 if (!(txt[i] ==
'_' || (txt[i] >=
'a' && txt[i] <=
'z') || (txt[i] >=
'0' && txt[i] <=
'9')))
break;
313 variable[i] = txt[i];
321 const char *valitem =
FindItemValue(variable, grp, default_grp);
322 if (valitem != NULL) _stored_output.
Add(valitem);
324 _stored_output.
Add(
"$", 1);
327 _stored_output.
Add(
"\n", 1);
329 _stored_output.
Add(
"#endif\n");
340 static void CopyFile(
const char *fname, FILE *out_fp)
342 if (fname == NULL)
return;
344 FILE *in_fp = fopen(fname,
"r");
346 fprintf(stderr,
"settingsgen: Warning: Cannot open file %s for copying\n", fname);
353 length = fread(buffer, 1,
lengthof(buffer), in_fp);
354 if (fwrite(buffer, 1, length, out_fp) != length) {
355 fprintf(stderr,
"Error: Cannot copy file\n");
358 }
while (length ==
lengthof(buffer));
371 FILE *f2 = fopen(n2,
"rb");
372 if (f2 == NULL)
return false;
374 FILE *f1 = fopen(n1,
"rb");
375 if (f1 == NULL)
error(
"can't open %s", n1);
381 l1 = fread(b1, 1,
sizeof(b1), f1);
382 l2 = fread(b2, 1,
sizeof(b2), f2);
384 if (l1 != l2 || memcmp(b1, b2, l1) != 0) {
441 int CDECL
main(
int argc,
char *argv[])
443 const char *output_file = NULL;
444 const char *before_file = NULL;
445 const char *after_file = NULL;
458 puts(
"settingsgen - $Revision$\n" 459 "Usage: settingsgen [options] ini-file...\n" 461 " -v, --version Print version information and exit\n" 462 " -h, -?, --help Print this help message and exit\n" 463 " -b FILE, --before FILE Copy FILE before all settings\n" 464 " -a FILE, --after FILE Copy FILE after all settings\n" 465 " -o FILE, --output FILE Write output to FILE\n");
469 output_file = mgo.
opt;
473 after_file = mgo.
opt;
477 before_file = mgo.
opt;
481 fprintf(stderr,
"Invalid arguments\n");
486 _stored_output.
Clear();
491 if (output_file == NULL) {
493 _stored_output.
Write(stdout);
496 static const char *
const tmp_output =
"tmp2.xxx";
498 FILE *fp = fopen(tmp_output,
"w");
500 fprintf(stderr,
"settingsgen: Warning: Cannot open file %s\n", tmp_output);
504 _stored_output.
Write(fp);
513 #if defined(WIN32) || defined(WIN64) 516 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.
void Add(const char *text, int length=0)
Add text to the output storage.
int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap)
Safer implementation of vsnprintf; same as vsnprintf except:
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.
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.
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.
char * opt
Option value, if available (else NULL).
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.
SettingsIniFile(const char *const *list_group_names=NULL, const char *const *seq_group_names=NULL)
Construct a new ini loader.
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.
static const int OUTPUT_BLOCK_SIZE
Block size of the buffer in OutputBuffer.
int Add(const char *text, int length)
Add text to the output buffer.
SmallVector< OutputBuffer, 2 > OutputBufferVector
Vector type for output buffers.
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 size
Number of bytes stored in data.
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.
Derived class for loading INI files without going through Fio stuff.