(svn r23572) -Codechange: split actual file reading from logic for parsing

This commit is contained in:
rubidium 2011-12-17 16:56:32 +00:00
parent 4fbbbdd78f
commit ad7f577931
1 changed files with 121 additions and 36 deletions

View File

@ -642,11 +642,102 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a
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)) {
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)) {
strecpy(_lang.name, str + 5, lastof(_lang.name));
} else if (!memcmp(str, "ownname ", 8)) {
@ -690,7 +781,7 @@ static void HandlePragma(StringData &data, char *str, bool master)
}
_lang.newgrflangid = (uint8)langid;
} 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;
for (;;) {
@ -702,7 +793,7 @@ static void HandlePragma(StringData &data, char *str, bool master)
_lang.num_genders++;
}
} 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;
for (;;) {
@ -823,10 +914,10 @@ static bool CheckCommandsMatch(char *a, char *b, const char *name)
return result;
}
static void HandleString(StringData &data, char *str, bool master)
void StringReader::HandleString(char *str)
{
if (*str == '#') {
if (str[1] == '#' && str[2] != '#') HandlePragma(data, str + 2, master);
if (str[1] == '#' && str[2] != '#') this->HandlePragma(str + 2);
return;
}
@ -869,9 +960,9 @@ static void HandleString(StringData &data, char *str, bool master)
if (casep != NULL) *casep++ = '\0';
/* 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) {
strgen_error("Cases in the base translation are not supported.");
return;
@ -882,13 +973,13 @@ static void HandleString(StringData &data, char *str, bool master)
return;
}
if (data.strings[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);
if (this->data.strings[this->data.next_string_id] != NULL) {
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;
}
/* 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 {
if (ent == NULL) {
strgen_warning("String name '%s' does not exist in master file", str);
@ -923,37 +1014,25 @@ static void rstrip(char *buf)
buf[i] = '\0';
}
static void ParseFile(StringData &data, const char *file, bool english)
void StringReader::ParseFile()
{
FILE *in;
char buf[2048];
/* Only look at the final filename to determine whether it's the base language or not */
const char *cur_file = strrchr(_file, PATHSEPCHAR);
const char *next_file = strrchr(file, PATHSEPCHAR);
_translation = next_file != NULL && cur_file != NULL && strcmp(cur_file, next_file) != 0;
_file = file;
_translation = this->master || this->translation;
_file = this->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);
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_decimal_separator, ".", lastof(_lang.digit_decimal_separator));
in = fopen(file, "r");
if (in == NULL) error("Cannot open file");
_cur_line = 1;
while (fgets(buf, sizeof(buf), in) != NULL) {
while (this->ReadLine(buf, sizeof(buf)) != NULL) {
rstrip(buf);
HandleString(data, buf, english);
this->HandleString(buf);
_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)
@ -1523,15 +1602,16 @@ int CDECL main(int argc, char *argv[])
try {
/* strgen has two modes of operation. If no (free) arguments are passed
* strgen generates strings.h to the destination directory. If it is supplied
* with a (free) parameter the program will translate that language to destination
* directory. As input english.txt is parsed from the source directory */
* strgen generates strings.h to the destination directory. If it is supplied
* with a (free) parameter the program will translate that language to destination
* directory. As input english.txt is parsed from the source directory */
if (mgo.numleft == 0) {
mkpath(pathbuf, lengthof(pathbuf), src_dir, "english.txt");
StringData data;
/* parse master file */
ParseFile(data, pathbuf, true);
StringData data;
FileStringReader master_reader(data, pathbuf, true, false);
master_reader.ParseFile();
if (_errors != 0) return 1;
/* write strings.h */
@ -1548,8 +1628,13 @@ int CDECL main(int argc, char *argv[])
StringData data;
/* parse master file and check if target file is correct */
ParseFile(data, pathbuf, true);
ParseFile(data, replace_pathsep(mgo.argv[0]), false); // target file
FileStringReader master_reader(data, pathbuf, true, false);
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;
/* get the targetfile, strip any directories and append to destination path */