From 1a4f1c8177f7ee351cb0096e3456d055b97dc60a Mon Sep 17 00:00:00 2001 From: peter1138 Date: Thu, 16 Nov 2006 22:05:33 +0000 Subject: (svn r7182) -Feature: Merge utf8 branch. This brings us support for Unicode/UTF-8 and the option for fonts rendered by FreeType. Language changes to come. --- strings.c | 341 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 179 insertions(+), 162 deletions(-) (limited to 'strings.c') diff --git a/strings.c b/strings.c index ef6bd90c8..a38febca5 100644 --- a/strings.c +++ b/strings.c @@ -18,6 +18,7 @@ #include "variables.h" #include "newgrf_text.h" #include "table/landscape_const.h" +#include "table/control_codes.h" #include "music.h" #include "date.h" #include "industry.h" @@ -236,6 +237,14 @@ char *GetString(char *buffr, StringID string, const char* last) } +char *InlineString(char *buf, StringID string) +{ + buf += Utf8Encode(buf, SCC_STRING_ID); + buf += Utf8Encode(buf, string); + return buf; +} + + // This function takes a C-string and allocates a temporary string ID. // The duration of the bound string is valid only until the next GetString, // so be careful. @@ -564,54 +573,57 @@ static const Units units[] = { static char* FormatString(char* buff, const char* str, const int32* argv, uint casei, const char* last) { extern const char _openttd_revision[]; - byte b; + WChar b; const int32 *argv_orig = argv; uint modifier = 0; - while ((b = *str++) != '\0') { + while ((b = Utf8Consume(&str)) != '\0') { switch (b) { - case 0x1: // {SETX} - if (buff != last && buff + 1 != last) { - *buff++ = b; - *buff++ = *str++; - } - break; - case 0x2: // {SETXY} - if (buff != last && buff + 1 != last && buff + 2 != last) { - *buff++ = b; - *buff++ = *str++; - *buff++ = *str++; + case SCC_SETX: // {SETX} + if (buff + Utf8CharLen(SCC_SETX) + 1 < last) { + buff += Utf8Encode(buff, SCC_SETX); + *buff++ = *str++; + } + break; + + case SCC_SETXY: // {SETXY} + if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) { + buff += Utf8Encode(buff, SCC_SETXY); + *buff++ = *str++; + *buff++ = *str++; + } + break; + + case SCC_STRING_ID: // {STRINL} + buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last); + break; + + case SCC_DATE_LONG: // {DATE_LONG} + buff = FormatYmdString(buff, GetInt32(&argv), last); + break; + + case SCC_DATE_SHORT: // {DATE_SHORT} + buff = FormatMonthAndYear(buff, GetInt32(&argv), last); + break; + + case SCC_VELOCITY: {// {VELOCITY} + int32 args[1]; + assert(_opt_ptr->units < lengthof(units)); + args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s; + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last); + modifier = 0; + break; } - break; - case 0x81: // {STRINL} - buff = GetStringWithArgs(buff, ReadLE16Unaligned(str), argv, last); - str += 2; - break; - case 0x82: // {DATE_LONG} - buff = FormatYmdString(buff, GetInt32(&argv), last); - break; - case 0x83: // {DATE_SHORT} - buff = FormatMonthAndYear(buff, GetInt32(&argv), last); - break; - case 0x84: {// {VELOCITY} - int32 args[1]; - assert(_opt_ptr->units < lengthof(units)); - args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last); - modifier = 0; - break; - } - // 0x85 is used as escape character.. - case 0x85: - switch (*str++) { - case 0: /* {CURRCOMPACT} */ + case SCC_CURRENCY_COMPACT: /* {CURRCOMPACT} */ buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last); break; - case 2: /* {REV} */ + + case SCC_REVISION: /* {REV} */ buff = strecpy(buff, _openttd_revision, last); break; - case 3: { /* {SHORTCARGO} */ + + case SCC_CARGO_SHORT: { /* {SHORTCARGO} */ // Short description of cargotypes. Layout: // 8-bit = cargo type // 16-bit = cargo count @@ -642,40 +654,46 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } } break; - case 4: {/* {CURRCOMPACT64} */ + + case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */ // 64 bit compact currency-unit buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last); break; } - case 5: { /* {STRING1} */ + + case SCC_STRING1: { /* {STRING1} */ // String that consumes ONE argument uint str = modifier + GetInt32(&argv); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last); modifier = 0; break; } - case 6: { /* {STRING2} */ + + case SCC_STRING2: { /* {STRING2} */ // String that consumes TWO arguments uint str = modifier + GetInt32(&argv); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last); modifier = 0; break; } - case 7: { /* {STRING3} */ + + case SCC_STRING3: { /* {STRING3} */ // String that consumes THREE arguments uint str = modifier + GetInt32(&argv); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last); modifier = 0; break; } - case 8: { /* {STRING4} */ + + case SCC_STRING4: { /* {STRING4} */ // String that consumes FOUR arguments uint str = modifier + GetInt32(&argv); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last); modifier = 0; break; } - case 9: { /* {STRING5} */ + + case SCC_STRING5: { /* {STRING5} */ // String that consumes FIVE arguments uint str = modifier + GetInt32(&argv); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last); @@ -683,12 +701,12 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 10: { /* {STATIONFEATURES} */ + case SCC_STATION_FEATURES: { /* {STATIONFEATURES} */ buff = StationGetSpecialString(buff, GetInt32(&argv), last); break; } - case 11: { /* {INDUSTRY} */ + case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */ const Industry* i = GetIndustry(GetInt32(&argv)); int32 args[2]; @@ -704,7 +722,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 12: { // {VOLUME} + case SCC_VOLUME: { // {VOLUME} int32 args[1]; assert(_opt_ptr->units < lengthof(units)); args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s; @@ -713,22 +731,22 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 13: { // {G 0 Der Die Das} - const byte* s = (const byte*)GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender. + case SCC_GENDER_LIST: { // {G 0 Der Die Das} + const char* s = GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender. int len; int gender = 0; - if (s != NULL && s[0] == 0x87) gender = s[1]; + if (s != NULL && Utf8Consume(&s) == SCC_GENDER_INDEX) gender = (byte)s[0]; str = ParseStringChoice(str, gender, buff, &len); buff += len; break; } - case 14: { // {DATE_TINY} + case SCC_DATE_TINY: { // {DATE_TINY} buff = FormatTinyDate(buff, GetInt32(&argv), last); break; } - case 15: { // {CARGO} + case SCC_CARGO: { // {CARGO} // Layout now is: // 8bit - cargo type // 16-bit - cargo count @@ -738,7 +756,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 16: { // {POWER} + case SCC_POWER: { // {POWER} int32 args[1]; assert(_opt_ptr->units < lengthof(units)); args[0] = GetInt32(&argv) * units[_opt_ptr->units].p_m >> units[_opt_ptr->units].p_s; @@ -747,7 +765,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 17: { // {VOLUME_S} + case SCC_VOLUME_SHORT: { // {VOLUME_S} int32 args[1]; assert(_opt_ptr->units < lengthof(units)); args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s; @@ -756,7 +774,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 18: { // {WEIGHT} + case SCC_WEIGHT: { // {WEIGHT} int32 args[1]; assert(_opt_ptr->units < lengthof(units)); args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s; @@ -765,7 +783,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 19: { // {WEIGHT_S} + case SCC_WEIGHT_SHORT: { // {WEIGHT_S} int32 args[1]; assert(_opt_ptr->units < lengthof(units)); args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s; @@ -774,7 +792,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - case 20: { // {FORCE} + case SCC_FORCE: { // {FORCE} int32 args[1]; assert(_opt_ptr->units < lengthof(units)); args[0] = GetInt32(&argv) * units[_opt_ptr->units].f_m >> units[_opt_ptr->units].f_s; @@ -783,124 +801,122 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c break; } - default: - error("!invalid escape sequence in string"); - } - break; - - case 0x86: // {SKIP} - argv++; - break; + case SCC_SKIP: // {SKIP} + argv++; + break; - // This sets up the gender for the string. - // We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. - case 0x87: // {GENDER 0} - str++; - break; + // This sets up the gender for the string. + // We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. + case SCC_GENDER_INDEX: // {GENDER 0} + str++; + break; - case 0x88: {// {STRING} - uint str = modifier + GetInt32(&argv); - // WARNING. It's prohibited for the included string to consume any arguments. - // For included strings that consume argument, you should use STRING1, STRING2 etc. - // To debug stuff you can set argv to NULL and it will tell you - buff = GetStringWithArgs(buff, str, argv, last); - modifier = 0; - break; - } + case SCC_STRING: {// {STRING} + uint str = modifier + GetInt32(&argv); + // WARNING. It's prohibited for the included string to consume any arguments. + // For included strings that consume argument, you should use STRING1, STRING2 etc. + // To debug stuff you can set argv to NULL and it will tell you + buff = GetStringWithArgs(buff, str, argv, last); + modifier = 0; + break; + } - case 0x8B: // {COMMA} - buff = FormatCommaNumber(buff, GetInt32(&argv), last); - break; + case SCC_COMMA: // {COMMA} + buff = FormatCommaNumber(buff, GetInt32(&argv), last); + break; - case 0x8C: // Move argument pointer - argv = argv_orig + (byte)*str++; - break; + case SCC_ARG_INDEX: // Move argument pointer + argv = argv_orig + (byte)*str++; + break; - case 0x8D: { // {P} - int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural - int len; - str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len); - buff += len; - break; - } + case SCC_PLURAL_LIST: { // {P} + int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural + int len; + str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len); + buff += len; + break; + } - case 0x8E: // {NUM} - buff = FormatNoCommaNumber(buff, GetInt32(&argv), last); - break; + case SCC_NUM: // {NUM} + buff = FormatNoCommaNumber(buff, GetInt32(&argv), last); + break; - case 0x8F: // {CURRENCY} - buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last); - break; + case SCC_CURRENCY: // {CURRENCY} + buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last); + break; - case 0x99: { // {WAYPOINT} - int32 temp[2]; - Waypoint *wp = GetWaypoint(GetInt32(&argv)); - StringID str; - if (wp->string != STR_NULL) { - str = wp->string; - } else { - temp[0] = wp->town_index; - temp[1] = wp->town_cn + 1; - str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL; + case SCC_WAYPOINT_NAME: { // {WAYPOINT} + int32 temp[2]; + Waypoint *wp = GetWaypoint(GetInt32(&argv)); + StringID str; + if (wp->string != STR_NULL) { + str = wp->string; + } else { + temp[0] = wp->town_index; + temp[1] = wp->town_cn + 1; + str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL; + } + buff = GetStringWithArgs(buff, str, temp, last); + break; } - buff = GetStringWithArgs(buff, str, temp, last); - } break; - case 0x9A: { // {STATION} - const Station* st = GetStation(GetInt32(&argv)); + case SCC_STATION_NAME: { // {STATION} + const Station* st = GetStation(GetInt32(&argv)); - if (!IsValidStation(st)) { // station doesn't exist anymore - buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last); - } else { - int32 temp[2]; - temp[0] = st->town->townnametype; - temp[1] = st->town->townnameparts; - buff = GetStringWithArgs(buff, st->string_id, temp, last); + if (!IsValidStation(st)) { // station doesn't exist anymore + buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last); + } else { + int32 temp[2]; + temp[0] = st->town->townnametype; + temp[1] = st->town->townnameparts; + buff = GetStringWithArgs(buff, st->string_id, temp, last); + } + break; } - break; - } - case 0x9B: { // {TOWN} - const Town* t = GetTown(GetInt32(&argv)); - int32 temp[1]; - assert(IsValidTown(t)); + case SCC_TOWN_NAME: { // {TOWN} + const Town* t = GetTown(GetInt32(&argv)); + int32 temp[1]; - temp[0] = t->townnameparts; - buff = GetStringWithArgs(buff, t->townnametype, temp, last); - break; - } + assert(IsValidTown(t)); - case 0x9C: { // {CURRENCY64} - buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last); - break; - } + temp[0] = t->townnameparts; + buff = GetStringWithArgs(buff, t->townnametype, temp, last); + break; + } - case 0x9D: { // {SETCASE} - // This is a pseudo command, it's outputted when someone does {STRING.ack} - // The modifier is added to all subsequent GetStringWithArgs that accept the modifier. - modifier = (byte)*str++ << 24; - break; - } + case SCC_CURRENCY_64: { // {CURRENCY64} + buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last); + break; + } - case 0x9E: { // {Used to implement case switching} - // <0x9E> - // Each LEN is printed using 2 bytes in big endian order. - uint num = (byte)*str++; - while (num) { - if ((byte)str[0] == casei) { - // Found the case, adjust str pointer and continue - str += 3; - break; + case SCC_SETCASE: { // {SETCASE} + // This is a pseudo command, it's outputted when someone does {STRING.ack} + // The modifier is added to all subsequent GetStringWithArgs that accept the modifier. + modifier = (byte)*str++ << 24; + break; + } + + case SCC_SWITCH_CASE: { // {Used to implement case switching} + // <0x9E> + // Each LEN is printed using 2 bytes in big endian order. + uint num = (byte)*str++; + while (num) { + if ((byte)str[0] == casei) { + // Found the case, adjust str pointer and continue + str += 3; + break; + } + // Otherwise skip to the next case + str += 3 + (str[1] << 8) + str[2]; + num--; } - // Otherwise skip to the next case - str += 3 + (str[1] << 8) + str[2]; - num--; + break; } - break; - } - default: - if (buff != last) *buff++ = b; + default: + if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b); + break; } } *buff = '\0'; @@ -910,11 +926,12 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c static char *StationGetSpecialString(char *buff, int x, const char* last) { - if (x & 0x01) buff = strecpy(buff, "\x94", last); - if (x & 0x02) buff = strecpy(buff, "\x95", last); - if (x & 0x04) buff = strecpy(buff, "\x96", last); - if (x & 0x08) buff = strecpy(buff, "\x97", last); - if (x & 0x10) buff = strecpy(buff, "\x98", last); + if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN); + if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY); + if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS); + if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE); + if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP); + *buff = '\0'; return buff; } @@ -1122,7 +1139,7 @@ bool ReadLanguagePack(int lang_index) { char *lang = str_fmt("%s%s", _path.lang_dir, _dynlang.ent[lang_index].file); - lang_pack = ReadFileToMem(lang, &len, 100000); + lang_pack = ReadFileToMem(lang, &len, 200000); free(lang); } if (lang_pack == NULL) return false; @@ -1237,7 +1254,7 @@ void InitializeLanguagePacks(void) int fallback; LanguagePack hdr; FILE *in; - char *files[32]; + char *files[MAX_LANG]; const char* lang; lang = GetCurrentLocale("LC_MESSAGES"); -- cgit v1.2.3-54-g00ecf