From ee27bb497c0790d86da6025fa48034f01f36d6e0 Mon Sep 17 00:00:00 2001 From: Darkvater Date: Sat, 21 Oct 2006 23:31:34 +0000 Subject: [PATCH] (svn r6884) -Codechange: Add strict bounds checking in string formatting system. The last parameter should point to the end of the buffer (eg lastof(buf)) Courtesy of Tron. --- build_vehicle_gui.c | 4 +- console_cmds.c | 2 +- functions.h | 2 +- genworld_gui.c | 2 +- gfx.c | 20 ++-- graph_gui.c | 4 +- industry_gui.c | 4 +- main_gui.c | 4 +- misc.c | 4 +- misc_gui.c | 14 +-- network.c | 26 ++-- network_client.c | 4 +- network_data.h | 2 +- network_gui.c | 16 +-- network_server.c | 9 +- newgrf_text.c | 4 +- newgrf_text.h | 2 +- news_gui.c | 2 +- openttd.c | 12 +- order_cmd.c | 2 +- players.c | 10 +- screenshot.c | 2 +- station_gui.c | 4 +- string.c | 11 +- strings.c | 281 ++++++++++++++++++++++---------------------- strings.h | 2 +- texteff.c | 2 +- town_cmd.c | 4 +- town_gui.c | 4 +- train_gui.c | 4 +- vehicle.c | 2 +- vehicle_gui.c | 4 +- viewport.c | 2 +- 33 files changed, 240 insertions(+), 231 deletions(-) diff --git a/build_vehicle_gui.c b/build_vehicle_gui.c index ce7f91a83d..9fe1d97bc8 100644 --- a/build_vehicle_gui.c +++ b/build_vehicle_gui.c @@ -99,12 +99,12 @@ static int CDECL EngineNameSorter(const void *a, const void *b) if (va != last_engine[0]) { last_engine[0] = va; - GetString(last_name[0], GetCustomEngineName(va)); + GetString(last_name[0], GetCustomEngineName(va), lastof(last_name[0])); } if (vb != last_engine[1]) { last_engine[1] = vb; - GetString(last_name[1], GetCustomEngineName(vb)); + GetString(last_name[1], GetCustomEngineName(vb), lastof(last_name[1])); } r = strcmp(last_name[0], last_name[1]); // sort by name diff --git a/console_cmds.c b/console_cmds.c index aa7f44c847..ad0efb817d 100644 --- a/console_cmds.c +++ b/console_cmds.c @@ -1217,7 +1217,7 @@ DEF_CONSOLE_CMD(ConPlayers) if (!p->is_active) continue; - GetString(buffer, STR_00D1_DARK_BLUE + _player_colors[p->index]); + GetString(buffer, STR_00D1_DARK_BLUE + _player_colors[p->index], lastof(buffer)); IConsolePrintF(8, "#:%d(%s) Company Name: '%s' Year Founded: %d Money: %d Loan: %d Value: %" OTTD_PRINTF64 "d (T:%d, R:%d, P:%d, S:%d)", p->index + 1, buffer, _network_player_info[p->index].company_name, p->inaugurated_year, p->player_money, p->current_loan, CalculateCompanyValue(p), /* trains */ _network_player_info[p->index].num_vehicle[0], diff --git a/functions.h b/functions.h index a7237a778c..415f7a0cc5 100644 --- a/functions.h +++ b/functions.h @@ -140,7 +140,7 @@ void InitializeLandscapeVariables(bool only_constants); /* misc.c */ bool IsCustomName(StringID id); void DeleteName(StringID id); -char *GetName(int id, char *buff); +char *GetName(char *buff, StringID id, const char* last); // AllocateNameUnique also tests if the name used is not used anywere else // and if it is used, it returns an error. diff --git a/genworld_gui.c b/genworld_gui.c index 304540fc63..3cc7454328 100644 --- a/genworld_gui.c +++ b/genworld_gui.c @@ -284,7 +284,7 @@ void GenerateLandscapeWndProc(Window *w, WindowEvent *e) SetDParam(0, _heightmap_x); SetDParam(1, _heightmap_y); } - GetString(buffer, STR_HEIGHTMAP_SIZE); + GetString(buffer, STR_HEIGHTMAP_SIZE, lastof(buffer)); DrawStringRightAligned(326, 91, STR_HEIGHTMAP_SIZE, 0x10); DrawString( 12, 91, STR_HEIGHTMAP_NAME, 0x10); diff --git a/gfx.c b/gfx.c index 415ca517e0..d7b66f05d4 100644 --- a/gfx.c +++ b/gfx.c @@ -329,9 +329,9 @@ static int TruncateString(char *str, int maxw) return w; } -static inline int TruncateStringID(StringID src, char *dest, int maxw) +static inline int TruncateStringID(StringID src, char *dest, int maxw, const char* last) { - GetString(dest, src); + GetString(dest, src, last); return TruncateString(dest, maxw); } @@ -340,14 +340,14 @@ int DrawString(int x, int y, StringID str, uint16 color) { char buffer[512]; - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); return DoDrawString(buffer, x, y, color); } int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw) { char buffer[512]; - TruncateStringID(str, buffer, maxw); + TruncateStringID(str, buffer, maxw, lastof(buffer)); return DoDrawString(buffer, x, y, color); } @@ -357,7 +357,7 @@ int DrawStringRightAligned(int x, int y, StringID str, uint16 color) char buffer[512]; int w; - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); w = GetStringBoundingBox(buffer).width; DoDrawString(buffer, x - w, y, color); @@ -368,7 +368,7 @@ void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, u { char buffer[512]; - TruncateStringID(str, buffer, maxw); + TruncateStringID(str, buffer, maxw, lastof(buffer)); DoDrawString(buffer, x - GetStringBoundingBox(buffer).width, y, color); } @@ -384,7 +384,7 @@ int DrawStringCentered(int x, int y, StringID str, uint16 color) char buffer[512]; int w; - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); w = GetStringBoundingBox(buffer).width; DoDrawString(buffer, x - w / 2, y, color); @@ -395,7 +395,7 @@ int DrawStringCentered(int x, int y, StringID str, uint16 color) int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color) { char buffer[512]; - int w = TruncateStringID(str, buffer, xr - xl); + int w = TruncateStringID(str, buffer, xr - xl, lastof(buffer)); return DoDrawString(buffer, (xl + xr - w) / 2, y, color); } @@ -466,7 +466,7 @@ void DrawStringMultiCenter(int x, int y, StringID str, int maxw) const char *src; byte c; - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); tmp = FormatStringLinebreaks(buffer, maxw); num = GB(tmp, 0, 16); @@ -508,7 +508,7 @@ void DrawStringMultiLine(int x, int y, StringID str, int maxw) const char *src; byte c; - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); tmp = FormatStringLinebreaks(buffer, maxw); num = GB(tmp, 0, 16); diff --git a/graph_gui.c b/graph_gui.c index 5919e4505c..9502ba1cdd 100644 --- a/graph_gui.c +++ b/graph_gui.c @@ -1135,11 +1135,11 @@ static int CDECL SignNameSorter(const void *a, const void *b) const Sign *sign1 = *(const Sign**)b; char buf1[64]; - GetString(buf1, sign0->str); + GetString(buf1, sign0->str, lastof(buf1)); if (sign1 != _last_sign) { _last_sign = sign1; - GetString(_bufcache, sign1->str); + GetString(_bufcache, sign1->str, lastof(_bufcache)); } return strcmp(buf1, _bufcache); // sort by name diff --git a/industry_gui.c b/industry_gui.c index a5c9258bce..b97595e7f7 100644 --- a/industry_gui.c +++ b/industry_gui.c @@ -536,12 +536,12 @@ static int CDECL GeneralIndustrySorter(const void *a, const void *b) char buf1[96]; SetDParam(0, i->town->index); - GetString(buf1, STR_TOWN); + GetString(buf1, STR_TOWN, lastof(buf1)); if (j != _last_industry) { _last_industry = j; SetDParam(0, j->town->index); - GetString(_bufcache, STR_TOWN); + GetString(_bufcache, STR_TOWN, lastof(_bufcache)); } r = strcmp(buf1, _bufcache); } diff --git a/main_gui.c b/main_gui.c index 1a5cacbac8..5ddab1c814 100644 --- a/main_gui.c +++ b/main_gui.c @@ -658,7 +658,7 @@ static int GetStringListMaxWidth(StringID base_string, byte count) max_width = 0; for (i = 0; i != count; i++) { - GetString(buffer, base_string + i); + GetString(buffer, base_string + i, lastof(buffer)); width = GetStringBoundingBox(buffer).width; if (width > max_width) max_width = width; } @@ -2108,7 +2108,7 @@ static bool DrawScrollingStatusText(const NewsItem *ni, int pos) str = ni->string_id; } - GetString(buf, str); + GetString(buf, str, lastof(buf)); s = buf; d = buffer; diff --git a/misc.c b/misc.c index 80ef97c725..4d60dfdf18 100644 --- a/misc.c +++ b/misc.c @@ -162,9 +162,9 @@ void DeleteName(StringID id) } } -char *GetName(int id, char *buff) +char *GetName(char *buff, StringID id, const char* last) { - return strecpy(buff, _name_array[id & ~0x600], NULL); + return strecpy(buff, _name_array[id & ~0x600], last); } diff --git a/misc_gui.c b/misc_gui.c index 7df37a8d3a..eeebf6588d 100644 --- a/misc_gui.c +++ b/misc_gui.c @@ -92,7 +92,7 @@ static void LandInfoWndProc(Window *w, WindowEvent *e) { char buf[512]; - char *p = GetString(buf, STR_01CE_CARGO_ACCEPTED); + char *p = GetString(buf, STR_01CE_CARGO_ACCEPTED, lastof(buf)); bool found = false; for (i = 0; i < NUM_CARGO; ++i) { @@ -108,9 +108,9 @@ static void LandInfoWndProc(Window *w, WindowEvent *e) if (lid->ac[i] < 8) { SetDParam(0, lid->ac[i]); SetDParam(1, _cargoc.names_s[i]); - p = GetString(p, STR_01D1_8); + p = GetString(p, STR_01D1_8, lastof(buf)); } else { - p = GetString(p, _cargoc.names_s[i]); + p = GetString(p, _cargoc.names_s[i], lastof(buf)); } } } @@ -679,7 +679,7 @@ void GuiShowTooltipsWithArgs(StringID str, uint paramcount, const uint32 params[ if (str == STR_NULL || (paramcount != 0 && !_patches.measure_tooltip)) return; for (i = 0; i != paramcount; i++) SetDParam(i, params[i]); - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); br = GetStringBoundingBox(buffer); br.width += 6; br.height += 4; // increase slightly to have some space around the box @@ -1076,7 +1076,7 @@ void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, w = AllocateWindowDesc(&_query_string_desc); - GetString(_edit_str_buf, str); + GetString(_edit_str_buf, str, lastof(_edit_str_buf)); _edit_str_buf[realmaxlen-1] = '\0'; if (maxlen & 0x1000) { @@ -1311,7 +1311,7 @@ static void GenerateFileName(void) SetDParam(0, p->name_1); SetDParam(1, p->name_2); SetDParam(2, _date); - GetString(_edit_str_buf, STR_4004); + GetString(_edit_str_buf, STR_4004, lastof(_edit_str_buf)); } extern void StartupEngines(void); @@ -1777,7 +1777,7 @@ static void CheatsWndProc(Window *w, WindowEvent *e) /* Draw colored flag for change player cheat */ case STR_CHEAT_CHANGE_PLAYER: SetDParam(0, val); - GetString(buf, STR_CHEAT_CHANGE_PLAYER); + GetString(buf, STR_CHEAT_CHANGE_PLAYER, lastof(buf)); DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2); break; /* Set correct string for switch climate cheat */ diff --git a/network.c b/network.c index 4388dc3493..5742eb045a 100644 --- a/network.c +++ b/network.c @@ -131,54 +131,54 @@ void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send switch (action) { case NETWORK_ACTION_JOIN: - GetString(temp, STR_NETWORK_CLIENT_JOINED); + GetString(temp, STR_NETWORK_CLIENT_JOINED, lastof(temp)); snprintf(message, sizeof(message), "*** %s %s", name, temp); break; case NETWORK_ACTION_LEAVE: - GetString(temp, STR_NETWORK_ERR_LEFT); + GetString(temp, STR_NETWORK_ERR_LEFT, lastof(temp)); snprintf(message, sizeof(message), "*** %s %s (%s)", name, temp, buf); break; case NETWORK_ACTION_GIVE_MONEY: if (self_send) { SetDParamStr(0, name); SetDParam(1, atoi(buf)); - GetString(temp, STR_NETWORK_GAVE_MONEY_AWAY); + GetString(temp, STR_NETWORK_GAVE_MONEY_AWAY, lastof(temp)); snprintf(message, sizeof(message), "*** %s", temp); } else { SetDParam(0, atoi(buf)); - GetString(temp, STR_NETWORK_GIVE_MONEY); + GetString(temp, STR_NETWORK_GIVE_MONEY, lastof(temp)); snprintf(message, sizeof(message), "*** %s %s", name, temp); } break; case NETWORK_ACTION_CHAT_COMPANY: if (self_send) { SetDParamStr(0, name); - GetString(temp, STR_NETWORK_CHAT_TO_COMPANY); + GetString(temp, STR_NETWORK_CHAT_TO_COMPANY, lastof(temp)); snprintf(message, sizeof(message), "%s %s", temp, buf); } else { SetDParamStr(0, name); - GetString(temp, STR_NETWORK_CHAT_COMPANY); + GetString(temp, STR_NETWORK_CHAT_COMPANY, lastof(temp)); snprintf(message, sizeof(message), "%s %s", temp, buf); } break; case NETWORK_ACTION_CHAT_CLIENT: if (self_send) { SetDParamStr(0, name); - GetString(temp, STR_NETWORK_CHAT_TO_CLIENT); + GetString(temp, STR_NETWORK_CHAT_TO_CLIENT, lastof(temp)); snprintf(message, sizeof(message), "%s %s", temp, buf); } else { SetDParamStr(0, name); - GetString(temp, STR_NETWORK_CHAT_CLIENT); + GetString(temp, STR_NETWORK_CHAT_CLIENT, lastof(temp)); snprintf(message, sizeof(message), "%s %s", temp, buf); } break; case NETWORK_ACTION_NAME_CHANGE: - GetString(temp, STR_NETWORK_NAME_CHANGE); + GetString(temp, STR_NETWORK_NAME_CHANGE, lastof(temp)); snprintf(message, sizeof(message), "*** %s %s %s", name, temp, buf); break; default: SetDParamStr(0, name); - GetString(temp, STR_NETWORK_CHAT_ALL); + GetString(temp, STR_NETWORK_CHAT_ALL, lastof(temp)); snprintf(message, sizeof(message), "%s %s", temp, buf); break; } @@ -260,7 +260,7 @@ static void NetworkClientError(NetworkRecvStatus res, NetworkClientState* cs) * @param buf buffer where the error message will be stored * @param err NetworkErrorCode * @return returns a pointer to the error message (buf) */ -char *GetNetworkErrorMsg(char *buf, NetworkErrorCode err) +char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last) { /* List of possible network errors, used by * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */ @@ -283,7 +283,7 @@ char *GetNetworkErrorMsg(char *buf, NetworkErrorCode err) if (err >= lengthof(network_error_strings)) err = 0; - return GetString(buf, network_error_strings[err]); + return GetString(buf, network_error_strings[err], last); } /* Count the number of active clients connected */ @@ -599,7 +599,7 @@ void NetworkCloseClient(NetworkClientState *cs) NetworkGetClientName(client_name, sizeof(client_name), cs); - GetNetworkErrorMsg(str, errorno); + GetNetworkErrorMsg(str, errorno, lastof(str)); NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str); diff --git a/network_client.c b/network_client.c index 6904298959..80dd45b94b 100644 --- a/network_client.c +++ b/network_client.c @@ -628,7 +628,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT) /* For speaking to player or give money, we need the player-name */ if (!IsValidPlayer(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY; // This should never happen - GetString(name, GetPlayer(ci_to->client_playas)->name_1); + GetString(name, GetPlayer(ci_to->client_playas)->name_1, lastof(name)); ci = NetworkFindClientInfoFromIndex(_network_own_client_index); break; default: @@ -654,7 +654,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT) NetworkClientInfo *ci; index = NetworkRecv_uint16(MY_CLIENT, p); - GetNetworkErrorMsg(str, NetworkRecv_uint8(MY_CLIENT, p)); + GetNetworkErrorMsg(str, NetworkRecv_uint8(MY_CLIENT, p), lastof(str)); ci = NetworkFindClientInfoFromIndex(index); if (ci != NULL) { diff --git a/network_data.h b/network_data.h index 75259e9a6d..40a2b57045 100644 --- a/network_data.h +++ b/network_data.h @@ -230,7 +230,7 @@ NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index); NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip); NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index); unsigned long NetworkResolveHost(const char *hostname); -char *GetNetworkErrorMsg(char *buf, NetworkErrorCode err); +char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last); #endif /* ENABLE_NETWORK */ diff --git a/network_gui.c b/network_gui.c index 0e45846a30..d200f4da4e 100644 --- a/network_gui.c +++ b/network_gui.c @@ -1181,36 +1181,36 @@ static Window *PopupClientList(Window *w, int client_no, int x, int y) i = 0; if (_network_own_client_index != ci->client_index) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT); + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i])); _clientlist_proc[i++] = &ClientList_SpeakToClient; } if (IsValidPlayer(ci->client_playas)) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY); + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i])); _clientlist_proc[i++] = &ClientList_SpeakToCompany; } - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL); + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i])); _clientlist_proc[i++] = &ClientList_SpeakToAll; if (_network_own_client_index != ci->client_index) { /* We are no spectator and the player we want to give money to is no spectator */ if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas)) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY); + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i])); _clientlist_proc[i++] = &ClientList_GiveMoney; } } // A server can kick clients (but not himself) if (_network_server && _network_own_client_index != ci->client_index) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK); + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i])); _clientlist_proc[i++] = &ClientList_Kick; - sprintf(_clientlist_action[i],"Ban"); + sprintf(_clientlist_action[i],"Ban"); // XXX GetString? _clientlist_proc[i++] = &ClientList_Ban; } if (i == 0) { - GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE); + GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i])); _clientlist_proc[i++] = &ClientList_None; } @@ -1511,7 +1511,7 @@ static const char *ChatTabCompletionNextItem(uint *item) FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) { /* Get the town-name via the string-system */ SetDParam(0, t->townnameparts); - GetString(chat_tab_temp_buffer, t->townnametype); + GetString(chat_tab_temp_buffer, t->townnametype, lastof(chat_tab_temp_buffer)); return &chat_tab_temp_buffer[0]; } } diff --git a/network_server.c b/network_server.c index 714daf9ccb..f8e4b61c8c 100644 --- a/network_server.c +++ b/network_server.c @@ -3,6 +3,7 @@ #ifdef ENABLE_NETWORK #include "stdafx.h" +#include "openttd.h" // XXX StringID #include "debug.h" #include "string.h" #include "strings.h" @@ -144,7 +145,7 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, Netwo NetworkSend_uint8(p, error); NetworkSend_Packet(p, cs); - GetNetworkErrorMsg(str, error); + GetNetworkErrorMsg(str, error, lastof(str)); // Only send when the current client was in game if (cs->status > STATUS_AUTH) { @@ -899,7 +900,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR) NetworkGetClientName(client_name, sizeof(client_name), cs); - GetNetworkErrorMsg(str, errorno); + GetNetworkErrorMsg(str, errorno, lastof(str)); DEBUG(net, 2)("[NET] %s reported an error and is closing his connection (%s)", client_name, str); @@ -1043,7 +1044,7 @@ void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, if (ci != NULL && show_local) { if (from_index == NETWORK_SERVER_INDEX) { char name[NETWORK_NAME_LENGTH]; - GetString(name, GetPlayer(ci_to->client_playas)->name_1); + GetString(name, GetPlayer(ci_to->client_playas)->name_1, lastof(name)); NetworkTextMessage(action, GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg); } else { FOR_ALL_CLIENTS(cs) { @@ -1211,7 +1212,7 @@ void NetworkPopulateCompanyInfo(void) // Grap the company name SetDParam(0, p->name_1); SetDParam(1, p->name_2); - GetString(_network_player_info[p->index].company_name, STR_JUST_STRING); + GetString(_network_player_info[p->index].company_name, STR_JUST_STRING, lastof(_network_player_info[p->index].company_name)); // Check the income if (_cur_year - 1 == p->inaugurated_year) { diff --git a/newgrf_text.c b/newgrf_text.c index 0c576f0064..d89475f960 100644 --- a/newgrf_text.c +++ b/newgrf_text.c @@ -292,7 +292,7 @@ StringID GetGRFStringID(uint32 grfid, uint16 stringid) } -char *GetGRFString(char *buff, uint16 stringid) +char *GetGRFString(char *buff, uint16 stringid, const char* last) { const GRFText *default_text = NULL; const GRFText *search_text; @@ -319,7 +319,7 @@ char *GetGRFString(char *buff, uint16 stringid) if (default_text != NULL) return strecpy(buff, default_text->text, NULL); /* Use the default string ID if the fallback string isn't available */ - return GetString(buff, _grf_text[stringid].def_string); + return GetString(buff, _grf_text[stringid].def_string, last); } /** diff --git a/newgrf_text.h b/newgrf_text.h index d5b787a8cd..62dc3c4730 100644 --- a/newgrf_text.h +++ b/newgrf_text.h @@ -8,7 +8,7 @@ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid, bool new_scheme, const char *text_to_add, StringID def_string); StringID GetGRFStringID(uint32 grfid, uint16 stringid); -char *GetGRFString(char *buff, uint16 stringid); +char *GetGRFString(char *buff, uint16 stringid, const char* last); void CleanUpStrings(void); void SetCurrentGrfLangID(const char *iso_name); diff --git a/news_gui.c b/news_gui.c index fa56a6ea04..4980091088 100644 --- a/news_gui.c +++ b/news_gui.c @@ -579,7 +579,7 @@ static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint str = ni->string_id; } - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); /* Copy the just gotten string to another buffer to remove any formatting * from it such as big fonts, etc. */ for (ptr = buffer, dest = buffer2; *ptr != '\0'; ptr++) { diff --git a/openttd.c b/openttd.c index ba7cddcd51..cd28d9697f 100644 --- a/openttd.c +++ b/openttd.c @@ -17,6 +17,7 @@ #include "functions.h" #include "mixer.h" #include "spritecache.h" +#include "strings.h" #include "gfx.h" #include "gfxinit.h" #include "gui.h" @@ -878,16 +879,17 @@ static void DoAutosave(void) if (_patches.keep_all_autosave && _local_player != PLAYER_SPECTATOR) { const Player *p = GetPlayer(_local_player); - char *s; - sprintf(buf, "%s%s", _path.autosave_dir, PATHSEP); + char* s = buf; + + s += snprintf(buf, lengthof(buf), "%s%s", _path.autosave_dir, PATHSEP); SetDParam(0, p->name_1); SetDParam(1, p->name_2); SetDParam(2, _date); - s = GetString(buf + strlen(_path.autosave_dir) + strlen(PATHSEP), STR_4004); - strcpy(s, ".sav"); + s = GetString(s, STR_4004, lastof(buf)); + strecpy(s, ".sav", lastof(buf)); } else { /* generate a savegame name and number according to _patches.max_num_autosaves */ - sprintf(buf, "%s%sautosave%d.sav", _path.autosave_dir, PATHSEP, _autosave_ctr); + snprintf(buf, lengthof(buf), "%s%sautosave%d.sav", _path.autosave_dir, PATHSEP, _autosave_ctr); _autosave_ctr++; if (_autosave_ctr >= _patches.max_num_autosaves) { diff --git a/order_cmd.c b/order_cmd.c index 8614bb6390..3d79daf2ee 100644 --- a/order_cmd.c +++ b/order_cmd.c @@ -826,7 +826,7 @@ void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak) if (!IsCustomName(v->string_id)) { bak->name[0] = '\0'; } else { - GetName(v->string_id & 0x7FF, bak->name); + GetName(bak->name, v->string_id & 0x7FF, lastof(bak->name)); } /* If we have shared orders, store it on a special way */ diff --git a/players.c b/players.c index d343f43aae..89c0f469dd 100644 --- a/players.c +++ b/players.c @@ -331,7 +331,7 @@ verify_name:; if (pp->name_1 == str && pp->name_2 == strp) goto bad_town_name; } - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 150) goto bad_town_name; @@ -438,14 +438,14 @@ restart:; p->president_name_1 = SPECSTR_PRESIDENT_NAME; SetDParam(0, p->president_name_2); - GetString(buffer, p->president_name_1); + GetString(buffer, p->president_name_1, lastof(buffer)); if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 94) continue; FOR_ALL_PLAYERS(pp) { if (pp->is_active && p != pp) { SetDParam(0, pp->president_name_2); - GetString(buffer2, pp->president_name_1); + GetString(buffer2, pp->president_name_1, lastof(buffer)); if (strcmp(buffer2, buffer) == 0) goto restart; } @@ -998,7 +998,7 @@ int8 SaveHighScoreValue(const Player *p) SetDParam(1, p->president_name_2); SetDParam(2, p->name_1); SetDParam(3, p->name_2); - GetString(hs[i].company, STR_HIGHSCORE_NAME); // get manager/company name string + GetString(hs[i].company, STR_HIGHSCORE_NAME, lastof(hs[i].company)); // get manager/company name string hs[i].score = score; hs[i].title = EndGameGetPerformanceTitleFromValue(score); return i; @@ -1043,7 +1043,7 @@ int8 SaveHighScoreValueNetwork(void) SetDParam(1, pl[i]->president_name_2); SetDParam(2, pl[i]->name_1); SetDParam(3, pl[i]->name_2); - GetString(hs->company, STR_HIGHSCORE_NAME); // get manager/company name string + GetString(hs->company, STR_HIGHSCORE_NAME, lastof(hs->company)); // get manager/company name string hs->score = pl[i]->old_economy[0].performance_history; hs->title = EndGameGetPerformanceTitleFromValue(hs->score); diff --git a/screenshot.c b/screenshot.c index 8d5bc718d3..82124ba6da 100644 --- a/screenshot.c +++ b/screenshot.c @@ -504,7 +504,7 @@ static char *MakeScreenshotName(const char *ext) SetDParam(0, p->name_1); SetDParam(1, p->name_2); SetDParam(2, _date); - GetString(_screenshot_name, STR_4004); + GetString(_screenshot_name, STR_4004, lastof(_screenshot_name)); } base = strchr(_screenshot_name, 0); diff --git a/station_gui.c b/station_gui.c index a28a54393c..4ae747172b 100644 --- a/station_gui.c +++ b/station_gui.c @@ -81,12 +81,12 @@ static int CDECL StationNameSorter(const void *a, const void *b) int r; SetDParam(0, st1->index); - GetString(buf1, STR_STATION); + GetString(buf1, STR_STATION, lastof(buf1)); if (st2 != _last_station) { _last_station = st2; SetDParam(0, st2->index); - GetString(_bufcache, STR_STATION); + GetString(_bufcache, STR_STATION, lastof(_bufcache)); } r = strcmp(buf1, _bufcache); // sort by name diff --git a/string.c b/string.c index a0e6b42a64..50625c2fbf 100644 --- a/string.c +++ b/string.c @@ -1,6 +1,8 @@ /* $Id$ */ #include "stdafx.h" +#include "openttd.h" +#include "functions.h" #include "string.h" #include @@ -26,7 +28,7 @@ void ttd_strlcpy(char *dst, const char *src, size_t size) char* strecat(char* dst, const char* src, const char* last) { - assert(last == NULL || dst <= last); + assert(dst <= last); for (; *dst != '\0'; ++dst) if (dst == last) return dst; for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src; @@ -37,9 +39,14 @@ char* strecat(char* dst, const char* src, const char* last) char* strecpy(char* dst, const char* src, const char* last) { - assert(last == NULL || dst <= last); + assert(dst <= last); for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src; *dst = '\0'; +#if 0 + if (dst == last && *src != '\0') { + error("String too long for destination buffer"); + } +#endif return dst; } diff --git a/strings.c b/strings.c index ead83f84f8..71e330bfea 100644 --- a/strings.c +++ b/strings.c @@ -31,11 +31,11 @@ char _userstring[128]; -static char *StationGetSpecialString(char *buff, int x); -static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed); -static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv); +static char *StationGetSpecialString(char *buff, int x, const char* last); +static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last); +static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last); -static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei); +static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei, const char* last); typedef struct LanguagePack { uint32 ident; @@ -166,7 +166,7 @@ static const char *GetStringPtr(StringID string) // These 8 bits will only be set when FormatString wants to print // the string in a different case. No one else except FormatString // should set those bits, therefore string CANNOT be StringID, but uint32. -static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv) +static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv, const char* last) { uint index = GB(string, 0, 11); uint tab = GB(string, 11, 5); @@ -177,46 +177,46 @@ static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv) switch (tab) { case 4: if (index >= 0xC0) - return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv)); + return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last); break; case 14: if (index >= 0xE4) - return GetSpecialPlayerNameString(buffr, index - 0xE4, argv); + return GetSpecialPlayerNameString(buffr, index - 0xE4, argv, last); break; // User defined name case 15: - return GetName(index, buffr); + return GetName(buffr, index, last); case 26: /* Include string within newgrf text (format code 81) */ if (HASBIT(index, 10)) { StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10)); - return GetStringWithArgs(buffr, string, argv); + return GetStringWithArgs(buffr, string, argv, last); } break; case 28: - GetGRFString(buff, index); - return FormatString(buffr, buff, argv, 0); + GetGRFString(buff, index, last); + return FormatString(buffr, buff, argv, 0, last); case 29: - GetGRFString(buff, index + 0x800); - return FormatString(buffr, buff, argv, 0); + GetGRFString(buff, index + 0x800, last); + return FormatString(buffr, buff, argv, 0, last); case 30: - GetGRFString(buff, index + 0x1000); - return FormatString(buffr, buff, argv, 0); + GetGRFString(buff, index + 0x1000, last); + return FormatString(buffr, buff, argv, 0, last); case 31: // dynamic strings. These are NOT to be passed through the formatter, // but passed through verbatim. if (index < (STR_SPEC_USERSTRING & 0x7FF)) { - return strecpy(buffr, _bound_strings[index], NULL); + return strecpy(buffr, _bound_strings[index], last); } - return FormatString(buffr, _userstring, NULL, 0); + return FormatString(buffr, _userstring, NULL, 0, last); } if (index >= _langtab_num[tab]) { @@ -226,12 +226,12 @@ static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv) ); } - return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, GB(string, 24, 8)); + return FormatString(buffr, GetStringPtr(GB(string, 0, 16)), argv, GB(string, 24, 8), last); } -char *GetString(char *buffr, StringID string) +char *GetString(char *buffr, StringID string, const char* last) { - return GetStringWithArgs(buffr, string, (int32*)_decode_parameters); + return GetStringWithArgs(buffr, string, (int32*)_decode_parameters, last); } @@ -270,7 +270,8 @@ static const uint32 _divisor_table[] = { 1 }; -static char *FormatCommaNumber(char *buff, int32 number) +// TODO +static char *FormatCommaNumber(char *buff, int32 number, const char* last) { uint32 quot,divisor; int i; @@ -303,7 +304,8 @@ static char *FormatCommaNumber(char *buff, int32 number) return buff; } -static char *FormatNoCommaNumber(char *buff, int32 number) +// TODO +static char *FormatNoCommaNumber(char *buff, int32 number, const char* last) { uint32 quot,divisor; int i; @@ -311,7 +313,7 @@ static char *FormatNoCommaNumber(char *buff, int32 number) uint32 num; if (number < 0) { - *buff++ = '-'; + buff = strecpy(buff, "-", last); number = -number; } @@ -336,50 +338,50 @@ static char *FormatNoCommaNumber(char *buff, int32 number) } -static char *FormatYmdString(char *buff, Date date) +static char *FormatYmdString(char *buff, Date date, const char* last) { - const char *src; YearMonthDay ymd; ConvertDateToYMD(date, &ymd); - for (src = GetStringPtr(ymd.day + STR_01AC_1ST - 1); (*buff++ = *src++) != '\0';) {} - buff[-1] = ' '; + buff = strecpy(buff, GetStringPtr(ymd.day + STR_01AC_1ST - 1), last); + buff = strecpy(buff, " ", last); + buff = strecpy(buff, GetStringPtr(STR_0162_JAN + ymd.month), last); + buff = strecpy(buff, " ", last); - for (src = GetStringPtr(STR_0162_JAN + ymd.month); (*buff++ = *src++) != '\0';) {} - buff[-1] = ' '; - - return FormatNoCommaNumber(buff, ymd.year); + return FormatNoCommaNumber(buff, ymd.year, last); } -static char *FormatMonthAndYear(char *buff, Date date) +static char *FormatMonthAndYear(char *buff, Date date, const char* last) { - const char *src; YearMonthDay ymd; ConvertDateToYMD(date, &ymd); - for (src = GetStringPtr(STR_MONTH_JAN + ymd.month); (*buff++ = *src++) != '\0';) {} - buff[-1] = ' '; + buff = strecpy(buff, GetStringPtr(STR_MONTH_JAN + ymd.month), last); + buff = strecpy(buff, " ", last); - return FormatNoCommaNumber(buff, ymd.year); + return FormatNoCommaNumber(buff, ymd.year, last); } -static char *FormatTinyDate(char *buff, Date date) +static char *FormatTinyDate(char *buff, Date date, const char* last) { YearMonthDay ymd; ConvertDateToYMD(date, &ymd); - buff += sprintf(buff, " %02i-%02i-%04i", ymd.day, ymd.month + 1, ymd.year); + buff += snprintf( + buff, last - buff + 1, + " %02i-%02i-%04i", ymd.day, ymd.month + 1, ymd.year + ); return buff; } -static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, int64 number, bool compact) +static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, int64 number, bool compact, const char* last) { - const char *s; - char c; - char buf[40], *p; + const char* multiplier = ""; + char buf[40]; + char* p; int j; // multiply by exchange rate @@ -387,51 +389,45 @@ static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, int64 n // convert from negative if (number < 0) { - *buff++ = '-'; + buff = strecpy(buff, "-", last); number = -number; } /* Add prefix part, folowing symbol_pos specification. * Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix). * The only remaining value is 1 (suffix), so everything that is not 1 */ - if (spec->symbol_pos != 1){ - s = spec->prefix; - while (s != spec->prefix + lengthof(spec->prefix) && (c = *(s++)) != '\0') *(buff)++ = c; - } + if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last); // for huge numbers, compact the number into k or M if (compact) { - compact = 0; if (number >= 1000000000) { number = (number + 500000) / 1000000; - compact = 'M'; + multiplier = "M"; } else if (number >= 1000000) { number = (number + 500) / 1000; - compact = 'k'; + multiplier = "k"; } } // convert to ascii number and add commas - p = buf; + p = endof(buf); + *--p = '\0'; j = 4; do { if (--j == 0) { - *p++ = spec->separator; + *--p = spec->separator; j = 3; } - *p++ = '0' + number % 10; - } while (number /= 10); - do *buff++ = *--p; while (p != buf); + *--p = '0' + number % 10; + } while ((number /= 10) != 0); + buff = strecpy(buff, p, last); - if (compact) *buff++ = compact; + buff = strecpy(buff, multiplier, last); /* Add suffix part, folowing symbol_pos specification. * Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix). * The only remaining value is 1 (prefix), so everything that is not 0 */ - if (spec->symbol_pos != 0) { - s = spec->suffix; - while (s != spec->suffix + lengthof(spec->suffix) && (c = *(s++)) != '\0') *(buff++) = c; - } + if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last); return buff; } @@ -564,7 +560,7 @@ static const Units units[] = { }, }; -static char *FormatString(char *buff, const char *str, const int32 *argv, uint casei) +static char* FormatString(char* buff, const char* str, const int32* argv, uint casei, const char* last) { extern const char _openttd_revision[]; byte b; @@ -574,30 +570,34 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c while ((b = *str++) != '\0') { switch (b) { case 0x1: // {SETX} - *buff++ = b; - *buff++ = *str++; + if (buff != last && buff + 1 != last) { + *buff++ = b; + *buff++ = *str++; + } break; case 0x2: // {SETXY} - *buff++ = b; - *buff++ = *str++; - *buff++ = *str++; + if (buff != last && buff + 1 != last && buff + 2 != last) { + *buff++ = b; + *buff++ = *str++; + *buff++ = *str++; + } break; case 0x81: // {STRINL} - buff = GetStringWithArgs(buff, ReadLE16Unaligned(str), argv); + buff = GetStringWithArgs(buff, ReadLE16Unaligned(str), argv, last); str += 2; break; case 0x82: // {DATE_LONG} - buff = FormatYmdString(buff, GetInt32(&argv)); + buff = FormatYmdString(buff, GetInt32(&argv), last); break; case 0x83: // {DATE_SHORT} - buff = FormatMonthAndYear(buff, GetInt32(&argv)); + 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); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last); modifier = 0; break; } @@ -605,10 +605,10 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c case 0x85: switch (*str++) { case 0: /* {CURRCOMPACT} */ - buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true); + buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last); break; case 2: /* {REV} */ - buff = strecpy(buff, _openttd_revision, NULL); + buff = strecpy(buff, _openttd_revision, last); break; case 3: { /* {SHORTCARGO} */ // Short description of cargotypes. Layout: @@ -620,7 +620,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last); modifier = 0; break; } @@ -629,61 +629,61 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last); modifier = 0; break; } default: - buff = FormatCommaNumber(buff, GetInt32(&argv)); - buff = strecpy(buff, " ", NULL); - buff = strecpy(buff, GetStringPtr(cargo_str), NULL); + buff = FormatCommaNumber(buff, GetInt32(&argv), last); + buff = strecpy(buff, " ", last); + buff = strecpy(buff, GetStringPtr(cargo_str), last); break; } } break; case 4: {/* {CURRCOMPACT64} */ // 64 bit compact currency-unit - buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true); + buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last); break; } case 5: { /* {STRING1} */ // String that consumes ONE argument uint str = modifier + GetInt32(&argv); - buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1)); + buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last); modifier = 0; break; } case 6: { /* {STRING2} */ // String that consumes TWO arguments uint str = modifier + GetInt32(&argv); - buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2)); + buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last); modifier = 0; break; } case 7: { /* {STRING3} */ // String that consumes THREE arguments uint str = modifier + GetInt32(&argv); - buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3)); + buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last); modifier = 0; break; } case 8: { /* {STRING4} */ // String that consumes FOUR arguments uint str = modifier + GetInt32(&argv); - buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4)); + buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last); modifier = 0; break; } case 9: { /* {STRING5} */ // String that consumes FIVE arguments uint str = modifier + GetInt32(&argv); - buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5)); + buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last); modifier = 0; break; } case 10: { /* {STATIONFEATURES} */ - buff = StationGetSpecialString(buff, GetInt32(&argv)); + buff = StationGetSpecialString(buff, GetInt32(&argv), last); break; } @@ -698,7 +698,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c // The string STR_INDUSTRY_PATTERN controls the formatting args[0] = i->town->index; args[1] = i->type + STR_4802_COAL_MINE; - buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(STR_INDUSTRY_FORMAT), args, modifier >> 24, last); modifier = 0; break; } @@ -707,7 +707,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_volume), args, modifier >> 24, last); modifier = 0; break; } @@ -723,7 +723,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c } case 14: { // {DATE_TINY} - buff = FormatTinyDate(buff, GetInt32(&argv)); + buff = FormatTinyDate(buff, GetInt32(&argv), last); break; } @@ -733,7 +733,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c // 16-bit - cargo count CargoID cargo = GetInt32(&argv); StringID cargo_str = (cargo == CT_INVALID) ? STR_8838_N_A : _cargoc.names_long[cargo]; - buff = GetStringWithArgs(buff, cargo_str, argv++); + buff = GetStringWithArgs(buff, cargo_str, argv++, last); break; } @@ -741,7 +741,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].power), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].power), args, modifier >> 24, last); modifier = 0; break; } @@ -750,7 +750,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_volume), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_volume), args, modifier >> 24, last); modifier = 0; break; } @@ -759,7 +759,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].l_weight), args, modifier >> 24, last); modifier = 0; break; } @@ -768,7 +768,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_weight), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].s_weight), args, modifier >> 24, last); modifier = 0; break; } @@ -777,7 +777,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c 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; - buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].force), args, modifier >> 24); + buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].force), args, modifier >> 24, last); modifier = 0; break; } @@ -802,13 +802,13 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c // 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); + buff = GetStringWithArgs(buff, str, argv, last); modifier = 0; break; } case 0x8B: // {COMMA} - buff = FormatCommaNumber(buff, GetInt32(&argv)); + buff = FormatCommaNumber(buff, GetInt32(&argv), last); break; case 0x8C: // Move argument pointer @@ -824,11 +824,11 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c } case 0x8E: // {NUM} - buff = FormatNoCommaNumber(buff, GetInt32(&argv)); + buff = FormatNoCommaNumber(buff, GetInt32(&argv), last); break; case 0x8F: // {CURRENCY} - buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false); + buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last); break; case 0x99: { // {WAYPOINT} @@ -842,20 +842,20 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c temp[1] = wp->town_cn + 1; str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL; } - buff = GetStringWithArgs(buff, str, temp); + buff = GetStringWithArgs(buff, str, temp, last); } break; case 0x9A: { // {STATION} const Station* st = GetStation(GetInt32(&argv)); - int32 temp[2]; if (!IsValidStation(st)) { // station doesn't exist anymore - buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL); - break; + 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); } - temp[0] = st->town->townnametype; - temp[1] = st->town->townnameparts; - buff = GetStringWithArgs(buff, st->string_id, temp); break; } case 0x9B: { // {TOWN} @@ -865,12 +865,12 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c assert(IsValidTown(t)); temp[0] = t->townnameparts; - buff = GetStringWithArgs(buff, t->townnametype, temp); + buff = GetStringWithArgs(buff, t->townnametype, temp, last); break; } case 0x9C: { // {CURRENCY64} - buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false); + buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last); break; } @@ -899,7 +899,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c } default: - *buff++ = b; + if (buff != last) *buff++ = b; } } *buff = '\0'; @@ -907,23 +907,22 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c } -static char *StationGetSpecialString(char *buff, int x) +static char *StationGetSpecialString(char *buff, int x, const char* last) { - if (x & 0x01) *buff++ = '\x94'; - if (x & 0x02) *buff++ = '\x95'; - if (x & 0x04) *buff++ = '\x96'; - if (x & 0x08) *buff++ = '\x97'; - if (x & 0x10) *buff++ = '\x98'; - *buff = '\0'; + 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); return buff; } -static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed) +static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last) { - _town_name_generators[ind](buff, seed); + char name[512]; - while (*buff != '\0') buff++; - return buff; + _town_name_generators[ind](name, seed); // TODO + return strecpy(buff, name, last); } static const char* const _silly_company_names[] = { @@ -994,7 +993,7 @@ static const char _initial_name_letters[] = { 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', }; -static char *GenAndCoName(char *buff, uint32 arg) +static char *GenAndCoName(char *buff, uint32 arg, const char* last) { const char* const* base; uint num; @@ -1007,29 +1006,26 @@ static char *GenAndCoName(char *buff, uint32 arg) num = lengthof(_surname_list); } - buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], NULL); - buff = strecpy(buff, " & Co.", NULL); + buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last); + buff = strecpy(buff, " & Co.", last); return buff; } -static char *GenPresidentName(char *buff, uint32 x) +static char *GenPresidentName(char *buff, uint32 x, const char* last) { + char initial[] = "?. "; const char* const* base; uint num; uint i; - buff[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8]; - buff[1] = '.'; - buff[2] = ' '; // Insert a space after initial and period "I. Firstname" instead of "I.Firstname" - buff += 3; + initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8]; + buff = strecpy(buff, initial, last); i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8; if (i < sizeof(_initial_name_letters)) { - buff[0] = _initial_name_letters[i]; - buff[1] = '.'; - buff[2] = ' '; // Insert a space after initial and period "I. J. Firstname" instead of "I.J.Firstname" - buff += 3; + initial[0] = _initial_name_letters[i]; + buff = strecpy(buff, initial, last); } if (_opt_ptr->landscape == LT_CANDY) { @@ -1040,50 +1036,53 @@ static char *GenPresidentName(char *buff, uint32 x) num = lengthof(_surname_list); } - buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], NULL); + buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last); return buff; } -static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv) +static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv, const char* last) { switch (ind) { case 1: // not used - return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], NULL); + return strecpy(buff, _silly_company_names[GetInt32(&argv) & 0xFFFF], last); case 2: // used for Foobar & Co company names - return GenAndCoName(buff, GetInt32(&argv)); + return GenAndCoName(buff, GetInt32(&argv), last); case 3: // President name - return GenPresidentName(buff, GetInt32(&argv)); + return GenPresidentName(buff, GetInt32(&argv), last); case 4: // song names - return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, NULL); + return strecpy(buff, origin_songs_specs[GetInt32(&argv) - 1].song_name, last); } // town name? if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) { - buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv)); - return strecpy(buff, " Transport", NULL); + buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last); + return strecpy(buff, " Transport", last); } // language name? if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) { int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4); return strecpy(buff, - i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, NULL); + i == _dynlang.curr ? _langpack->own_name : _dynlang.ent[i].name, last); } // resolution size? if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) { int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4); - return buff + sprintf(buff, "%dx%d", _resolutions[i][0], _resolutions[i][1]); + buff += snprintf( + buff, last - buff + 1, "%dx%d", _resolutions[i][0], _resolutions[i][1] + ); + return buff; } // screenshot format name? if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) { int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4); - return strecpy(buff, GetScreenshotFormatDesc(i), NULL); + return strecpy(buff, GetScreenshotFormatDesc(i), last); } assert(0); diff --git a/strings.h b/strings.h index 8194fc9589..0aa105545f 100644 --- a/strings.h +++ b/strings.h @@ -11,7 +11,7 @@ static inline char* InlineString(char* buf, uint16 string) return buf; } -char *GetString(char *buffr, uint16 string); +char *GetString(char *buffr, uint16 string, const char* last); extern char _userstring[128]; diff --git a/texteff.c b/texteff.c index 982b964a90..cd1d0a9d34 100644 --- a/texteff.c +++ b/texteff.c @@ -246,7 +246,7 @@ void AddTextEffect(StringID msg, int x, int y, uint16 duration) te->params_1 = GetDParam(0); te->params_2 = GetDParam(4); - GetString(buffer, msg); + GetString(buffer, msg, lastof(buffer)); w = GetStringBoundingBox(buffer).width; te->x = x - (w >> 1); diff --git a/town_cmd.c b/town_cmd.c index 981cdbfdeb..5ca064f9c3 100644 --- a/town_cmd.c +++ b/town_cmd.c @@ -886,7 +886,7 @@ restart: r = Random(); SetDParam(0, r); - GetString(buf1, townnametype); + GetString(buf1, townnametype, lastof(buf1)); // Check size and width if (strlen(buf1) >= 31 || GetStringBoundingBox(buf1).width > 130) continue; @@ -895,7 +895,7 @@ restart: // We can't just compare the numbers since // several numbers may map to a single name. SetDParam(0, t2->index); - GetString(buf2, STR_TOWN); + GetString(buf2, STR_TOWN, lastof(buf2)); if (strcmp(buf1, buf2) == 0) { if (tries-- < 0) return false; goto restart; diff --git a/town_gui.c b/town_gui.c index e89b7da5fe..52020ca102 100644 --- a/town_gui.c +++ b/town_gui.c @@ -378,7 +378,7 @@ static int CDECL TownNameSorter(const void *a, const void *b) int r; SetDParam(0, ta->index); - GetString(buf1, STR_TOWN); + GetString(buf1, STR_TOWN, lastof(buf1)); /* If 'b' is the same town as in the last round, use the cached value * We do this to speed stuff up ('b' is called with the same value a lot of @@ -386,7 +386,7 @@ static int CDECL TownNameSorter(const void *a, const void *b) if (tb != _last_town) { _last_town = tb; SetDParam(0, tb->index); - GetString(_bufcache, STR_TOWN); + GetString(_bufcache, STR_TOWN, lastof(_bufcache)); } r = strcmp(buf1, _bufcache); diff --git a/train_gui.c b/train_gui.c index fc02c67924..1c52d719b4 100644 --- a/train_gui.c +++ b/train_gui.c @@ -135,13 +135,13 @@ static int CDECL TrainEngineNameSorter(const void *a, const void *b) char buf1[64]; int r; - GetString(buf1, GetCustomEngineName(va)); + GetString(buf1, GetCustomEngineName(va), lastof(buf1)); if (vb != _last_engine) { _last_engine = vb; _bufcache[0] = '\0'; - GetString(_bufcache, GetCustomEngineName(vb)); + GetString(_bufcache, GetCustomEngineName(vb), lastof(_bufcache)); } r = strcasecmp(buf1, _bufcache); // sort by name diff --git a/vehicle.c b/vehicle.c index bccc9a7753..c422682dc6 100644 --- a/vehicle.c +++ b/vehicle.c @@ -2076,7 +2076,7 @@ static int32 ReplaceVehicle(Vehicle **w, byte flags, int32 total_cost) if (!IsCustomName(old_v->string_id)) { vehicle_name[0] = '\0'; } else { - GetName(old_v->string_id & 0x7FF, vehicle_name); + GetName(vehicle_name, old_v->string_id & 0x7FF, lastof(vehicle_name)); } } else { // flags & DC_EXEC not set /* Ensure that the player will not end up having negative money while autoreplacing diff --git a/vehicle_gui.c b/vehicle_gui.c index 1787bda489..9d8faa19a2 100644 --- a/vehicle_gui.c +++ b/vehicle_gui.c @@ -516,7 +516,7 @@ static int CDECL VehicleNameSorter(const void *a, const void *b) if (va != last_vehicle[0]) { last_vehicle[0] = va; if (IsCustomName(va->string_id)) { - GetString(last_name[0], va->string_id); + GetString(last_name[0], va->string_id, lastof(last_name[0])); } else { last_name[0][0] = '\0'; } @@ -525,7 +525,7 @@ static int CDECL VehicleNameSorter(const void *a, const void *b) if (vb != last_vehicle[1]) { last_vehicle[1] = vb; if (IsCustomName(vb->string_id)) { - GetString(last_name[1], vb->string_id); + GetString(last_name[1], vb->string_id, lastof(last_name[1])); } else { last_name[1][0] = '\0'; } diff --git a/viewport.c b/viewport.c index 337f0b1342..5738e0fef5 100644 --- a/viewport.c +++ b/viewport.c @@ -1017,7 +1017,7 @@ void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str) sign->top = top; - GetString(buffer, str); + GetString(buffer, str, lastof(buffer)); w = GetStringBoundingBox(buffer).width + 3; sign->width_1 = w; sign->left = left - w / 2;