(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.
This commit is contained in:
Darkvater 2006-10-21 23:31:34 +00:00
parent 7f36a980c7
commit ee27bb497c
33 changed files with 240 additions and 231 deletions

View File

@ -99,12 +99,12 @@ static int CDECL EngineNameSorter(const void *a, const void *b)
if (va != last_engine[0]) { if (va != last_engine[0]) {
last_engine[0] = va; 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]) { if (vb != last_engine[1]) {
last_engine[1] = vb; 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 r = strcmp(last_name[0], last_name[1]); // sort by name

View File

@ -1217,7 +1217,7 @@ DEF_CONSOLE_CMD(ConPlayers)
if (!p->is_active) continue; 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)", 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), 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], /* trains */ _network_player_info[p->index].num_vehicle[0],

View File

@ -140,7 +140,7 @@ void InitializeLandscapeVariables(bool only_constants);
/* misc.c */ /* misc.c */
bool IsCustomName(StringID id); bool IsCustomName(StringID id);
void DeleteName(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 // AllocateNameUnique also tests if the name used is not used anywere else
// and if it is used, it returns an error. // and if it is used, it returns an error.

View File

@ -284,7 +284,7 @@ void GenerateLandscapeWndProc(Window *w, WindowEvent *e)
SetDParam(0, _heightmap_x); SetDParam(0, _heightmap_x);
SetDParam(1, _heightmap_y); SetDParam(1, _heightmap_y);
} }
GetString(buffer, STR_HEIGHTMAP_SIZE); GetString(buffer, STR_HEIGHTMAP_SIZE, lastof(buffer));
DrawStringRightAligned(326, 91, STR_HEIGHTMAP_SIZE, 0x10); DrawStringRightAligned(326, 91, STR_HEIGHTMAP_SIZE, 0x10);
DrawString( 12, 91, STR_HEIGHTMAP_NAME, 0x10); DrawString( 12, 91, STR_HEIGHTMAP_NAME, 0x10);

20
gfx.c
View File

@ -329,9 +329,9 @@ static int TruncateString(char *str, int maxw)
return w; 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); return TruncateString(dest, maxw);
} }
@ -340,14 +340,14 @@ int DrawString(int x, int y, StringID str, uint16 color)
{ {
char buffer[512]; char buffer[512];
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
return DoDrawString(buffer, x, y, color); return DoDrawString(buffer, x, y, color);
} }
int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw) int DrawStringTruncated(int x, int y, StringID str, uint16 color, uint maxw)
{ {
char buffer[512]; char buffer[512];
TruncateStringID(str, buffer, maxw); TruncateStringID(str, buffer, maxw, lastof(buffer));
return DoDrawString(buffer, x, y, color); return DoDrawString(buffer, x, y, color);
} }
@ -357,7 +357,7 @@ int DrawStringRightAligned(int x, int y, StringID str, uint16 color)
char buffer[512]; char buffer[512];
int w; int w;
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
w = GetStringBoundingBox(buffer).width; w = GetStringBoundingBox(buffer).width;
DoDrawString(buffer, x - w, y, color); DoDrawString(buffer, x - w, y, color);
@ -368,7 +368,7 @@ void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, u
{ {
char buffer[512]; char buffer[512];
TruncateStringID(str, buffer, maxw); TruncateStringID(str, buffer, maxw, lastof(buffer));
DoDrawString(buffer, x - GetStringBoundingBox(buffer).width, y, color); 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]; char buffer[512];
int w; int w;
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
w = GetStringBoundingBox(buffer).width; w = GetStringBoundingBox(buffer).width;
DoDrawString(buffer, x - w / 2, y, color); 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) int DrawStringCenteredTruncated(int xl, int xr, int y, StringID str, uint16 color)
{ {
char buffer[512]; 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); 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; const char *src;
byte c; byte c;
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
tmp = FormatStringLinebreaks(buffer, maxw); tmp = FormatStringLinebreaks(buffer, maxw);
num = GB(tmp, 0, 16); num = GB(tmp, 0, 16);
@ -508,7 +508,7 @@ void DrawStringMultiLine(int x, int y, StringID str, int maxw)
const char *src; const char *src;
byte c; byte c;
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
tmp = FormatStringLinebreaks(buffer, maxw); tmp = FormatStringLinebreaks(buffer, maxw);
num = GB(tmp, 0, 16); num = GB(tmp, 0, 16);

View File

@ -1135,11 +1135,11 @@ static int CDECL SignNameSorter(const void *a, const void *b)
const Sign *sign1 = *(const Sign**)b; const Sign *sign1 = *(const Sign**)b;
char buf1[64]; char buf1[64];
GetString(buf1, sign0->str); GetString(buf1, sign0->str, lastof(buf1));
if (sign1 != _last_sign) { if (sign1 != _last_sign) {
_last_sign = sign1; _last_sign = sign1;
GetString(_bufcache, sign1->str); GetString(_bufcache, sign1->str, lastof(_bufcache));
} }
return strcmp(buf1, _bufcache); // sort by name return strcmp(buf1, _bufcache); // sort by name

View File

@ -536,12 +536,12 @@ static int CDECL GeneralIndustrySorter(const void *a, const void *b)
char buf1[96]; char buf1[96];
SetDParam(0, i->town->index); SetDParam(0, i->town->index);
GetString(buf1, STR_TOWN); GetString(buf1, STR_TOWN, lastof(buf1));
if (j != _last_industry) { if (j != _last_industry) {
_last_industry = j; _last_industry = j;
SetDParam(0, j->town->index); SetDParam(0, j->town->index);
GetString(_bufcache, STR_TOWN); GetString(_bufcache, STR_TOWN, lastof(_bufcache));
} }
r = strcmp(buf1, _bufcache); r = strcmp(buf1, _bufcache);
} }

View File

@ -658,7 +658,7 @@ static int GetStringListMaxWidth(StringID base_string, byte count)
max_width = 0; max_width = 0;
for (i = 0; i != count; i++) { for (i = 0; i != count; i++) {
GetString(buffer, base_string + i); GetString(buffer, base_string + i, lastof(buffer));
width = GetStringBoundingBox(buffer).width; width = GetStringBoundingBox(buffer).width;
if (width > max_width) max_width = width; if (width > max_width) max_width = width;
} }
@ -2108,7 +2108,7 @@ static bool DrawScrollingStatusText(const NewsItem *ni, int pos)
str = ni->string_id; str = ni->string_id;
} }
GetString(buf, str); GetString(buf, str, lastof(buf));
s = buf; s = buf;
d = buffer; d = buffer;

4
misc.c
View File

@ -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);
} }

View File

@ -92,7 +92,7 @@ static void LandInfoWndProc(Window *w, WindowEvent *e)
{ {
char buf[512]; char buf[512];
char *p = GetString(buf, STR_01CE_CARGO_ACCEPTED); char *p = GetString(buf, STR_01CE_CARGO_ACCEPTED, lastof(buf));
bool found = false; bool found = false;
for (i = 0; i < NUM_CARGO; ++i) { for (i = 0; i < NUM_CARGO; ++i) {
@ -108,9 +108,9 @@ static void LandInfoWndProc(Window *w, WindowEvent *e)
if (lid->ac[i] < 8) { if (lid->ac[i] < 8) {
SetDParam(0, lid->ac[i]); SetDParam(0, lid->ac[i]);
SetDParam(1, _cargoc.names_s[i]); SetDParam(1, _cargoc.names_s[i]);
p = GetString(p, STR_01D1_8); p = GetString(p, STR_01D1_8, lastof(buf));
} else { } 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; if (str == STR_NULL || (paramcount != 0 && !_patches.measure_tooltip)) return;
for (i = 0; i != paramcount; i++) SetDParam(i, params[i]); for (i = 0; i != paramcount; i++) SetDParam(i, params[i]);
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
br = GetStringBoundingBox(buffer); br = GetStringBoundingBox(buffer);
br.width += 6; br.height += 4; // increase slightly to have some space around the box 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); 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'; _edit_str_buf[realmaxlen-1] = '\0';
if (maxlen & 0x1000) { if (maxlen & 0x1000) {
@ -1311,7 +1311,7 @@ static void GenerateFileName(void)
SetDParam(0, p->name_1); SetDParam(0, p->name_1);
SetDParam(1, p->name_2); SetDParam(1, p->name_2);
SetDParam(2, _date); SetDParam(2, _date);
GetString(_edit_str_buf, STR_4004); GetString(_edit_str_buf, STR_4004, lastof(_edit_str_buf));
} }
extern void StartupEngines(void); extern void StartupEngines(void);
@ -1777,7 +1777,7 @@ static void CheatsWndProc(Window *w, WindowEvent *e)
/* Draw colored flag for change player cheat */ /* Draw colored flag for change player cheat */
case STR_CHEAT_CHANGE_PLAYER: case STR_CHEAT_CHANGE_PLAYER:
SetDParam(0, val); 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); DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2);
break; break;
/* Set correct string for switch climate cheat */ /* Set correct string for switch climate cheat */

View File

@ -131,54 +131,54 @@ void CDECL NetworkTextMessage(NetworkAction action, uint16 color, bool self_send
switch (action) { switch (action) {
case NETWORK_ACTION_JOIN: 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); snprintf(message, sizeof(message), "*** %s %s", name, temp);
break; break;
case NETWORK_ACTION_LEAVE: 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); snprintf(message, sizeof(message), "*** %s %s (%s)", name, temp, buf);
break; break;
case NETWORK_ACTION_GIVE_MONEY: case NETWORK_ACTION_GIVE_MONEY:
if (self_send) { if (self_send) {
SetDParamStr(0, name); SetDParamStr(0, name);
SetDParam(1, atoi(buf)); 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); snprintf(message, sizeof(message), "*** %s", temp);
} else { } else {
SetDParam(0, atoi(buf)); 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); snprintf(message, sizeof(message), "*** %s %s", name, temp);
} }
break; break;
case NETWORK_ACTION_CHAT_COMPANY: case NETWORK_ACTION_CHAT_COMPANY:
if (self_send) { if (self_send) {
SetDParamStr(0, name); 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); snprintf(message, sizeof(message), "%s %s", temp, buf);
} else { } else {
SetDParamStr(0, name); 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); snprintf(message, sizeof(message), "%s %s", temp, buf);
} }
break; break;
case NETWORK_ACTION_CHAT_CLIENT: case NETWORK_ACTION_CHAT_CLIENT:
if (self_send) { if (self_send) {
SetDParamStr(0, name); 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); snprintf(message, sizeof(message), "%s %s", temp, buf);
} else { } else {
SetDParamStr(0, name); 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); snprintf(message, sizeof(message), "%s %s", temp, buf);
} }
break; break;
case NETWORK_ACTION_NAME_CHANGE: 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); snprintf(message, sizeof(message), "*** %s %s %s", name, temp, buf);
break; break;
default: default:
SetDParamStr(0, name); 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); snprintf(message, sizeof(message), "%s %s", temp, buf);
break; break;
} }
@ -260,7 +260,7 @@ static void NetworkClientError(NetworkRecvStatus res, NetworkClientState* cs)
* @param buf buffer where the error message will be stored * @param buf buffer where the error message will be stored
* @param err NetworkErrorCode * @param err NetworkErrorCode
* @return returns a pointer to the error message (buf) */ * @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 /* List of possible network errors, used by
* PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */ * 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; 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 */ /* Count the number of active clients connected */
@ -599,7 +599,7 @@ void NetworkCloseClient(NetworkClientState *cs)
NetworkGetClientName(client_name, sizeof(client_name), 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); NetworkTextMessage(NETWORK_ACTION_LEAVE, 1, false, client_name, "%s", str);

View File

@ -628,7 +628,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT)
/* For speaking to player or give money, we need the player-name */ /* 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 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); ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
break; break;
default: default:
@ -654,7 +654,7 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT)
NetworkClientInfo *ci; NetworkClientInfo *ci;
index = NetworkRecv_uint16(MY_CLIENT, p); 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); ci = NetworkFindClientInfoFromIndex(index);
if (ci != NULL) { if (ci != NULL) {

View File

@ -230,7 +230,7 @@ NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index);
NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip); NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip);
NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index); NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index);
unsigned long NetworkResolveHost(const char *hostname); unsigned long NetworkResolveHost(const char *hostname);
char *GetNetworkErrorMsg(char *buf, NetworkErrorCode err); char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last);
#endif /* ENABLE_NETWORK */ #endif /* ENABLE_NETWORK */

View File

@ -1181,36 +1181,36 @@ static Window *PopupClientList(Window *w, int client_no, int x, int y)
i = 0; i = 0;
if (_network_own_client_index != ci->client_index) { 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; _clientlist_proc[i++] = &ClientList_SpeakToClient;
} }
if (IsValidPlayer(ci->client_playas)) { 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; _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; _clientlist_proc[i++] = &ClientList_SpeakToAll;
if (_network_own_client_index != ci->client_index) { if (_network_own_client_index != ci->client_index) {
/* We are no spectator and the player we want to give money to is no spectator */ /* We are no spectator and the player we want to give money to is no spectator */
if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas)) { 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; _clientlist_proc[i++] = &ClientList_GiveMoney;
} }
} }
// A server can kick clients (but not himself) // A server can kick clients (but not himself)
if (_network_server && _network_own_client_index != ci->client_index) { 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; _clientlist_proc[i++] = &ClientList_Kick;
sprintf(_clientlist_action[i],"Ban"); sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
_clientlist_proc[i++] = &ClientList_Ban; _clientlist_proc[i++] = &ClientList_Ban;
} }
if (i == 0) { 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; _clientlist_proc[i++] = &ClientList_None;
} }
@ -1511,7 +1511,7 @@ static const char *ChatTabCompletionNextItem(uint *item)
FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) { FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) {
/* Get the town-name via the string-system */ /* Get the town-name via the string-system */
SetDParam(0, t->townnameparts); 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]; return &chat_tab_temp_buffer[0];
} }
} }

View File

@ -3,6 +3,7 @@
#ifdef ENABLE_NETWORK #ifdef ENABLE_NETWORK
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h" // XXX StringID
#include "debug.h" #include "debug.h"
#include "string.h" #include "string.h"
#include "strings.h" #include "strings.h"
@ -144,7 +145,7 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, Netwo
NetworkSend_uint8(p, error); NetworkSend_uint8(p, error);
NetworkSend_Packet(p, cs); NetworkSend_Packet(p, cs);
GetNetworkErrorMsg(str, error); GetNetworkErrorMsg(str, error, lastof(str));
// Only send when the current client was in game // Only send when the current client was in game
if (cs->status > STATUS_AUTH) { if (cs->status > STATUS_AUTH) {
@ -899,7 +900,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR)
NetworkGetClientName(client_name, sizeof(client_name), cs); 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); 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 (ci != NULL && show_local) {
if (from_index == NETWORK_SERVER_INDEX) { if (from_index == NETWORK_SERVER_INDEX) {
char name[NETWORK_NAME_LENGTH]; 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); NetworkTextMessage(action, GetDrawStringPlayerColor(ci_own->client_playas), true, name, "%s", msg);
} else { } else {
FOR_ALL_CLIENTS(cs) { FOR_ALL_CLIENTS(cs) {
@ -1211,7 +1212,7 @@ void NetworkPopulateCompanyInfo(void)
// Grap the company name // Grap the company name
SetDParam(0, p->name_1); SetDParam(0, p->name_1);
SetDParam(1, p->name_2); 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 // Check the income
if (_cur_year - 1 == p->inaugurated_year) { if (_cur_year - 1 == p->inaugurated_year) {

View File

@ -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 *default_text = NULL;
const GRFText *search_text; 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); if (default_text != NULL) return strecpy(buff, default_text->text, NULL);
/* Use the default string ID if the fallback string isn't available */ /* 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);
} }
/** /**

View File

@ -8,7 +8,7 @@
StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid, bool new_scheme, const char *text_to_add, StringID def_string); 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); 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 CleanUpStrings(void);
void SetCurrentGrfLangID(const char *iso_name); void SetCurrentGrfLangID(const char *iso_name);

View File

@ -579,7 +579,7 @@ static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint
str = ni->string_id; str = ni->string_id;
} }
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
/* Copy the just gotten string to another buffer to remove any formatting /* Copy the just gotten string to another buffer to remove any formatting
* from it such as big fonts, etc. */ * from it such as big fonts, etc. */
for (ptr = buffer, dest = buffer2; *ptr != '\0'; ptr++) { for (ptr = buffer, dest = buffer2; *ptr != '\0'; ptr++) {

View File

@ -17,6 +17,7 @@
#include "functions.h" #include "functions.h"
#include "mixer.h" #include "mixer.h"
#include "spritecache.h" #include "spritecache.h"
#include "strings.h"
#include "gfx.h" #include "gfx.h"
#include "gfxinit.h" #include "gfxinit.h"
#include "gui.h" #include "gui.h"
@ -878,16 +879,17 @@ static void DoAutosave(void)
if (_patches.keep_all_autosave && _local_player != PLAYER_SPECTATOR) { if (_patches.keep_all_autosave && _local_player != PLAYER_SPECTATOR) {
const Player *p = GetPlayer(_local_player); const Player *p = GetPlayer(_local_player);
char *s; char* s = buf;
sprintf(buf, "%s%s", _path.autosave_dir, PATHSEP);
s += snprintf(buf, lengthof(buf), "%s%s", _path.autosave_dir, PATHSEP);
SetDParam(0, p->name_1); SetDParam(0, p->name_1);
SetDParam(1, p->name_2); SetDParam(1, p->name_2);
SetDParam(2, _date); SetDParam(2, _date);
s = GetString(buf + strlen(_path.autosave_dir) + strlen(PATHSEP), STR_4004); s = GetString(s, STR_4004, lastof(buf));
strcpy(s, ".sav"); strecpy(s, ".sav", lastof(buf));
} else { /* generate a savegame name and number according to _patches.max_num_autosaves */ } 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++; _autosave_ctr++;
if (_autosave_ctr >= _patches.max_num_autosaves) { if (_autosave_ctr >= _patches.max_num_autosaves) {

View File

@ -826,7 +826,7 @@ void BackupVehicleOrders(const Vehicle *v, BackuppedOrders *bak)
if (!IsCustomName(v->string_id)) { if (!IsCustomName(v->string_id)) {
bak->name[0] = '\0'; bak->name[0] = '\0';
} else { } 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 */ /* If we have shared orders, store it on a special way */

View File

@ -331,7 +331,7 @@ verify_name:;
if (pp->name_1 == str && pp->name_2 == strp) goto bad_town_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) if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 150)
goto bad_town_name; goto bad_town_name;
@ -438,14 +438,14 @@ restart:;
p->president_name_1 = SPECSTR_PRESIDENT_NAME; p->president_name_1 = SPECSTR_PRESIDENT_NAME;
SetDParam(0, p->president_name_2); 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) if (strlen(buffer) >= 32 || GetStringBoundingBox(buffer).width >= 94)
continue; continue;
FOR_ALL_PLAYERS(pp) { FOR_ALL_PLAYERS(pp) {
if (pp->is_active && p != pp) { if (pp->is_active && p != pp) {
SetDParam(0, pp->president_name_2); 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) if (strcmp(buffer2, buffer) == 0)
goto restart; goto restart;
} }
@ -998,7 +998,7 @@ int8 SaveHighScoreValue(const Player *p)
SetDParam(1, p->president_name_2); SetDParam(1, p->president_name_2);
SetDParam(2, p->name_1); SetDParam(2, p->name_1);
SetDParam(3, p->name_2); 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].score = score;
hs[i].title = EndGameGetPerformanceTitleFromValue(score); hs[i].title = EndGameGetPerformanceTitleFromValue(score);
return i; return i;
@ -1043,7 +1043,7 @@ int8 SaveHighScoreValueNetwork(void)
SetDParam(1, pl[i]->president_name_2); SetDParam(1, pl[i]->president_name_2);
SetDParam(2, pl[i]->name_1); SetDParam(2, pl[i]->name_1);
SetDParam(3, pl[i]->name_2); 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->score = pl[i]->old_economy[0].performance_history;
hs->title = EndGameGetPerformanceTitleFromValue(hs->score); hs->title = EndGameGetPerformanceTitleFromValue(hs->score);

View File

@ -504,7 +504,7 @@ static char *MakeScreenshotName(const char *ext)
SetDParam(0, p->name_1); SetDParam(0, p->name_1);
SetDParam(1, p->name_2); SetDParam(1, p->name_2);
SetDParam(2, _date); SetDParam(2, _date);
GetString(_screenshot_name, STR_4004); GetString(_screenshot_name, STR_4004, lastof(_screenshot_name));
} }
base = strchr(_screenshot_name, 0); base = strchr(_screenshot_name, 0);

View File

@ -81,12 +81,12 @@ static int CDECL StationNameSorter(const void *a, const void *b)
int r; int r;
SetDParam(0, st1->index); SetDParam(0, st1->index);
GetString(buf1, STR_STATION); GetString(buf1, STR_STATION, lastof(buf1));
if (st2 != _last_station) { if (st2 != _last_station) {
_last_station = st2; _last_station = st2;
SetDParam(0, st2->index); SetDParam(0, st2->index);
GetString(_bufcache, STR_STATION); GetString(_bufcache, STR_STATION, lastof(_bufcache));
} }
r = strcmp(buf1, _bufcache); // sort by name r = strcmp(buf1, _bufcache); // sort by name

View File

@ -1,6 +1,8 @@
/* $Id$ */ /* $Id$ */
#include "stdafx.h" #include "stdafx.h"
#include "openttd.h"
#include "functions.h"
#include "string.h" #include "string.h"
#include <stdarg.h> #include <stdarg.h>
@ -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) char* strecat(char* dst, const char* src, const char* last)
{ {
assert(last == NULL || dst <= last); assert(dst <= last);
for (; *dst != '\0'; ++dst) for (; *dst != '\0'; ++dst)
if (dst == last) return dst; if (dst == last) return dst;
for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src; 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) 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; for (; *src != '\0' && dst != last; ++dst, ++src) *dst = *src;
*dst = '\0'; *dst = '\0';
#if 0
if (dst == last && *src != '\0') {
error("String too long for destination buffer");
}
#endif
return dst; return dst;
} }

281
strings.c
View File

@ -31,11 +31,11 @@
char _userstring[128]; char _userstring[128];
static char *StationGetSpecialString(char *buff, int x); static char *StationGetSpecialString(char *buff, int x, const char* last);
static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed); static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char* last);
static char *GetSpecialPlayerNameString(char *buff, int ind, const int32 *argv); 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 { typedef struct LanguagePack {
uint32 ident; uint32 ident;
@ -166,7 +166,7 @@ static const char *GetStringPtr(StringID string)
// These 8 bits will only be set when FormatString wants to print // These 8 bits will only be set when FormatString wants to print
// the string in a different case. No one else except FormatString // the string in a different case. No one else except FormatString
// should set those bits, therefore string CANNOT be StringID, but uint32. // 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 index = GB(string, 0, 11);
uint tab = GB(string, 11, 5); uint tab = GB(string, 11, 5);
@ -177,46 +177,46 @@ static char *GetStringWithArgs(char *buffr, uint string, const int32 *argv)
switch (tab) { switch (tab) {
case 4: case 4:
if (index >= 0xC0) if (index >= 0xC0)
return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv)); return GetSpecialTownNameString(buffr, index - 0xC0, GetInt32(&argv), last);
break; break;
case 14: case 14:
if (index >= 0xE4) if (index >= 0xE4)
return GetSpecialPlayerNameString(buffr, index - 0xE4, argv); return GetSpecialPlayerNameString(buffr, index - 0xE4, argv, last);
break; break;
// User defined name // User defined name
case 15: case 15:
return GetName(index, buffr); return GetName(buffr, index, last);
case 26: case 26:
/* Include string within newgrf text (format code 81) */ /* Include string within newgrf text (format code 81) */
if (HASBIT(index, 10)) { if (HASBIT(index, 10)) {
StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10)); StringID string = GetGRFStringID(0, 0xD000 + GB(index, 0, 10));
return GetStringWithArgs(buffr, string, argv); return GetStringWithArgs(buffr, string, argv, last);
} }
break; break;
case 28: case 28:
GetGRFString(buff, index); GetGRFString(buff, index, last);
return FormatString(buffr, buff, argv, 0); return FormatString(buffr, buff, argv, 0, last);
case 29: case 29:
GetGRFString(buff, index + 0x800); GetGRFString(buff, index + 0x800, last);
return FormatString(buffr, buff, argv, 0); return FormatString(buffr, buff, argv, 0, last);
case 30: case 30:
GetGRFString(buff, index + 0x1000); GetGRFString(buff, index + 0x1000, last);
return FormatString(buffr, buff, argv, 0); return FormatString(buffr, buff, argv, 0, last);
case 31: case 31:
// dynamic strings. These are NOT to be passed through the formatter, // dynamic strings. These are NOT to be passed through the formatter,
// but passed through verbatim. // but passed through verbatim.
if (index < (STR_SPEC_USERSTRING & 0x7FF)) { 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]) { 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 1
}; };
static char *FormatCommaNumber(char *buff, int32 number) // TODO
static char *FormatCommaNumber(char *buff, int32 number, const char* last)
{ {
uint32 quot,divisor; uint32 quot,divisor;
int i; int i;
@ -303,7 +304,8 @@ static char *FormatCommaNumber(char *buff, int32 number)
return buff; return buff;
} }
static char *FormatNoCommaNumber(char *buff, int32 number) // TODO
static char *FormatNoCommaNumber(char *buff, int32 number, const char* last)
{ {
uint32 quot,divisor; uint32 quot,divisor;
int i; int i;
@ -311,7 +313,7 @@ static char *FormatNoCommaNumber(char *buff, int32 number)
uint32 num; uint32 num;
if (number < 0) { if (number < 0) {
*buff++ = '-'; buff = strecpy(buff, "-", last);
number = -number; 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; YearMonthDay ymd;
ConvertDateToYMD(date, &ymd); ConvertDateToYMD(date, &ymd);
for (src = GetStringPtr(ymd.day + STR_01AC_1ST - 1); (*buff++ = *src++) != '\0';) {} buff = strecpy(buff, GetStringPtr(ymd.day + STR_01AC_1ST - 1), last);
buff[-1] = ' '; 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';) {} return FormatNoCommaNumber(buff, ymd.year, last);
buff[-1] = ' ';
return FormatNoCommaNumber(buff, ymd.year);
} }
static char *FormatMonthAndYear(char *buff, Date date) static char *FormatMonthAndYear(char *buff, Date date, const char* last)
{ {
const char *src;
YearMonthDay ymd; YearMonthDay ymd;
ConvertDateToYMD(date, &ymd); ConvertDateToYMD(date, &ymd);
for (src = GetStringPtr(STR_MONTH_JAN + ymd.month); (*buff++ = *src++) != '\0';) {} buff = strecpy(buff, GetStringPtr(STR_MONTH_JAN + ymd.month), last);
buff[-1] = ' '; 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; YearMonthDay ymd;
ConvertDateToYMD(date, &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; 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; const char* multiplier = "";
char c; char buf[40];
char buf[40], *p; char* p;
int j; int j;
// multiply by exchange rate // multiply by exchange rate
@ -387,51 +389,45 @@ static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, int64 n
// convert from negative // convert from negative
if (number < 0) { if (number < 0) {
*buff++ = '-'; buff = strecpy(buff, "-", last);
number = -number; number = -number;
} }
/* Add prefix part, folowing symbol_pos specification. /* Add prefix part, folowing symbol_pos specification.
* Here, it can can be either 0 (prefix) or 2 (both prefix anf suffix). * 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 */ * The only remaining value is 1 (suffix), so everything that is not 1 */
if (spec->symbol_pos != 1){ if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last);
s = spec->prefix;
while (s != spec->prefix + lengthof(spec->prefix) && (c = *(s++)) != '\0') *(buff)++ = c;
}
// for huge numbers, compact the number into k or M // for huge numbers, compact the number into k or M
if (compact) { if (compact) {
compact = 0;
if (number >= 1000000000) { if (number >= 1000000000) {
number = (number + 500000) / 1000000; number = (number + 500000) / 1000000;
compact = 'M'; multiplier = "M";
} else if (number >= 1000000) { } else if (number >= 1000000) {
number = (number + 500) / 1000; number = (number + 500) / 1000;
compact = 'k'; multiplier = "k";
} }
} }
// convert to ascii number and add commas // convert to ascii number and add commas
p = buf; p = endof(buf);
*--p = '\0';
j = 4; j = 4;
do { do {
if (--j == 0) { if (--j == 0) {
*p++ = spec->separator; *--p = spec->separator;
j = 3; j = 3;
} }
*p++ = '0' + number % 10; *--p = '0' + number % 10;
} while (number /= 10); } while ((number /= 10) != 0);
do *buff++ = *--p; while (p != buf); buff = strecpy(buff, p, last);
if (compact) *buff++ = compact; buff = strecpy(buff, multiplier, last);
/* Add suffix part, folowing symbol_pos specification. /* Add suffix part, folowing symbol_pos specification.
* Here, it can can be either 1 (suffix) or 2 (both prefix anf suffix). * 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 */ * The only remaining value is 1 (prefix), so everything that is not 0 */
if (spec->symbol_pos != 0) { if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
s = spec->suffix;
while (s != spec->suffix + lengthof(spec->suffix) && (c = *(s++)) != '\0') *(buff++) = c;
}
return buff; 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[]; extern const char _openttd_revision[];
byte b; byte b;
@ -574,30 +570,34 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
while ((b = *str++) != '\0') { while ((b = *str++) != '\0') {
switch (b) { switch (b) {
case 0x1: // {SETX} case 0x1: // {SETX}
*buff++ = b; if (buff != last && buff + 1 != last) {
*buff++ = *str++; *buff++ = b;
*buff++ = *str++;
}
break; break;
case 0x2: // {SETXY} case 0x2: // {SETXY}
*buff++ = b; if (buff != last && buff + 1 != last && buff + 2 != last) {
*buff++ = *str++; *buff++ = b;
*buff++ = *str++; *buff++ = *str++;
*buff++ = *str++;
}
break; break;
case 0x81: // {STRINL} case 0x81: // {STRINL}
buff = GetStringWithArgs(buff, ReadLE16Unaligned(str), argv); buff = GetStringWithArgs(buff, ReadLE16Unaligned(str), argv, last);
str += 2; str += 2;
break; break;
case 0x82: // {DATE_LONG} case 0x82: // {DATE_LONG}
buff = FormatYmdString(buff, GetInt32(&argv)); buff = FormatYmdString(buff, GetInt32(&argv), last);
break; break;
case 0x83: // {DATE_SHORT} case 0x83: // {DATE_SHORT}
buff = FormatMonthAndYear(buff, GetInt32(&argv)); buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
break; break;
case 0x84: {// {VELOCITY} case 0x84: {// {VELOCITY}
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s; 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; modifier = 0;
break; break;
} }
@ -605,10 +605,10 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
case 0x85: case 0x85:
switch (*str++) { switch (*str++) {
case 0: /* {CURRCOMPACT} */ case 0: /* {CURRCOMPACT} */
buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true); buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last);
break; break;
case 2: /* {REV} */ case 2: /* {REV} */
buff = strecpy(buff, _openttd_revision, NULL); buff = strecpy(buff, _openttd_revision, last);
break; break;
case 3: { /* {SHORTCARGO} */ case 3: { /* {SHORTCARGO} */
// Short description of cargotypes. Layout: // 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]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s; 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; modifier = 0;
break; break;
} }
@ -629,61 +629,61 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s; 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; modifier = 0;
break; break;
} }
default: default:
buff = FormatCommaNumber(buff, GetInt32(&argv)); buff = FormatCommaNumber(buff, GetInt32(&argv), last);
buff = strecpy(buff, " ", NULL); buff = strecpy(buff, " ", last);
buff = strecpy(buff, GetStringPtr(cargo_str), NULL); buff = strecpy(buff, GetStringPtr(cargo_str), last);
break; break;
} }
} break; } break;
case 4: {/* {CURRCOMPACT64} */ case 4: {/* {CURRCOMPACT64} */
// 64 bit compact currency-unit // 64 bit compact currency-unit
buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true); buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
break; break;
} }
case 5: { /* {STRING1} */ case 5: { /* {STRING1} */
// String that consumes ONE argument // String that consumes ONE argument
uint str = modifier + GetInt32(&argv); uint str = modifier + GetInt32(&argv);
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1)); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
modifier = 0; modifier = 0;
break; break;
} }
case 6: { /* {STRING2} */ case 6: { /* {STRING2} */
// String that consumes TWO arguments // String that consumes TWO arguments
uint str = modifier + GetInt32(&argv); uint str = modifier + GetInt32(&argv);
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2)); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
modifier = 0; modifier = 0;
break; break;
} }
case 7: { /* {STRING3} */ case 7: { /* {STRING3} */
// String that consumes THREE arguments // String that consumes THREE arguments
uint str = modifier + GetInt32(&argv); uint str = modifier + GetInt32(&argv);
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3)); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
modifier = 0; modifier = 0;
break; break;
} }
case 8: { /* {STRING4} */ case 8: { /* {STRING4} */
// String that consumes FOUR arguments // String that consumes FOUR arguments
uint str = modifier + GetInt32(&argv); uint str = modifier + GetInt32(&argv);
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4)); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
modifier = 0; modifier = 0;
break; break;
} }
case 9: { /* {STRING5} */ case 9: { /* {STRING5} */
// String that consumes FIVE arguments // String that consumes FIVE arguments
uint str = modifier + GetInt32(&argv); uint str = modifier + GetInt32(&argv);
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5)); buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
modifier = 0; modifier = 0;
break; break;
} }
case 10: { /* {STATIONFEATURES} */ case 10: { /* {STATIONFEATURES} */
buff = StationGetSpecialString(buff, GetInt32(&argv)); buff = StationGetSpecialString(buff, GetInt32(&argv), last);
break; 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 // The string STR_INDUSTRY_PATTERN controls the formatting
args[0] = i->town->index; args[0] = i->town->index;
args[1] = i->type + STR_4802_COAL_MINE; 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; modifier = 0;
break; break;
} }
@ -707,7 +707,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s; 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; modifier = 0;
break; break;
} }
@ -723,7 +723,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
} }
case 14: { // {DATE_TINY} case 14: { // {DATE_TINY}
buff = FormatTinyDate(buff, GetInt32(&argv)); buff = FormatTinyDate(buff, GetInt32(&argv), last);
break; break;
} }
@ -733,7 +733,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
// 16-bit - cargo count // 16-bit - cargo count
CargoID cargo = GetInt32(&argv); CargoID cargo = GetInt32(&argv);
StringID cargo_str = (cargo == CT_INVALID) ? STR_8838_N_A : _cargoc.names_long[cargo]; 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; break;
} }
@ -741,7 +741,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].p_m >> units[_opt_ptr->units].p_s; 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; modifier = 0;
break; break;
} }
@ -750,7 +750,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s; 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; modifier = 0;
break; break;
} }
@ -759,7 +759,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s; 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; modifier = 0;
break; break;
} }
@ -768,7 +768,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s; 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; modifier = 0;
break; break;
} }
@ -777,7 +777,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
int32 args[1]; int32 args[1];
assert(_opt_ptr->units < lengthof(units)); assert(_opt_ptr->units < lengthof(units));
args[0] = GetInt32(&argv) * units[_opt_ptr->units].f_m >> units[_opt_ptr->units].f_s; 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; modifier = 0;
break; 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. // WARNING. It's prohibited for the included string to consume any arguments.
// For included strings that consume argument, you should use STRING1, STRING2 etc. // 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 // 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; modifier = 0;
break; break;
} }
case 0x8B: // {COMMA} case 0x8B: // {COMMA}
buff = FormatCommaNumber(buff, GetInt32(&argv)); buff = FormatCommaNumber(buff, GetInt32(&argv), last);
break; break;
case 0x8C: // Move argument pointer 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} case 0x8E: // {NUM}
buff = FormatNoCommaNumber(buff, GetInt32(&argv)); buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
break; break;
case 0x8F: // {CURRENCY} case 0x8F: // {CURRENCY}
buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false); buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
break; break;
case 0x99: { // {WAYPOINT} 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; temp[1] = wp->town_cn + 1;
str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL; str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
} }
buff = GetStringWithArgs(buff, str, temp); buff = GetStringWithArgs(buff, str, temp, last);
} break; } break;
case 0x9A: { // {STATION} case 0x9A: { // {STATION}
const Station* st = GetStation(GetInt32(&argv)); const Station* st = GetStation(GetInt32(&argv));
int32 temp[2];
if (!IsValidStation(st)) { // station doesn't exist anymore if (!IsValidStation(st)) { // station doesn't exist anymore
buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL); buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
break; } 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; break;
} }
case 0x9B: { // {TOWN} case 0x9B: { // {TOWN}
@ -865,12 +865,12 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
assert(IsValidTown(t)); assert(IsValidTown(t));
temp[0] = t->townnameparts; temp[0] = t->townnameparts;
buff = GetStringWithArgs(buff, t->townnametype, temp); buff = GetStringWithArgs(buff, t->townnametype, temp, last);
break; break;
} }
case 0x9C: { // {CURRENCY64} case 0x9C: { // {CURRENCY64}
buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false); buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
break; break;
} }
@ -899,7 +899,7 @@ static char *FormatString(char *buff, const char *str, const int32 *argv, uint c
} }
default: default:
*buff++ = b; if (buff != last) *buff++ = b;
} }
} }
*buff = '\0'; *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 & 0x01) buff = strecpy(buff, "\x94", last);
if (x & 0x02) *buff++ = '\x95'; if (x & 0x02) buff = strecpy(buff, "\x95", last);
if (x & 0x04) *buff++ = '\x96'; if (x & 0x04) buff = strecpy(buff, "\x96", last);
if (x & 0x08) *buff++ = '\x97'; if (x & 0x08) buff = strecpy(buff, "\x97", last);
if (x & 0x10) *buff++ = '\x98'; if (x & 0x10) buff = strecpy(buff, "\x98", last);
*buff = '\0';
return buff; 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++; _town_name_generators[ind](name, seed); // TODO
return buff; return strecpy(buff, name, last);
} }
static const char* const _silly_company_names[] = { 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', '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; const char* const* base;
uint num; uint num;
@ -1007,29 +1006,26 @@ static char *GenAndCoName(char *buff, uint32 arg)
num = lengthof(_surname_list); num = lengthof(_surname_list);
} }
buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], NULL); buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last);
buff = strecpy(buff, " & Co.", NULL); buff = strecpy(buff, " & Co.", last);
return buff; 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; const char* const* base;
uint num; uint num;
uint i; uint i;
buff[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8]; initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8];
buff[1] = '.'; buff = strecpy(buff, initial, last);
buff[2] = ' '; // Insert a space after initial and period "I. Firstname" instead of "I.Firstname"
buff += 3;
i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8; i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8;
if (i < sizeof(_initial_name_letters)) { if (i < sizeof(_initial_name_letters)) {
buff[0] = _initial_name_letters[i]; initial[0] = _initial_name_letters[i];
buff[1] = '.'; buff = strecpy(buff, initial, last);
buff[2] = ' '; // Insert a space after initial and period "I. J. Firstname" instead of "I.J.Firstname"
buff += 3;
} }
if (_opt_ptr->landscape == LT_CANDY) { if (_opt_ptr->landscape == LT_CANDY) {
@ -1040,50 +1036,53 @@ static char *GenPresidentName(char *buff, uint32 x)
num = lengthof(_surname_list); 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; 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) { switch (ind) {
case 1: // not used 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 case 2: // used for Foobar & Co company names
return GenAndCoName(buff, GetInt32(&argv)); return GenAndCoName(buff, GetInt32(&argv), last);
case 3: // President name case 3: // President name
return GenPresidentName(buff, GetInt32(&argv)); return GenPresidentName(buff, GetInt32(&argv), last);
case 4: // song names 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? // town name?
if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) { if (IS_INT_INSIDE(ind - 6, 0, SPECSTR_TOWNNAME_LAST-SPECSTR_TOWNNAME_START + 1)) {
buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv)); buff = GetSpecialTownNameString(buff, ind - 6, GetInt32(&argv), last);
return strecpy(buff, " Transport", NULL); return strecpy(buff, " Transport", last);
} }
// language name? // language name?
if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) { if (IS_INT_INSIDE(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4); int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
return strecpy(buff, 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? // resolution size?
if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) { if (IS_INT_INSIDE(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4); 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? // screenshot format name?
if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) { if (IS_INT_INSIDE(ind, (SPECSTR_SCREENSHOT_START - 0x70E4), (SPECSTR_SCREENSHOT_END - 0x70E4) + 1)) {
int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4); int i = ind - (SPECSTR_SCREENSHOT_START - 0x70E4);
return strecpy(buff, GetScreenshotFormatDesc(i), NULL); return strecpy(buff, GetScreenshotFormatDesc(i), last);
} }
assert(0); assert(0);

View File

@ -11,7 +11,7 @@ static inline char* InlineString(char* buf, uint16 string)
return buf; return buf;
} }
char *GetString(char *buffr, uint16 string); char *GetString(char *buffr, uint16 string, const char* last);
extern char _userstring[128]; extern char _userstring[128];

View File

@ -246,7 +246,7 @@ void AddTextEffect(StringID msg, int x, int y, uint16 duration)
te->params_1 = GetDParam(0); te->params_1 = GetDParam(0);
te->params_2 = GetDParam(4); te->params_2 = GetDParam(4);
GetString(buffer, msg); GetString(buffer, msg, lastof(buffer));
w = GetStringBoundingBox(buffer).width; w = GetStringBoundingBox(buffer).width;
te->x = x - (w >> 1); te->x = x - (w >> 1);

View File

@ -886,7 +886,7 @@ restart:
r = Random(); r = Random();
SetDParam(0, r); SetDParam(0, r);
GetString(buf1, townnametype); GetString(buf1, townnametype, lastof(buf1));
// Check size and width // Check size and width
if (strlen(buf1) >= 31 || GetStringBoundingBox(buf1).width > 130) continue; if (strlen(buf1) >= 31 || GetStringBoundingBox(buf1).width > 130) continue;
@ -895,7 +895,7 @@ restart:
// We can't just compare the numbers since // We can't just compare the numbers since
// several numbers may map to a single name. // several numbers may map to a single name.
SetDParam(0, t2->index); SetDParam(0, t2->index);
GetString(buf2, STR_TOWN); GetString(buf2, STR_TOWN, lastof(buf2));
if (strcmp(buf1, buf2) == 0) { if (strcmp(buf1, buf2) == 0) {
if (tries-- < 0) return false; if (tries-- < 0) return false;
goto restart; goto restart;

View File

@ -378,7 +378,7 @@ static int CDECL TownNameSorter(const void *a, const void *b)
int r; int r;
SetDParam(0, ta->index); 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 /* 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 * 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) { if (tb != _last_town) {
_last_town = tb; _last_town = tb;
SetDParam(0, tb->index); SetDParam(0, tb->index);
GetString(_bufcache, STR_TOWN); GetString(_bufcache, STR_TOWN, lastof(_bufcache));
} }
r = strcmp(buf1, _bufcache); r = strcmp(buf1, _bufcache);

View File

@ -135,13 +135,13 @@ static int CDECL TrainEngineNameSorter(const void *a, const void *b)
char buf1[64]; char buf1[64];
int r; int r;
GetString(buf1, GetCustomEngineName(va)); GetString(buf1, GetCustomEngineName(va), lastof(buf1));
if (vb != _last_engine) { if (vb != _last_engine) {
_last_engine = vb; _last_engine = vb;
_bufcache[0] = '\0'; _bufcache[0] = '\0';
GetString(_bufcache, GetCustomEngineName(vb)); GetString(_bufcache, GetCustomEngineName(vb), lastof(_bufcache));
} }
r = strcasecmp(buf1, _bufcache); // sort by name r = strcasecmp(buf1, _bufcache); // sort by name

View File

@ -2076,7 +2076,7 @@ static int32 ReplaceVehicle(Vehicle **w, byte flags, int32 total_cost)
if (!IsCustomName(old_v->string_id)) { if (!IsCustomName(old_v->string_id)) {
vehicle_name[0] = '\0'; vehicle_name[0] = '\0';
} else { } 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 } else { // flags & DC_EXEC not set
/* Ensure that the player will not end up having negative money while autoreplacing /* Ensure that the player will not end up having negative money while autoreplacing

View File

@ -516,7 +516,7 @@ static int CDECL VehicleNameSorter(const void *a, const void *b)
if (va != last_vehicle[0]) { if (va != last_vehicle[0]) {
last_vehicle[0] = va; last_vehicle[0] = va;
if (IsCustomName(va->string_id)) { if (IsCustomName(va->string_id)) {
GetString(last_name[0], va->string_id); GetString(last_name[0], va->string_id, lastof(last_name[0]));
} else { } else {
last_name[0][0] = '\0'; last_name[0][0] = '\0';
} }
@ -525,7 +525,7 @@ static int CDECL VehicleNameSorter(const void *a, const void *b)
if (vb != last_vehicle[1]) { if (vb != last_vehicle[1]) {
last_vehicle[1] = vb; last_vehicle[1] = vb;
if (IsCustomName(vb->string_id)) { if (IsCustomName(vb->string_id)) {
GetString(last_name[1], vb->string_id); GetString(last_name[1], vb->string_id, lastof(last_name[1]));
} else { } else {
last_name[1][0] = '\0'; last_name[1][0] = '\0';
} }

View File

@ -1017,7 +1017,7 @@ void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str)
sign->top = top; sign->top = top;
GetString(buffer, str); GetString(buffer, str, lastof(buffer));
w = GetStringBoundingBox(buffer).width + 3; w = GetStringBoundingBox(buffer).width + 3;
sign->width_1 = w; sign->width_1 = w;
sign->left = left - w / 2; sign->left = left - w / 2;