Changeset - r25554:3bffaeffba17
[Not reviewed]
master
0 22 0
Patric Stout - 3 years ago 2021-05-29 09:21:38
truebrain@openttd.org
Codechange: rename str_validate to StrMakeValid(InPlace) (#9304)

This to be more explicit the function changes the value, and not
returns yes/no.
22 files changed with 63 insertions and 62 deletions:
0 comments (0 inline, 0 general)
src/console.cpp
Show inline comments
 
@@ -90,49 +90,49 @@ void IConsoleFree()
 
 * used as a history to print them onscreen
 
 * @param colour_code the colour of the command. Red in case of errors, etc.
 
 * @param string the message entered or output on the console (notice, error, etc.)
 
 */
 
void IConsolePrint(TextColour colour_code, const char *string)
 
{
 
	assert(IsValidConsoleColour(colour_code));
 

	
 
	char *str;
 
	if (_redirect_console_to_client != INVALID_CLIENT_ID) {
 
		/* Redirect the string to the client */
 
		NetworkServerSendRcon(_redirect_console_to_client, colour_code, string);
 
		return;
 
	}
 

	
 
	if (_redirect_console_to_admin != INVALID_ADMIN_ID) {
 
		NetworkServerSendAdminRcon(_redirect_console_to_admin, colour_code, string);
 
		return;
 
	}
 

	
 
	/* Create a copy of the string, strip if of colours and invalid
 
	 * characters and (when applicable) assign it to the console buffer */
 
	str = stredup(string);
 
	str_strip_colours(str);
 
	str_validate(str, str + strlen(str));
 
	StrMakeValidInPlace(str);
 

	
 
	if (_network_dedicated) {
 
		NetworkAdminConsole("console", str);
 
		fprintf(stdout, "%s%s\n", GetLogPrefix(), str);
 
		fflush(stdout);
 
		IConsoleWriteToLogFile(str);
 
		free(str); // free duplicated string since it's not used anymore
 
		return;
 
	}
 

	
 
	IConsoleWriteToLogFile(str);
 
	IConsoleGUIPrint(colour_code, str);
 
}
 

	
 
/**
 
 * Handle the printing of text entered into the console or redirected there
 
 * by any other means. Uses printf() style format, for more information look
 
 * at IConsolePrint()
 
 */
 
void CDECL IConsolePrintF(TextColour colour_code, const char *format, ...)
 
{
 
	assert(IsValidConsoleColour(colour_code));
 

	
 
	va_list va;
src/fios.cpp
Show inline comments
 
@@ -321,49 +321,49 @@ bool FiosFileScanner::AddFile(const std:
 
		} else {
 
			fios->mtime = 0;
 
		}
 

	
 
		CloseHandle(fh);
 
#else
 
	struct stat sb;
 
	if (stat(filename.c_str(), &sb) == 0) {
 
		fios->mtime = sb.st_mtime;
 
#endif
 
	} else {
 
		fios->mtime = 0;
 
	}
 

	
 
	fios->type = type;
 
	strecpy(fios->name, filename.c_str(), lastof(fios->name));
 

	
 
	/* If the file doesn't have a title, use its filename */
 
	const char *t = fios_title;
 
	if (StrEmpty(fios_title)) {
 
		auto ps = filename.rfind(PATHSEPCHAR);
 
		t = filename.c_str() + (ps == std::string::npos ? 0 : ps + 1);
 
	}
 
	strecpy(fios->title, t, lastof(fios->title));
 
	str_validate(fios->title, lastof(fios->title));
 
	StrMakeValidInPlace(fios->title, lastof(fios->title));
 

	
 
	return true;
 
}
 

	
 

	
 
/**
 
 * Fill the list of the files in a directory, according to some arbitrary rule.
 
 * @param fop Purpose of collecting the list.
 
 * @param callback_proc The function that is called where you need to do the filtering.
 
 * @param subdir The directory from where to start (global) searching.
 
 * @param file_list Destination of the found files.
 
 */
 
static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *callback_proc, Subdirectory subdir, FileList &file_list)
 
{
 
	struct stat sb;
 
	struct dirent *dirent;
 
	DIR *dir;
 
	FiosItem *fios;
 
	size_t sort_start;
 
	char d_name[sizeof(fios->name)];
 

	
 
	file_list.clear();
 

	
 
	assert(_fios_path != nullptr);
 
@@ -373,49 +373,49 @@ static void FiosGetFileList(SaveLoadOper
 
		fios = &file_list.emplace_back();
 
		fios->type = FIOS_TYPE_PARENT;
 
		fios->mtime = 0;
 
		strecpy(fios->name, "..", lastof(fios->name));
 
		SetDParamStr(0, "..");
 
		GetString(fios->title, STR_SAVELOAD_PARENT_DIRECTORY, lastof(fios->title));
 
	}
 

	
 
	/* Show subdirectories */
 
	if ((dir = ttd_opendir(_fios_path->c_str())) != nullptr) {
 
		while ((dirent = readdir(dir)) != nullptr) {
 
			strecpy(d_name, FS2OTTD(dirent->d_name).c_str(), lastof(d_name));
 

	
 
			/* found file must be directory, but not '.' or '..' */
 
			if (FiosIsValidFile(_fios_path->c_str(), dirent, &sb) && S_ISDIR(sb.st_mode) &&
 
					(!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
 
					strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
 
				fios = &file_list.emplace_back();
 
				fios->type = FIOS_TYPE_DIR;
 
				fios->mtime = 0;
 
				strecpy(fios->name, d_name, lastof(fios->name));
 
				std::string dirname = std::string(d_name) + PATHSEP;
 
				SetDParamStr(0, dirname);
 
				GetString(fios->title, STR_SAVELOAD_DIRECTORY, lastof(fios->title));
 
				str_validate(fios->title, lastof(fios->title));
 
				StrMakeValidInPlace(fios->title, lastof(fios->title));
 
			}
 
		}
 
		closedir(dir);
 
	}
 

	
 
	/* Sort the subdirs always by name, ascending, remember user-sorting order */
 
	{
 
		SortingBits order = _savegame_sort_order;
 
		_savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
 
		std::sort(file_list.begin(), file_list.end());
 
		_savegame_sort_order = order;
 
	}
 

	
 
	/* This is where to start sorting for the filenames */
 
	sort_start = file_list.size();
 

	
 
	/* Show files */
 
	FiosFileScanner scanner(fop, callback_proc, file_list);
 
	if (subdir == NO_DIRECTORY) {
 
		scanner.Scan(nullptr, _fios_path->c_str(), false);
 
	} else {
 
		scanner.Scan(nullptr, subdir, true, true);
 
	}
 

	
 
@@ -425,49 +425,49 @@ static void FiosGetFileList(SaveLoadOper
 
	FiosGetDrives(file_list);
 

	
 
	file_list.shrink_to_fit();
 
}
 

	
 
/**
 
 * Get the title of a file, which (if exists) is stored in a file named
 
 * the same as the data file but with '.title' added to it.
 
 * @param file filename to get the title for
 
 * @param title the title buffer to fill
 
 * @param last the last element in the title buffer
 
 * @param subdir the sub directory to search in
 
 */
 
static void GetFileTitle(const std::string &file, char *title, const char *last, Subdirectory subdir)
 
{
 
	std::string buf = file;
 
	buf += ".title";
 

	
 
	FILE *f = FioFOpenFile(buf, "r", subdir);
 
	if (f == nullptr) return;
 

	
 
	size_t read = fread(title, 1, last - title, f);
 
	assert(title + read <= last);
 
	title[read] = '\0';
 
	str_validate(title, last);
 
	StrMakeValidInPlace(title, last);
 
	FioFCloseFile(f);
 
}
 

	
 
/**
 
 * Callback for FiosGetFileList. It tells if a file is a savegame or not.
 
 * @param fop Purpose of collecting the list.
 
 * @param file Name of the file to check.
 
 * @param ext A pointer to the extension identifier inside file
 
 * @param title Buffer if a callback wants to lookup the title of the file; nullptr to skip the lookup
 
 * @param last Last available byte in buffer (to prevent buffer overflows); not used when title == nullptr
 
 * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a savegame
 
 * @see FiosGetFileList
 
 * @see FiosGetSavegameList
 
 */
 
FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last)
 
{
 
	/* Show savegame files
 
	 * .SAV OpenTTD saved game
 
	 * .SS1 Transport Tycoon Deluxe preset game
 
	 * .SV1 Transport Tycoon Deluxe (Patch) saved game
 
	 * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */
 

	
 
	/* Don't crash if we supply no extension */
 
	if (ext == nullptr) return FIOS_TYPE_INVALID;
src/highscore.cpp
Show inline comments
 
@@ -149,31 +149,31 @@ void SaveToHighScore()
 
}
 

	
 
/** Initialize the highscore table to 0 and if any file exists, load in values */
 
void LoadFromHighScore()
 
{
 
	FILE *fp = fopen(_highscore_file.c_str(), "rb");
 

	
 
	memset(_highscore_table, 0, sizeof(_highscore_table));
 

	
 
	if (fp != nullptr) {
 
		uint i;
 
		HighScore *hs;
 

	
 
		for (i = 0; i < SP_SAVED_HIGHSCORE_END; i++) {
 
			for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
 
				byte length;
 
				if (fread(&length, sizeof(length), 1, fp)                              !=  1 ||
 
						fread(hs->company, std::min<int>(lengthof(hs->company), length), 1, fp) >   1 || // Yes... could be 0 bytes too
 
						fread(&hs->score, sizeof(hs->score), 1, fp)                        !=  1 ||
 
						fseek(fp, 2, SEEK_CUR)                                             == -1) { // XXX - placeholder for hs->title, not saved anymore; compatibility
 
					DEBUG(misc, 1, "Highscore corrupted");
 
					i = SP_SAVED_HIGHSCORE_END;
 
					break;
 
				}
 
				str_validate(hs->company, lastof(hs->company), SVS_NONE);
 
				StrMakeValidInPlace(hs->company, lastof(hs->company), SVS_NONE);
 
				hs->title = EndGameGetPerformanceTitleFromValue(hs->score);
 
			}
 
		}
 
		fclose(fp);
 
	}
 
}
src/ini_load.cpp
Show inline comments
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file ini_load.cpp Definition of the #IniLoadFile class, related to reading and storing '*.ini' files. */
 

	
 
#include "stdafx.h"
 
#include "core/alloc_func.hpp"
 
#include "core/mem_func.hpp"
 
#include "ini_type.h"
 
#include "string_func.h"
 

	
 
#include "safeguards.h"
 

	
 
/**
 
 * Construct a new in-memory item of an Ini file.
 
 * @param parent the group we belong to
 
 * @param name   the name of the item
 
 */
 
IniItem::IniItem(IniGroup *parent, const std::string &name) : next(nullptr)
 
{
 
	this->name = str_validate(name);
 
	this->name = StrMakeValid(name);
 

	
 
	*parent->last_item = this;
 
	parent->last_item = &this->next;
 
}
 

	
 
/** Free everything we loaded. */
 
IniItem::~IniItem()
 
{
 
	delete this->next;
 
}
 

	
 
/**
 
 * Replace the current value with another value.
 
 * @param value the value to replace with.
 
 */
 
void IniItem::SetValue(const std::string_view value)
 
{
 
	this->value.emplace(value);
 
}
 

	
 
/**
 
 * Construct a new in-memory group of an Ini file.
 
 * @param parent the file we belong to
 
 * @param name   the name of the group
 
 */
 
IniGroup::IniGroup(IniLoadFile *parent, const std::string &name) : next(nullptr), type(IGT_VARIABLES), item(nullptr)
 
{
 
	this->name = str_validate(name);
 
	this->name = StrMakeValid(name);
 

	
 
	this->last_item = &this->item;
 
	*parent->last_group = this;
 
	parent->last_group = &this->next;
 

	
 
	if (parent->list_group_names != nullptr) {
 
		for (uint i = 0; parent->list_group_names[i] != nullptr; i++) {
 
			if (this->name == parent->list_group_names[i]) {
 
				this->type = IGT_LIST;
 
				return;
 
			}
 
		}
 
	}
 
	if (parent->seq_group_names != nullptr) {
 
		for (uint i = 0; parent->seq_group_names[i] != nullptr; i++) {
 
			if (this->name == parent->seq_group_names[i]) {
 
				this->type = IGT_SEQUENCE;
 
				return;
 
			}
 
		}
 
	}
 
}
 

	
 
/** Free everything we loaded. */
 
@@ -267,41 +267,41 @@ void IniLoadFile::LoadFromDisk(const std
 
			}
 

	
 
			/* it's an item in an existing group */
 
			IniItem *item = new IniItem(group, std::string(s, t - s));
 
			if (comment_size != 0) {
 
				item->comment.assign(comment, comment_size);
 
				comment_size = 0;
 
			}
 

	
 
			/* find start of parameter */
 
			while (*t == '=' || *t == ' ' || *t == '\t') t++;
 

	
 
			bool quoted = (*t == '\"');
 
			/* remove starting quotation marks */
 
			if (*t == '\"') t++;
 
			/* remove ending quotation marks */
 
			e = t + strlen(t);
 
			if (e > t && e[-1] == '\"') e--;
 
			*e = '\0';
 

	
 
			/* If the value was not quoted and empty, it must be nullptr */
 
			if (!quoted && e == t) {
 
				item->value.reset();
 
			} else {
 
				item->value = str_validate(std::string(t));
 
				item->value = StrMakeValid(std::string(t));
 
			}
 
		} else {
 
			/* it's an orphan item */
 
			this->ReportFileError("ini: '", buffer, "' outside of group");
 
		}
 
	}
 

	
 
	if (comment_size > 0) {
 
		this->comment.assign(comment, comment_size);
 
		comment_size = 0;
 
	}
 

	
 
	free(comment);
 
	fclose(in);
 
}
 

	
src/misc_gui.cpp
Show inline comments
 
@@ -976,49 +976,49 @@ void QueryString::ClickEditBox(Window *w
 
		}
 
		return;
 
	}
 

	
 
	if (w->window_class != WC_OSK && _settings_client.gui.osk_activation != OSKA_DISABLED &&
 
		(!focus_changed || _settings_client.gui.osk_activation == OSKA_IMMEDIATELY) &&
 
		(click_count == 2 || _settings_client.gui.osk_activation != OSKA_DOUBLE_CLICK)) {
 
		/* Open the OSK window */
 
		ShowOnScreenKeyboard(w, wid);
 
	}
 
}
 

	
 
/** Class for the string query window. */
 
struct QueryStringWindow : public Window
 
{
 
	QueryString editbox;    ///< Editbox.
 
	QueryStringFlags flags; ///< Flags controlling behaviour of the window.
 
	Dimension warning_size; ///< How much space to use for the warning text
 

	
 
	QueryStringWindow(StringID str, StringID caption, uint max_bytes, uint max_chars, WindowDesc *desc, Window *parent, CharSetFilter afilter, QueryStringFlags flags) :
 
			Window(desc), editbox(max_bytes, max_chars)
 
	{
 
		char *last_of = &this->editbox.text.buf[this->editbox.text.max_bytes - 1];
 
		GetString(this->editbox.text.buf, str, last_of);
 
		str_validate(this->editbox.text.buf, last_of, SVS_NONE);
 
		StrMakeValidInPlace(this->editbox.text.buf, last_of, SVS_NONE);
 

	
 
		/* Make sure the name isn't too long for the text buffer in the number of
 
		 * characters (not bytes). max_chars also counts the '\0' characters. */
 
		while (Utf8StringLength(this->editbox.text.buf) + 1 > this->editbox.text.max_chars) {
 
			*Utf8PrevChar(this->editbox.text.buf + strlen(this->editbox.text.buf)) = '\0';
 
		}
 

	
 
		this->editbox.text.UpdateSize();
 

	
 
		if ((flags & QSF_ACCEPT_UNCHANGED) == 0) this->editbox.orig = stredup(this->editbox.text.buf);
 

	
 
		this->querystrings[WID_QS_TEXT] = &this->editbox;
 
		this->editbox.caption = caption;
 
		this->editbox.cancel_button = WID_QS_CANCEL;
 
		this->editbox.ok_button = WID_QS_OK;
 
		this->editbox.text.afilter = afilter;
 
		this->flags = flags;
 

	
 
		this->InitNested(WN_QUERY_STRING);
 
		this->UpdateWarningStringSize();
 

	
 
		this->parent = parent;
 

	
 
		this->SetFocusedWidget(WID_QS_TEXT);
src/network/core/packet.cpp
Show inline comments
 
@@ -373,64 +373,64 @@ uint64 Packet::Recv_uint64()
 
 * @param settings The string validation settings.
 
 */
 
void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings settings)
 
{
 
	char *bufp = buffer;
 
	const char *last = buffer + size - 1;
 

	
 
	/* Don't allow reading from a closed socket */
 
	if (cs->HasClientQuit()) return;
 

	
 
	size_t pos = this->pos;
 
	while (--size > 0 && pos < this->Size() && (*buffer++ = this->buffer[pos++]) != '\0') {}
 

	
 
	if (size == 0 || pos == this->Size()) {
 
		*buffer = '\0';
 
		/* If size was sooner to zero then the string in the stream
 
		 *  skip till the \0, so than packet can be read out correctly for the rest */
 
		while (pos < this->Size() && this->buffer[pos] != '\0') pos++;
 
		pos++;
 
	}
 

	
 
	assert(pos <= std::numeric_limits<PacketSize>::max());
 
	this->pos = static_cast<PacketSize>(pos);
 

	
 
	str_validate(bufp, last, settings);
 
	StrMakeValidInPlace(bufp, last, settings);
 
}
 

	
 
/**
 
 * Reads characters (bytes) from the packet until it finds a '\0', or reaches a
 
 * maximum of \c length characters.
 
 * When the '\0' has not been reached in the first \c length read characters,
 
 * more characters are read from the packet until '\0' has been reached. However,
 
 * these characters will not end up in the returned string.
 
 * The length of the returned string will be at most \c length - 1 characters.
 
 * @param length   The maximum length of the string including '\0'.
 
 * @param settings The string validation settings.
 
 * @return The validated string.
 
 */
 
std::string Packet::Recv_string(size_t length, StringValidationSettings settings)
 
{
 
	assert(length > 1);
 

	
 
	/* Both loops with Recv_uint8 terminate when reading past the end of the
 
	 * packet as Recv_uint8 then closes the connection and returns 0. */
 
	std::string str;
 
	char character;
 
	while (--length > 0 && (character = this->Recv_uint8()) != '\0') str.push_back(character);
 

	
 
	if (length == 0) {
 
		/* The string in the packet was longer. Read until the termination. */
 
		while (this->Recv_uint8() != '\0') {}
 
	}
 

	
 
	return str_validate(str, settings);
 
	return StrMakeValid(str, settings);
 
}
 

	
 
/**
 
 * Get the amount of bytes that are still available for the Transfer functions.
 
 * @return The number of bytes that still have to be transfered.
 
 */
 
size_t Packet::RemainingBytesToTransfer() const
 
{
 
	return this->Size() - this->pos;
 
}
src/newgrf.cpp
Show inline comments
 
@@ -2577,49 +2577,49 @@ static ChangeInfoResult LoadTranslationT
 
		grfmsg(1, "LoadTranslationTable: %s translation table must start at zero", name);
 
		return CIR_INVALID_ID;
 
	}
 

	
 
	translation_table.clear();
 
	for (int i = 0; i < numinfo; i++) {
 
		uint32 item = buf->ReadDWord();
 
		translation_table.push_back(BSWAP32(item));
 
	}
 

	
 
	return CIR_SUCCESS;
 
}
 

	
 
/**
 
 * Helper to read a DWord worth of bytes from the reader
 
 * and to return it as a valid string.
 
 * @param reader The source of the DWord.
 
 * @return The read DWord as string.
 
 */
 
static std::string ReadDWordAsString(ByteReader *reader)
 
{
 
	char output[5];
 
	for (int i = 0; i < 4; i++) output[i] = reader->ReadByte();
 
	output[4] = '\0';
 
	str_validate(output, lastof(output));
 
	StrMakeValidInPlace(output, lastof(output));
 

	
 
	return std::string(output);
 
}
 

	
 
/**
 
 * Define properties for global variables
 
 * @param gvid ID of the global variable.
 
 * @param numinfo Number of subsequent IDs to change the property for.
 
 * @param prop The property to change.
 
 * @param buf The property value.
 
 * @return ChangeInfoResult.
 
 */
 
static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, ByteReader *buf)
 
{
 
	/* Properties which are handled as a whole */
 
	switch (prop) {
 
		case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos)
 
			return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->cargo_list, "Cargo");
 

	
 
		case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes)
 
			return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type");
 

	
 
		case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes)
 
			return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->roadtype_list, "Road type");
src/os/os2/os2.cpp
Show inline comments
 
@@ -153,49 +153,49 @@ void ShowInfo(const char *str)
 
}
 

	
 
void ShowOSErrorBox(const char *buf, bool system)
 
{
 
	HAB hab;
 
	HMQ hmq;
 
	ULONG rc;
 

	
 
	/* init PM env. */
 
	hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0);
 

	
 
	/* display the box */
 
	rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (const unsigned char *)buf, (const unsigned char *)"OpenTTD", 0, MB_OK | MB_MOVEABLE | MB_ERROR);
 

	
 
	/* terminate PM env. */
 
	WinDestroyMsgQueue(hmq);
 
	WinTerminate(hab);
 
}
 

	
 
int CDECL main(int argc, char *argv[])
 
{
 
	SetRandomSeed(time(nullptr));
 

	
 
	/* Make sure our arguments contain only valid UTF-8 characters. */
 
	for (int i = 0; i < argc; i++) ValidateString(argv[i]);
 
	for (int i = 0; i < argc; i++) StrMakeValidInPlace(argv[i]);
 

	
 
	return openttd_main(argc, argv);
 
}
 

	
 
bool GetClipboardContents(char *buffer, const char *last)
 
{
 
/* XXX -- Currently no clipboard support implemented with GCC */
 
#ifndef __INNOTEK_LIBC__
 
	HAB hab = 0;
 

	
 
	if (WinOpenClipbrd(hab))
 
	{
 
		const char *text = (const char*)WinQueryClipbrdData(hab, CF_TEXT);
 

	
 
		if (text != nullptr)
 
		{
 
			strecpy(buffer, text, last);
 
			WinCloseClipbrd(hab);
 
			return true;
 
		}
 

	
 
		WinCloseClipbrd(hab);
 
	}
 
#endif
src/os/unix/unix.cpp
Show inline comments
 
@@ -222,49 +222,49 @@ void ShowInfo(const char *str)
 
{
 
	fprintf(stderr, "%s\n", str);
 
}
 

	
 
#if !defined(__APPLE__)
 
void ShowOSErrorBox(const char *buf, bool system)
 
{
 
	/* All unix systems, except OSX. Only use escape codes on a TTY. */
 
	if (isatty(fileno(stderr))) {
 
		fprintf(stderr, "\033[1;31mError: %s\033[0;39m\n", buf);
 
	} else {
 
		fprintf(stderr, "Error: %s\n", buf);
 
	}
 
}
 
#endif
 

	
 
#ifdef WITH_COCOA
 
void CocoaSetupAutoreleasePool();
 
void CocoaReleaseAutoreleasePool();
 
#endif
 

	
 
int CDECL main(int argc, char *argv[])
 
{
 
	/* Make sure our arguments contain only valid UTF-8 characters. */
 
	for (int i = 0; i < argc; i++) ValidateString(argv[i]);
 
	for (int i = 0; i < argc; i++) StrMakeValidInPlace(argv[i]);
 

	
 
#ifdef WITH_COCOA
 
	CocoaSetupAutoreleasePool();
 
	/* This is passed if we are launched by double-clicking */
 
	if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) {
 
		argv[1] = nullptr;
 
		argc = 1;
 
	}
 
#endif
 
	CrashLog::InitialiseCrashLog();
 

	
 
	SetRandomSeed(time(nullptr));
 

	
 
	signal(SIGPIPE, SIG_IGN);
 

	
 
	int ret = openttd_main(argc, argv);
 

	
 
#ifdef WITH_COCOA
 
	CocoaReleaseAutoreleasePool();
 
#endif
 

	
 
	return ret;
 
}
 

	
src/os/windows/win32.cpp
Show inline comments
 
@@ -408,49 +408,49 @@ int APIENTRY WinMain(HINSTANCE hInstance
 
	char *argv[64]; // max 64 command line arguments
 

	
 
	/* Set system timer resolution to 1ms. */
 
	timeBeginPeriod(1);
 

	
 
	CrashLog::InitialiseCrashLog();
 

	
 
	/* Convert the command line to UTF-8. We need a dedicated buffer
 
	 * for this because argv[] points into this buffer and this needs to
 
	 * be available between subsequent calls to FS2OTTD(). */
 
	char *cmdline = stredup(FS2OTTD(GetCommandLine()).c_str());
 

	
 
#if defined(_DEBUG)
 
	CreateConsole();
 
#endif
 

	
 
	_set_error_mode(_OUT_TO_MSGBOX); // force assertion output to messagebox
 

	
 
	/* setup random seed to something quite random */
 
	SetRandomSeed(GetTickCount());
 

	
 
	argc = ParseCommandLine(cmdline, argv, lengthof(argv));
 

	
 
	/* Make sure our arguments contain only valid UTF-8 characters. */
 
	for (int i = 0; i < argc; i++) ValidateString(argv[i]);
 
	for (int i = 0; i < argc; i++) StrMakeValidInPlace(argv[i]);
 

	
 
	openttd_main(argc, argv);
 

	
 
	/* Restore system timer resolution. */
 
	timeEndPeriod(1);
 

	
 
	free(cmdline);
 
	return 0;
 
}
 

	
 
char *getcwd(char *buf, size_t size)
 
{
 
	wchar_t path[MAX_PATH];
 
	GetCurrentDirectory(MAX_PATH - 1, path);
 
	convert_from_fs(path, buf, size);
 
	return buf;
 
}
 

	
 
extern std::string _config_file;
 

	
 
void DetermineBasePaths(const char *exe)
 
{
 
	extern std::array<std::string, NUM_SEARCHPATHS> _searchpaths;
 

	
src/saveload/oldloader.cpp
Show inline comments
 
@@ -213,49 +213,49 @@ static bool VerifyOldNameChecksum(char *
 
	for (uint i = 0; i < len - 2; i++) {
 
		sum += title[i];
 
		sum = ROL(sum, 1);
 
	}
 

	
 
	sum ^= 0xAAAA; // computed checksum
 

	
 
	uint16 sum2 = title[len - 2]; // checksum in file
 
	SB(sum2, 8, 8, title[len - 1]);
 

	
 
	return sum == sum2;
 
}
 

	
 
static inline bool CheckOldSavegameType(FILE *f, char *temp, const char *last, uint len)
 
{
 
	assert(last - temp + 1 >= (int)len);
 

	
 
	if (fread(temp, 1, len, f) != len) {
 
		temp[0] = '\0'; // if reading failed, make the name empty
 
		return false;
 
	}
 

	
 
	bool ret = VerifyOldNameChecksum(temp, len);
 
	temp[len - 2] = '\0'; // name is null-terminated in savegame, but it's better to be sure
 
	str_validate(temp, last);
 
	StrMakeValidInPlace(temp, last);
 

	
 
	return ret;
 
}
 

	
 
static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *last)
 
{
 
	static_assert(TTD_HEADER_SIZE >= TTO_HEADER_SIZE);
 
	char temp[TTD_HEADER_SIZE] = "Unknown";
 

	
 
	SavegameType type = SGT_TTO;
 

	
 
	/* Can't fseek to 0 as in tar files that is not correct */
 
	long pos = ftell(f);
 
	if (pos >= 0 && !CheckOldSavegameType(f, temp, lastof(temp), TTO_HEADER_SIZE)) {
 
		type = SGT_TTD;
 
		if (fseek(f, pos, SEEK_SET) < 0 || !CheckOldSavegameType(f, temp, lastof(temp), TTD_HEADER_SIZE)) {
 
			type = SGT_INVALID;
 
		}
 
	}
 

	
 
	if (title != nullptr) {
 
		switch (type) {
 
			case SGT_TTO: title = strecpy(title, "(TTO) ", last);    break;
 
			case SGT_TTD: title = strecpy(title, "(TTD) ", last);    break;
src/saveload/saveload.cpp
Show inline comments
 
@@ -951,93 +951,93 @@ static void SlString(void *ptr, size_t l
 
				case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate
 
					free(*(char **)ptr);
 
					if (len == 0) {
 
						*(char **)ptr = nullptr;
 
						return;
 
					} else {
 
						*(char **)ptr = MallocT<char>(len + 1); // terminating '\0'
 
						ptr = *(char **)ptr;
 
						SlCopyBytes(ptr, len);
 
					}
 
					break;
 
			}
 

	
 
			((char *)ptr)[len] = '\0'; // properly terminate the string
 
			StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
 
			if ((conv & SLF_ALLOW_CONTROL) != 0) {
 
				settings = settings | SVS_ALLOW_CONTROL_CODE;
 
				if (IsSavegameVersionBefore(SLV_169)) {
 
					str_fix_scc_encoded((char *)ptr, (char *)ptr + len);
 
				}
 
			}
 
			if ((conv & SLF_ALLOW_NEWLINE) != 0) {
 
				settings = settings | SVS_ALLOW_NEWLINE;
 
			}
 
			str_validate((char *)ptr, (char *)ptr + len, settings);
 
			StrMakeValidInPlace((char *)ptr, (char *)ptr + len, settings);
 
			break;
 
		}
 
		case SLA_PTRS: break;
 
		case SLA_NULL: break;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Save/Load a \c std::string.
 
 * @param ptr the string being manipulated
 
 * @param conv must be SLE_FILE_STRING
 
 */
 
static void SlStdString(void *ptr, VarType conv)
 
{
 
	std::string *str = reinterpret_cast<std::string *>(ptr);
 

	
 
	switch (_sl.action) {
 
		case SLA_SAVE: {
 
			size_t len = str->length();
 
			SlWriteArrayLength(len);
 
			SlCopyBytes(const_cast<void *>(static_cast<const void *>(str->c_str())), len);
 
			break;
 
		}
 

	
 
		case SLA_LOAD_CHECK:
 
		case SLA_LOAD: {
 
			size_t len = SlReadArrayLength();
 
			char *buf = AllocaM(char, len + 1);
 

	
 
			SlCopyBytes(buf, len);
 
			buf[len] = '\0'; // properly terminate the string
 

	
 
			StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
 
			if ((conv & SLF_ALLOW_CONTROL) != 0) {
 
				settings = settings | SVS_ALLOW_CONTROL_CODE;
 
				if (IsSavegameVersionBefore(SLV_169)) {
 
					str_fix_scc_encoded(buf, buf + len);
 
				}
 
			}
 
			if ((conv & SLF_ALLOW_NEWLINE) != 0) {
 
				settings = settings | SVS_ALLOW_NEWLINE;
 
			}
 
			str_validate(buf, buf + len, settings);
 
			StrMakeValidInPlace(buf, buf + len, settings);
 

	
 
			// Store sanitized string.
 
			str->assign(buf);
 
		}
 

	
 
		case SLA_PTRS: break;
 
		case SLA_NULL: break;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Return the size in bytes of a certain type of atomic array
 
 * @param length The length of the array counted in elements
 
 * @param conv VarType type of the variable that is used in calculating the size
 
 */
 
static inline size_t SlCalcArrayLen(size_t length, VarType conv)
 
{
 
	return SlCalcConvFileLen(conv) * length;
 
}
 

	
 
/**
 
 * Save/Load an array.
 
 * @param array The array being manipulated
src/script/api/script_object.cpp
Show inline comments
 
@@ -262,78 +262,78 @@ ScriptObject::ActiveInstance::~ActiveIns
 
{
 
	return GetStorage()->root_company;
 
}
 

	
 
/* static */ bool ScriptObject::CanSuspend()
 
{
 
	Squirrel *squirrel = ScriptObject::GetActiveInstance()->engine;
 
	return GetStorage()->allow_do_command && squirrel->CanSuspend();
 
}
 

	
 
/* static */ void *&ScriptObject::GetEventPointer()
 
{
 
	return GetStorage()->event_data;
 
}
 

	
 
/* static */ void *&ScriptObject::GetLogPointer()
 
{
 
	return GetStorage()->log_data;
 
}
 

	
 
/* static */ char *ScriptObject::GetString(StringID string)
 
{
 
	char buffer[64];
 
	::GetString(buffer, string, lastof(buffer));
 
	::str_validate(buffer, lastof(buffer), SVS_NONE);
 
	::StrMakeValidInPlace(buffer, lastof(buffer), SVS_NONE);
 
	return ::stredup(buffer);
 
}
 

	
 
/* static */ void ScriptObject::SetCallbackVariable(int index, int value)
 
{
 
	if ((size_t)index >= GetStorage()->callback_value.size()) GetStorage()->callback_value.resize(index + 1);
 
	GetStorage()->callback_value[index] = value;
 
}
 

	
 
/* static */ int ScriptObject::GetCallbackVariable(int index)
 
{
 
	return GetStorage()->callback_value[index];
 
}
 

	
 
/* static */ bool ScriptObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, Script_SuspendCallbackProc *callback)
 
{
 
	if (!ScriptObject::CanSuspend()) {
 
		throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
 
	}
 

	
 
	if (ScriptObject::GetCompany() != OWNER_DEITY && !::Company::IsValidID(ScriptObject::GetCompany())) {
 
		ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY);
 
		return false;
 
	}
 

	
 
	if (!StrEmpty(text) && (GetCommandFlags(cmd) & CMD_STR_CTRL) == 0) {
 
		/* The string must be valid, i.e. not contain special codes. Since some
 
		 * can be made with GSText, make sure the control codes are removed. */
 
		::str_validate(const_cast<char *>(text), text + strlen(text), SVS_NONE);
 
		::StrMakeValidInPlace(text, SVS_NONE);
 
	}
 

	
 
	/* Set the default callback to return a true/false result of the DoCommand */
 
	if (callback == nullptr) callback = &ScriptInstance::DoCommandReturn;
 

	
 
	/* Are we only interested in the estimate costs? */
 
	bool estimate_only = GetDoCommandMode() != nullptr && !GetDoCommandMode()();
 

	
 
	/* Only set p2 when the command does not come from the network. */
 
	if (GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = UINT32_MAX;
 

	
 
	/* Store the command for command callback validation. */
 
	if (!estimate_only && _networking && !_generating_world) SetLastCommand(tile, p1, p2, cmd);
 

	
 
	/* Try to perform the command. */
 
	CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : nullptr, text, false, estimate_only);
 

	
 
	/* We failed; set the error and bail out */
 
	if (res.Failed()) {
 
		SetLastError(ScriptError::StringToError(res.GetErrorMessage()));
 
		return false;
 
	}
 

	
 
	/* No error, then clear it. */
src/script/api/script_text.cpp
Show inline comments
 
@@ -61,49 +61,49 @@ ScriptText::~ScriptText()
 
{
 
	for (int i = 0; i < SCRIPT_TEXT_MAX_PARAMETERS; i++) {
 
		free(this->params[i]);
 
		if (this->paramt[i] != nullptr) this->paramt[i]->Release();
 
	}
 
}
 

	
 
SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
 
{
 
	if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
 

	
 
	free(this->params[parameter]);
 
	if (this->paramt[parameter] != nullptr) this->paramt[parameter]->Release();
 

	
 
	this->parami[parameter] = 0;
 
	this->params[parameter] = nullptr;
 
	this->paramt[parameter] = nullptr;
 

	
 
	switch (sq_gettype(vm, -1)) {
 
		case OT_STRING: {
 
			const SQChar *value;
 
			sq_getstring(vm, -1, &value);
 

	
 
			this->params[parameter] = stredup(value);
 
			ValidateString(this->params[parameter]);
 
			StrMakeValidInPlace(this->params[parameter]);
 
			break;
 
		}
 

	
 
		case OT_INTEGER: {
 
			SQInteger value;
 
			sq_getinteger(vm, -1, &value);
 

	
 
			this->parami[parameter] = value;
 
			break;
 
		}
 

	
 
		case OT_INSTANCE: {
 
			SQUserPointer real_instance = nullptr;
 
			HSQOBJECT instance;
 

	
 
			sq_getstackobj(vm, -1, &instance);
 

	
 
			/* Validate if it is a GSText instance */
 
			sq_pushroottable(vm);
 
			sq_pushstring(vm, "GSText", -1);
 
			sq_get(vm, -2);
 
			sq_pushobject(vm, instance);
 
			if (sq_instanceof(vm) != SQTrue) return SQ_ERROR;
 
			sq_pop(vm, 3);
 
@@ -136,49 +136,49 @@ SQInteger ScriptText::SetParam(HSQUIRREL
 
	if (k < 1) return SQ_ERROR;
 
	k--;
 

	
 
	return this->_SetParam(k, vm);
 
}
 

	
 
SQInteger ScriptText::AddParam(HSQUIRRELVM vm)
 
{
 
	SQInteger res;
 
	res = this->_SetParam(this->paramc, vm);
 
	if (res != 0) return res;
 

	
 
	/* Push our own instance back on top of the stack */
 
	sq_push(vm, 1);
 
	return 1;
 
}
 

	
 
SQInteger ScriptText::_set(HSQUIRRELVM vm)
 
{
 
	int32 k;
 

	
 
	if (sq_gettype(vm, 2) == OT_STRING) {
 
		const SQChar *key_string;
 
		sq_getstring(vm, 2, &key_string);
 
		ValidateString(key_string);
 
		StrMakeValidInPlace(key_string);
 

	
 
		if (strncmp(key_string, "param_", 6) != 0 || strlen(key_string) > 8) return SQ_ERROR;
 
		k = atoi(key_string + 6);
 
	} else if (sq_gettype(vm, 2) == OT_INTEGER) {
 
		SQInteger key;
 
		sq_getinteger(vm, 2, &key);
 
		k = (int32)key;
 
	} else {
 
		return SQ_ERROR;
 
	}
 

	
 
	if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
 
	if (k < 1) return SQ_ERROR;
 
	k--;
 

	
 
	return this->_SetParam(k, vm);
 
}
 

	
 
const char *ScriptText::GetEncodedText()
 
{
 
	static char buf[1024];
 
	int param_count = 0;
 
	this->_GetEncodedText(buf, lastof(buf), param_count);
 
	return (param_count > SCRIPT_TEXT_MAX_PARAMETERS) ? nullptr : buf;
src/script/script_info.cpp
Show inline comments
 
@@ -101,68 +101,68 @@ bool ScriptInfo::CheckMethod(const char 
 
		if (!info->GetSettings()) return SQ_ERROR;
 
	}
 

	
 
	return 0;
 
}
 

	
 
bool ScriptInfo::GetSettings()
 
{
 
	return this->engine->CallMethod(*this->SQ_instance, "GetSettings", nullptr, MAX_GET_SETTING_OPS);
 
}
 

	
 
SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
 
{
 
	ScriptConfigItem config;
 
	memset(&config, 0, sizeof(config));
 
	config.max_value = 1;
 
	config.step_size = 1;
 
	uint items = 0;
 

	
 
	/* Read the table, and find all properties we care about */
 
	sq_pushnull(vm);
 
	while (SQ_SUCCEEDED(sq_next(vm, -2))) {
 
		const SQChar *key;
 
		if (SQ_FAILED(sq_getstring(vm, -2, &key))) return SQ_ERROR;
 
		ValidateString(key);
 
		StrMakeValidInPlace(key);
 

	
 
		if (strcmp(key, "name") == 0) {
 
			const SQChar *sqvalue;
 
			if (SQ_FAILED(sq_getstring(vm, -1, &sqvalue))) return SQ_ERROR;
 
			char *name = stredup(sqvalue);
 
			char *s;
 
			ValidateString(name);
 
			StrMakeValidInPlace(name);
 

	
 
			/* Don't allow '=' and ',' in configure setting names, as we need those
 
			 *  2 chars to nicely store the settings as a string. */
 
			while ((s = strchr(name, '=')) != nullptr) *s = '_';
 
			while ((s = strchr(name, ',')) != nullptr) *s = '_';
 
			config.name = name;
 
			items |= 0x001;
 
		} else if (strcmp(key, "description") == 0) {
 
			const SQChar *sqdescription;
 
			if (SQ_FAILED(sq_getstring(vm, -1, &sqdescription))) return SQ_ERROR;
 
			config.description = stredup(sqdescription);
 
			ValidateString(config.description);
 
			StrMakeValidInPlace(config.description);
 
			items |= 0x002;
 
		} else if (strcmp(key, "min_value") == 0) {
 
			SQInteger res;
 
			if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
 
			config.min_value = res;
 
			items |= 0x004;
 
		} else if (strcmp(key, "max_value") == 0) {
 
			SQInteger res;
 
			if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
 
			config.max_value = res;
 
			items |= 0x008;
 
		} else if (strcmp(key, "easy_value") == 0) {
 
			SQInteger res;
 
			if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
 
			config.easy_value = res;
 
			items |= 0x010;
 
		} else if (strcmp(key, "medium_value") == 0) {
 
			SQInteger res;
 
			if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
 
			config.medium_value = res;
 
			items |= 0x020;
 
		} else if (strcmp(key, "hard_value") == 0) {
 
			SQInteger res;
 
			if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
 
@@ -205,76 +205,76 @@ SQInteger ScriptInfo::AddSetting(HSQUIRR
 
		seprintf(error, lastof(error), "Setting both random_deviation and SCRIPTCONFIG_RANDOM is not allowed");
 
		this->engine->ThrowError(error);
 
		return SQ_ERROR;
 
	}
 
	/* Reset the bit for random_deviation as it's optional. */
 
	items &= ~0x200;
 

	
 
	/* Make sure all properties are defined */
 
	uint mask = (config.flags & SCRIPTCONFIG_BOOLEAN) ? 0x1F3 : 0x1FF;
 
	if (items != mask) {
 
		char error[1024];
 
		seprintf(error, lastof(error), "please define all properties of a setting (min/max not allowed for booleans)");
 
		this->engine->ThrowError(error);
 
		return SQ_ERROR;
 
	}
 

	
 
	this->config_list.push_back(config);
 
	return 0;
 
}
 

	
 
SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
 
{
 
	const SQChar *setting_name;
 
	if (SQ_FAILED(sq_getstring(vm, -2, &setting_name))) return SQ_ERROR;
 
	ValidateString(setting_name);
 
	StrMakeValidInPlace(setting_name);
 

	
 
	ScriptConfigItem *config = nullptr;
 
	for (auto &item : this->config_list) {
 
		if (strcmp(item.name, setting_name) == 0) config = &item;
 
	}
 

	
 
	if (config == nullptr) {
 
		char error[1024];
 
		seprintf(error, lastof(error), "Trying to add labels for non-defined setting '%s'", setting_name);
 
		this->engine->ThrowError(error);
 
		return SQ_ERROR;
 
	}
 
	if (config->labels != nullptr) return SQ_ERROR;
 

	
 
	config->labels = new LabelMapping;
 

	
 
	/* Read the table and find all labels */
 
	sq_pushnull(vm);
 
	while (SQ_SUCCEEDED(sq_next(vm, -2))) {
 
		const SQChar *key_string;
 
		const SQChar *label;
 
		if (SQ_FAILED(sq_getstring(vm, -2, &key_string))) return SQ_ERROR;
 
		if (SQ_FAILED(sq_getstring(vm, -1, &label))) return SQ_ERROR;
 
		/* Because squirrel doesn't support identifiers starting with a digit,
 
		 * we skip the first character. */
 
		int key = atoi(key_string + 1);
 
		ValidateString(label);
 
		StrMakeValidInPlace(label);
 

	
 
		/* !Contains() prevents stredup from leaking. */
 
		if (!config->labels->Contains(key)) config->labels->Insert(key, stredup(label));
 

	
 
		sq_pop(vm, 2);
 
	}
 
	sq_pop(vm, 1);
 

	
 
	/* Check labels for completeness */
 
	config->complete_labels = true;
 
	for (int value = config->min_value; value <= config->max_value; value++) {
 
		if (!config->labels->Contains(value)) {
 
			config->complete_labels = false;
 
			break;
 
		}
 
	}
 

	
 
	return 0;
 
}
 

	
 
const ScriptConfigItemList *ScriptInfo::GetConfigList() const
 
{
 
	return &this->config_list;
 
}
src/script/squirrel.cpp
Show inline comments
 
@@ -427,49 +427,49 @@ bool Squirrel::CallMethod(HSQOBJECT inst
 
	if (SQ_FAILED(sq_get(this->vm, -2))) {
 
		DEBUG(misc, 0, "[squirrel] Could not find '%s' in the class", method_name);
 
		sq_settop(this->vm, top);
 
		return false;
 
	}
 
	/* Call the method */
 
	sq_pushobject(this->vm, instance);
 
	if (SQ_FAILED(sq_call(this->vm, 1, ret == nullptr ? SQFalse : SQTrue, SQTrue, suspend))) return false;
 
	if (ret != nullptr) sq_getstackobj(vm, -1, ret);
 
	/* Reset the top, but don't do so for the script main function, as we need
 
	 *  a correct stack when resuming. */
 
	if (suspend == -1 || !this->IsSuspended()) sq_settop(this->vm, top);
 
	/* Restore the return-value location. */
 
	this->vm->_suspended_target = last_target;
 

	
 
	return true;
 
}
 

	
 
bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend)
 
{
 
	HSQOBJECT ret;
 
	if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
 
	if (ret._type != OT_STRING) return false;
 
	*res = stredup(ObjectToString(&ret));
 
	ValidateString(*res);
 
	StrMakeValidInPlace(*res);
 
	return true;
 
}
 

	
 
bool Squirrel::CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend)
 
{
 
	HSQOBJECT ret;
 
	if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
 
	if (ret._type != OT_INTEGER) return false;
 
	*res = ObjectToInteger(&ret);
 
	return true;
 
}
 

	
 
bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend)
 
{
 
	HSQOBJECT ret;
 
	if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
 
	if (ret._type != OT_BOOL) return false;
 
	*res = ObjectToBool(&ret);
 
	return true;
 
}
 

	
 
/* static */ bool Squirrel::CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name)
 
{
 
	Squirrel *engine = (Squirrel *)sq_getforeignptr(vm);
src/script/squirrel_helper.hpp
Show inline comments
 
@@ -95,49 +95,49 @@ namespace SQConvert {
 
	 * To get a param from squirrel, we call this function. It converts to the right format.
 
	 */
 
	template <typename T> static T GetParam(ForceType<T>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr);
 

	
 
	template <> inline uint8       GetParam(ForceType<uint8>       , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline uint16      GetParam(ForceType<uint16>      , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline uint32      GetParam(ForceType<uint32>      , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline int8        GetParam(ForceType<int8>        , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline int16       GetParam(ForceType<int16>       , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline int32       GetParam(ForceType<int32>       , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline int64       GetParam(ForceType<int64>       , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline Money       GetParam(ForceType<Money>       , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger     tmp; sq_getinteger    (vm, index, &tmp); return tmp; }
 
	template <> inline bool        GetParam(ForceType<bool>        , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool        tmp; sq_getbool       (vm, index, &tmp); return tmp != 0; }
 
	template <> inline void       *GetParam(ForceType<void *>      , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; }
 
	template <> inline const char *GetParam(ForceType<const char *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr)
 
	{
 
		/* Convert what-ever there is as parameter to a string */
 
		sq_tostring(vm, index);
 

	
 
		const SQChar *tmp;
 
		sq_getstring(vm, -1, &tmp);
 
		char *tmp_str = stredup(tmp);
 
		sq_poptop(vm);
 
		ptr->push_back((void *)tmp_str);
 
		str_validate(tmp_str, tmp_str + strlen(tmp_str));
 
		StrMakeValidInPlace(tmp_str);
 
		return tmp_str;
 
	}
 

	
 
	template <> inline Array      *GetParam(ForceType<Array *>,      HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr)
 
	{
 
		/* Sanity check of the size. */
 
		if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large");
 

	
 
		SQObject obj;
 
		sq_getstackobj(vm, index, &obj);
 
		sq_pushobject(vm, obj);
 
		sq_pushnull(vm);
 

	
 
		std::vector<int32> data;
 

	
 
		while (SQ_SUCCEEDED(sq_next(vm, -2))) {
 
			SQInteger tmp;
 
			if (SQ_SUCCEEDED(sq_getinteger(vm, -1, &tmp))) {
 
				data.push_back((int32)tmp);
 
			} else {
 
				sq_pop(vm, 4);
 
				throw sq_throwerror(vm, "a member of an array used as parameter to a function is not numeric");
 
			}
 

	
src/settings.cpp
Show inline comments
 
@@ -476,49 +476,49 @@ void IntSettingDesc::Write(const void *o
 
 * @param object The object the setting is to be saved in.
 
 * @return The value of the saved integer.
 
 */
 
int32 IntSettingDesc::Read(const void *object) const
 
{
 
	void *ptr = GetVariableAddress(object, &this->save);
 
	return (int32)ReadValue(ptr, this->save.conv);
 
}
 

	
 
/**
 
 * Make the value valid given the limitations of this setting.
 
 *
 
 * In the case of string settings this is ensuring the string contains only accepted
 
 * Utf8 characters and is at most the maximum length defined in this setting.
 
 * @param str The string to make valid.
 
 */
 
void StringSettingDesc::MakeValueValid(std::string &str) const
 
{
 
	if (this->max_length == 0 || str.size() < this->max_length) return;
 

	
 
	/* In case a maximum length is imposed by the setting, the length
 
	 * includes the '\0' termination for network transfer purposes.
 
	 * Also ensure the string is valid after chopping of some bytes. */
 
	std::string stdstr(str, this->max_length - 1);
 
	str.assign(str_validate(stdstr, SVS_NONE));
 
	str.assign(StrMakeValid(stdstr, SVS_NONE));
 
}
 

	
 
/**
 
 * Write a string to the actual setting.
 
 * @param object The object the setting is to be saved in.
 
 * @param str The string to save.
 
 */
 
void StringSettingDesc::Write(const void *object, const std::string &str) const
 
{
 
	reinterpret_cast<std::string *>(GetVariableAddress(object, &this->save))->assign(str);
 
}
 

	
 
/**
 
 * Read the string from the the actual setting.
 
 * @param object The object the setting is to be saved in.
 
 * @return The value of the saved string.
 
 */
 
const std::string &StringSettingDesc::Read(const void *object) const
 
{
 
	return *reinterpret_cast<std::string *>(GetVariableAddress(object, &this->save));
 
}
 

	
 
/**
 
 * Load values from a group of an IniFile structure into the internal representation
src/string.cpp
Show inline comments
 
@@ -165,49 +165,49 @@ char *CDECL str_fmt(const char *str, ...
 
 * it's new, static value.
 
 * @param str the string to scan
 
 * @param last the last valid character of str
 
 */
 
void str_fix_scc_encoded(char *str, const char *last)
 
{
 
	while (str <= last && *str != '\0') {
 
		size_t len = Utf8EncodedCharLen(*str);
 
		if ((len == 0 && str + 4 > last) || str + len > last) break;
 

	
 
		WChar c;
 
		Utf8Decode(&c, str);
 
		if (c == '\0') break;
 

	
 
		if (c == 0xE028 || c == 0xE02A) {
 
			c = SCC_ENCODED;
 
		}
 
		str += Utf8Encode(str, c);
 
	}
 
	*str = '\0';
 
}
 

	
 

	
 
template <class T>
 
static void str_validate(T &dst, const char *str, const char *last, StringValidationSettings settings)
 
static void StrMakeValidInPlace(T &dst, const char *str, const char *last, StringValidationSettings settings)
 
{
 
	/* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */
 

	
 
	while (str <= last && *str != '\0') {
 
		size_t len = Utf8EncodedCharLen(*str);
 
		WChar c;
 
		/* If the first byte does not look like the first byte of an encoded
 
		 * character, i.e. encoded length is 0, then this byte is definitely bad
 
		 * and it should be skipped.
 
		 * When the first byte looks like the first byte of an encoded character,
 
		 * then the remaining bytes in the string are checked whether the whole
 
		 * encoded character can be there. If that is not the case, this byte is
 
		 * skipped.
 
		 * Finally we attempt to decode the encoded character, which does certain
 
		 * extra validations to see whether the correct number of bytes were used
 
		 * to encode the character. If that is not the case, the byte is probably
 
		 * invalid and it is skipped. We could emit a question mark, but then the
 
		 * logic below cannot just copy bytes, it would need to re-encode the
 
		 * decoded characters as the length in bytes may have changed.
 
		 *
 
		 * The goals here is to get as much valid Utf8 encoded characters from the
 
		 * source string to the destination string.
 
		 *
 
		 * Note: a multi-byte encoded termination ('\0') will trigger the encoded
 
@@ -225,92 +225,93 @@ static void str_validate(T &dst, const c
 
		if ((IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END)) || ((settings & SVS_ALLOW_CONTROL_CODE) != 0 && c == SCC_ENCODED)) {
 
			/* Copy the character back. Even if dst is current the same as str
 
			 * (i.e. no characters have been changed) this is quicker than
 
			 * moving the pointers ahead by len */
 
			do {
 
				*dst++ = *str++;
 
			} while (--len != 0);
 
		} else if ((settings & SVS_ALLOW_NEWLINE) != 0 && c == '\n') {
 
			*dst++ = *str++;
 
		} else {
 
			if ((settings & SVS_ALLOW_NEWLINE) != 0 && c == '\r' && str[1] == '\n') {
 
				str += len;
 
				continue;
 
			}
 
			/* Replace the undesirable character with a question mark */
 
			str += len;
 
			if ((settings & SVS_REPLACE_WITH_QUESTION_MARK) != 0) *dst++ = '?';
 
		}
 
	}
 

	
 
	/* String termination, if needed, is left to the caller of this function. */
 
}
 

	
 
/**
 
 * Scans the string for valid characters and if it finds invalid ones,
 
 * replaces them with a question mark '?' (if not ignored)
 
 * @param str the string to validate
 
 * @param last the last valid character of str
 
 * @param settings the settings for the string validation.
 
 * Scans the string for invalid characters and replaces then with a
 
 * question mark '?' (if not ignored).
 
 * @param str The string to validate.
 
 * @param last The last valid character of str.
 
 * @param settings The settings for the string validation.
 
 */
 
void str_validate(char *str, const char *last, StringValidationSettings settings)
 
void StrMakeValidInPlace(char *str, const char *last, StringValidationSettings settings)
 
{
 
	char *dst = str;
 
	str_validate(dst, str, last, settings);
 
	StrMakeValidInPlace(dst, str, last, settings);
 
	*dst = '\0';
 
}
 

	
 
/**
 
 * Scans the string for valid characters and if it finds invalid ones,
 
 * replaces them with a question mark '?' (if not ignored)
 
 * @param str the string to validate
 
 * @param settings the settings for the string validation.
 
 * Scans the string for invalid characters and replaces then with a
 
 * question mark '?' (if not ignored).
 
 * Only use this function when you are sure the string ends with a '\0';
 
 * otherwise use StrMakeValidInPlace(str, last, settings) variant.
 
 * @param str The string (of which you are sure ends with '\0') to validate.
 
 */
 
std::string str_validate(const std::string &str, StringValidationSettings settings)
 
void StrMakeValidInPlace(const char *str, StringValidationSettings settings)
 
{
 
	/* We know it is '\0' terminated. */
 
	StrMakeValidInPlace(const_cast<char *>(str), str + strlen(str), settings);
 
}
 

	
 
/**
 
 * Scans the string for invalid characters and replaces then with a
 
 * question mark '?' (if not ignored).
 
 * @param str The string to validate.
 
 * @param settings The settings for the string validation.
 
 */
 
std::string StrMakeValid(const std::string &str, StringValidationSettings settings)
 
{
 
	auto buf = str.data();
 
	auto last = buf + str.size();
 

	
 
	std::ostringstream dst;
 
	std::ostreambuf_iterator<char> dst_iter(dst);
 
	str_validate(dst_iter, buf, last, settings);
 
	StrMakeValidInPlace(dst_iter, buf, last, settings);
 

	
 
	return dst.str();
 
}
 

	
 
/**
 
 * Scans the string for valid characters and if it finds invalid ones,
 
 * replaces them with a question mark '?'.
 
 * @param str the string to validate
 
 */
 
void ValidateString(const char *str)
 
{
 
	/* We know it is '\0' terminated. */
 
	str_validate(const_cast<char *>(str), str + strlen(str) + 1);
 
}
 

	
 

	
 
/**
 
 * Checks whether the given string is valid, i.e. contains only
 
 * valid (printable) characters and is properly terminated.
 
 * @param str  The string to validate.
 
 * @param last The last character of the string, i.e. the string
 
 *             must be terminated here or earlier.
 
 */
 
bool StrValid(const char *str, const char *last)
 
{
 
	/* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */
 

	
 
	while (str <= last && *str != '\0') {
 
		size_t len = Utf8EncodedCharLen(*str);
 
		/* Encoded length is 0 if the character isn't known.
 
		 * The length check is needed to prevent Utf8Decode to read
 
		 * over the terminating '\0' if that happens to be placed
 
		 * within the encoding of an UTF8 character. */
 
		if (len == 0 || str + len > last) return false;
 

	
 
		WChar c;
 
		len = Utf8Decode(&c, str);
 
		if (!IsPrintable(c) || (c >= SCC_SPRITE_START && c <= SCC_SPRITE_END)) {
 
			return false;
 
		}
 

	
src/string_func.h
Show inline comments
 
@@ -18,51 +18,51 @@
 
 *   subsequent snprintf alikes write outside of the buffer. Use
 
 *   [v]seprintf instead; it will return the number of bytes actually
 
 *   added so no [v]seprintf will cause outside of bounds writes.
 
 * - [v]sprintf: does not bounds checking: use [v]seprintf instead.
 
 */
 

	
 
#ifndef STRING_FUNC_H
 
#define STRING_FUNC_H
 

	
 
#include <stdarg.h>
 
#include <iosfwd>
 

	
 
#include "core/bitmath_func.hpp"
 
#include "string_type.h"
 

	
 
char *strecat(char *dst, const char *src, const char *last) NOACCESS(3);
 
char *strecpy(char *dst, const char *src, const char *last) NOACCESS(3);
 
char *stredup(const char *src, const char *last = nullptr) NOACCESS(2);
 

	
 
int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4) NOACCESS(2);
 
int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) WARN_FORMAT(3, 0) NOACCESS(2);
 

	
 
char *CDECL str_fmt(const char *str, ...) WARN_FORMAT(1, 2);
 

	
 
void str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) NOACCESS(2);
 
[[nodiscard]] std::string str_validate(const std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
 
void ValidateString(const char *str);
 
void StrMakeValidInPlace(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) NOACCESS(2);
 
[[nodiscard]] std::string StrMakeValid(const std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
 
void StrMakeValidInPlace(const char *str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
 

	
 
void str_fix_scc_encoded(char *str, const char *last) NOACCESS(2);
 
void str_strip_colours(char *str);
 
bool strtolower(char *str);
 
bool strtolower(std::string &str, std::string::size_type offs = 0);
 

	
 
bool StrValid(const char *str, const char *last) NOACCESS(2);
 
void StrTrimInPlace(std::string &str);
 

	
 
/**
 
 * Check if a string buffer is empty.
 
 *
 
 * @param s The pointer to the first element of the buffer
 
 * @return true if the buffer starts with the terminating null-character or
 
 *         if the given pointer points to nullptr else return false
 
 */
 
static inline bool StrEmpty(const char *s)
 
{
 
	return s == nullptr || s[0] == '\0';
 
}
 

	
 
/**
 
 * Get the length of a string, within a limited buffer.
 
 *
src/textfile_gui.cpp
Show inline comments
 
@@ -354,58 +354,58 @@ static void Xunzip(byte **bufp, size_t *
 

	
 
	if (read != filesize) return;
 

	
 
#if defined(WITH_ZLIB) || defined(WITH_LIBLZMA)
 
	const char *suffix = strrchr(textfile, '.');
 
	if (suffix == nullptr) return;
 
#endif
 

	
 
#if defined(WITH_ZLIB)
 
	/* In-place gunzip */
 
	if (strcmp(suffix, ".gz") == 0) Gunzip((byte**)&this->text, &filesize);
 
#endif
 

	
 
#if defined(WITH_LIBLZMA)
 
	/* In-place xunzip */
 
	if (strcmp(suffix, ".xz") == 0) Xunzip((byte**)&this->text, &filesize);
 
#endif
 

	
 
	if (!this->text) return;
 

	
 
	/* Add space for trailing \0 */
 
	this->text = ReallocT(this->text, filesize + 1);
 
	this->text[filesize] = '\0';
 

	
 
	/* Replace tabs and line feeds with a space since str_validate removes those. */
 
	/* Replace tabs and line feeds with a space since StrMakeValidInPlace removes those. */
 
	for (char *p = this->text; *p != '\0'; p++) {
 
		if (*p == '\t' || *p == '\r') *p = ' ';
 
	}
 

	
 
	/* Check for the byte-order-mark, and skip it if needed. */
 
	char *p = this->text + (strncmp(u8"\ufeff", this->text, 3) == 0 ? 3 : 0);
 

	
 
	/* Make sure the string is a valid UTF-8 sequence. */
 
	str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
 
	StrMakeValidInPlace(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
 

	
 
	/* Split the string on newlines. */
 
	int row = 0;
 
	this->lines.emplace_back(row, p);
 
	for (; *p != '\0'; p++) {
 
		if (*p == '\n') {
 
			*p = '\0';
 
			this->lines.emplace_back(++row, p + 1);
 
		}
 
	}
 

	
 
	/* Calculate maximum text line length. */
 
	uint max_length = 0;
 
	for (auto &line : this->lines) {
 
		max_length = std::max(max_length, GetStringBoundingBox(line.text, FS_MONO).width);
 
	}
 
	this->max_length = max_length;
 

	
 
	CheckForMissingGlyphs(true, this);
 
}
 

	
 
/**
 
 * Search a textfile file next to the given content.
 
 * @param type The type of the textfile to search for.
src/video/dedicated_v.cpp
Show inline comments
 
@@ -208,49 +208,49 @@ static bool InputWaiting()
 
static void DedicatedHandleKeyInput()
 
{
 
	static char input_line[1024] = "";
 

	
 
	if (!InputWaiting()) return;
 

	
 
	if (_exit_game) return;
 

	
 
#if defined(UNIX) || defined(__OS2__)
 
	if (fgets(input_line, lengthof(input_line), stdin) == nullptr) return;
 
#else
 
	/* Handle console input, and signal console thread, it can accept input again */
 
	static_assert(lengthof(_win_console_thread_buffer) <= lengthof(input_line));
 
	strecpy(input_line, _win_console_thread_buffer, lastof(input_line));
 
	SetEvent(_hWaitForInputHandling);
 
#endif
 

	
 
	/* Remove trailing \r or \n */
 
	for (char *c = input_line; *c != '\0'; c++) {
 
		if (*c == '\n' || *c == '\r' || c == lastof(input_line)) {
 
			*c = '\0';
 
			break;
 
		}
 
	}
 
	str_validate(input_line, lastof(input_line));
 
	StrMakeValidInPlace(input_line, lastof(input_line));
 

	
 
	IConsoleCmdExec(input_line); // execute command
 
}
 

	
 
void VideoDriver_Dedicated::MainLoop()
 
{
 
	/* Signal handlers */
 
#if defined(UNIX)
 
	signal(SIGTERM, DedicatedSignalHandler);
 
	signal(SIGINT, DedicatedSignalHandler);
 
	signal(SIGQUIT, DedicatedSignalHandler);
 
#endif
 

	
 
	/* Load the dedicated server stuff */
 
	_is_network_server = true;
 
	_network_dedicated = true;
 
	_current_company = _local_company = COMPANY_SPECTATOR;
 

	
 
	/* If SwitchMode is SM_LOAD_GAME, it means that the user used the '-g' options */
 
	if (_switch_mode != SM_LOAD_GAME) {
 
		StartNewGameWithoutGUI(GENERATE_NEW_SEED);
 
	} else {
 
		/* First we need to test if the savegame can be loaded, else we will end up playing the
 
		 *  intro game... */
0 comments (0 inline, 0 general)