diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index 8e5624188a..52bee9eb3f 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -71,9 +71,6 @@ static LanguagePackHeader _lang; ///< Header information about a language. #define HASH_SIZE 32767 static uint16 _hash_head[HASH_SIZE]; -/** The buffer for writing a single string. */ -typedef SmallVector Buffer; -Buffer _put_buf; static int _next_string_id; static uint32 _hash; @@ -168,33 +165,42 @@ void NORETURN CDECL error(const char *s, ...) throw std::exception(); } -static void PutByte(byte c) -{ - *_put_buf.Append() = c; -} - - -static void PutUtf8(uint32 value) -{ - if (value < 0x80) { - PutByte(value); - } else if (value < 0x800) { - PutByte(0xC0 + GB(value, 6, 5)); - PutByte(0x80 + GB(value, 0, 6)); - } else if (value < 0x10000) { - PutByte(0xE0 + GB(value, 12, 4)); - PutByte(0x80 + GB(value, 6, 6)); - PutByte(0x80 + GB(value, 0, 6)); - } else if (value < 0x110000) { - PutByte(0xF0 + GB(value, 18, 3)); - PutByte(0x80 + GB(value, 12, 6)); - PutByte(0x80 + GB(value, 6, 6)); - PutByte(0x80 + GB(value, 0, 6)); - } else { - strgen_warning("Invalid unicode value U+0x%X", value); +/** The buffer for writing a single string. */ +struct Buffer : SmallVector { + /** + * Conveniance method for adding a byte. + * @param value The value to add. + */ + void AppendByte(byte value) + { + *this->Append() = value; } -} + /** + * Add an Unicode character encoded in UTF-8 to the buffer. + * @param value The character to add. + */ + void AppendUtf8(uint32 value) + { + if (value < 0x80) { + *this->Append() = value; + } else if (value < 0x800) { + *this->Append() = 0xC0 + GB(value, 6, 5); + *this->Append() = 0x80 + GB(value, 0, 6); + } else if (value < 0x10000) { + *this->Append() = 0xE0 + GB(value, 12, 4); + *this->Append() = 0x80 + GB(value, 6, 6); + *this->Append() = 0x80 + GB(value, 0, 6); + } else if (value < 0x110000) { + *this->Append() = 0xF0 + GB(value, 18, 3); + *this->Append() = 0x80 + GB(value, 12, 6); + *this->Append() = 0x80 + GB(value, 6, 6); + *this->Append() = 0x80 + GB(value, 0, 6); + } else { + strgen_warning("Invalid unicode value U+0x%X", value); + } + } +}; size_t Utf8Validate(const char *s) { @@ -221,10 +227,10 @@ size_t Utf8Validate(const char *s) } -static void EmitSingleChar(char *buf, int value) +static void EmitSingleChar(Buffer *buffer, char *buf, int value) { if (*buf != '\0') strgen_warning("Ignoring trailing letters in command"); - PutUtf8(value); + buffer->AppendUtf8(value); } @@ -300,17 +306,17 @@ char *ParseWord(char **buf) /* Forward declaration */ static int TranslateArgumentIdx(int arg, int offset = 0); -static void EmitWordList(const char * const *words, uint nw) +static void EmitWordList(Buffer *buffer, const char * const *words, uint nw) { - PutByte(nw); - for (uint i = 0; i < nw; i++) PutByte(strlen(words[i]) + 1); + buffer->AppendByte(nw); + for (uint i = 0; i < nw; i++) buffer->AppendByte(strlen(words[i]) + 1); for (uint i = 0; i < nw; i++) { - for (uint j = 0; words[i][j] != '\0'; j++) PutByte(words[i][j]); - PutByte(0); + for (uint j = 0; words[i][j] != '\0'; j++) buffer->AppendByte(words[i][j]); + buffer->AppendByte(0); } } -static void EmitPlural(char *buf, int value) +static void EmitPlural(Buffer *buffer, char *buf, int value) { int argidx = _cur_argidx; int offset = 0; @@ -346,14 +352,14 @@ static void EmitPlural(char *buf, int value) } } - PutUtf8(SCC_PLURAL_LIST); - PutByte(_lang.plural_form); - PutByte(TranslateArgumentIdx(argidx, offset)); - EmitWordList(words, nw); + buffer->AppendUtf8(SCC_PLURAL_LIST); + buffer->AppendByte(_lang.plural_form); + buffer->AppendByte(TranslateArgumentIdx(argidx, offset)); + EmitWordList(buffer, words, nw); } -static void EmitGender(char *buf, int value) +static void EmitGender(Buffer *buffer, char *buf, int value) { int argidx = _cur_argidx; int offset = 0; @@ -367,8 +373,8 @@ static void EmitGender(char *buf, int value) if (nw >= MAX_NUM_GENDERS) error("G argument '%s' invalid", buf); /* now nw contains the gender index */ - PutUtf8(SCC_GENDER_INDEX); - PutByte(nw); + buffer->AppendUtf8(SCC_GENDER_INDEX); + buffer->AppendByte(nw); } else { const char *words[MAX_NUM_GENDERS]; @@ -388,9 +394,9 @@ static void EmitGender(char *buf, int value) if (nw != _lang.num_genders) error("Bad # of arguments for gender command"); assert(IsInsideBS(cmd->value, SCC_CONTROL_START, UINT8_MAX)); - PutUtf8(SCC_GENDER_LIST); - PutByte(TranslateArgumentIdx(argidx, offset)); - EmitWordList(words, nw); + buffer->AppendUtf8(SCC_GENDER_LIST); + buffer->AppendByte(TranslateArgumentIdx(argidx, offset)); + EmitWordList(buffer, words, nw); } } @@ -1054,21 +1060,21 @@ static int TranslateArgumentIdx(int argidx, int offset) return sum + offset; } -static void PutArgidxCommand() +static void PutArgidxCommand(Buffer *buffer) { - PutUtf8(SCC_ARG_INDEX); - PutByte(TranslateArgumentIdx(_cur_argidx)); + buffer->AppendUtf8(SCC_ARG_INDEX); + buffer->AppendByte(TranslateArgumentIdx(_cur_argidx)); } -static void PutCommandString(const char *str) +static void PutCommandString(Buffer *buffer, const char *str) { _cur_argidx = 0; while (*str != '\0') { /* Process characters as they are until we encounter a { */ if (*str != '{') { - PutByte(*str++); + buffer->AppendByte(*str++); continue; } @@ -1079,8 +1085,8 @@ static void PutCommandString(const char *str) if (cs == NULL) break; if (casei != -1) { - PutUtf8(SCC_SET_CASE); // {SET_CASE} - PutByte(casei); + buffer->AppendUtf8(SCC_SET_CASE); // {SET_CASE} + buffer->AppendByte(casei); } /* For params that consume values, we need to handle the argindex properly */ @@ -1088,7 +1094,7 @@ static void PutCommandString(const char *str) /* Check if we need to output a move-param command */ if (argno != -1 && argno != _cur_argidx) { _cur_argidx = argno; - PutArgidxCommand(); + PutArgidxCommand(buffer); } /* Output the one from the master string... it's always accurate. */ @@ -1098,7 +1104,7 @@ static void PutCommandString(const char *str) } } - cs->proc(param, cs->value); + cs->proc(buffer, param, cs->value); } } @@ -1169,6 +1175,7 @@ struct LanguageWriter { _lang.winlangid = TO_LE16(_lang.winlangid); this->WriteHeader(&_lang); + Buffer buffer; for (int i = 0; i != 32; i++) { for (uint j = 0; j != in_use[i]; j++) { @@ -1192,7 +1199,7 @@ struct LanguageWriter { } if ((_show_todo & 1) != 0) { const char *s = " "; - while (*s != '\0') PutByte(*s++); + while (*s != '\0') buffer.AppendByte(*s++); } } @@ -1217,33 +1224,33 @@ struct LanguageWriter { * It has this format * <0x9E> * Each LEN is printed using 2 bytes in big endian order. */ - PutUtf8(SCC_SWITCH_CASE); + buffer.AppendUtf8(SCC_SWITCH_CASE); /* Count the number of cases */ for (num = 0, c = casep; c; c = c->next) num++; - PutByte(num); + buffer.AppendByte(num); /* Write each case */ for (c = casep; c != NULL; c = c->next) { - PutByte(c->caseidx); + buffer.AppendByte(c->caseidx); /* Make some space for the 16-bit length */ - size_t pos = _put_buf.Length(); - PutByte(0); - PutByte(0); + size_t pos = buffer.Length(); + buffer.AppendByte(0); + buffer.AppendByte(0); /* Write string */ - PutCommandString(c->string); - PutByte(0); // terminate with a zero + PutCommandString(&buffer, c->string); + buffer.AppendByte(0); // terminate with a zero /* Fill in the length */ - size_t size = _put_buf.Length() - (pos + 2); - _put_buf[pos + 0] = GB(size, 8, 8); - _put_buf[pos + 1] = GB(size, 0, 8); + size_t size = buffer.Length() - (pos + 2); + buffer[pos + 0] = GB(size, 8, 8); + buffer[pos + 1] = GB(size, 0, 8); } } - if (cmdp != NULL) PutCommandString(cmdp); + if (cmdp != NULL) PutCommandString(&buffer, cmdp); - this->WriteLength(_put_buf.Length()); - this->Write(_put_buf.Begin(), _put_buf.Length()); - _put_buf.Clear(); + this->WriteLength(buffer.Length()); + this->Write(buffer.Begin(), buffer.Length()); + buffer.Clear(); } } } diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index ba852ed60d..bed658eac9 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -19,7 +19,8 @@ enum CmdFlags { }; DECLARE_ENUM_AS_BIT_SET(CmdFlags) -typedef void (*ParseCmdProc)(char *buf, int value); +struct Buffer; +typedef void (*ParseCmdProc)(Buffer *buffer, char *buf, int value); struct CmdStruct { const char *cmd; @@ -29,9 +30,9 @@ struct CmdStruct { CmdFlags flags; }; -static void EmitSingleChar(char *buf, int value); -static void EmitPlural(char *buf, int value); -static void EmitGender(char *buf, int value); +static void EmitSingleChar(Buffer *buffer, char *buf, int value); +static void EmitPlural(Buffer *buffer, char *buf, int value); +static void EmitGender(Buffer *buffer, char *buf, int value); static const CmdStruct _cmd_structs[] = { /* Font size */