mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-17 21:25:40 +00:00
(svn r23572) -Codechange: split actual file reading from logic for parsing
This commit is contained in:
parent
14c8a3d2b1
commit
446f2f5147
@ -642,11 +642,102 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Helper for reading strings. */
|
||||||
|
struct StringReader {
|
||||||
|
StringData &data; ///< The data to fill during reading.
|
||||||
|
const char *file; ///< The file we are reading.
|
||||||
|
bool master; ///< Are we reading the master file?
|
||||||
|
bool translation; ///< Are we reading a translation, implies !master. However, the base translation will have this false.
|
||||||
|
|
||||||
static void HandlePragma(StringData &data, char *str, bool master)
|
/**
|
||||||
|
* Prepare reading.
|
||||||
|
* @param data The data to fill during reading.
|
||||||
|
* @param file The file we are reading.
|
||||||
|
* @param master Are we reading the master file?
|
||||||
|
* @param translation Are we reading a translation?
|
||||||
|
*/
|
||||||
|
StringReader(StringData &data, const char *file, bool master, bool translation) :
|
||||||
|
data(data), file(strdup(file)), master(master), translation(translation)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Make sure the right reader gets freed. */
|
||||||
|
virtual ~StringReader()
|
||||||
|
{
|
||||||
|
free(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a single line from the source of strings.
|
||||||
|
* @param buffer The buffer to read the data in to.
|
||||||
|
* @param size The size of the buffer.
|
||||||
|
* @return The buffer, or NULL if at the end of the file.
|
||||||
|
*/
|
||||||
|
virtual char *ReadLine(char *buffer, size_t size) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the pragma of the file.
|
||||||
|
* @param str The pragma string to parse.
|
||||||
|
*/
|
||||||
|
virtual void HandlePragma(char *str) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle reading a single string.
|
||||||
|
* @param str The string to handle.
|
||||||
|
*/
|
||||||
|
void HandleString(char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start parsing the file.
|
||||||
|
*/
|
||||||
|
virtual void ParseFile();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A reader that simply reads using fopen. */
|
||||||
|
struct FileStringReader : StringReader {
|
||||||
|
FILE *fh; ///< The file we are reading.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the reader.
|
||||||
|
* @param data The data to fill during reading.
|
||||||
|
* @param file The file we are reading.
|
||||||
|
* @param master Are we reading the master file?
|
||||||
|
* @param translation Are we reading a translation?
|
||||||
|
*/
|
||||||
|
FileStringReader(StringData &data, const char *file, bool master, bool translation) :
|
||||||
|
StringReader(data, file, master, translation)
|
||||||
|
{
|
||||||
|
this->fh = fopen(file, "rb");
|
||||||
|
if (this->fh == NULL) error("Could not open %s", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Free/close the file. */
|
||||||
|
virtual ~FileStringReader()
|
||||||
|
{
|
||||||
|
fclose(this->fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ char *ReadLine(char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
return fgets(buffer, size, this->fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* virtual */ void HandlePragma(char *str);
|
||||||
|
|
||||||
|
/* virtual */ void ParseFile()
|
||||||
|
{
|
||||||
|
this->StringReader::ParseFile();
|
||||||
|
|
||||||
|
if (StrEmpty(_lang.name) || StrEmpty(_lang.own_name) || StrEmpty(_lang.isocode)) {
|
||||||
|
error("Language must include ##name, ##ownname and ##isocode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void FileStringReader::HandlePragma(char *str)
|
||||||
{
|
{
|
||||||
if (!memcmp(str, "id ", 3)) {
|
if (!memcmp(str, "id ", 3)) {
|
||||||
data.next_string_id = strtoul(str + 3, NULL, 0);
|
this->data.next_string_id = strtoul(str + 3, NULL, 0);
|
||||||
} else if (!memcmp(str, "name ", 5)) {
|
} else if (!memcmp(str, "name ", 5)) {
|
||||||
strecpy(_lang.name, str + 5, lastof(_lang.name));
|
strecpy(_lang.name, str + 5, lastof(_lang.name));
|
||||||
} else if (!memcmp(str, "ownname ", 8)) {
|
} else if (!memcmp(str, "ownname ", 8)) {
|
||||||
@ -690,7 +781,7 @@ static void HandlePragma(StringData &data, char *str, bool master)
|
|||||||
}
|
}
|
||||||
_lang.newgrflangid = (uint8)langid;
|
_lang.newgrflangid = (uint8)langid;
|
||||||
} else if (!memcmp(str, "gender ", 7)) {
|
} else if (!memcmp(str, "gender ", 7)) {
|
||||||
if (master) error("Genders are not allowed in the base translation.");
|
if (this->master) error("Genders are not allowed in the base translation.");
|
||||||
char *buf = str + 7;
|
char *buf = str + 7;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -702,7 +793,7 @@ static void HandlePragma(StringData &data, char *str, bool master)
|
|||||||
_lang.num_genders++;
|
_lang.num_genders++;
|
||||||
}
|
}
|
||||||
} else if (!memcmp(str, "case ", 5)) {
|
} else if (!memcmp(str, "case ", 5)) {
|
||||||
if (master) error("Cases are not allowed in the base translation.");
|
if (this->master) error("Cases are not allowed in the base translation.");
|
||||||
char *buf = str + 5;
|
char *buf = str + 5;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -823,10 +914,10 @@ static bool CheckCommandsMatch(char *a, char *b, const char *name)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleString(StringData &data, char *str, bool master)
|
void StringReader::HandleString(char *str)
|
||||||
{
|
{
|
||||||
if (*str == '#') {
|
if (*str == '#') {
|
||||||
if (str[1] == '#' && str[2] != '#') HandlePragma(data, str + 2, master);
|
if (str[1] == '#' && str[2] != '#') this->HandlePragma(str + 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -869,9 +960,9 @@ static void HandleString(StringData &data, char *str, bool master)
|
|||||||
if (casep != NULL) *casep++ = '\0';
|
if (casep != NULL) *casep++ = '\0';
|
||||||
|
|
||||||
/* Check if this string already exists.. */
|
/* Check if this string already exists.. */
|
||||||
LangString *ent = data.Find(str);
|
LangString *ent = this->data.Find(str);
|
||||||
|
|
||||||
if (master) {
|
if (this->master) {
|
||||||
if (casep != NULL) {
|
if (casep != NULL) {
|
||||||
strgen_error("Cases in the base translation are not supported.");
|
strgen_error("Cases in the base translation are not supported.");
|
||||||
return;
|
return;
|
||||||
@ -882,13 +973,13 @@ static void HandleString(StringData &data, char *str, bool master)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.strings[data.next_string_id] != NULL) {
|
if (this->data.strings[this->data.next_string_id] != NULL) {
|
||||||
strgen_error("String ID 0x%X for '%s' already in use by '%s'", data.next_string_id, str, data.strings[data.next_string_id]->name);
|
strgen_error("String ID 0x%X for '%s' already in use by '%s'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a new LangString */
|
/* Allocate a new LangString */
|
||||||
data.Add(str, new LangString(str, s, data.next_string_id++, _cur_line));
|
this->data.Add(str, new LangString(str, s, this->data.next_string_id++, _cur_line));
|
||||||
} else {
|
} else {
|
||||||
if (ent == NULL) {
|
if (ent == NULL) {
|
||||||
strgen_warning("String name '%s' does not exist in master file", str);
|
strgen_warning("String name '%s' does not exist in master file", str);
|
||||||
@ -923,37 +1014,25 @@ static void rstrip(char *buf)
|
|||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StringReader::ParseFile()
|
||||||
static void ParseFile(StringData &data, const char *file, bool english)
|
|
||||||
{
|
{
|
||||||
FILE *in;
|
|
||||||
char buf[2048];
|
char buf[2048];
|
||||||
|
|
||||||
/* Only look at the final filename to determine whether it's the base language or not */
|
_translation = this->master || this->translation;
|
||||||
const char *cur_file = strrchr(_file, PATHSEPCHAR);
|
_file = this->file;
|
||||||
const char *next_file = strrchr(file, PATHSEPCHAR);
|
|
||||||
_translation = next_file != NULL && cur_file != NULL && strcmp(cur_file, next_file) != 0;
|
|
||||||
_file = file;
|
|
||||||
|
|
||||||
/* For each new file we parse, reset the genders, and language codes */
|
/* For each new file we parse, reset the genders, and language codes. */
|
||||||
MemSetT(&_lang, 0);
|
MemSetT(&_lang, 0);
|
||||||
strecpy(_lang.digit_group_separator, ",", lastof(_lang.digit_group_separator));
|
strecpy(_lang.digit_group_separator, ",", lastof(_lang.digit_group_separator));
|
||||||
strecpy(_lang.digit_group_separator_currency, ",", lastof(_lang.digit_group_separator_currency));
|
strecpy(_lang.digit_group_separator_currency, ",", lastof(_lang.digit_group_separator_currency));
|
||||||
strecpy(_lang.digit_decimal_separator, ".", lastof(_lang.digit_decimal_separator));
|
strecpy(_lang.digit_decimal_separator, ".", lastof(_lang.digit_decimal_separator));
|
||||||
|
|
||||||
in = fopen(file, "r");
|
|
||||||
if (in == NULL) error("Cannot open file");
|
|
||||||
_cur_line = 1;
|
_cur_line = 1;
|
||||||
while (fgets(buf, sizeof(buf), in) != NULL) {
|
while (this->ReadLine(buf, sizeof(buf)) != NULL) {
|
||||||
rstrip(buf);
|
rstrip(buf);
|
||||||
HandleString(data, buf, english);
|
this->HandleString(buf);
|
||||||
_cur_line++;
|
_cur_line++;
|
||||||
}
|
}
|
||||||
fclose(in);
|
|
||||||
|
|
||||||
if (StrEmpty(_lang.name) || StrEmpty(_lang.own_name) || StrEmpty(_lang.isocode)) {
|
|
||||||
error("Language must include ##name, ##ownname and ##isocode");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompareFiles(const char *n1, const char *n2)
|
bool CompareFiles(const char *n1, const char *n2)
|
||||||
@ -1523,15 +1602,16 @@ int CDECL main(int argc, char *argv[])
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
/* strgen has two modes of operation. If no (free) arguments are passed
|
/* strgen has two modes of operation. If no (free) arguments are passed
|
||||||
* strgen generates strings.h to the destination directory. If it is supplied
|
* strgen generates strings.h to the destination directory. If it is supplied
|
||||||
* with a (free) parameter the program will translate that language to destination
|
* with a (free) parameter the program will translate that language to destination
|
||||||
* directory. As input english.txt is parsed from the source directory */
|
* directory. As input english.txt is parsed from the source directory */
|
||||||
if (mgo.numleft == 0) {
|
if (mgo.numleft == 0) {
|
||||||
mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
|
mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
|
||||||
|
|
||||||
StringData data;
|
|
||||||
/* parse master file */
|
/* parse master file */
|
||||||
ParseFile(data, pathbuf, true);
|
StringData data;
|
||||||
|
FileStringReader master_reader(data, pathbuf, true, false);
|
||||||
|
master_reader.ParseFile();
|
||||||
if (_errors != 0) return 1;
|
if (_errors != 0) return 1;
|
||||||
|
|
||||||
/* write strings.h */
|
/* write strings.h */
|
||||||
@ -1548,8 +1628,13 @@ int CDECL main(int argc, char *argv[])
|
|||||||
|
|
||||||
StringData data;
|
StringData data;
|
||||||
/* parse master file and check if target file is correct */
|
/* parse master file and check if target file is correct */
|
||||||
ParseFile(data, pathbuf, true);
|
FileStringReader master_reader(data, pathbuf, true, false);
|
||||||
ParseFile(data, replace_pathsep(mgo.argv[0]), false); // target file
|
master_reader.ParseFile();
|
||||||
|
|
||||||
|
const char *translation = replace_pathsep(mgo.argv[0]);
|
||||||
|
const char *file = strrchr(translation, PATHSEPCHAR);
|
||||||
|
FileStringReader translation_reader(data, translation, false, file == NULL || strcmp(file + 1, "english.txt") != 0);
|
||||||
|
translation_reader.ParseFile(); // target file
|
||||||
if (_errors != 0) return 1;
|
if (_errors != 0) return 1;
|
||||||
|
|
||||||
/* get the targetfile, strip any directories and append to destination path */
|
/* get the targetfile, strip any directories and append to destination path */
|
||||||
|
Loading…
Reference in New Issue
Block a user