Changeset - r5108:28640689af54
[Not reviewed]
master
0 39 4
peter1138 - 18 years ago 2006-11-16 22:05:33
peter1138@openttd.org
(svn r7182) -Feature: Merge utf8 branch. This brings us support for Unicode/UTF-8 and the option for fonts rendered by FreeType. Language changes to come.
43 files changed with 1769 insertions and 858 deletions:
0 comments (0 inline, 0 general)
Makefile
Show inline comments
 
@@ -235,6 +235,12 @@ ifdef WITH_PNG
 
	endif
 
endif
 

	
 
ifdef WITH_FREETYPE
 
	ifndef FREETYPE_CONFIG
 
$(error WITH_FREETYPE can't be used when FREETYPE_CONFIG is not set. Edit Makefile.config to correct this)
 
	endif
 
endif
 

	
 
##############################################################################
 
#
 
# Compiler configuration
 
@@ -493,6 +499,15 @@ ifndef MINGW
 
	LIBS += -lc
 
endif
 

	
 
# freetype config
 
ifdef WITH_FREETYPE
 
CDEFS += -DWITH_FREETYPE
 
CCFLAGS_FREETYPE := $(shell $(FREETYPE_CONFIG) --cflags)
 
LDFLAGS_FREETYPE := $(shell $(FREETYPE_CONFIG) --libs)
 
CFLAGS += $(CCFLAGS_FREETYPE)
 
LIBS += $(LDFLAGS_FREETYPE)
 
endif
 

	
 
# iconv is enabled defaultly on OSX >= 10.3
 
ifdef OSX
 
	ifndef JAGUAR
 
@@ -670,6 +685,7 @@ SRCS += engine.c
 
SRCS += engine_gui.c
 
SRCS += fileio.c
 
SRCS += fios.c
 
SRCS += fontcache.c
 
SRCS += genworld.c
 
SRCS += genworld_gui.c
 
SRCS += gfx.c
 
@@ -884,7 +900,7 @@ ifndef MACOSX_BUILD
 
	$(Q)$(CXX_TARGET) $(LDFLAGS) $(TTDLDFLAGS) $(OBJS) $(LIBS) -o $@
 
endif
 

	
 
$(STRGEN): strgen/strgen.c string.c endian_host.h
 
$(STRGEN): strgen/strgen.c string.c endian_host.h table/control_codes.h
 
	@echo '===> Compiling and Linking $@'
 
	$(Q)$(CC_HOST) $(CFLAGS_HOST) -DSTRGEN strgen/strgen.c string.c -o $@
 

	
configure
Show inline comments
 
@@ -35,11 +35,13 @@ function showhelp() {
 
	echo " iconv              Do you want iconv-support?          [no]"
 
	echo " network            Do you want network-support?        [yes]"
 
	echo " cocoa              Do you want cocoa-support? (MacOSX) [no]"
 
	echo " freetype           Do you want freetype-support?       [yes]"
 
	echo ""
 
	echo "Params used to configure external libs:"
 
	echo " --static-zlib-path Set the path to your static zlib    []"
 
	echo " --sdl-config       Where is your sdl-config            [sdl-config]"
 
	echo " --libpng-config    Where is your libpng-config         [libpng-config]"
 
	echo " --freetype-config  Where is your freetype-config       [freetype-config]"
 
	echo " --with-iconv       Set the path to your iconv headers  []"
 
	echo " "
 
}
 
@@ -181,6 +183,12 @@ do
 
		--without-cocoa)
 
			PARAM="$PARAM WITH_COCOA="
 
			;;
 
		--with-freetype)
 
			PARAM="$PARAM WITH_FREETYPE=1"
 
			;;
 
		--without-freetype)
 
			PARAM="$PARAM WITH_FREETYPE="
 
			;;
 
		--static-zlib-path=*)
 
			handle STATIC_ZLIB_PATH "$n"
 
			;;
 
@@ -199,6 +207,12 @@ do
 
		--libpng-config)
 
			ITEM="LIBPNG_CONFIG"
 
			;;
 
		--freetype-config=*)
 
			handle FREETYPE_CONFIG "$n"
 
			;;
 
		--freetype-config)
 
			ITEM="FREETYPE_CONFIG"
 
			;;
 

	
 
		--*=*)
 
			echo -n "Unknown switch "
console.c
Show inline comments
 
@@ -181,9 +181,9 @@ static void IConsoleWndProc(Window *w, W
 
					}
 
					break;
 
				default:
 
					if (IsValidAsciiChar(e->we.keypress.ascii, CS_ALPHANUMERAL)) {
 
					if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
 
						_iconsole_scroll = ICON_BUFFER;
 
						InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.ascii);
 
						InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
 
						IConsoleResetHistoryPos();
 
						SetWindowDirty(w);
 
					} else {
 
@@ -1057,7 +1057,7 @@ void IConsoleCmdExec(const char *cmdstr)
 
	if (cmdstr[0] == '#') return; // comments
 

	
 
	for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
 
		if (!IsValidAsciiChar(*cmdptr, CS_ALPHANUMERAL)) {
 
		if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
 
			IConsoleError("command contains malformed characters, aborting");
 
			IConsolePrintF(_icolour_err, "ERROR: command was: '%s'", cmdstr);
 
			return;
currency.c
Show inline comments
 
@@ -13,14 +13,14 @@
 
	//   |   |    Euro year  |       |       |    name
 
	//   |   |    |          |       |       |    |
 
static const CurrencySpec origin_currency_specs[NUM_CURRENCY] = {
 
	{    1, ',', CF_NOEURO, "\xA3", "",      0,  STR_CURR_GBP    }, // british pounds
 
	{    1, ',', CF_NOEURO, "£",    "",      0,  STR_CURR_GBP    }, // british pounds
 
	{    2, ',', CF_NOEURO, "$",    "",      0,  STR_CURR_USD    }, // us dollars
 
	{    2, ',', CF_ISEURO, "¤",    "",      0,  STR_CURR_EUR    }, // Euro
 
	{  220, ',', CF_NOEURO, "\xA5", "",      0,  STR_CURR_YEN    }, // yen
 
	{    2, ',', CF_ISEURO, "€",    "",      0,  STR_CURR_EUR    }, // Euro
 
	{  220, ',', CF_NOEURO, "¥",    "",      0,  STR_CURR_YEN    }, // yen
 
	{   20, ',', 2002,      "",     " S.",   1,  STR_CURR_ATS    }, // austrian schilling
 
	{   59, ',', 2002,      "BEF ", "",      0,  STR_CURR_BEF    }, // belgian franc
 
	{    2, ',', CF_NOEURO, "CHF ", "",      0,  STR_CURR_CHF    }, // swiss franc
 
	{   41, ',', CF_NOEURO, "",     " Kc",   1,  STR_CURR_CZK    }, // czech koruna // TODO: Should use the "c" with an upside down "^"
 
	{   41, ',', CF_NOEURO, "",     " ",   1,  STR_CURR_CZK    }, // czech koruna
 
	{    3, '.', 2002,      "DM ",  "",      0,  STR_CURR_DEM    }, // deutsche mark
 
	{   11, '.', CF_NOEURO, "",     " kr",   1,  STR_CURR_DKK    }, // danish krone
 
	{  245, '.', 2002,      "Pts ", "",      0,  STR_CURR_ESP    }, // spanish pesetas
debug.c
Show inline comments
 
@@ -21,6 +21,7 @@ int _debug_oldloader_level;
 
int _debug_ntp_level;
 
int _debug_npf_level;
 
int _debug_yapf_level;
 
int _debug_freetype_level;
 

	
 

	
 
void CDECL debug(const char *s, ...)
 
@@ -53,7 +54,8 @@ typedef struct DebugLevel {
 
	DEBUG_LEVEL(oldloader),
 
	DEBUG_LEVEL(ntp),
 
	DEBUG_LEVEL(npf),
 
	DEBUG_LEVEL(yapf)
 
	DEBUG_LEVEL(yapf),
 
	DEBUG_LEVEL(freetype)
 
	};
 
#undef DEBUG_LEVEL
 

	
debug.h
Show inline comments
 
@@ -20,6 +20,7 @@
 
	extern int _debug_ntp_level;
 
	extern int _debug_npf_level;
 
	extern int _debug_yapf_level;
 
	extern int _debug_freetype_level;
 
#endif
 

	
 
void CDECL debug(const char *s, ...);
fontcache.c
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "functions.h"
 
#include "macros.h"
 
#include "debug.h"
 
#include "table/sprites.h"
 
#include "table/control_codes.h"
 
#include "spritecache.h"
 
#include "gfx.h"
 
#include "string.h"
 
#include "fontcache.h"
 

	
 
#ifdef WITH_FREETYPE
 

	
 
#include <ft2build.h>
 
#include FT_FREETYPE_H
 
#include FT_GLYPH_H
 

	
 
static FT_Library _library = NULL;
 
static FT_Face _face_small = NULL;
 
static FT_Face _face_medium = NULL;
 
static FT_Face _face_large = NULL;
 

	
 
FreeTypeSettings _freetype;
 

	
 
enum {
 
	FACE_COLOUR = 1,
 
	SHADOW_COLOUR = 2,
 
};
 

	
 

	
 
static void LoadFreeTypeFont(const char *font_name, FT_Face *face, const char *type)
 
{
 
	FT_Error error;
 

	
 
	if (strlen(font_name) == 0) return;
 

	
 
	error = FT_New_Face(_library, font_name, 0, face);
 
	if (error == FT_Err_Ok) {
 
		/* Attempt to select the unicode character map */
 
		error = FT_Select_Charmap(*face, ft_encoding_unicode);
 
		if (error == FT_Err_Ok) {
 
			/* Success */
 
			return;
 
		} else if (error == FT_Err_Invalid_CharMap_Handle) {
 
			/* Try to pick a different character map instead. We default to
 
			 * the first map, but platform_id 0 encoding_id 0 should also
 
			 * be unicode (strange system...) */
 
			FT_CharMap found = (*face)->charmaps[0];
 
			int i;
 

	
 
			for (i = 0; i < (*face)->num_charmaps; i++) {
 
				FT_CharMap charmap = (*face)->charmaps[i];
 
				if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
 
					found = charmap;
 
				}
 
			}
 

	
 
			if (found != NULL) {
 
				error = FT_Set_Charmap(*face, found);
 
				if (error == FT_Err_Ok) return;
 
			}
 
		}
 

	
 
		FT_Done_Face(*face);
 
		*face = NULL;
 
	}
 

	
 
	ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, type, error);
 
}
 

	
 

	
 
void InitFreeType(void)
 
{
 
	if (strlen(_freetype.small_font) == 0 && strlen(_freetype.medium_font) == 0 && strlen(_freetype.large_font) == 0) {
 
		DEBUG(freetype, 1) ("[FreeType] No font faces specified, using sprite fonts instead");
 
		return;
 
	}
 

	
 
	if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
 
		ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
 
		return;
 
	}
 

	
 
	DEBUG(freetype, 2) ("[FreeType] Initialized");
 

	
 
	/* Load each font */
 
	LoadFreeTypeFont(_freetype.small_font,  &_face_small,  "small");
 
	LoadFreeTypeFont(_freetype.medium_font, &_face_medium, "medium");
 
	LoadFreeTypeFont(_freetype.large_font,  &_face_large,  "large");
 

	
 
	/* Set each font size */
 
	if (_face_small  != NULL) FT_Set_Pixel_Sizes(_face_small,  0, _freetype.small_size);
 
	if (_face_medium != NULL) FT_Set_Pixel_Sizes(_face_medium, 0, _freetype.medium_size);
 
	if (_face_large  != NULL) FT_Set_Pixel_Sizes(_face_large,  0, _freetype.large_size);
 
}
 

	
 

	
 
static FT_Face GetFontFace(FontSize size)
 
{
 
	switch (size) {
 
		default: NOT_REACHED();
 
		case FS_NORMAL: return _face_medium;
 
		case FS_SMALL:  return _face_small;
 
		case FS_LARGE:  return _face_large;
 
	}
 
}
 

	
 

	
 
typedef struct GlyphEntry {
 
	Sprite *sprite;
 
	byte width;
 
} GlyphEntry;
 

	
 

	
 
/* The glyph cache. This is structured to reduce memory consumption.
 
 * 1) There is a 'segment' table for each font size.
 
 * 2) Each segment table is a discrete block of characters.
 
 * 3) Each block contains 256 (aligned) characters sequential characters.
 
 *
 
 * The cache is accessed in the following way:
 
 * For character 0x0041  ('A'): _glyph_ptr[FS_NORMAL][0x00][0x41]
 
 * For character 0x20AC (Euro): _glyph_ptr[FS_NORMAL][0x20][0xAC]
 
 *
 
 * Currently only 256 segments are allocated, "limiting" us to 65536 characters.
 
 * This can be simply changed in the two functions Get & SetGlyphPtr.
 
 */
 
static GlyphEntry **_glyph_ptr[FS_END];
 

	
 

	
 
static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
 
{
 
	if (_glyph_ptr[size] == NULL) return NULL;
 
	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) return NULL;
 
	return &_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)];
 
}
 

	
 

	
 
static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
 
{
 
	if (_glyph_ptr[size] == NULL) {
 
		DEBUG(freetype, 3) ("[FreeType] Allocating root glyph cache for size %u", size);
 
		_glyph_ptr[size] = calloc(256, sizeof(**_glyph_ptr));
 
	}
 

	
 
	if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) {
 
		DEBUG(freetype, 3) ("[FreeType] Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), size);
 
		_glyph_ptr[size][GB(key, 8, 8)] = calloc(256, sizeof(***_glyph_ptr));
 
	}
 

	
 
	DEBUG(freetype, 4) ("[FreeType] Set glyph for unicode character 0x%04X, size %u", key, size);
 
	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
 
	_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width  = glyph->width;
 
}
 

	
 

	
 
const Sprite *GetGlyph(FontSize size, WChar key)
 
{
 
	FT_Face face = GetFontFace(size);
 
	FT_GlyphSlot slot;
 
	GlyphEntry new_glyph;
 
	GlyphEntry *glyph;
 
	Sprite *sprite;
 
	int width;
 
	int height;
 
	int x;
 
	int y;
 
	int y_adj;
 

	
 
	assert(IsPrintable(key));
 

	
 
	/* Bail out if no face loaded, or for our special characters */
 
	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
 
		SpriteID sprite = GetUnicodeGlyph(size, key);
 
		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
 
		return GetSprite(sprite);
 
	}
 

	
 
	/* Check for the glyph in our cache */
 
	glyph = GetGlyphPtr(size, key);
 
	if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
 

	
 
	slot = face->glyph;
 

	
 
	FT_Load_Char(face, key, FT_LOAD_DEFAULT);
 
	FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
 

	
 
	/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
 
	width  = max(1, slot->bitmap.width + (size == FS_NORMAL));
 
	height = max(1, slot->bitmap.rows  + (size == FS_NORMAL));
 

	
 
	/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
 
	sprite = calloc(width * height + 8, 1);
 
	sprite->info   = 1;
 
	sprite->width  = width;
 
	sprite->height = height;
 
	sprite->x_offs = slot->bitmap_left;
 
	// XXX 2 should be determined somehow... it's right for the normal face
 
	y_adj = (size == FS_NORMAL) ? 2 : 0;
 
	sprite->y_offs = GetCharacterHeight(size) - slot->bitmap_top - y_adj;
 

	
 
	/* Draw shadow for medium size */
 
	if (size == FS_NORMAL) {
 
		for (y = 0; y < slot->bitmap.rows; y++) {
 
			for (x = 0; x < slot->bitmap.width; x++) {
 
				if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
 
					sprite->data[1 + x + (1 + y) * sprite->width] = SHADOW_COLOUR;
 
				}
 
			}
 
		}
 
	}
 

	
 
	for (y = 0; y < slot->bitmap.rows; y++) {
 
		for (x = 0; x < slot->bitmap.width; x++) {
 
			if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
 
				sprite->data[x + y * sprite->width] = FACE_COLOUR;
 
			}
 
		}
 
	}
 

	
 
	new_glyph.sprite = sprite;
 
	new_glyph.width  = (slot->advance.x >> 6) + (size != FS_NORMAL);
 

	
 
	SetGlyphPtr(size, key, &new_glyph);
 

	
 
	return sprite;
 
}
 

	
 

	
 
uint GetGlyphWidth(FontSize size, WChar key)
 
{
 
	FT_Face face = GetFontFace(size);
 
	GlyphEntry *glyph;
 

	
 
	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
 
		SpriteID sprite = GetUnicodeGlyph(size, key);
 
		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
 
		return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
 
	}
 

	
 
	glyph = GetGlyphPtr(size, key);
 
	if (glyph == NULL || glyph->sprite == NULL) {
 
		GetGlyph(size, key);
 
		glyph = GetGlyphPtr(size, key);
 
	}
 

	
 
	return glyph->width;
 
}
 

	
 

	
 
#endif /* WITH_FREETYPE */
 

	
 
/* Sprite based glyph mapping */
 

	
 
#include "table/unicode.h"
 

	
 
static SpriteID **_unicode_glyph_map[FS_END];
 

	
 

	
 
/** Get the SpriteID of the first glyph for the given font size */
 
static SpriteID GetFontBase(FontSize size)
 
{
 
	switch (size) {
 
		default: NOT_REACHED();
 
		case FS_NORMAL: return SPR_ASCII_SPACE;
 
		case FS_SMALL:  return SPR_ASCII_SPACE_SMALL;
 
		case FS_LARGE:  return SPR_ASCII_SPACE_BIG;
 
	}
 
}
 

	
 

	
 
SpriteID GetUnicodeGlyph(FontSize size, uint32 key)
 
{
 
	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) return 0;
 
	return _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)];
 
}
 

	
 

	
 
void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite)
 
{
 
	if (_unicode_glyph_map[size] == NULL) _unicode_glyph_map[size] = calloc(256, sizeof(*_unicode_glyph_map[size]));
 
	if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) _unicode_glyph_map[size][GB(key, 8, 8)] = calloc(256, sizeof(**_unicode_glyph_map[size]));
 
	_unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
 
}
 

	
 

	
 
void InitializeUnicodeGlyphMap(void)
 
{
 
	FontSize size;
 
	SpriteID base;
 
	SpriteID sprite;
 
	uint i;
 

	
 
	for (size = FS_NORMAL; size != FS_END; size++) {
 
		base = GetFontBase(size);
 
		for (i = ASCII_LETTERSTART; i < 256; i++) {
 
			sprite = base + i - ASCII_LETTERSTART;
 
			if (!SpriteExists(sprite)) continue;
 
			SetUnicodeGlyph(size, i, sprite);
 
			SetUnicodeGlyph(size, i + SCC_SPRITE_START, sprite);
 
		}
 
		for (i = 0; i < lengthof(_default_unicode_map); i++) {
 
			sprite = base + _default_unicode_map[i].key - ASCII_LETTERSTART;
 
			SetUnicodeGlyph(size, _default_unicode_map[i].code, sprite);
 
		}
 
	}
 
}
 

	
fontcache.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
#ifndef FONTCACHE_H
 
#define FONTCACHE_H
 

	
 
/** Get the SpriteID mapped to the given font size and key */
 
SpriteID GetUnicodeGlyph(FontSize size, uint32 key);
 

	
 
/** Map a SpriteID to the font size and key */
 
void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite);
 

	
 
/** Initialize the glyph map */
 
void InitializeUnicodeGlyphMap(void);
 

	
 
#ifdef WITH_FREETYPE
 

	
 
typedef struct FreeTypeSettings {
 
	char small_font[260];
 
	char medium_font[260];
 
	char large_font[260];
 
	uint small_size;
 
	uint medium_size;
 
	uint large_size;
 
} FreeTypeSettings;
 

	
 
extern FreeTypeSettings _freetype;
 

	
 
void InitFreeType(void);
 
const struct Sprite *GetGlyph(FontSize size, uint32 key);
 
uint GetGlyphWidth(FontSize size, uint32 key);
 

	
 
#else
 

	
 
/* Stub for initializiation */
 
static inline void InitFreeType(void) {}
 

	
 
/** Get the Sprite for a glyph */
 
static inline const Sprite *GetGlyph(FontSize size, uint32 key)
 
{
 
	SpriteID sprite = GetUnicodeGlyph(size, key);
 
	if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
 
	return GetSprite(sprite);
 
}
 

	
 

	
 
/** Get the width of a glyph */
 
static inline uint GetGlyphWidth(FontSize size, uint32 key)
 
{
 
	SpriteID sprite = GetUnicodeGlyph(size, key);
 
	if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
 
	return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
 
}
 

	
 
#endif /* WITH_FREETYPE */
 

	
 
#endif /* FONTCACHE_H */
functions.h
Show inline comments
 
@@ -147,6 +147,7 @@ char *GetName(char *buff, StringID id, c
 
#define AllocateNameUnique(name, skip) RealAllocateName(name, skip, true)
 
#define AllocateName(name, skip) RealAllocateName(name, skip, false)
 
StringID RealAllocateName(const char *name, byte skip, bool check_double);
 
void ConvertNameArray(void);
 

	
 
/* misc functions */
 
void MarkTileDirty(int x, int y);
gfx.c
Show inline comments
 
@@ -12,6 +12,8 @@
 
#include "table/sprites.h"
 
#include "hal.h"
 
#include "variables.h"
 
#include "table/control_codes.h"
 
#include "fontcache.h"
 
#include "genworld.h"
 

	
 
#ifdef _DEBUG
 
@@ -244,40 +246,6 @@ void GfxDrawLine(int x, int y, int x2, i
 
}
 

	
 

	
 
static inline SpriteID GetFontBase(FontSize size)
 
{
 
	switch (size) {
 
		default: NOT_REACHED();
 
		case FS_NORMAL: return SPR_ASCII_SPACE;
 
		case FS_SMALL:  return SPR_ASCII_SPACE_SMALL;
 
		case FS_LARGE:  return SPR_ASCII_SPACE_BIG;
 
	}
 
}
 

	
 

	
 
// ASSIGNMENT OF ASCII LETTERS < 32
 
// 0 - end of string
 
// 1 - SETX <BYTE>
 
// 2 - SETXY <BYTE> <BYTE>
 
// 3-7 -
 
// 8 - TINYFONT
 
// 9 - BIGFONT
 
// 10 - newline
 
// 11-14 -
 
// 15-31 - 17 colors
 

	
 

	
 
enum {
 
	ASCII_SETX       =  1,
 
	ASCII_SETXY      =  2,
 

	
 
	ASCII_TINYFONT   =  8,
 
	ASCII_BIGFONT    =  9,
 
	ASCII_NL         = 10,
 

	
 
	ASCII_COLORSTART = 15,
 
};
 

	
 
/** Truncate a given string to a maximum width if neccessary.
 
 * If the string is truncated, add three dots ('...') to show this.
 
 * @param *dest string that is checked and possibly truncated
 
@@ -289,13 +257,13 @@ static int TruncateString(char *str, int
 
	FontSize size = _cur_fontsize;
 
	int ddd, ddd_w;
 

	
 
	byte c;
 
	WChar c;
 
	char *ddd_pos;
 

	
 
	ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
 

	
 
	for (ddd_pos = str; (c = *str++) != '\0'; ) {
 
		if (c >= ASCII_LETTERSTART) {
 
	for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) {
 
		if (IsPrintable(c)) {
 
			w += GetCharacterWidth(size, c);
 

	
 
			if (w >= maxw) {
 
@@ -305,12 +273,12 @@ static int TruncateString(char *str, int
 
				return ddd_w;
 
			}
 
		} else {
 
			if (c == ASCII_SETX) str++;
 
			else if (c == ASCII_SETXY) str += 2;
 
			else if (c == ASCII_TINYFONT) {
 
			if (c == SCC_SETX) str++;
 
			else if (c == SCC_SETXY) str += 2;
 
			else if (c == SCC_TINYFONT) {
 
				size = FS_SMALL;
 
				ddd = GetCharacterWidth(size, '.') * 3;
 
			} else if (c == ASCII_BIGFONT) {
 
			} else if (c == SCC_BIGFONT) {
 
				size = FS_LARGE;
 
				ddd = GetCharacterWidth(size, '.') * 3;
 
			}
 
@@ -443,11 +411,11 @@ uint32 FormatStringLinebreaks(char *str,
 
		int w = 0;
 

	
 
		for (;;) {
 
			byte c = *str++;
 
			WChar c = Utf8Consume((const char **)&str);
 
			/* whitespace is where we will insert the line-break */
 
			if (c == ASCII_LETTERSTART) last_space = str;
 
			if (c == ' ') last_space = str;
 

	
 
			if (c >= ASCII_LETTERSTART) {
 
			if (IsPrintable(c)) {
 
				w += GetCharacterWidth(size, c);
 
				/* string is longer than maximum width so we need to decide what to
 
				 * do. We can do two things:
 
@@ -465,11 +433,11 @@ uint32 FormatStringLinebreaks(char *str,
 
			} else {
 
				switch (c) {
 
					case '\0': return num + (size << 16); break;
 
					case ASCII_SETX:  str++; break;
 
					case ASCII_SETXY: str +=2; break;
 
					case ASCII_TINYFONT: size = FS_SMALL; break;
 
					case ASCII_BIGFONT:  size = FS_LARGE; break;
 
					case ASCII_NL: goto end_of_inner_loop;
 
					case SCC_SETX:  str++; break;
 
					case SCC_SETXY: str +=2; break;
 
					case SCC_TINYFONT: size = FS_SMALL; break;
 
					case SCC_BIGFONT:  size = FS_LARGE; break;
 
					case '\n': goto end_of_inner_loop;
 
				}
 
			}
 
		}
 
@@ -486,7 +454,7 @@ void DrawStringMultiCenter(int x, int y,
 
	uint32 tmp;
 
	int num, w, mt;
 
	const char *src;
 
	byte c;
 
	WChar c;
 

	
 
	GetString(buffer, str, lastof(buffer));
 

	
 
@@ -505,7 +473,7 @@ void DrawStringMultiCenter(int x, int y,
 
		_cur_fontsize = _last_fontsize;
 

	
 
		for (;;) {
 
			c = *src++;
 
			c = Utf8Consume(&src);
 
			if (c == 0) {
 
				y += mt;
 
				if (--num < 0) {
 
@@ -513,9 +481,9 @@ void DrawStringMultiCenter(int x, int y,
 
					return;
 
				}
 
				break;
 
			} else if (c == ASCII_SETX) {
 
			} else if (c == SCC_SETX) {
 
				src++;
 
			} else if (c == ASCII_SETXY) {
 
			} else if (c == SCC_SETXY) {
 
				src+=2;
 
			}
 
		}
 
@@ -530,7 +498,7 @@ uint DrawStringMultiLine(int x, int y, S
 
	int num, mt;
 
	uint total_height;
 
	const char *src;
 
	byte c;
 
	WChar c;
 

	
 
	GetString(buffer, str, lastof(buffer));
 

	
 
@@ -547,7 +515,7 @@ uint DrawStringMultiLine(int x, int y, S
 
		_cur_fontsize = _last_fontsize;
 

	
 
		for (;;) {
 
			c = *src++;
 
			c = Utf8Consume(&src);
 
			if (c == 0) {
 
				y += mt;
 
				if (--num < 0) {
 
@@ -555,9 +523,9 @@ uint DrawStringMultiLine(int x, int y, S
 
					return total_height;
 
				}
 
				break;
 
			} else if (c == ASCII_SETX) {
 
			} else if (c == SCC_SETX) {
 
				src++;
 
			} else if (c == ASCII_SETXY) {
 
			} else if (c == SCC_SETXY) {
 
				src+=2;
 
			}
 
		}
 
@@ -576,22 +544,24 @@ BoundingRect GetStringBoundingBox(const 
 
	FontSize size = _cur_fontsize;
 
	BoundingRect br;
 
	int max_width;
 
	byte c;
 
	WChar c;
 

	
 
	br.width = br.height = max_width = 0;
 
	for (c = *str; c != '\0'; c = *(++str)) {
 
		if (c >= ASCII_LETTERSTART) {
 
	for (;;) {
 
		c = Utf8Consume(&str);
 
		if (c == 0) break;
 
		if (IsPrintable(c)) {
 
			br.width += GetCharacterWidth(size, c);
 
		} else {
 
			switch (c) {
 
				case ASCII_SETX: br.width += (byte)*++str; break;
 
				case ASCII_SETXY:
 
				case SCC_SETX: br.width += (byte)*++str; break;
 
				case SCC_SETXY:
 
					br.width += (byte)*++str;
 
					br.height += (byte)*++str;
 
					break;
 
				case ASCII_TINYFONT: size = FS_SMALL; break;
 
				case ASCII_BIGFONT:  size = FS_LARGE; break;
 
				case ASCII_NL:
 
				case SCC_TINYFONT: size = FS_SMALL; break;
 
				case SCC_BIGFONT:  size = FS_LARGE; break;
 
				case '\n':
 
					br.height += GetCharacterHeight(size);
 
					if (br.width > max_width) max_width = br.width;
 
					br.width = 0;
 
@@ -617,7 +587,7 @@ int DoDrawString(const char *string, int
 
{
 
	DrawPixelInfo *dpi = _cur_dpi;
 
	FontSize size = _cur_fontsize;
 
	byte c;
 
	WChar c;
 
	byte color;
 
	int xo = x, yo = y;
 

	
 
@@ -647,39 +617,39 @@ check_bounds:
 
	if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) {
 
skip_char:;
 
		for (;;) {
 
			c = *string++;
 
			if (c < ASCII_LETTERSTART) goto skip_cont;
 
			c = Utf8Consume(&string);
 
			if (!IsPrintable(c)) goto skip_cont;
 
		}
 
	}
 

	
 
	for (;;) {
 
		c = *string++;
 
		c = Utf8Consume(&string);
 
skip_cont:;
 
		if (c == 0) {
 
			_last_fontsize = size;
 
			return x;
 
		}
 
		if (c >= ASCII_LETTERSTART) {
 
		if (IsPrintable(c)) {
 
			if (x >= dpi->left + dpi->width) goto skip_char;
 
			if (x + 26 >= dpi->left) {
 
				GfxMainBlitter(GetSprite(GetFontBase(size) + c - ASCII_LETTERSTART), x, y, 1);
 
				GfxMainBlitter(GetGlyph(size, c), x, y, 1);
 
			}
 
			x += GetCharacterWidth(size, c);
 
		} else if (c == ASCII_NL) { // newline = {}
 
		} else if (c == '\n') { // newline = {}
 
			x = xo;
 
			y += GetCharacterHeight(size);
 
			goto check_bounds;
 
		} else if (c >= ASCII_COLORSTART) { // change color?
 
			color = (byte)(c - ASCII_COLORSTART);
 
		} else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change color?
 
			color = (byte)(c - SCC_BLUE);
 
			goto switch_color;
 
		} else if (c == ASCII_SETX) { // {SETX}
 
		} else if (c == SCC_SETX) { // {SETX}
 
			x = xo + (byte)*string++;
 
		} else if (c == ASCII_SETXY) {// {SETXY}
 
		} else if (c == SCC_SETXY) {// {SETXY}
 
			x = xo + (byte)*string++;
 
			y = yo + (byte)*string++;
 
		} else if (c == ASCII_TINYFONT) { // {TINYFONT}
 
		} else if (c == SCC_TINYFONT) { // {TINYFONT}
 
			size = FS_SMALL;
 
		} else if (c == ASCII_BIGFONT) { // {BIGFONT}
 
		} else if (c == SCC_BIGFONT) { // {BIGFONT}
 
			size = FS_LARGE;
 
		} else {
 
			printf("Unknown string command character %d\n", c);
 
@@ -1641,28 +1611,33 @@ void DoPaletteAnimations(void)
 

	
 
void LoadStringWidthTable(void)
 
{
 
	SpriteID base;
 
	uint i;
 

	
 
	/* Normal font */
 
	base = GetFontBase(FS_NORMAL);
 
	for (i = 0; i != 224; i++) {
 
		_stringwidth_table[FS_NORMAL][i] = SpriteExists(base + i) ? GetSprite(base + i)->width : 0;
 
		_stringwidth_table[FS_NORMAL][i] = GetGlyphWidth(FS_NORMAL, i + 32);
 
	}
 

	
 
	/* Small font */
 
	base = GetFontBase(FS_SMALL);
 
	for (i = 0; i != 224; i++) {
 
		_stringwidth_table[FS_SMALL][i] = SpriteExists(base + i) ? GetSprite(base + i)->width + 1 : 0;
 
		_stringwidth_table[FS_SMALL][i] = GetGlyphWidth(FS_SMALL, i + 32);
 
	}
 

	
 
	/* Large font */
 
	base = GetFontBase(FS_LARGE);
 
	for (i = 0; i != 224; i++) {
 
		_stringwidth_table[FS_LARGE][i] = SpriteExists(base + i) ? GetSprite(base + i)->width + 1 : 0;
 
		_stringwidth_table[FS_LARGE][i] = GetGlyphWidth(FS_LARGE, i + 32);
 
	}
 
}
 

	
 

	
 
byte GetCharacterWidth(FontSize size, WChar key)
 
{
 
	if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32];
 

	
 
	return GetGlyphWidth(size, key);
 
}
 

	
 

	
 
void ScreenSizeChanged(void)
 
{
 
	// check the dirty rect
gfx.h
Show inline comments
 
@@ -43,8 +43,8 @@ void GfxScroll(int left, int top, int wi
 

	
 
// XXX doesn't really belong here, but the only
 
// consumers always use it in conjunction with DoDrawString()
 
#define UPARROW   "\x80"
 
#define DOWNARROW "\xAA"
 
#define UPARROW   "\xEE\x8A\x80"
 
#define DOWNARROW "\xEE\x8A\xAA"
 

	
 

	
 
int DrawStringCentered(int x, int y, StringID str, uint16 color);
 
@@ -96,13 +96,8 @@ void ToggleFullScreen(bool fs);
 
/* gfx.c */
 
#define ASCII_LETTERSTART 32
 
extern FontSize _cur_fontsize;
 
extern byte _stringwidth_table[FS_END][224];
 

	
 
static inline byte GetCharacterWidth(FontSize size, byte key)
 
{
 
	assert(key >= ASCII_LETTERSTART);
 
	return _stringwidth_table[size][key - ASCII_LETTERSTART];
 
}
 
byte GetCharacterWidth(FontSize size, uint32 key);
 

	
 
static inline byte GetCharacterHeight(FontSize size)
 
{
gui.h
Show inline comments
 
@@ -109,7 +109,7 @@ bool HandleCaret(Textbuf *tb);
 

	
 
void DeleteTextBufferAll(Textbuf *tb);
 
bool DeleteTextBufferChar(Textbuf *tb, int delmode);
 
bool InsertTextBufferChar(Textbuf *tb, byte key);
 
bool InsertTextBufferChar(Textbuf *tb, uint32 key);
 
bool InsertTextBufferClipboard(Textbuf *tb);
 
bool MoveTextBufferPos(Textbuf *tb, int navmode);
 
void InitializeTextBuffer(Textbuf *tb, const char *buf, uint16 maxlength, uint16 maxwidth);
lang/english.txt
Show inline comments
 
@@ -2001,8 +2001,8 @@ STR_26816_NONE                          
 
STR_6816_LOW                                                    :Low
 
STR_6817_NORMAL                                                 :Normal
 
STR_6818_HIGH                                                   :High
 
STR_6819                                                        :{BLACK}<
 
STR_681A                                                        :{BLACK}>
 
STR_6819                                                        :{BLACK}{SMALLLEFTARROW}
 
STR_681A                                                        :{BLACK}{SMALLRIGHTARROW}
 
STR_681B_VERY_SLOW                                              :Very Slow
 
STR_681C_SLOW                                                   :Slow
 
STR_681D_MEDIUM                                                 :Medium
main_gui.c
Show inline comments
 
@@ -29,6 +29,7 @@
 
#include "variables.h"
 
#include "train.h"
 
#include "unmovable_map.h"
 
#include "string.h"
 
#include "screenshot.h"
 
#include "genworld.h"
 
#include "settings.h"
 
@@ -2085,15 +2086,16 @@ static bool DrawScrollingStatusText(cons
 
	s = buf;
 
	d = buffer;
 

	
 
	for (;; s++) {
 
		if (*s == '\0') {
 
	for (;;) {
 
		WChar c = Utf8Consume(&s);
 
		if (c == 0) {
 
			*d = '\0';
 
			break;
 
		} else if (*s == 0x0D) {
 
			d[0] = d[1] = d[2] = d[3] = ' ';
 
			d += 4;
 
		} else if ((byte)*s >= ' ' && ((byte)*s < 0x88 || (byte)*s >= 0x99)) {
 
			*d++ = *s;
 
		} else if (IsPrintable(c)) {
 
			d += Utf8Encode(d, c);
 
		}
 
	}
 

	
makefiledir/Makefile.config_writer
Show inline comments
 
@@ -73,6 +73,7 @@ CONFIG_LINE=@$(SHELL) -c 'echo $(1)' >> 
 
	$(call CONFIG_LINE,WITH_ICONV_PATH:=$(WITH_ICONV_PATH))
 
	$(call CONFIG_LINE,STATIC_ZLIB_PATH:=$(STATIC_ZLIB_PATH))
 
	$(call CONFIG_LINE,WITH_COCOA:=$(WITH_COCOA))
 
	$(call CONFIG_LINE,WITH_FREETYPE:=$(WITH_FREETYPE))
 
	$(call CONFIG_LINE,)
 

	
 
	$(call CONFIG_LINE,\# OS flags)
 
@@ -100,6 +101,7 @@ CONFIG_LINE=@$(SHELL) -c 'echo $(1)' >> 
 
	$(call CONFIG_LINE,\# misc)
 
	$(call CONFIG_LINE,SDL_CONFIG:=$(SDL_CONFIG))
 
	$(call CONFIG_LINE,LIBPNG_CONFIG:=$(LIBPNG_CONFIG))
 
	$(call CONFIG_LINE,FREETYPE_CONFIG:=$(FREETYPE_CONFIG))
 
	$(call CONFIG_LINE,BEOS_NET_SERVER:=$(BEOS_NET_SERVER))
 
	$(call CONFIG_LINE,CONFIG_INCLUDED:=yes)
 
	$(call CONFIG_LINE,PATH_SET:=$(PATH_SET))
makefiledir/Makefile.libdetection
Show inline comments
 
@@ -66,6 +66,9 @@ SDL_CONFIG:=sdl-config
 
# set libpng-config to the default value
 
LIBPNG_CONFIG :=libpng-config
 

	
 
# set freetype-config to the default value
 
FREETYPE_CONFIG:=freetype-config
 

	
 
# Networking, enabled by default
 
WITH_NETWORK:=1
 

	
 
@@ -75,6 +78,9 @@ WITH_SDL:=$(shell $(SDL_CONFIG) --versio
 
# libpng detection
 
WITH_PNG:=$(shell $(LIBPNG_CONFIG) --version 2>/dev/null)
 

	
 
# Freetype detection
 
WITH_FREETYPE:=$(shell $(FREETYPE_CONFIG) --ftversion 2>/dev/null)
 

	
 
ifdef WITH_PNG
 
	# LibPNG depends on Zlib
 
	WITH_ZLIB:=1
misc.c
Show inline comments
 
@@ -202,6 +202,38 @@ StringID RealAllocateName(const char *na
 
	}
 
}
 

	
 
void ConvertNameArray(void)
 
{
 
	uint i;
 

	
 
	for (i = 0; i < lengthof(_name_array); i++) {
 
		const char *strfrom = _name_array[i];
 
		char tmp[sizeof(*_name_array)];
 
		char *strto = tmp;
 

	
 
		for (; *strfrom != '\0'; strfrom++) {
 
			WChar c = (byte)*strfrom;
 
			switch (c) {
 
				case 0xA4: c = 0x20AC; break; // Euro
 
				case 0xA6: c = 0x0160; break; // S with caron
 
				case 0xA8: c = 0x0161; break; // s with caron
 
				case 0xB4: c = 0x017D; break; // Z with caron
 
				case 0xB8: c = 0x017E; break; // z with caron
 
				case 0xBC: c = 0x0152; break; // OE ligature
 
				case 0xBD: c = 0x0153; break; // oe ligature
 
				case 0xBE: c = 0x0178; break; // Y with diaresis
 
				default: break;
 
			}
 
			if (strto + Utf8CharLen(c) > lastof(tmp)) break;
 
			strto += Utf8Encode(strto, c);
 
		}
 

	
 
		/* Terminate the new string and copy it back to the name array */
 
		*strto = '\0';
 
		memcpy(_name_array[i], tmp, sizeof(*_name_array));
 
	}
 
}
 

	
 
// Calculate constants that depend on the landscape type.
 
void InitializeLandscapeVariables(bool only_constants)
 
{
misc_gui.c
Show inline comments
 
@@ -205,8 +205,8 @@ static const char *credits[] = {
 
	"  Bjarni Corfitzen (Bjarni) - MacOSX port, coder",
 
	"  Matthijs Kooijman (blathijs) - Pathfinder-god",
 
	"  Victor Fischer (Celestar) - Programming everywhere you need him to",
 
	"  Tamás Faragó (Darkvater) - Lead coder",
 
	"  Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
 
	"  Tamás Faragó (Darkvater) - Lead coder",
 
	"  Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
 
	"  Owen Rudge (orudge) - Forum- and masterserver host, OS/2 port",
 
	"  Peter Nelson (peter1138) - Spiritual descendant from newgrf gods",
 
	"  Christoph Mallon (Tron) - Programmer, code correctness police",
 
@@ -221,13 +221,13 @@ static const char *credits[] = {
 
	"  Josef Drexler - For his great work on TTDPatch",
 
	"  Marcin Grzegorczyk - For his documentation of TTD internals",
 
	"  Petr Baudis (pasky) - Many patches, newgrf support",
 
	"  Stefan Meißner (sign_de) - For his work on the console",
 
	"  Stefan Meißner (sign_de) - For his work on the console",
 
	"  Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with (and PBS)",
 
	"  Cian Duffy (MYOB) - BeOS port / manual writing",
 
	"  Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
 
	"",
 
	"  Michael Blunck - Pre-Signals and Semaphores © 2003",
 
	"  George - Canal/Lock graphics © 2003-2004",
 
	"  Michael Blunck - Pre-Signals and Semaphores © 2003",
 
	"  George - Canal/Lock graphics © 2003-2004",
 
	"  Marcin Grzegorczyk - Foundations for Tracks on Slopes",
 
	"  All Translators - Who made OpenTTD a truly international game",
 
	"  Bug Reporters - Without whom OpenTTD would still be full of bugs!",
 
@@ -782,11 +782,30 @@ void SetHScrollCount(Window *w, int num)
 
	if (num < w->hscroll.pos) w->hscroll.pos = num;
 
}
 

	
 
static void DelChar(Textbuf *tb)
 
/* Delete a character at the caret position in a text buf.
 
 * If backspace is set, delete the character before the caret,
 
 * else delete the character after it. */
 
static void DelChar(Textbuf *tb, bool backspace)
 
{
 
	tb->width -= GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
 
	memmove(tb->buf + tb->caretpos, tb->buf + tb->caretpos + 1, tb->length - tb->caretpos);
 
	tb->length--;
 
	WChar c;
 
	uint width;
 
	size_t len;
 

	
 
	if (backspace) {
 
		do {
 
			tb->caretpos--;
 
		} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
 
	}
 

	
 
	len = Utf8Decode(&c, tb->buf + tb->caretpos);
 
	width = GetCharacterWidth(FS_NORMAL, c);
 

	
 
	tb->width  -= width;
 
	if (backspace) tb->caretxoffs -= width;
 

	
 
	/* Move the remaining characters over the marker */
 
	memmove(tb->buf + tb->caretpos, tb->buf + tb->caretpos + len, tb->length - tb->caretpos - len + 1);
 
	tb->length -= len;
 
}
 

	
 
/**
 
@@ -799,13 +818,10 @@ static void DelChar(Textbuf *tb)
 
bool DeleteTextBufferChar(Textbuf *tb, int delmode)
 
{
 
	if (delmode == WKC_BACKSPACE && tb->caretpos != 0) {
 
		tb->caretpos--;
 
		tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
 

	
 
		DelChar(tb);
 
		DelChar(tb, true);
 
		return true;
 
	} else if (delmode == WKC_DELETE && tb->caretpos < tb->length) {
 
		DelChar(tb);
 
		DelChar(tb, false);
 
		return true;
 
	}
 

	
 
@@ -831,16 +847,17 @@ void DeleteTextBufferAll(Textbuf *tb)
 
 * @param key Character to be inserted
 
 * @return Return true on successfull change of Textbuf, or false otherwise
 
 */
 
bool InsertTextBufferChar(Textbuf *tb, byte key)
 
bool InsertTextBufferChar(Textbuf *tb, WChar key)
 
{
 
	const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
 
	if (tb->length < (tb->maxlength - 1) && (tb->maxwidth == 0 || tb->width + charwidth <= tb->maxwidth)) {
 
		memmove(tb->buf + tb->caretpos + 1, tb->buf + tb->caretpos, (tb->length - tb->caretpos) + 1);
 
		tb->buf[tb->caretpos] = key;
 
		tb->length++;
 
		tb->width += charwidth;
 
	size_t len = Utf8CharLen(key);
 
	if (tb->length < (tb->maxlength - len) && (tb->maxwidth == 0 || tb->width + charwidth <= tb->maxwidth)) {
 
		memmove(tb->buf + tb->caretpos + len, tb->buf + tb->caretpos, tb->length - tb->caretpos + 1);
 
		Utf8Encode(tb->buf + tb->caretpos, key);
 
		tb->length += len;
 
		tb->width  += charwidth;
 

	
 
		tb->caretpos++;
 
		tb->caretpos   += len;
 
		tb->caretxoffs += charwidth;
 
		return true;
 
	}
 
@@ -859,15 +876,25 @@ bool MoveTextBufferPos(Textbuf *tb, int 
 
	switch (navmode) {
 
	case WKC_LEFT:
 
		if (tb->caretpos != 0) {
 
			tb->caretpos--;
 
			tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
 
			WChar c;
 

	
 
			do {
 
				tb->caretpos--;
 
			} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
 

	
 
			Utf8Decode(&c, tb->buf + tb->caretpos);
 
			tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
 

	
 
			return true;
 
		}
 
		break;
 
	case WKC_RIGHT:
 
		if (tb->caretpos < tb->length) {
 
			tb->caretxoffs += GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
 
			tb->caretpos++;
 
			WChar c;
 

	
 
			tb->caretpos   += Utf8Decode(&c, tb->buf + tb->caretpos);
 
			tb->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
 

	
 
			return true;
 
		}
 
		break;
 
@@ -910,16 +937,16 @@ void InitializeTextBuffer(Textbuf *tb, c
 
 */
 
void UpdateTextBufferSize(Textbuf *tb)
 
{
 
	const char *buf;
 
	const char *buf = tb->buf;
 
	WChar c = Utf8Consume(&buf);
 

	
 
	tb->length = 0;
 
	tb->width = 0;
 

	
 
	for (buf = tb->buf; *buf != '\0' && tb->length < (tb->maxlength - 1); buf++) {
 
		tb->length++;
 
		tb->width += GetCharacterWidth(FS_NORMAL, (byte)*buf);
 
	for (; c != '\0' && tb->length < (tb->maxlength - 1); c = Utf8Consume(&buf)) {
 
		tb->width += GetCharacterWidth(FS_NORMAL, c);
 
	}
 

	
 
	tb->length = buf - tb->buf - 1;
 
	tb->caretpos = tb->length;
 
	tb->caretxoffs = tb->width;
 
}
 
@@ -948,9 +975,10 @@ int HandleEditBoxKey(Window *w, querystr
 
			InvalidateWidget(w, wid);
 
		break;
 
	default:
 
		if (IsValidAsciiChar(e->we.keypress.ascii, string->afilter)) {
 
			if (InsertTextBufferChar(&string->text, e->we.keypress.ascii))
 
		if (IsValidChar(e->we.keypress.key, string->afilter)) {
 
			if (InsertTextBufferChar(&string->text, e->we.keypress.key)) {
 
				InvalidateWidget(w, wid);
 
			}
 
		} else { // key wasn't caught. Continue only if standard entry specified
 
			e->we.keypress.cont = (string->afilter == CS_ALPHANUMERAL);
 
		}
namegen.c
Show inline comments
 
@@ -480,13 +480,15 @@ static byte MakeCzechTownName(char *buf,
 

	
 
		strecat(buf, name_czech_adj[prefix].name, last);
 
		endpos = strlen(buf) - 1;
 
		/* Find the first character in a UTF-8 sequence */
 
		while (GB(buf[endpos], 6, 2) == 2) endpos--;
 
		if (gender == CZG_SMASC && pattern == CZP_PRIVL) {
 
			/* -ovX -> -uv */
 
			buf[endpos - 2] = 'u';
 
			assert(buf[endpos - 1] == 'v');
 
			buf[endpos] = '\0';
 
		} else {
 
			buf[endpos] = name_czech_patmod[gender][pattern];
 
			strecpy(buf + endpos, name_czech_patmod[gender][pattern], last);
 
		}
 

	
 
		strecat(buf, " ", last);
network.c
Show inline comments
 
@@ -526,7 +526,7 @@ void ParseConnectionString(const char **
 
		if (*p == '#') {
 
			*p = '\0';
 
			*player = ++p;
 
			while (IsValidAsciiChar(*p, CS_NUMERAL)) p++;
 
			while (IsValidChar(*p, CS_NUMERAL)) p++;
 
			if (*p == '\0') break;
 
		} else if (*p == ':') {
 
			*port = p + 1;
newgrf.c
Show inline comments
 
@@ -23,6 +23,7 @@
 
#include "vehicle.h"
 
#include "newgrf_text.h"
 
#include "table/sprites.h"
 
#include "fontcache.h"
 
#include "date.h"
 
#include "currency.h"
 
#include "sound.h"
 
@@ -3039,6 +3040,42 @@ static void LoadGRFSound(byte *buf, int 
 
	}
 
}
 

	
 
/* Action 0x12 */
 
static void LoadFontGlyph(byte *buf, int len)
 
{
 
	/* <12> <num_def> <font_size> <num_char> <base_char>
 
	 *
 
	 * B num_def      Number of definitions
 
	 * B font_size    Size of font (0 = normal, 1 = small, 2 = large)
 
	 * B num_char     Number of consecutive glyphs
 
	 * W base_char    First character index */
 

	
 
	uint8 num_def;
 
	uint i;
 

	
 
	buf++; len--;
 
	check_length(len, 1, "LoadFontGlyph");
 

	
 
	num_def = grf_load_byte(&buf);
 

	
 
	check_length(len, 1 + num_def * 4, "LoadFontGlyph");
 

	
 
	for (i = 0; i < num_def; i++) {
 
		FontSize size    = grf_load_byte(&buf);
 
		uint8  num_char  = grf_load_byte(&buf);
 
		uint16 base_char = grf_load_word(&buf);
 
		uint c;
 

	
 
		DEBUG(grf, 7) ("LoadFontGlyph: Loading %u glyph(s) at 0x%04X for size %u", num_char, base_char, size);
 

	
 
		for (c = 0; c < num_char; c++) {
 
			SetUnicodeGlyph(size, base_char + c, _cur_spriteid);
 
			LoadNextSprite(_cur_spriteid++, _file_index);
 
			_nfo_line++;
 
		}
 
	}
 
}
 

	
 
/* 'Action 0xFF' */
 
static void GRFDataBlock(byte *buf, int len)
 
{
 
@@ -3421,6 +3458,7 @@ static void DecodeSpecialSprite(uint num
 
		/* 0x0F */ { NULL,            NULL,       NULL, },
 
		/* 0x10 */ { DefineGotoLabel, NULL,       NULL, },
 
		/* 0x11 */ { NULL,            NULL,       GRFSound, },
 
		/* 0x12 */ { NULL,            NULL,       LoadFontGlyph, },
 
	};
 

	
 
	byte* buf;
newgrf_text.c
Show inline comments
 
@@ -18,6 +18,7 @@
 
#include "macros.h"
 
#include "table/strings.h"
 
#include "newgrf_text.h"
 
#include "table/control_codes.h"
 

	
 
#define GRFTAB  28
 
#define TABSIZE 11
 
@@ -153,46 +154,104 @@ static GRFTextEntry _grf_text[(1 << TABS
 
static byte _currentLangID = GRFLX_ENGLISH;  //by default, english is used.
 

	
 

	
 
static void TranslateTTDPatchCodes(char *str)
 
static char *TranslateTTDPatchCodes(const char *str)
 
{
 
	char *c;
 
	char *tmp = malloc(strlen(str) * 10); /* Allocate space to allow for expansion */
 
	char *d = tmp;
 
	bool unicode = false;
 
	WChar c = Utf8Consume(&str);
 

	
 
	if (c == 0x00DE) {
 
		/* The thorn ('þ') indicates a unicode string to TTDPatch */
 
		unicode = true;
 
	} else {
 
		str--;
 
	}
 

	
 
	for (;;) {
 
		const char *tmp = str; /* Used for UTF-8 decoding */
 

	
 
	for (c = str; *c != '\0'; c++) {
 
		switch ((byte)*c) {
 
			case 0x01: c++; break;
 
			case 0x0D: *c = 10; break;
 
			case 0x0E: *c = 8; break;
 
			case 0x0F: *c = 9; break;
 
			case 0x1F: *c = 2; c += 2; break;
 
		c = (byte)*str++;
 
		if (c == 0) break;
 

	
 
		switch (c) {
 
			case 0x01:
 
				d += Utf8Encode(d, SCC_SETX);
 
				*d++ = *str++;
 
				break;
 
			case 0x0D: *d++ = 10; break;
 
			case 0x0E: d += Utf8Encode(d, SCC_TINYFONT); break;
 
			case 0x0F: d += Utf8Encode(d, SCC_BIGFONT); break;
 
			case 0x1F:
 
				d += Utf8Encode(d, SCC_SETXY);
 
				*d++ = *str++;
 
				*d++ = *str++;
 
				break;
 
			case 0x7B:
 
			case 0x7C:
 
			case 0x7D:
 
			case 0x7E: *c = 0x8E; break;
 
			case 0x81: c += 2; break;
 
			case 0x85: *c = 0x86; break;
 
			case 0x88: *c = 15; break;
 
			case 0x89: *c = 16; break;
 
			case 0x8A: *c = 17; break;
 
			case 0x8B: *c = 18; break;
 
			case 0x8C: *c = 19; break;
 
			case 0x8D: *c = 20; break;
 
			case 0x8E: *c = 21; break;
 
			case 0x8F: *c = 22; break;
 
			case 0x90: *c = 23; break;
 
			case 0x91: *c = 24; break;
 
			case 0x92: *c = 25; break;
 
			case 0x93: *c = 26; break;
 
			case 0x94: *c = 27; break;
 
			case 0x95: *c = 28; break;
 
			case 0x96: *c = 29; break;
 
			case 0x97: *c = 30; break;
 
			case 0x98: *c = 31; break;
 
			case 0x7E: d += Utf8Encode(d, SCC_NUM); break;
 
			case 0x7F: d += Utf8Encode(d, SCC_CURRENCY); break;
 
			case 0x80: d += Utf8Encode(d, SCC_STRING); break;
 
			case 0x81: {
 
				StringID string;
 
				string  = *str++;
 
				string |= *str++ << 8;
 
				d += Utf8Encode(d, SCC_STRING_ID);
 
				d += Utf8Encode(d, string);
 
				break;
 
			}
 
			case 0x82: d += Utf8Encode(d, SCC_DATE_TINY); break;
 
			case 0x83: d += Utf8Encode(d, SCC_DATE_SHORT); break;
 
			case 0x84: d += Utf8Encode(d, SCC_VELOCITY); break;
 
			case 0x85: d += Utf8Encode(d, SCC_SKIP);    break;
 
			case 0x86: /* "Rotate down top 4 words on stack" */ break;
 
			case 0x87: d += Utf8Encode(d, SCC_VOLUME);  break;
 
			case 0x88: d += Utf8Encode(d, SCC_BLUE);    break;
 
			case 0x89: d += Utf8Encode(d, SCC_SILVER);  break;
 
			case 0x8A: d += Utf8Encode(d, SCC_GOLD);    break;
 
			case 0x8B: d += Utf8Encode(d, SCC_RED);     break;
 
			case 0x8C: d += Utf8Encode(d, SCC_PURPLE);  break;
 
			case 0x8D: d += Utf8Encode(d, SCC_LTBROWN); break;
 
			case 0x8E: d += Utf8Encode(d, SCC_ORANGE);  break;
 
			case 0x8F: d += Utf8Encode(d, SCC_GREEN);   break;
 
			case 0x90: d += Utf8Encode(d, SCC_YELLOW);  break;
 
			case 0x91: d += Utf8Encode(d, SCC_DKGREEN); break;
 
			case 0x92: d += Utf8Encode(d, SCC_CREAM);   break;
 
			case 0x93: d += Utf8Encode(d, SCC_BROWN);   break;
 
			case 0x94: d += Utf8Encode(d, SCC_WHITE);   break;
 
			case 0x95: d += Utf8Encode(d, SCC_LTBLUE);  break;
 
			case 0x96: d += Utf8Encode(d, SCC_GRAY);    break;
 
			case 0x97: d += Utf8Encode(d, SCC_DKBLUE);  break;
 
			case 0x98: d += Utf8Encode(d, SCC_BLACK);   break;
 
			case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro
 
			case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis
 
			case 0xA0: d += Utf8Encode(d, SCC_UPARROW); break;
 
			case 0xAA: d += Utf8Encode(d, SCC_DOWNARROW); break;
 
			case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break;
 
			case 0xAD: d += Utf8Encode(d, SCC_CROSS); break;
 
			case 0xAF: d += Utf8Encode(d, SCC_RIGHTARROW); break;
 
			case 0xB4: d += Utf8Encode(d, SCC_TRAIN); break;
 
			case 0xB5: d += Utf8Encode(d, SCC_LORRY); break;
 
			case 0xB6: d += Utf8Encode(d, SCC_BUS); break;
 
			case 0xB7: d += Utf8Encode(d, SCC_PLANE); break;
 
			case 0xB8: d += Utf8Encode(d, SCC_SHIP); break;
 
			default:
 
				if (unicode) {
 
					d += Utf8Encode(d, Utf8Consume(&tmp));
 
					str = tmp;
 
					break;
 
				}
 

	
 
				/* Validate any unhandled character */
 
				if (!IsValidAsciiChar(*c, CS_ALPHANUMERAL)) *c = '?';
 
				if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
 
				d += Utf8Encode(d, c);
 
				break;
 
		}
 
	}
 

	
 
	*d = '\0';
 
	return realloc(tmp, strlen(tmp) + 1);
 
}
 

	
 

	
 
@@ -201,6 +260,7 @@ static void TranslateTTDPatchCodes(char 
 
 */
 
StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, const char *text_to_add, StringID def_string)
 
{
 
	char *translatedtext;
 
	GRFText *newtext;
 
	uint id;
 

	
 
@@ -231,12 +291,14 @@ StringID AddGRFString(uint32 grfid, uint
 
	/* Too many strings allocated, return empty */
 
	if (id == lengthof(_grf_text)) return STR_EMPTY;
 

	
 
	newtext = malloc(sizeof(*newtext) + strlen(text_to_add) + 1);
 
	translatedtext = TranslateTTDPatchCodes(text_to_add);
 

	
 
	newtext = malloc(sizeof(*newtext) + strlen(translatedtext) + 1);
 
	newtext->next   = NULL;
 
	newtext->langid = langid_to_add;
 
	strcpy(newtext->text, text_to_add);
 
	strcpy(newtext->text, translatedtext);
 

	
 
	TranslateTTDPatchCodes(newtext->text);
 
	free(translatedtext);
 

	
 
	/* If we didn't find our stringid and grfid in the list, allocate a new id */
 
	if (id == _num_grf_texts) _num_grf_texts++;
news_gui.c
Show inline comments
 
@@ -15,6 +15,7 @@
 
#include "sound.h"
 
#include "variables.h"
 
#include "date.h"
 
#include "string.h"
 

	
 
/* News system
 
 * News system is realized as a FIFO queue (in an array)
 
@@ -569,7 +570,8 @@ static byte getNews(byte i)
 
static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint maxw)
 
{
 
	char buffer[512], buffer2[512];
 
	char *ptr, *dest;
 
	const char *ptr;
 
	char *dest;
 
	StringID str;
 

	
 
	if (ni->display_mode == 3) {
 
@@ -582,12 +584,16 @@ static void DrawNewsString(int x, int y,
 
	GetString(buffer, str, lastof(buffer));
 
	/* Copy the just gotten string to another buffer to remove any formatting
 
	 * from it such as big fonts, etc. */
 
	for (ptr = buffer, dest = buffer2; *ptr != '\0'; ptr++) {
 
		if (*ptr == '\r') {
 
	ptr  = buffer;
 
	dest = buffer2;
 
	for (;;) {
 
		WChar c = Utf8Consume(&ptr);
 
		if (c == 0) break;
 
		if (c == '\r') {
 
			dest[0] = dest[1] = dest[2] = dest[3] = ' ';
 
			dest += 4;
 
		} else if ((byte)*ptr >= ' ' && ((byte)*ptr < 0x88 || (byte)*ptr >= 0x99)) {
 
			*dest++ = *ptr;
 
		} else if (IsPrintable(c)) {
 
			dest += Utf8Encode(dest, c);
 
		}
 
	}
 

	
openttd.c
Show inline comments
 
@@ -52,6 +52,7 @@
 
#include "genworld.h"
 
#include "date.h"
 
#include "clear_map.h"
 
#include "fontcache.h"
 

	
 
#include <stdarg.h>
 

	
 
@@ -432,10 +433,15 @@ int ttd_main(int argc, char *argv[])
 
	MxInitialize(11025);
 
	SoundInitialize("sample.cat");
 

	
 
	/* Initialize FreeType */
 
	InitFreeType();
 

	
 
	// This must be done early, since functions use the InvalidateWindow* calls
 
	InitWindowSystem();
 

	
 
	GfxLoadSprites();
 
	/* Initialize the unicode to sprite mapping table */
 
	InitializeUnicodeGlyphMap();
 
	LoadStringWidthTable();
 

	
 
	DEBUG(driver, 1) ("Loading drivers...");
 
@@ -1526,5 +1532,9 @@ bool AfterLoadGame(void)
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(37)) {
 
		ConvertNameArray();
 
	}
 

	
 
	return true;
 
}
openttd.h
Show inline comments
 
@@ -464,6 +464,10 @@ enum {
 
	EXPENSES_OTHER        = 12,
 
};
 

	
 
enum {
 
	MAX_LANG = 64,
 
};
 

	
 
// special string constants
 
enum SpecialStrings {
 

	
 
@@ -506,17 +510,17 @@ enum SpecialStrings {
 
	SPECSTR_PRESIDENT_NAME     = 0x70E7,
 
	SPECSTR_SONGNAME           = 0x70E8,
 

	
 
	// reserve 32 strings for the *.lng files
 
	// reserve MAX_LANG strings for the *.lng files
 
	SPECSTR_LANGUAGE_START     = 0x7100,
 
	SPECSTR_LANGUAGE_END       = 0x711f,
 
	SPECSTR_LANGUAGE_END       = SPECSTR_LANGUAGE_START + MAX_LANG - 1,
 

	
 
	// reserve 32 strings for various screen resolutions
 
	SPECSTR_RESOLUTION_START   = 0x7120,
 
	SPECSTR_RESOLUTION_END     = 0x713f,
 
	SPECSTR_RESOLUTION_START   = SPECSTR_LANGUAGE_END + 1,
 
	SPECSTR_RESOLUTION_END     = SPECSTR_RESOLUTION_START + 0x1F,
 

	
 
	// reserve 32 strings for screenshot formats
 
	SPECSTR_SCREENSHOT_START   = 0x7140,
 
	SPECSTR_SCREENSHOT_END     = 0x715F,
 
	SPECSTR_SCREENSHOT_START   = SPECSTR_RESOLUTION_END + 1,
 
	SPECSTR_SCREENSHOT_END     = SPECSTR_SCREENSHOT_START + 0x1F,
 

	
 
	// Used to implement SetDParamStr
 
	STR_SPEC_DYNSTRING         = 0xF800,
openttd.vcproj
Show inline comments
 
@@ -235,6 +235,9 @@
 
				RelativePath=".\fios.c">
 
			</File>
 
			<File
 
				RelativePath=".\fontcache.c">
 
			</File>
 
			<File
 
				RelativePath=".\genworld.c">
 
			</File>
 
			<File
 
@@ -479,6 +482,9 @@
 
				RelativePath=".\fileio.h">
 
			</File>
 
			<File
 
				RelativePath=".\fontcache.h">
 
			</File>
 
			<File
 
				RelativePath=".\functions.h">
 
			</File>
 
			<File
 
@@ -854,6 +860,9 @@
 
				RelativePath=".\table\clear_land.h">
 
			</File>
 
			<File
 
				RelativePath=".\table\control_codes.h">
 
			</File>
 
			<File
 
				RelativePath=".\table\elrail_data.h">
 
			</File>
 
			<File
 
@@ -911,6 +920,9 @@
 
				RelativePath=".\table\tunnel_land.h">
 
			</File>
 
			<File
 
				RelativePath=".\table\unicode.h">
 
			</File>
 
			<File
 
				RelativePath=".\table\unmovable_land.h">
 
			</File>
 
			<File
openttd_vs80.vcproj
Show inline comments
 
@@ -561,6 +561,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\fontcache.c"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\genworld.c"
 
				>
 
			</File>
 
@@ -932,6 +936,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\fontcache.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\functions.h"
 
				>
 
			</File>
 
@@ -1436,6 +1444,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\table\control_codes.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\table\elrail_data.h"
 
				>
 
			</File>
 
@@ -1512,6 +1524,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\table\unicode.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\table\unmovable_land.h"
 
				>
 
			</File>
saveload.c
Show inline comments
 
@@ -30,7 +30,7 @@
 
#include "variables.h"
 
#include <setjmp.h>
 

	
 
const uint16 SAVEGAME_VERSION = 36;
 
const uint16 SAVEGAME_VERSION = 37;
 
uint16 _sl_version;       /// the major savegame version identifier
 
byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
 

	
settings.c
Show inline comments
 
@@ -38,6 +38,10 @@
 
#include "newgrf.h"
 
#include "genworld.h"
 
#include "date.h"
 
#ifdef WITH_FREETYPE
 
#include "gfx.h"
 
#include "fontcache.h"
 
#endif
 

	
 
/** The patch values that are used for new games and/or modified in config file */
 
Patches _patches_newgame;
 
@@ -1186,6 +1190,14 @@ static const SettingDescGlobVarList _mis
 
	  SDTG_STR("screenshot_format",SLE_STRB, S, 0, _screenshot_format_name,NULL,    STR_NULL, NULL),
 
	  SDTG_STR("savegame_format",  SLE_STRB, S, 0, _savegame_format,       NULL,    STR_NULL, NULL),
 
	 SDTG_BOOL("rightclick_emulate",         S, 0, _rightclick_emulate,   false,    STR_NULL, NULL),
 
#ifdef WITH_FREETYPE
 
	  SDTG_STR("small_font",       SLE_STRB, S, 0, _freetype.small_font,   NULL,    STR_NULL, NULL),
 
	  SDTG_STR("medium_font",      SLE_STRB, S, 0, _freetype.medium_font,  NULL,    STR_NULL, NULL),
 
	  SDTG_STR("large_font",       SLE_STRB, S, 0, _freetype.large_font,   NULL,    STR_NULL, NULL),
 
	  SDTG_VAR("small_size",       SLE_UINT, S, 0, _freetype.small_size,   6, 0, 72, 0, STR_NULL, NULL),
 
	  SDTG_VAR("medium_size",      SLE_UINT, S, 0, _freetype.medium_size, 10, 0, 72, 0, STR_NULL, NULL),
 
	  SDTG_VAR("large_size",       SLE_UINT, S, 0, _freetype.large_size,  16, 0, 72, 0, STR_NULL, NULL),
 
#endif
 
	  SDTG_END()
 
};
 

	
strgen/strgen.c
Show inline comments
 
@@ -3,6 +3,7 @@
 
#include "../stdafx.h"
 
#include "../macros.h"
 
#include "../string.h"
 
#include "../table/control_codes.h"
 
#include <stdio.h>
 
#include <string.h>
 
#include <stdlib.h>
 
@@ -199,26 +200,41 @@ static void PutByte(byte c)
 
}
 

	
 

	
 
static void EmitSingleByte(char *buf, int value)
 
static void PutUtf8(uint32 value)
 
{
 
	if (*buf != '\0') warning("Ignoring trailing letters in command");
 
	PutByte((byte)value);
 
	if (value < 0x80) {
 
		PutByte(value);
 
	} else if (value < 0x800) {
 
		PutByte(0xC0 + GB(value,  6, 5));
 
		PutByte(0x80 + GB(value,  0, 6));
 
	} else if (value < 0x10000) {
 
		PutByte(0xE0 + GB(value, 12, 4));
 
		PutByte(0x80 + GB(value,  6, 6));
 
		PutByte(0x80 + GB(value,  0, 6));
 
	} else if (value < 0x110000) {
 
		PutByte(0xF0 + GB(value, 18, 3));
 
		PutByte(0x80 + GB(value, 12, 6));
 
		PutByte(0x80 + GB(value,  6, 6));
 
		PutByte(0x80 + GB(value,  0, 6));
 
	} else {
 
		warning("Invalid unicode value U+0x%X\n", value);
 
	}
 
}
 

	
 

	
 
static void EmitEscapedByte(char *buf, int value)
 
static void EmitSingleChar(char *buf, int value)
 
{
 
	if (*buf != '\0') warning("Ignoring trailing letters in command");
 
	PutByte(0x85);
 
	PutByte((byte)value);
 
	PutUtf8(value);
 
}
 

	
 

	
 
static void EmitSetX(char *buf, int value)
 
{
 
	char *err;
 
	int x = strtol(buf, &err, 0);
 
	if (*err != 0) fatal("SetX param invalid");
 
	PutByte(1);
 
	PutUtf8(SCC_SETX);
 
	PutByte((byte)x);
 
}
 

	
 
@@ -234,7 +250,7 @@ static void EmitSetXY(char *buf, int val
 
	y = strtol(err + 1, &err, 0);
 
	if (*err != 0) fatal("SetXY param invalid");
 

	
 
	PutByte(2);
 
	PutUtf8(SCC_SETXY);
 
	PutByte((byte)x);
 
	PutByte((byte)y);
 
}
 
@@ -352,7 +368,7 @@ static void EmitPlural(char *buf, int va
 
		}
 
	}
 

	
 
	PutByte(0x8D);
 
	PutUtf8(SCC_PLURAL_LIST);
 
	PutByte(TranslateArgumentIdx(argidx));
 
	EmitWordList(words, nw);
 
}
 
@@ -372,7 +388,7 @@ static void EmitGender(char *buf, int va
 
			if (strcmp(buf, _genders[nw]) == 0) break;
 
		}
 
		// now nw contains the gender index
 
		PutByte(0x87);
 
		PutUtf8(SCC_GENDER_INDEX);
 
		PutByte(nw);
 
	} else {
 
		const char* words[8];
 
@@ -386,8 +402,7 @@ static void EmitGender(char *buf, int va
 
			if (words[nw] == NULL) break;
 
		}
 
		if (nw != _numgenders) fatal("Bad # of arguments for gender command");
 
		PutByte(0x85);
 
		PutByte(13);
 
		PutUtf8(SCC_GENDER_LIST);
 
		PutByte(TranslateArgumentIdx(argidx));
 
		EmitWordList(words, nw);
 
	}
 
@@ -396,109 +411,108 @@ static void EmitGender(char *buf, int va
 

	
 
static const CmdStruct _cmd_structs[] = {
 
	// Update position
 
	{"SETX",  EmitSetX,  1, 0, 0},
 
	{"SETXY", EmitSetXY, 2, 0, 0},
 
	{"SETX",  EmitSetX,  SCC_SETX,  0, 0},
 
	{"SETXY", EmitSetXY, SCC_SETXY, 0, 0},
 

	
 
	// Font size
 
	{"TINYFONT", EmitSingleByte, 8, 0, 0},
 
	{"BIGFONT",  EmitSingleByte, 9, 0, 0},
 
	{"TINYFONT", EmitSingleChar, SCC_TINYFONT, 0, 0},
 
	{"BIGFONT",  EmitSingleChar, SCC_BIGFONT,  0, 0},
 

	
 
	// Colors
 
	{"BLUE",    EmitSingleByte, 15, 0, 0},
 
	{"SILVER",  EmitSingleByte, 16, 0, 0},
 
	{"GOLD",    EmitSingleByte, 17, 0, 0},
 
	{"RED",     EmitSingleByte, 18, 0, 0},
 
	{"PURPLE",  EmitSingleByte, 19, 0, 0},
 
	{"LTBROWN", EmitSingleByte, 20, 0, 0},
 
	{"ORANGE",  EmitSingleByte, 21, 0, 0},
 
	{"GREEN",   EmitSingleByte, 22, 0, 0},
 
	{"YELLOW",  EmitSingleByte, 23, 0, 0},
 
	{"DKGREEN", EmitSingleByte, 24, 0, 0},
 
	{"CREAM",   EmitSingleByte, 25, 0, 0},
 
	{"BROWN",   EmitSingleByte, 26, 0, 0},
 
	{"WHITE",   EmitSingleByte, 27, 0, 0},
 
	{"LTBLUE",  EmitSingleByte, 28, 0, 0},
 
	{"GRAY",    EmitSingleByte, 29, 0, 0},
 
	{"DKBLUE",  EmitSingleByte, 30, 0, 0},
 
	{"BLACK",   EmitSingleByte, 31, 0, 0},
 
	{"BLUE",    EmitSingleChar, SCC_BLUE,    0, 0},
 
	{"SILVER",  EmitSingleChar, SCC_SILVER,  0, 0},
 
	{"GOLD",    EmitSingleChar, SCC_GOLD,    0, 0},
 
	{"RED",     EmitSingleChar, SCC_RED,     0, 0},
 
	{"PURPLE",  EmitSingleChar, SCC_PURPLE,  0, 0},
 
	{"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, 0},
 
	{"ORANGE",  EmitSingleChar, SCC_ORANGE,  0, 0},
 
	{"GREEN",   EmitSingleChar, SCC_GREEN,   0, 0},
 
	{"YELLOW",  EmitSingleChar, SCC_YELLOW,  0, 0},
 
	{"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, 0},
 
	{"CREAM",   EmitSingleChar, SCC_CREAM,   0, 0},
 
	{"BROWN",   EmitSingleChar, SCC_BROWN,   0, 0},
 
	{"WHITE",   EmitSingleChar, SCC_WHITE,   0, 0},
 
	{"LTBLUE",  EmitSingleChar, SCC_LTBLUE,  0, 0},
 
	{"GRAY",    EmitSingleChar, SCC_GRAY,    0, 0},
 
	{"DKBLUE",  EmitSingleChar, SCC_DKBLUE,  0, 0},
 
	{"BLACK",   EmitSingleChar, SCC_BLACK,   0, 0},
 

	
 
	{"CURRCOMPACT",   EmitEscapedByte, 0, 1, 0}, // compact currency (32 bits)
 
	{"REV",           EmitEscapedByte, 2, 0, 0}, // openttd revision string
 
	{"SHORTCARGO",    EmitEscapedByte, 3, 2, 0}, // short cargo description, only ### tons, or ### litres
 
	{"CURRCOMPACT64", EmitEscapedByte, 4, 2, 0}, // compact currency 64 bits
 
	{"CURRCOMPACT",   EmitSingleChar, SCC_CURRENCY_COMPACT,    1, 0}, // compact currency (32 bits)
 
	{"REV",           EmitSingleChar, SCC_REVISION,            0, 0}, // openttd revision string
 
	{"SHORTCARGO",    EmitSingleChar, SCC_CARGO_SHORT,         2, 0}, // short cargo description, only ### tons, or ### litres
 
	{"CURRCOMPACT64", EmitSingleChar, SCC_CURRENCY_COMPACT_64, 2, 0}, // compact currency 64 bits
 

	
 
	// These are special versions of {STRING1}
 
	// The first string includes the second string.
 
	{"COMPANY",    EmitEscapedByte, 5, 1, 0},
 
	{"PLAYERNAME", EmitEscapedByte, 5, 1, 0},
 
	{"VEHICLE",    EmitEscapedByte, 5, 1, 0},
 
	{"COMPANY",    EmitSingleChar, SCC_STRING1, 1, 0},
 
	{"PLAYERNAME", EmitSingleChar, SCC_STRING1, 1, 0},
 
	{"VEHICLE",    EmitSingleChar, SCC_STRING1, 1, 0},
 

	
 
	{"STRING1", EmitEscapedByte, 5, 1, C_CASE}, // included string that consumes ONE argument
 
	{"STRING2", EmitEscapedByte, 6, 2, C_CASE}, // included string that consumes TWO arguments
 
	{"STRING3", EmitEscapedByte, 7, 3, C_CASE}, // included string that consumes THREE arguments
 
	{"STRING4", EmitEscapedByte, 8, 4, C_CASE}, // included string that consumes FOUR arguments
 
	{"STRING5", EmitEscapedByte, 9, 5, C_CASE}, // included string that consumes FIVE arguments
 
	{"STRING1", EmitSingleChar, SCC_STRING1, 1, C_CASE}, // included string that consumes ONE argument
 
	{"STRING2", EmitSingleChar, SCC_STRING2, 2, C_CASE}, // included string that consumes TWO arguments
 
	{"STRING3", EmitSingleChar, SCC_STRING3, 3, C_CASE}, // included string that consumes THREE arguments
 
	{"STRING4", EmitSingleChar, SCC_STRING4, 4, C_CASE}, // included string that consumes FOUR arguments
 
	{"STRING5", EmitSingleChar, SCC_STRING5, 5, C_CASE}, // included string that consumes FIVE arguments
 

	
 
	{"STATIONFEATURES", EmitEscapedByte, 10, 1, 0}, // station features string, icons of the features
 
	{"INDUSTRY",        EmitEscapedByte, 11, 1, 0}, // industry, takes an industry #
 
	{"VOLUME",          EmitEscapedByte, 12, 1, 0},
 
	{"DATE_TINY",       EmitEscapedByte, 14, 1, 0},
 
	{"CARGO",           EmitEscapedByte, 15, 2, 0},
 
	{"POWER",           EmitEscapedByte, 16, 1, 0},
 
	{"VOLUME_S",        EmitEscapedByte, 17, 1, 0},
 
	{"WEIGHT",          EmitEscapedByte, 18, 1, 0},
 
	{"WEIGHT_S",        EmitEscapedByte, 19, 1, 0},
 
	{"FORCE",           EmitEscapedByte, 20, 1, 0},
 
	{"STATIONFEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, 0}, // station features string, icons of the features
 
	{"INDUSTRY",        EmitSingleChar, SCC_INDUSTRY_NAME,    1, 0}, // industry, takes an industry #
 
	{"CARGO",           EmitSingleChar, SCC_CARGO,            2, 0},
 
	{"POWER",           EmitSingleChar, SCC_POWER,            1, 0},
 
	{"VOLUME",          EmitSingleChar, SCC_VOLUME,           1, 0},
 
	{"VOLUME_S",        EmitSingleChar, SCC_VOLUME_SHORT,     1, 0},
 
	{"WEIGHT",          EmitSingleChar, SCC_WEIGHT,           1, 0},
 
	{"WEIGHT_S",        EmitSingleChar, SCC_WEIGHT_SHORT,     1, 0},
 
	{"FORCE",           EmitSingleChar, SCC_FORCE,            1, 0},
 
	{"VELOCITY",        EmitSingleChar, SCC_VELOCITY,         1, 0},
 

	
 
	{"P", EmitPlural, 0, 0, C_DONTCOUNT}, // plural specifier
 
	{"G", EmitGender, 0, 0, C_DONTCOUNT}, // gender specifier
 

	
 
	{"DATE_LONG",  EmitSingleByte, 0x82, 1, 0},
 
	{"DATE_SHORT", EmitSingleByte, 0x83, 1, 0},
 

	
 
	{"VELOCITY", EmitSingleByte, 0x84, 1, 0},
 
	{"DATE_TINY",  EmitSingleChar, SCC_DATE_TINY, 1, 0},
 
	{"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, 0},
 
	{"DATE_LONG",  EmitSingleChar, SCC_DATE_LONG, 1, 0},
 

	
 
	// 0x85 is the marker for escaped commands
 
	{"SKIP", EmitSingleChar, SCC_SKIP, 1, 0},
 

	
 
	{"SKIP", EmitSingleByte, 0x86, 1, 0},
 

	
 
	{"STRING", EmitSingleByte, 0x88, 1, C_CASE},
 
	{"STRING", EmitSingleChar, SCC_STRING, 1, C_CASE},
 

	
 
	// Numbers
 
	{"COMMA", EmitSingleByte, 0x8B, 1, 0}, // Number with comma
 
	{"NUM",   EmitSingleByte, 0x8E, 1, 0}, // Signed number
 
	{"COMMA", EmitSingleChar, SCC_COMMA, 1, 0}, // Number with comma
 
	{"NUM",   EmitSingleChar, SCC_NUM,   1, 0}, // Signed number
 

	
 
	{"CURRENCY",   EmitSingleByte, 0x8F, 1, 0},
 
	{"CURRENCY64", EmitSingleByte, 0x9C, 2, 0},
 
	{"CURRENCY",   EmitSingleChar, SCC_CURRENCY,    1, 0},
 
	{"CURRENCY64", EmitSingleChar, SCC_CURRENCY_64, 2, 0},
 

	
 
	{"WAYPOINT", EmitSingleByte, 0x99, 1, 0}, // waypoint name
 
	{"STATION",  EmitSingleByte, 0x9A, 1, 0},
 
	{"TOWN",     EmitSingleByte, 0x9B, 1, 0},
 
	{"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, 0}, // waypoint name
 
	{"STATION",  EmitSingleChar, SCC_STATION_NAME,  1, 0},
 
	{"TOWN",     EmitSingleChar, SCC_TOWN_NAME,     1, 0},
 

	
 
	// 0x9D is used for the pseudo command SETCASE
 
	// 0x9E is used for case switching
 

	
 
	{"",               EmitSingleByte, '\n', 0, C_DONTCOUNT},
 
	{"{",              EmitSingleByte, '{',  0, C_DONTCOUNT},
 
	{"UPARROW",        EmitSingleByte, 0x80, 0, 0},
 
	{"SMALLUPARROW",   EmitSingleByte, 0x90, 0, 0},
 
	{"SMALLDOWNARROW", EmitSingleByte, 0x91, 0, 0},
 
	{"TRAIN",          EmitSingleByte, 0x94, 0, 0},
 
	{"LORRY",          EmitSingleByte, 0x95, 0, 0},
 
	{"BUS",            EmitSingleByte, 0x96, 0, 0},
 
	{"PLANE",          EmitSingleByte, 0x97, 0, 0},
 
	{"SHIP",           EmitSingleByte, 0x98, 0, 0},
 
	{"NBSP",           EmitSingleByte, 0xA0, 0, C_DONTCOUNT},
 
	{"CENT",           EmitSingleByte, '¢',  0, C_DONTCOUNT},
 
	{"POUNDSIGN",      EmitSingleByte, '£',  0, C_DONTCOUNT},
 
	{"EURO",           EmitSingleByte, '¤',  0, C_DONTCOUNT},
 
	{"YENSIGN",        EmitSingleByte, '¥',  0, C_DONTCOUNT},
 
	{"COPYRIGHT",      EmitSingleByte, '©',  0, C_DONTCOUNT},
 
	{"DOWNARROW",      EmitSingleByte, 0xAA, 0, C_DONTCOUNT},
 
	{"CHECKMARK",      EmitSingleByte, 0xAC, 0, C_DONTCOUNT},
 
	{"CROSS",          EmitSingleByte, 0xAD, 0, C_DONTCOUNT},
 
	{"REGISTERED",     EmitSingleByte, '®',  0, C_DONTCOUNT},
 
	{"RIGHTARROW",     EmitSingleByte, 0xAF, 0, C_DONTCOUNT},
 
	{"",               EmitSingleChar, '\n',               0, C_DONTCOUNT},
 
	{"{",              EmitSingleChar, '{',                0, C_DONTCOUNT},
 
	{"UPARROW",        EmitSingleChar, SCC_UPARROW,        0, 0},
 
	{"SMALLUPARROW",   EmitSingleChar, SCC_SMALLUPARROW,   0, 0},
 
	{"SMALLDOWNARROW", EmitSingleChar, SCC_SMALLDOWNARROW, 0, 0},
 
	{"TRAIN",          EmitSingleChar, SCC_TRAIN,          0, 0},
 
	{"LORRY",          EmitSingleChar, SCC_LORRY,          0, 0},
 
	{"BUS",            EmitSingleChar, SCC_BUS,            0, 0},
 
	{"PLANE",          EmitSingleChar, SCC_PLANE,          0, 0},
 
	{"SHIP",           EmitSingleChar, SCC_SHIP,           0, 0},
 
	{"NBSP",           EmitSingleChar, 0xA0,               0, C_DONTCOUNT},
 
	{"CENT",           EmitSingleChar, 0xA2,               0, C_DONTCOUNT},
 
	{"POUNDSIGN",      EmitSingleChar, 0xA3,               0, C_DONTCOUNT},
 
	{"EURO",           EmitSingleChar, 0x20AC,             0, C_DONTCOUNT},
 
	{"YENSIGN",        EmitSingleChar, 0xA5,               0, C_DONTCOUNT},
 
	{"COPYRIGHT",      EmitSingleChar, 0xA9,               0, C_DONTCOUNT},
 
	{"DOWNARROW",      EmitSingleChar, SCC_DOWNARROW,      0, C_DONTCOUNT},
 
	{"CHECKMARK",      EmitSingleChar, SCC_CHECKMARK,      0, C_DONTCOUNT},
 
	{"CROSS",          EmitSingleChar, SCC_CROSS,          0, C_DONTCOUNT},
 
	{"REGISTERED",     EmitSingleChar, 0xAE,               0, C_DONTCOUNT},
 
	{"RIGHTARROW",     EmitSingleChar, SCC_RIGHTARROW,     0, C_DONTCOUNT},
 
	{"SMALLLEFTARROW", EmitSingleChar, SCC_LESSTHAN,       0, C_DONTCOUNT},
 
	{"SMALLRIGHTARROW",EmitSingleChar, SCC_GREATERTHAN,    0, C_DONTCOUNT},
 
};
 

	
 

	
 
@@ -1028,7 +1042,7 @@ static int TranslateArgumentIdx(int argi
 

	
 
static void PutArgidxCommand(void)
 
{
 
	PutByte(0x8C);
 
	PutUtf8(SCC_ARG_INDEX);
 
	PutByte(TranslateArgumentIdx(_cur_argidx));
 
}
 

	
 
@@ -1052,7 +1066,7 @@ static void PutCommandString(const char 
 
		if (cs == NULL) break;
 

	
 
		if (casei != -1) {
 
			PutByte(0x9D); // {SETCASE}
 
			PutUtf8(SCC_SETCASE); // {SETCASE}
 
			PutByte(casei);
 
		}
 

	
 
@@ -1163,7 +1177,7 @@ static void WriteLangfile(const char *fi
 
				// It has this format
 
				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
 
				// Each LEN is printed using 2 bytes in big endian order.
 
				PutByte(0x9E);
 
				PutUtf8(SCC_SWITCH_CASE);
 
				// Count the number of cases
 
				for (num = 0, c = casep; c; c = c->next) num++;
 
				PutByte(num);
string.c
Show inline comments
 
@@ -4,6 +4,8 @@
 
#include "openttd.h"
 
#include "functions.h"
 
#include "string.h"
 
#include "macros.h"
 
#include "table/control_codes.h"
 

	
 
#include <stdarg.h>
 
#include <ctype.h> // required for tolower()
 
@@ -68,8 +70,27 @@ char* CDECL str_fmt(const char* str, ...
 

	
 
void str_validate(char *str)
 
{
 
	for (; *str != '\0'; str++)
 
		if (!IsValidAsciiChar(*str, CS_ALPHANUMERAL)) *str = '?';
 
	char *dst = str;
 
	WChar c;
 
	size_t len = Utf8Decode(&c, str);
 

	
 
	for (; c != '\0'; len = Utf8Decode(&c, str)) {
 
		if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END ||
 
			IsValidChar(c - SCC_SPRITE_START, CS_ALPHANUMERAL))) {
 
			/* 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);
 
		} else {
 
			/* Replace the undesirable character with a question mark */
 
			str += len;
 
			*dst++ = '?';
 
		}
 
	}
 

	
 
	*dst = '\0';
 
}
 

	
 
void str_strip_colours(char *str)
 
@@ -92,29 +113,15 @@ void str_strip_colours(char *str)
 
 * @param afilter the filter to use
 
 * @return true or false depending if the character is printable/valid or not
 
 */
 
bool IsValidAsciiChar(byte key, CharSetFilter afilter)
 
bool IsValidChar(WChar key, CharSetFilter afilter)
 
{
 
	bool firsttest = false;
 

	
 
	switch (afilter) {
 
		case CS_ALPHANUMERAL:
 
			firsttest = (key >= ' ' && key < 127);
 
			break;
 

	
 
		/* We are very strict here */
 
		case CS_NUMERAL:
 
			return (key >= '0' && key <= '9');
 

	
 
		case CS_ALPHA:
 
		default:
 
			firsttest = ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'));
 
			break;
 
		case CS_ALPHANUMERAL: return IsPrintable(key);
 
		case CS_NUMERAL:      return (key >= '0' && key <= '9');
 
		case CS_ALPHA:        return IsPrintable(key) && !(key >= '0' && key <= '9');
 
	}
 

	
 
	/* Allow some special chars too that are non-ASCII but still valid (like '^' above 'a') */
 
	return (firsttest || (key >= 160 &&
 
		key != 0xAA && key != 0xAC && key != 0xAD && key != 0xAF &&
 
		key != 0xB5 && key != 0xB6 && key != 0xB7 && key != 0xB9));
 
	return false;
 
}
 

	
 
void strtolower(char *str)
 
@@ -145,3 +152,78 @@ int CDECL vsnprintf(char *str, size_t si
 
#endif /* _MSC_VER */
 

	
 
#endif /* WIN32 */
 

	
 

	
 
/* UTF-8 handling routines */
 

	
 

	
 
/* Decode and consume the next UTF-8 encoded character
 
 * @param c Buffer to place decoded character.
 
 * @param s Character stream to retrieve character from.
 
 * @return Number of characters in the sequence.
 
 */
 
size_t Utf8Decode(WChar *c, const char *s)
 
{
 
	assert(c != NULL);
 

	
 
	if (!HASBIT(s[0], 7)) {
 
		/* Single byte character: 0xxxxxxx */
 
		*c = s[0];
 
		return 1;
 
	} else if (GB(s[0], 5, 3) == 6) {
 
		if (IsUtf8Part(s[1])) {
 
			/* Double byte character: 110xxxxx 10xxxxxx */
 
			*c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
 
			if (*c >= 0x80) return 2;
 
		}
 
	} else if (GB(s[0], 4, 4) == 14) {
 
		if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
 
			/* Triple byte character: 1110xxxx 10xxxxxx 10xxxxxx */
 
			*c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
 
			if (*c >= 0x800) return 3;
 
		}
 
	} else if (GB(s[0], 3, 5) == 30) {
 
		if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
 
			/* 4 byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
 
			*c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
 
			if (*c >= 0x10000 && *c <= 0x10FFFF) return 4;
 
		}
 
	}
 

	
 
	//DEBUG(misc, 1) ("Invalid UTF-8 sequence");
 
	*c = '?';
 
	return 1;
 
}
 

	
 

	
 
/* Encode a unicode character and place it in the buffer
 
 * @param buf Buffer to place character.
 
 * @param c   Unicode character to encode.
 
 * @return Number of characters in the encoded sequence.
 
 */
 
size_t Utf8Encode(char *buf, WChar c)
 
{
 
	if (c < 0x80) {
 
		*buf = c;
 
		return 1;
 
	} else if (c < 0x800) {
 
		*buf++ = 0xC0 + GB(c,  6, 5);
 
		*buf   = 0x80 + GB(c,  0, 6);
 
		return 2;
 
	} else if (c < 0x10000) {
 
		*buf++ = 0xE0 + GB(c, 12, 4);
 
		*buf++ = 0x80 + GB(c,  6, 6);
 
		*buf   = 0x80 + GB(c,  0, 6);
 
		return 3;
 
	} else if (c < 0x110000) {
 
		*buf++ = 0xF0 + GB(c, 18, 3);
 
		*buf++ = 0x80 + GB(c, 12, 6);
 
		*buf++ = 0x80 + GB(c,  6, 6);
 
		*buf   = 0x80 + GB(c,  0, 6);
 
		return 4;
 
	}
 

	
 
	//DEBUG(misc, 1) ("Can't UTF-8 encode value 0x%X", c);
 
	*buf = '?';
 
	return 1;
 
}
string.h
Show inline comments
 
@@ -3,6 +3,8 @@
 
#ifndef STRING_H
 
#define STRING_H
 

	
 
#include "macros.h"
 

	
 
/*
 
 * dst: destination buffer
 
 * src: string to copy/concatenate
 
@@ -33,7 +35,7 @@ void str_validate(char *str);
 
void str_strip_colours(char *str);
 

	
 
/**
 
 * Valid filter types for IsValidAsciiChar.
 
 * Valid filter types for IsValidChar.
 
 */
 
typedef enum CharSetFilter {
 
	CS_ALPHANUMERAL,      //! Both numeric and alphabetic and spaces and stuff
 
@@ -41,6 +43,11 @@ typedef enum CharSetFilter {
 
	CS_ALPHA,             //! Only alphabetic values
 
} CharSetFilter;
 

	
 
/** Convert the given string to lowercase */
 
void strtolower(char *str);
 

	
 
typedef uint32 WChar;
 

	
 
/**
 
 * Only allow certain keys. You can define the filter to be used. This makes
 
 *  sure no invalid keys can get into an editbox, like BELL.
 
@@ -48,9 +55,50 @@ typedef enum CharSetFilter {
 
 * @param afilter the filter to use
 
 * @return true or false depending if the character is printable/valid or not
 
 */
 
bool IsValidAsciiChar(byte key, CharSetFilter afilter);
 
bool IsValidChar(WChar key, CharSetFilter afilter);
 

	
 
size_t Utf8Decode(WChar *c, const char *s);
 
size_t Utf8Encode(char *buf, WChar c);
 

	
 

	
 
static inline WChar Utf8Consume(const char **s)
 
{
 
	WChar c;
 
	*s += Utf8Decode(&c, *s);
 
	return c;
 
}
 

	
 

	
 
/** Convert the given string to lowercase */
 
void strtolower(char *str);
 
/** Return the length of a UTF-8 encoded character.
 
 * @param c Unicode character.
 
 * @return Length of UTF-8 encoding for character.
 
 */
 
static inline size_t Utf8CharLen(WChar c)
 
{
 
	if (c < 0x80)       return 1;
 
	if (c < 0x800)      return 2;
 
	if (c < 0x10000)    return 3;
 
	if (c < 0x110000)   return 4;
 

	
 
	/* Invalid valid, we encode as a '?' */
 
	return 1;
 
}
 

	
 

	
 
/* Check if the given character is part of a UTF8 sequence */
 
static inline bool IsUtf8Part(char c)
 
{
 
	return GB(c, 6, 2) == 2;
 
}
 

	
 

	
 
static inline bool IsPrintable(WChar c)
 
{
 
	if (c < 0x20)   return false;
 
	if (c < 0xE000) return true;
 
	if (c < 0xE200) return false;
 
	return true;
 
}
 

	
 

	
 
#endif /* STRING_H */
strings.c
Show inline comments
 
@@ -18,6 +18,7 @@
 
#include "variables.h"
 
#include "newgrf_text.h"
 
#include "table/landscape_const.h"
 
#include "table/control_codes.h"
 
#include "music.h"
 
#include "date.h"
 
#include "industry.h"
 
@@ -236,6 +237,14 @@ char *GetString(char *buffr, StringID st
 
}
 

	
 

	
 
char *InlineString(char *buf, StringID string)
 
{
 
	buf += Utf8Encode(buf, SCC_STRING_ID);
 
	buf += Utf8Encode(buf, string);
 
	return buf;
 
}
 

	
 

	
 
// This function takes a C-string and allocates a temporary string ID.
 
// The duration of the bound string is valid only until the next GetString,
 
// so be careful.
 
@@ -564,54 +573,57 @@ static const Units units[] = {
 
static char* FormatString(char* buff, const char* str, const int32* argv, uint casei, const char* last)
 
{
 
	extern const char _openttd_revision[];
 
	byte b;
 
	WChar b;
 
	const int32 *argv_orig = argv;
 
	uint modifier = 0;
 

	
 
	while ((b = *str++) != '\0') {
 
	while ((b = Utf8Consume(&str)) != '\0') {
 
		switch (b) {
 
		case 0x1: // {SETX}
 
			if (buff != last && buff + 1 != last) {
 
				*buff++ = b;
 
				*buff++ = *str++;
 
			}
 
			break;
 
		case 0x2: // {SETXY}
 
			if (buff != last && buff + 1 != last && buff + 2 != last) {
 
				*buff++ = b;
 
				*buff++ = *str++;
 
				*buff++ = *str++;
 
			}
 
			break;
 
			case SCC_SETX: // {SETX}
 
				if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
 
					buff += Utf8Encode(buff, SCC_SETX);
 
					*buff++ = *str++;
 
				}
 
				break;
 

	
 
			case SCC_SETXY: // {SETXY}
 
				if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
 
					buff += Utf8Encode(buff, SCC_SETXY);
 
					*buff++ = *str++;
 
					*buff++ = *str++;
 
				}
 
				break;
 

	
 
		case 0x81: // {STRINL}
 
			buff = GetStringWithArgs(buff, ReadLE16Unaligned(str), argv, last);
 
			str += 2;
 
			break;
 
		case 0x82: // {DATE_LONG}
 
			buff = FormatYmdString(buff, GetInt32(&argv), last);
 
			break;
 
		case 0x83: // {DATE_SHORT}
 
			buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
 
			break;
 
		case 0x84: {// {VELOCITY}
 
			int32 args[1];
 
			assert(_opt_ptr->units < lengthof(units));
 
			args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s;
 
			buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last);
 
			modifier = 0;
 
			break;
 
		}
 
		// 0x85 is used as escape character..
 
		case 0x85:
 
			switch (*str++) {
 
			case 0: /* {CURRCOMPACT} */
 
			case SCC_STRING_ID: // {STRINL}
 
				buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
 
				break;
 

	
 
			case SCC_DATE_LONG: // {DATE_LONG}
 
				buff = FormatYmdString(buff, GetInt32(&argv), last);
 
				break;
 

	
 
			case SCC_DATE_SHORT: // {DATE_SHORT}
 
				buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
 
				break;
 

	
 
			case SCC_VELOCITY: {// {VELOCITY}
 
				int32 args[1];
 
				assert(_opt_ptr->units < lengthof(units));
 
				args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s;
 
				buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last);
 
				modifier = 0;
 
				break;
 
			}
 

	
 
			case SCC_CURRENCY_COMPACT: /* {CURRCOMPACT} */
 
				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last);
 
				break;
 
			case 2: /* {REV} */
 

	
 
			case SCC_REVISION: /* {REV} */
 
				buff = strecpy(buff, _openttd_revision, last);
 
				break;
 
			case 3: { /* {SHORTCARGO} */
 

	
 
			case SCC_CARGO_SHORT: { /* {SHORTCARGO} */
 
				// Short description of cargotypes. Layout:
 
				// 8-bit = cargo type
 
				// 16-bit = cargo count
 
@@ -642,40 +654,46 @@ static char* FormatString(char* buff, co
 
						break;
 
				}
 
			} break;
 
			case 4: {/* {CURRCOMPACT64} */
 

	
 
			case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */
 
				// 64 bit compact currency-unit
 
				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
 
				break;
 
			}
 
			case 5: { /* {STRING1} */
 

	
 
			case SCC_STRING1: { /* {STRING1} */
 
				// String that consumes ONE argument
 
				uint str = modifier + GetInt32(&argv);
 
				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
 
				modifier = 0;
 
				break;
 
			}
 
			case 6: { /* {STRING2} */
 

	
 
			case SCC_STRING2: { /* {STRING2} */
 
				// String that consumes TWO arguments
 
				uint str = modifier + GetInt32(&argv);
 
				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
 
				modifier = 0;
 
				break;
 
			}
 
			case 7: { /* {STRING3} */
 

	
 
			case SCC_STRING3: { /* {STRING3} */
 
				// String that consumes THREE arguments
 
				uint str = modifier + GetInt32(&argv);
 
				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
 
				modifier = 0;
 
				break;
 
			}
 
			case 8: { /* {STRING4} */
 

	
 
			case SCC_STRING4: { /* {STRING4} */
 
				// String that consumes FOUR arguments
 
				uint str = modifier + GetInt32(&argv);
 
				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
 
				modifier = 0;
 
				break;
 
			}
 
			case 9: { /* {STRING5} */
 

	
 
			case SCC_STRING5: { /* {STRING5} */
 
				// String that consumes FIVE arguments
 
				uint str = modifier + GetInt32(&argv);
 
				buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
 
@@ -683,12 +701,12 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 10: { /* {STATIONFEATURES} */
 
			case SCC_STATION_FEATURES: { /* {STATIONFEATURES} */
 
				buff = StationGetSpecialString(buff, GetInt32(&argv), last);
 
				break;
 
			}
 

	
 
			case 11: { /* {INDUSTRY} */
 
			case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */
 
				const Industry* i = GetIndustry(GetInt32(&argv));
 
				int32 args[2];
 

	
 
@@ -704,7 +722,7 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 12: { // {VOLUME}
 
			case SCC_VOLUME: { // {VOLUME}
 
				int32 args[1];
 
				assert(_opt_ptr->units < lengthof(units));
 
				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
 
@@ -713,22 +731,22 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 13: { // {G 0 Der Die Das}
 
				const byte* s = (const byte*)GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
 
			case SCC_GENDER_LIST: { // {G 0 Der Die Das}
 
				const char* s = GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
 
				int len;
 
				int gender = 0;
 
				if (s != NULL && s[0] == 0x87) gender = s[1];
 
				if (s != NULL && Utf8Consume(&s) == SCC_GENDER_INDEX) gender = (byte)s[0];
 
				str = ParseStringChoice(str, gender, buff, &len);
 
				buff += len;
 
				break;
 
			}
 

	
 
			case 14: { // {DATE_TINY}
 
			case SCC_DATE_TINY: { // {DATE_TINY}
 
				buff = FormatTinyDate(buff, GetInt32(&argv), last);
 
				break;
 
			}
 

	
 
			case 15: { // {CARGO}
 
			case SCC_CARGO: { // {CARGO}
 
				// Layout now is:
 
				//   8bit   - cargo type
 
				//   16-bit - cargo count
 
@@ -738,7 +756,7 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 16: { // {POWER}
 
			case SCC_POWER: { // {POWER}
 
				int32 args[1];
 
				assert(_opt_ptr->units < lengthof(units));
 
				args[0] = GetInt32(&argv) * units[_opt_ptr->units].p_m >> units[_opt_ptr->units].p_s;
 
@@ -747,7 +765,7 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 17: { // {VOLUME_S}
 
			case SCC_VOLUME_SHORT: { // {VOLUME_S}
 
				int32 args[1];
 
				assert(_opt_ptr->units < lengthof(units));
 
				args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
 
@@ -756,7 +774,7 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 18: { // {WEIGHT}
 
			case SCC_WEIGHT: { // {WEIGHT}
 
				int32 args[1];
 
				assert(_opt_ptr->units < lengthof(units));
 
				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
 
@@ -765,7 +783,7 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 19: { // {WEIGHT_S}
 
			case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
 
				int32 args[1];
 
				assert(_opt_ptr->units < lengthof(units));
 
				args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
 
@@ -774,7 +792,7 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			case 20: { // {FORCE}
 
			case SCC_FORCE: { // {FORCE}
 
				int32 args[1];
 
				assert(_opt_ptr->units < lengthof(units));
 
				args[0] = GetInt32(&argv) * units[_opt_ptr->units].f_m >> units[_opt_ptr->units].f_s;
 
@@ -783,124 +801,122 @@ static char* FormatString(char* buff, co
 
				break;
 
			}
 

	
 
			default:
 
				error("!invalid escape sequence in string");
 
			}
 
			break;
 
			case SCC_SKIP: // {SKIP}
 
				argv++;
 
				break;
 

	
 
			// This sets up the gender for the string.
 
			// We just ignore this one. It's used in {G 0 Der Die Das} to determine the case.
 
			case SCC_GENDER_INDEX: // {GENDER 0}
 
				str++;
 
				break;
 

	
 
		case 0x86: // {SKIP}
 
			argv++;
 
			break;
 

	
 
		// This sets up the gender for the string.
 
		// We just ignore this one. It's used in {G 0 Der Die Das} to determine the case.
 
		case 0x87: // {GENDER 0}
 
			str++;
 
			break;
 
			case SCC_STRING: {// {STRING}
 
				uint str = modifier + GetInt32(&argv);
 
				// WARNING. It's prohibited for the included string to consume any arguments.
 
				// For included strings that consume argument, you should use STRING1, STRING2 etc.
 
				// To debug stuff you can set argv to NULL and it will tell you
 
				buff = GetStringWithArgs(buff, str, argv, last);
 
				modifier = 0;
 
				break;
 
			}
 

	
 
		case 0x88: {// {STRING}
 
			uint str = modifier + GetInt32(&argv);
 
			// WARNING. It's prohibited for the included string to consume any arguments.
 
			// For included strings that consume argument, you should use STRING1, STRING2 etc.
 
			// To debug stuff you can set argv to NULL and it will tell you
 
			buff = GetStringWithArgs(buff, str, argv, last);
 
			modifier = 0;
 
			break;
 
		}
 
			case SCC_COMMA: // {COMMA}
 
				buff = FormatCommaNumber(buff, GetInt32(&argv), last);
 
				break;
 

	
 
		case 0x8B: // {COMMA}
 
			buff = FormatCommaNumber(buff, GetInt32(&argv), last);
 
			break;
 
			case SCC_ARG_INDEX: // Move argument pointer
 
				argv = argv_orig + (byte)*str++;
 
				break;
 

	
 
		case 0x8C: // Move argument pointer
 
			argv = argv_orig + (byte)*str++;
 
			break;
 
			case SCC_PLURAL_LIST: { // {P}
 
				int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural
 
				int len;
 
				str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
 
				buff += len;
 
				break;
 
			}
 

	
 
		case 0x8D: { // {P}
 
			int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural
 
			int len;
 
			str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
 
			buff += len;
 
			break;
 
		}
 
			case SCC_NUM: // {NUM}
 
				buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
 
				break;
 

	
 
		case 0x8E: // {NUM}
 
			buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
 
			break;
 

	
 
		case 0x8F: // {CURRENCY}
 
			buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
 
			break;
 
			case SCC_CURRENCY: // {CURRENCY}
 
				buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
 
				break;
 

	
 
		case 0x99: { // {WAYPOINT}
 
			int32 temp[2];
 
			Waypoint *wp = GetWaypoint(GetInt32(&argv));
 
			StringID str;
 
			if (wp->string != STR_NULL) {
 
				str = wp->string;
 
			} else {
 
				temp[0] = wp->town_index;
 
				temp[1] = wp->town_cn + 1;
 
				str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
 
			case SCC_WAYPOINT_NAME: { // {WAYPOINT}
 
				int32 temp[2];
 
				Waypoint *wp = GetWaypoint(GetInt32(&argv));
 
				StringID str;
 
				if (wp->string != STR_NULL) {
 
					str = wp->string;
 
				} else {
 
					temp[0] = wp->town_index;
 
					temp[1] = wp->town_cn + 1;
 
					str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
 
				}
 
				buff = GetStringWithArgs(buff, str, temp, last);
 
				break;
 
			}
 
			buff = GetStringWithArgs(buff, str, temp, last);
 
		} break;
 

	
 
		case 0x9A: { // {STATION}
 
			const Station* st = GetStation(GetInt32(&argv));
 
			case SCC_STATION_NAME: { // {STATION}
 
				const Station* st = GetStation(GetInt32(&argv));
 

	
 
			if (!IsValidStation(st)) { // station doesn't exist anymore
 
				buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
 
			} else {
 
				int32 temp[2];
 
				temp[0] = st->town->townnametype;
 
				temp[1] = st->town->townnameparts;
 
				buff = GetStringWithArgs(buff, st->string_id, temp, last);
 
				if (!IsValidStation(st)) { // station doesn't exist anymore
 
					buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
 
				} else {
 
					int32 temp[2];
 
					temp[0] = st->town->townnametype;
 
					temp[1] = st->town->townnameparts;
 
					buff = GetStringWithArgs(buff, st->string_id, temp, last);
 
				}
 
				break;
 
			}
 
			break;
 
		}
 
		case 0x9B: { // {TOWN}
 
			const Town* t = GetTown(GetInt32(&argv));
 
			int32 temp[1];
 

	
 
			assert(IsValidTown(t));
 
			case SCC_TOWN_NAME: { // {TOWN}
 
				const Town* t = GetTown(GetInt32(&argv));
 
				int32 temp[1];
 

	
 
				assert(IsValidTown(t));
 

	
 
			temp[0] = t->townnameparts;
 
			buff = GetStringWithArgs(buff, t->townnametype, temp, last);
 
			break;
 
		}
 
				temp[0] = t->townnameparts;
 
				buff = GetStringWithArgs(buff, t->townnametype, temp, last);
 
				break;
 
			}
 

	
 
		case 0x9C: { // {CURRENCY64}
 
			buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
 
			break;
 
		}
 
			case SCC_CURRENCY_64: { // {CURRENCY64}
 
				buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
 
				break;
 
			}
 

	
 
		case 0x9D: { // {SETCASE}
 
			// This is a pseudo command, it's outputted when someone does {STRING.ack}
 
			// The modifier is added to all subsequent GetStringWithArgs that accept the modifier.
 
			modifier = (byte)*str++ << 24;
 
			break;
 
		}
 
			case SCC_SETCASE: { // {SETCASE}
 
				// This is a pseudo command, it's outputted when someone does {STRING.ack}
 
				// The modifier is added to all subsequent GetStringWithArgs that accept the modifier.
 
				modifier = (byte)*str++ << 24;
 
				break;
 
			}
 

	
 
		case 0x9E: { // {Used to implement case switching}
 
			// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
 
			// Each LEN is printed using 2 bytes in big endian order.
 
			uint num = (byte)*str++;
 
			while (num) {
 
				if ((byte)str[0] == casei) {
 
					// Found the case, adjust str pointer and continue
 
					str += 3;
 
					break;
 
			case SCC_SWITCH_CASE: { // {Used to implement case switching}
 
				// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
 
				// Each LEN is printed using 2 bytes in big endian order.
 
				uint num = (byte)*str++;
 
				while (num) {
 
					if ((byte)str[0] == casei) {
 
						// Found the case, adjust str pointer and continue
 
						str += 3;
 
						break;
 
					}
 
					// Otherwise skip to the next case
 
					str += 3 + (str[1] << 8) + str[2];
 
					num--;
 
				}
 
				// Otherwise skip to the next case
 
				str += 3 + (str[1] << 8) + str[2];
 
				num--;
 
				break;
 
			}
 
			break;
 
		}
 

	
 
		default:
 
			if (buff != last) *buff++ = b;
 
			default:
 
				if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
 
				break;
 
		}
 
	}
 
	*buff = '\0';
 
@@ -910,11 +926,12 @@ static char* FormatString(char* buff, co
 

	
 
static char *StationGetSpecialString(char *buff, int x, const char* last)
 
{
 
	if (x & 0x01) buff = strecpy(buff, "\x94", last);
 
	if (x & 0x02) buff = strecpy(buff, "\x95", last);
 
	if (x & 0x04) buff = strecpy(buff, "\x96", last);
 
	if (x & 0x08) buff = strecpy(buff, "\x97", last);
 
	if (x & 0x10) buff = strecpy(buff, "\x98", last);
 
	if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
 
	if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
 
	if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS)   < last)) buff += Utf8Encode(buff, SCC_BUS);
 
	if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
 
	if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP)  < last)) buff += Utf8Encode(buff, SCC_SHIP);
 
	*buff = '\0';
 
	return buff;
 
}
 

	
 
@@ -1122,7 +1139,7 @@ bool ReadLanguagePack(int lang_index)
 

	
 
	{
 
		char *lang = str_fmt("%s%s", _path.lang_dir, _dynlang.ent[lang_index].file);
 
		lang_pack = ReadFileToMem(lang, &len, 100000);
 
		lang_pack = ReadFileToMem(lang, &len, 200000);
 
		free(lang);
 
	}
 
	if (lang_pack == NULL) return false;
 
@@ -1237,7 +1254,7 @@ void InitializeLanguagePacks(void)
 
	int fallback;
 
	LanguagePack hdr;
 
	FILE *in;
 
	char *files[32];
 
	char *files[MAX_LANG];
 
	const char* lang;
 

	
 
	lang = GetCurrentLocale("LC_MESSAGES");
strings.h
Show inline comments
 
@@ -3,14 +3,7 @@
 
#ifndef STRINGS_H
 
#define STRINGS_H
 

	
 
static inline char* InlineString(char* buf, uint16 string)
 
{
 
	*buf++ = '\x81';
 
	*buf++ = string & 0xFF;
 
	*buf++ = string >> 8;
 
	return buf;
 
}
 

	
 
char *InlineString(char *buf, uint16 string);
 
char *GetString(char *buffr, uint16 string, const char* last);
 

	
 
extern char _userstring[128];
table/control_codes.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
#ifndef CONTROL_CODES_H
 
#define CONTROL_CODES_H
 

	
 
/* List of string control codes used for string formatting, displaying, and
 
 * by strgen to generate the language files. */
 

	
 
enum {
 
	SCC_CONTROL_START = 0xE000,
 
	SCC_CONTROL_END   = 0xE1FF,
 

	
 
	SCC_SPRITE_START  = 0xE200,
 
	SCC_SPRITE_END    = SCC_SPRITE_START + 0xFF,
 

	
 
	/* Display control codes */
 
	SCC_SETX = SCC_CONTROL_START,
 
	SCC_SETXY,
 
	SCC_TINYFONT,
 
	SCC_BIGFONT,
 

	
 
	/* Formatting control codes */
 
	SCC_REVISION,
 
	SCC_STATION_FEATURES,
 
	SCC_INDUSTRY_NAME,
 
	SCC_WAYPOINT_NAME,
 
	SCC_STATION_NAME,
 
	SCC_TOWN_NAME,
 

	
 
	SCC_CURRENCY_COMPACT,
 
	SCC_CURRENCY_COMPACT_64,
 
	SCC_CURRENCY,
 
	SCC_CURRENCY_64,
 

	
 
	SCC_CARGO,
 
	SCC_CARGO_SHORT,
 
	SCC_POWER,
 
	SCC_VOLUME,
 
	SCC_VOLUME_SHORT,
 
	SCC_WEIGHT,
 
	SCC_WEIGHT_SHORT,
 
	SCC_FORCE,
 
	SCC_VELOCITY,
 

	
 
	SCC_DATE_TINY,
 
	SCC_DATE_SHORT,
 
	SCC_DATE_LONG,
 

	
 
	SCC_STRING1,
 
	SCC_STRING2,
 
	SCC_STRING3,
 
	SCC_STRING4,
 
	SCC_STRING5,
 

	
 
	SCC_SKIP,
 
	SCC_STRING,
 
	SCC_COMMA,
 
	SCC_NUM,
 

	
 
	SCC_STRING_ID,
 
	SCC_PLURAL_LIST,
 
	SCC_GENDER_LIST,
 
	SCC_GENDER_INDEX,
 
	SCC_ARG_INDEX,
 
	SCC_SETCASE,
 
	SCC_SWITCH_CASE,
 

	
 
	/* Colour codes */
 
	SCC_BLUE,
 
	SCC_SILVER,
 
	SCC_GOLD,
 
	SCC_RED,
 
	SCC_PURPLE,
 
	SCC_LTBROWN,
 
	SCC_ORANGE,
 
	SCC_GREEN,
 
	SCC_YELLOW,
 
	SCC_DKGREEN,
 
	SCC_CREAM,
 
	SCC_BROWN,
 
	SCC_WHITE,
 
	SCC_LTBLUE,
 
	SCC_GRAY,
 
	SCC_DKBLUE,
 
	SCC_BLACK,
 

	
 
	/* Special printable symbols.
 
	 * These are mapped to the original glyphs */
 
	SCC_LESSTHAN       = SCC_SPRITE_START + 0x3C,
 
	SCC_GREATERTHAN    = SCC_SPRITE_START + 0x3E,
 
	SCC_UPARROW        = SCC_SPRITE_START + 0x80,
 
	SCC_SMALLUPARROW   = SCC_SPRITE_START + 0x90,
 
	SCC_SMALLDOWNARROW = SCC_SPRITE_START + 0x91,
 
	SCC_TRAIN          = SCC_SPRITE_START + 0x94,
 
	SCC_LORRY          = SCC_SPRITE_START + 0x95,
 
	SCC_BUS            = SCC_SPRITE_START + 0x96,
 
	SCC_PLANE          = SCC_SPRITE_START + 0x97,
 
	SCC_SHIP           = SCC_SPRITE_START + 0x98,
 
	SCC_DOWNARROW      = SCC_SPRITE_START + 0xAA,
 
	SCC_CHECKMARK      = SCC_SPRITE_START + 0xAC,
 
	SCC_CROSS          = SCC_SPRITE_START + 0xAD,
 
	SCC_RIGHTARROW     = SCC_SPRITE_START + 0xAF,
 
};
 

	
 
#endif /* CONTROL_CODES_H */
table/namegen.h
Show inline comments
 
@@ -304,7 +304,7 @@ static const char *name_austrian_a2[] = 
 
	"Aus",
 
	"Alten",
 
	"Braun",
 
	"Vösl",
 
	"Vösl",
 
	"Mittern",
 
	"Nuss",
 
	"Neu",
 
@@ -326,9 +326,9 @@ static const char *name_austrian_a2[] = 
 
	"Frauen",
 
	"Herren",
 
	"Hof",
 
	"Hütt",
 
	"Hütt",
 
	"Kaisers",
 
	"Königs",
 
	"Königs",
 
	"Knittel",
 
	"Lang",
 
	"Ober",
 
@@ -340,7 +340,7 @@ static const char *name_austrian_a2[] = 
 
	"Stocker",
 
	"Unter",
 
	"Utten",
 
	"Vösen",
 
	"Vösen",
 
	"Vill",
 
	"Weissen"
 
};
 
@@ -386,7 +386,7 @@ static const char *name_austrian_a5[] = 
 

	
 
static const char *name_austrian_a6[] = {
 
	"Aegyd",
 
	"Andrä",
 
	"Andrä",
 
	"Georgen",
 
	"Jakob",
 
	"Johann",
 
@@ -399,7 +399,7 @@ static const char *name_austrian_a6[] = 
 
	"Nikolai",
 
	"Oswald",
 
	"Peter",
 
	"Pölten",
 
	"Pölten",
 
	"Stefan",
 
	"Stephan",
 
	"Thomas",
 
@@ -460,10 +460,10 @@ static const char *name_german_real[] = 
 
	"Gera",
 
	"Kassel",
 
	"Kiel",
 
	"Köln",
 
	"Lübeck",
 
	"Köln",
 
	"Lübeck",
 
	"Magdeburg",
 
	"München",
 
	"München",
 
	"Potsdam",
 
	"Stuttgart",
 
	"Wiesbaden"
 
@@ -486,7 +486,7 @@ static const char *name_german_1[] = {
 
	"Cloppen",
 
	"Co",
 
	"Duis",
 
	"Düssel",
 
	"Düssel",
 
	"Dannen",
 
	"Elb",
 
	"Els",
 
@@ -500,7 +500,7 @@ static const char *name_german_1[] = {
 
	"Frei",
 
	"Freuden",
 
	"Fried",
 
	"Fürsten",
 
	"Fürsten",
 
	"Hahn",
 
	"Ham",
 
	"Harz",
 
@@ -521,10 +521,10 @@ static const char *name_german_1[] = {
 
	"Langen",
 
	"Lim",
 
	"Lohr",
 
	"Lüne",
 
	"Lüne",
 
	"Mel",
 
	"Michels",
 
	"Mühl",
 
	"Mühl",
 
	"Naum",
 
	"Nest",
 
	"Nord",
 
@@ -532,7 +532,7 @@ static const char *name_german_1[] = {
 
	"Nien",
 
	"Nidda",
 
	"Nieder",
 
	"Nürn",
 
	"Nürn",
 
	"Ober",
 
	"Offen",
 
	"Osna",
 
@@ -546,18 +546,18 @@ static const char *name_german_1[] = {
 
	"Regens",
 
	"Rott",
 
	"Ros",
 
	"Rüssels",
 
	"Rüssels",
 
	"Saal",
 
	"Saar",
 
	"Salz",
 
	"Schöne",
 
	"Schöne",
 
	"Schwein",
 
	"Sonder",
 
	"Sonnen",
 
	"Stein",
 
	"Strals",
 
	"Straus",
 
	"Süd",
 
	"Süd",
 
	"Ton",
 
	"Unter",
 
	"Ur",
 
@@ -568,14 +568,14 @@ static const char *name_german_1[] = {
 
	"Wester",
 
	"Witten",
 
	"Wolfs",
 
	"Würz"
 
	"Würz"
 
};
 

	
 
static const char *name_german_2[] = {
 
	"bach",
 
	"berg",
 
	"brück",
 
	"brücken",
 
	"brück",
 
	"brücken",
 
	"burg",
 
	"dorf",
 
	"feld",
 
@@ -585,7 +585,7 @@ static const char *name_german_2[] = {
 
	"heim",
 
	"horst",
 
	"mund",
 
	"münster",
 
	"münster",
 
	"stadt",
 
	"wald"
 
};
 
@@ -717,7 +717,7 @@ static const char *name_french_real[] = 
 
	"St. Tropez",
 
	"Marseilles",
 
	"Narbonne",
 
	"Sète",
 
	"Sète",
 
	"Aurillac",
 
	"Gueret",
 
	"Le Creusot",
 
@@ -725,8 +725,8 @@ static const char *name_french_real[] = 
 
	"Auxerre",
 
	"Versailles",
 
	"Meaux",
 
	"Châlons",
 
	"Compiègne",
 
	"Châlons",
 
	"Compiègne",
 
	"Metz",
 
	"Chaumont",
 
	"Langres",
 
@@ -739,8 +739,8 @@ static const char *name_french_real[] = 
 
	"Le Mans",
 
	"Angers",
 
	"Nantes",
 
	"Châteauroux",
 
	"Orléans",
 
	"Châteauroux",
 
	"Orléans",
 
	"Lisieux",
 
	"Cherbourg",
 
	"Morlaix",
 
@@ -751,7 +751,7 @@ static const char *name_french_real[] = 
 
	"Troyes",
 
	"Charolles",
 
	"Grenoble",
 
	"Chambéry",
 
	"Chambéry",
 
	"Tours",
 
	"St. Brieuc",
 
	"St. Malo",
 
@@ -765,11 +765,11 @@ static const char *name_french_real[] = 
 
	"Albi",
 
	"St. Valery",
 
	"Biarritz",
 
	"Béziers",
 
	"Nîmes",
 
	"Béziers",
 
	"Nîmes",
 
	"Chamonix",
 
	"Angoulème",
 
	"Alençon"
 
	"Angoulème",
 
	"Alençon"
 
};
 

	
 
static const char *name_silly_1[] = {
 
@@ -897,7 +897,7 @@ static const char *name_swedish_2[] = {
 
	"Es",
 
	"Fin",
 
	"Fisk",
 
	"Grön",
 
	"Grön",
 
	"Hag",
 
	"Halm",
 
	"Karl",
 
@@ -916,17 +916,17 @@ static const char *name_swedish_2[] = {
 
	"Skog",
 
	"Stock",
 
	"Stor",
 
	"Ström",
 
	"Ström",
 
	"Sund",
 
	"Söder",
 
	"Söder",
 
	"Tall",
 
	"Tratt",
 
	"Troll",
 
	"Upp",
 
	"Var",
 
	"Väster",
 
	"Ängel",
 
	"Öster"
 
	"Väster",
 
	"Ängel",
 
	"Öster"
 
};
 

	
 
static const char *name_swedish_2a[] = {
 
@@ -981,9 +981,9 @@ static const char *name_swedish_2b[] = {
 
	"o",
 
	"u",
 
	"y",
 
	"å",
 
	"ä",
 
	"ö"
 
	"å",
 
	"ä",
 
	"ö"
 
};
 

	
 
static const char *name_swedish_2c[] = {
 
@@ -1029,25 +1029,25 @@ static const char *name_swedish_3[] = {
 
	"hamn",
 
	"holm",
 
	"hus",
 
	"hättan",
 
	"hättan",
 
	"kulle",
 
	"köping",
 
	"köping",
 
	"lund",
 
	"löv",
 
	"löv",
 
	"sala",
 
	"skrona",
 
	"slätt",
 
	"spång",
 
	"slätt",
 
	"spång",
 
	"stad",
 
	"sund",
 
	"svall",
 
	"svik",
 
	"såker",
 
	"såker",
 
	"udde",
 
	"valla",
 
	"viken",
 
	"älv",
 
	"ås"
 
	"älv",
 
	"ås"
 
};
 

	
 
static const char *name_dutch_1[] = {
 
@@ -1214,7 +1214,7 @@ static const char *name_finnish_real[] =
 
	"Espoo",
 
	"Helsinki",
 
	"Tapiola",
 
	"Järvelä",
 
	"Järvelä",
 
	"Lahti",
 
	"Kotka",
 
	"Hamina",
 
@@ -1249,26 +1249,26 @@ static const char *name_finnish_1[] = {
 
	"Sauna",
 
	"Uusi",
 
	"Vanha",
 
	"Kesä",
 
	"Kesä",
 
	"Kuusi",
 
	"Pelto",
 
	"Tuomi",
 
	"Terva",
 
	"Olki",
 
	"Heinä",
 
	"Seinä",
 
	"Heinä",
 
	"Seinä",
 
	"Rova",
 
	"Koivu",
 
	"Kokko",
 
	"Mänty",
 
	"Mänty",
 
	"Pihlaja",
 
	"Petäjä",
 
	"Petäjä",
 
	"Kielo",
 
	"Kauha",
 
	"Viita",
 
	"Kivi",
 
	"Riihi",
 
	"Ääne",
 
	"Ääne",
 
	"Niini"
 
};
 

	
 
@@ -1277,27 +1277,27 @@ static const char *name_finnish_2[] = {
 
	"Lohjan",
 
	"Savon",
 
	"Lapin",
 
	"Pitäjän",
 
	"Pitäjän",
 
	"Martin",
 
	"Kuusan",
 
	"Kemi",
 
	"Keri",
 
	"Hämeen",
 
	"Hämeen",
 
	"Kangas"
 
};
 

	
 
static const char *name_finnish_3[] = {
 
	"harju",
 
	"linna",
 
	"järvi",
 
	"järvi",
 
	"kallio",
 
	"mäki",
 
	"mäki",
 
	"nummi",
 
	"joki",
 
	"kylä",
 
	"kylä",
 
	"lampi",
 
	"lahti",
 
	"metsä",
 
	"metsä",
 
	"suo",
 
	"laakso",
 
	"niitty",
 
@@ -1606,61 +1606,61 @@ static const char *name_czech_real[] = {
 
	"Blansko",
 
	"Breclav",
 
	"Brno",
 
	"Bruntál",
 
	"Ceská Lípa",
 
	"Ceské Budejovice",
 
	"Ceský Krumlov",
 
	"Decín",
 
	"Bruntál",
 
	"Ceská Lípa",
 
	"Ceské Budejovice",
 
	"Ceský Krumlov",
 
	"Decín",
 
	"Domazlice",
 
	"Dubí",
 
	"Frýdek-Místek",
 
	"Havlíckuv Brod",
 
	"Hodonín",
 
	"Hradec Králové",
 
	"Dubí",
 
	"Frýdek-Místek",
 
	"Havlíckuv Brod",
 
	"Hodonín",
 
	"Hradec Králové",
 
	"Humpolec",
 
	"Cheb",
 
	"Chomutov",
 
	"Chrudim",
 
	"Jablonec nad Nisou",
 
	"Jeseník",
 
	"Jicín",
 
	"Jeseník",
 
	"Jicín",
 
	"Jihlava",
 
	"Jindrichuv Hradec",
 
	"Karlovy Vary",
 
	"Karviná",
 
	"Karviná",
 
	"Kladno",
 
	"Klatovy",
 
	"Kolín",
 
	"Kolín",
 
	"Kosmonosy",
 
	"Kromeríz",
 
	"Kutná Hora",
 
	"Kromeríz",
 
	"Kutná Hora",
 
	"Liberec",
 
	"Litomerice",
 
	"Louny",
 
	"Manetín",
 
	"Melník",
 
	"Mladá Boleslav",
 
	"Manetín",
 
	"Melník",
 
	"Mladá Boleslav",
 
	"Most",
 
	"Náchod",
 
	"Nový Jicín",
 
	"Náchod",
 
	"Nový Jicín",
 
	"Nymburk",
 
	"Olomouc",
 
	"Opava",
 
	"Orácov",
 
	"Orácov",
 
	"Ostrava",
 
	"Pardubice",
 
	"Pelhrimov",
 
	"Polzice",
 
	"Písek",
 
	"Písek",
 
	"Plzen",
 
	"Praha",
 
	"Prachatice",
 
	"Prerov",
 
	"Príbram",
 
	"Príbram",
 
	"Prostejov",
 
	"Rakovník",
 
	"Rakovník",
 
	"Rokycany",
 
	"Rudná",
 
	"Rudná",
 
	"Rychnov nad Kneznou",
 
	"Semily",
 
	"Sokolov",
 
@@ -1668,18 +1668,18 @@ static const char *name_czech_real[] = {
 
	"Stredokluky",
 
	"Sumperk",
 
	"Svitavy",
 
	"Tábor",
 
	"Tábor",
 
	"Tachov",
 
	"Teplice",
 
	"Trebíc",
 
	"Trebíc",
 
	"Trutnov",
 
	"Uherské Hradiste",
 
	"Ústí nad Labem",
 
	"Ústí nad Orlicí",
 
	"Vsetín",
 
	"Uherské Hradiste",
 
	"Ústí nad Labem",
 
	"Ústí nad Orlicí",
 
	"Vsetín",
 
	"Vyskov",
 
	"Zdár nad Sázavou",
 
	"Zlín",
 
	"Zdár nad Sázavou",
 
	"Zlín",
 
	"Znojmo"
 
};
 

	
 
@@ -1710,13 +1710,13 @@ typedef enum CzechPattern {
 
/* [CzechGender][CzechPattern] - replaces the last character of the adjective
 
 * by this. */
 
// XXX: [CZG_SMASC][CZP_PRIVL] needs special handling: -ovX -> -uv.
 
static const char name_czech_patmod[][3] = {
 
	/* CZG_SMASC */ { 'í', 'ý', 'X' },
 
	/* CZG_SFEM */  { 'í', 'á', 'a' },
 
	/* CZG_SNEUT */ { 'í', 'é', 'o' },
 
	/* CZG_PMASC */ { 'í', 'é', 'y' },
 
	/* CZG_PFEM */  { 'í', 'é', 'y' },
 
	/* CZG_PNEUT */ { 'í', 'á', 'a' }
 
static const char *name_czech_patmod[][3] = {
 
	/* CZG_SMASC */ { "í", "ý", "X" },
 
	/* CZG_SFEM */  { "í", "á", "a" },
 
	/* CZG_SNEUT */ { "í", "é", "o" },
 
	/* CZG_PMASC */ { "í", "é", "y" },
 
	/* CZG_PFEM */  { "í", "é", "y" },
 
	/* CZG_PNEUT */ { "í", "á", "a" }
 
};
 

	
 
// This way the substantives can choose only some adjectives/endings:
 
@@ -1751,52 +1751,52 @@ typedef struct CzechNameAdj {
 

	
 
// Some of items which should be common are doubled.
 
static const CzechNameAdj name_czech_adj[] = {
 
	{ CZP_JARNI, CZC_ANY, "Horní" },
 
	{ CZP_JARNI, CZC_ANY, "Horní" },
 
	{ CZP_JARNI, CZC_ANY, "Dolní" },
 
	{ CZP_JARNI, CZC_ANY, "Dolní" },
 
	{ CZP_JARNI, CZC_ANY, "Prední" },
 
	{ CZP_JARNI, CZC_ANY, "Zadní" },
 
	{ CZP_JARNI, CZC_ANY, "Kostelní" },
 
	{ CZP_JARNI, CZC_ANY, "Havraní" },
 
	{ CZP_JARNI, CZC_ANY, "Rícní" },
 
	{ CZP_JARNI, CZC_ANY, "Jezerní" },
 
	{ CZP_MLADY, CZC_ANY, "Velký" },
 
	{ CZP_MLADY, CZC_ANY, "Velký" },
 
	{ CZP_MLADY, CZC_ANY, "Malý" },
 
	{ CZP_MLADY, CZC_ANY, "Malý" },
 
	{ CZP_MLADY, CZC_ANY, "Vysoký" },
 
	{ CZP_MLADY, CZC_ANY, "Ceský" },
 
	{ CZP_MLADY, CZC_ANY, "Moravský" },
 
	{ CZP_MLADY, CZC_ANY, "Slovácký" },
 
	{ CZP_MLADY, CZC_ANY, "Slezský" },
 
	{ CZP_MLADY, CZC_ANY, "Uherský" },
 
	{ CZP_MLADY, CZC_ANY, "Starý" },
 
	{ CZP_MLADY, CZC_ANY, "Starý" },
 
	{ CZP_MLADY, CZC_ANY, "Nový" },
 
	{ CZP_MLADY, CZC_ANY, "Nový" },
 
	{ CZP_MLADY, CZC_ANY, "Mladý" },
 
	{ CZP_MLADY, CZC_ANY, "Královský" },
 
	{ CZP_MLADY, CZC_ANY, "Kamenný" },
 
	{ CZP_MLADY, CZC_ANY, "Cihlový" },
 
	{ CZP_MLADY, CZC_ANY, "Divný" },
 
	{ CZP_MLADY, CZC_COLOR, "Cervená" },
 
	{ CZP_MLADY, CZC_COLOR, "Cervená" },
 
	{ CZP_MLADY, CZC_COLOR, "Cervená" },
 
	{ CZP_MLADY, CZC_COLOR, "Zelená" },
 
	{ CZP_MLADY, CZC_COLOR, "Zlutá" },
 
	{ CZP_MLADY, CZC_COLOR, "Sivá" },
 
	{ CZP_MLADY, CZC_COLOR, "Sedá" },
 
	{ CZP_MLADY, CZC_COLOR, "Bílá" },
 
	{ CZP_MLADY, CZC_COLOR, "Bílá" },
 
	{ CZP_MLADY, CZC_COLOR, "Modrá" },
 
	{ CZP_MLADY, CZC_COLOR, "Ruzová" },
 
	{ CZP_MLADY, CZC_COLOR, "Cerná" },
 
	{ CZP_PRIVL, CZC_ANY, "Králova" },
 
	{ CZP_JARNI, CZC_ANY, "Horní" },
 
	{ CZP_JARNI, CZC_ANY, "Horní" },
 
	{ CZP_JARNI, CZC_ANY, "Dolní" },
 
	{ CZP_JARNI, CZC_ANY, "Dolní" },
 
	{ CZP_JARNI, CZC_ANY, "Prední" },
 
	{ CZP_JARNI, CZC_ANY, "Zadní" },
 
	{ CZP_JARNI, CZC_ANY, "Kostelní" },
 
	{ CZP_JARNI, CZC_ANY, "Havraní" },
 
	{ CZP_JARNI, CZC_ANY, "Rícní" },
 
	{ CZP_JARNI, CZC_ANY, "Jezerní" },
 
	{ CZP_MLADY, CZC_ANY, "Velký" },
 
	{ CZP_MLADY, CZC_ANY, "Velký" },
 
	{ CZP_MLADY, CZC_ANY, "Malý" },
 
	{ CZP_MLADY, CZC_ANY, "Malý" },
 
	{ CZP_MLADY, CZC_ANY, "Vysoký" },
 
	{ CZP_MLADY, CZC_ANY, "Ceský" },
 
	{ CZP_MLADY, CZC_ANY, "Moravský" },
 
	{ CZP_MLADY, CZC_ANY, "Slovácký" },
 
	{ CZP_MLADY, CZC_ANY, "Slezský" },
 
	{ CZP_MLADY, CZC_ANY, "Uherský" },
 
	{ CZP_MLADY, CZC_ANY, "Starý" },
 
	{ CZP_MLADY, CZC_ANY, "Starý" },
 
	{ CZP_MLADY, CZC_ANY, "Nový" },
 
	{ CZP_MLADY, CZC_ANY, "Nový" },
 
	{ CZP_MLADY, CZC_ANY, "Mladý" },
 
	{ CZP_MLADY, CZC_ANY, "Královský" },
 
	{ CZP_MLADY, CZC_ANY, "Kamenný" },
 
	{ CZP_MLADY, CZC_ANY, "Cihlový" },
 
	{ CZP_MLADY, CZC_ANY, "Divný" },
 
	{ CZP_MLADY, CZC_COLOR, "Cervená" },
 
	{ CZP_MLADY, CZC_COLOR, "Cervená" },
 
	{ CZP_MLADY, CZC_COLOR, "Cervená" },
 
	{ CZP_MLADY, CZC_COLOR, "Zelená" },
 
	{ CZP_MLADY, CZC_COLOR, "Zlutá" },
 
	{ CZP_MLADY, CZC_COLOR, "Sivá" },
 
	{ CZP_MLADY, CZC_COLOR, "Sedá" },
 
	{ CZP_MLADY, CZC_COLOR, "Bílá" },
 
	{ CZP_MLADY, CZC_COLOR, "Bílá" },
 
	{ CZP_MLADY, CZC_COLOR, "Modrá" },
 
	{ CZP_MLADY, CZC_COLOR, "Ruzová" },
 
	{ CZP_MLADY, CZC_COLOR, "Cerná" },
 
	{ CZP_PRIVL, CZC_ANY, "Králova" },
 
	{ CZP_PRIVL, CZC_ANY, "Janova" },
 
	{ CZP_PRIVL, CZC_ANY, "Karlova" },
 
	{ CZP_PRIVL, CZC_ANY, "Krystofova" },
 
	{ CZP_PRIVL, CZC_ANY, "Jiríkova" },
 
	{ CZP_PRIVL, CZC_ANY, "Jiríkova" },
 
	{ CZP_PRIVL, CZC_ANY, "Petrova" },
 
	{ CZP_PRIVL, CZC_ANY, "Sudovo" },
 
};
 
@@ -1806,17 +1806,17 @@ static const CzechNameSubst name_czech_s
 
	{ CZG_SMASC, CZA_ALL, CZC_COLOR, "Sedlec" },
 
	{ CZG_SMASC, CZA_ALL, CZC_COLOR, "Brod" },
 
	{ CZG_SMASC, CZA_ALL, CZC_COLOR, "Brod" },
 
	{ CZG_SMASC, CZA_ALL, CZC_NONE, "Úval" },
 
	{ CZG_SMASC, CZA_ALL, CZC_COLOR, "Zdár" },
 
	{ CZG_SMASC, CZA_ALL, CZC_NONE, "Úval" },
 
	{ CZG_SMASC, CZA_ALL, CZC_COLOR, "Zdár" },
 
	{ CZG_SMASC, CZA_ALL, CZC_COLOR, "Smrk" },
 
	{ CZG_SFEM,  CZA_ALL, CZC_COLOR, "Hora" },
 
	{ CZG_SFEM,  CZA_ALL, CZC_COLOR, "Lhota" },
 
	{ CZG_SFEM,  CZA_ALL, CZC_COLOR, "Lhota" },
 
	{ CZG_SFEM,  CZA_ALL, CZC_COLOR, "Hlava" },
 
	{ CZG_SFEM,  CZA_ALL, CZC_COLOR, "Lípa" },
 
	{ CZG_SFEM,  CZA_ALL, CZC_COLOR, "Lípa" },
 
	{ CZG_SNEUT, CZA_ALL, CZC_COLOR, "Pole" },
 
	{ CZG_SNEUT, CZA_ALL, CZC_COLOR, "Údolí" },
 
	{ CZG_PMASC, CZA_ALL, CZC_NONE, "Úvaly" },
 
	{ CZG_SNEUT, CZA_ALL, CZC_COLOR, "Údolí" },
 
	{ CZG_PMASC, CZA_ALL, CZC_NONE, "Úvaly" },
 
	{ CZG_PFEM,  CZA_ALL, CZC_COLOR, "Luka" },
 
	{ CZG_PNEUT, CZA_ALL, CZC_COLOR, "Pole" },
 
};
 
@@ -1824,7 +1824,7 @@ static const CzechNameSubst name_czech_s
 
// TODO: More stems needed. --pasky
 
static const CzechNameSubst name_czech_subst_stem[] = {
 
	{ CZG_SMASC,             CZA_MIDDLE,            CZC_COLOR, "Kostel" },
 
	{ CZG_SMASC,             CZA_MIDDLE,            CZC_COLOR, "Kláster" },
 
	{ CZG_SMASC,             CZA_MIDDLE,            CZC_COLOR, "Kláster" },
 
	{ CZG_SMASC, CZA_SHORT,                         CZC_COLOR, "Lhot" },
 
	{ CZG_SFEM,  CZA_SHORT,                         CZC_COLOR, "Lhot" },
 
	{ CZG_SFEM,  CZA_SHORT,                         CZC_COLOR, "Hur" },
 
@@ -1848,7 +1848,7 @@ static const CzechNameSubst name_czech_s
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Harv" },
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Pruh" },
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Tach" },
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Písn" },
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Písn" },
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Jin" },
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Jes" },
 
	{ CZG_NFREE,                          CZA_LONG, CZC_NONE, "Jar" },
 
@@ -1877,17 +1877,17 @@ static const char *name_czech_subst_post
 
// This array must have the both neutral genders at the end!
 
static const CzechNameSubst name_czech_subst_ending[] = {
 
	{ CZG_SMASC, CZA_SHORT | CZA_MIDDLE,            CZC_ANY, "ec" },
 
	{ CZG_SMASC, CZA_SHORT | CZA_MIDDLE,            CZC_ANY, "ín" },
 
	{ CZG_SMASC, CZA_SHORT | CZA_MIDDLE,            CZC_ANY, "ín" },
 
	{ CZG_SMASC, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_ANY, "ov" },
 
	{ CZG_SMASC, CZA_SHORT       |        CZA_LONG, CZC_ANY, "kov" },
 
	{ CZG_SMASC,                          CZA_LONG, CZC_POSTFIX, "ín" },
 
	{ CZG_SMASC,                          CZA_LONG, CZC_POSTFIX, "ník" },
 
	{ CZG_SMASC,                          CZA_LONG, CZC_POSTFIX, "ín" },
 
	{ CZG_SMASC,                          CZA_LONG, CZC_POSTFIX, "ník" },
 
	{ CZG_SMASC,                          CZA_LONG, CZC_ANY, "burk" },
 
	{ CZG_SFEM,  CZA_SHORT,                         CZC_ANY, "ka" },
 
	{ CZG_SFEM,              CZA_MIDDLE,            CZC_ANY, "inka" },
 
	{ CZG_SFEM,              CZA_MIDDLE,            CZC_ANY, "ná" },
 
	{ CZG_SFEM,              CZA_MIDDLE,            CZC_ANY, "ná" },
 
	{ CZG_SFEM,                           CZA_LONG, CZC_ANY, "ava" },
 
	{ CZG_PMASC,                          CZA_LONG, CZC_POSTFIX, "íky" },
 
	{ CZG_PMASC,                          CZA_LONG, CZC_POSTFIX, "íky" },
 
	{ CZG_PMASC,                          CZA_LONG, CZC_ANY, "upy" },
 
	{ CZG_PMASC,                          CZA_LONG, CZC_ANY, "olupy" },
 
	{ CZG_PFEM,                           CZA_LONG, CZC_ANY, "avy" },
 
@@ -1900,21 +1900,21 @@ static const CzechNameSubst name_czech_s
 

	
 
static const char *name_czech_suffix[] = {
 
	"nad Cydlinou",
 
	"nad Dyjí",
 
	"nad Dyjí",
 
	"nad Jihlavou",
 
	"nad Labem",
 
	"nad Lesy",
 
	"nad Moravou",
 
	"nad Nisou",
 
	"nad Odrou",
 
	"nad Ostravicí",
 
	"nad Sázavou",
 
	"nad Ostravicí",
 
	"nad Sázavou",
 
	"nad Vltavou",
 
	"pod Pradedem",
 
	"pod Radhostem",
 
	"pod Rípem",
 
	"pod Rípem",
 
	"pod Snezkou",
 
	"pod Spicákem",
 
	"pod Spicákem",
 
	"pod Sedlem",
 
	"v Cechach",
 
	"na Morave",
 
@@ -1927,24 +1927,24 @@ static const char *name_romanian_real[]=
 
	"Alba Iulia",
 
	"Alexandria",
 
	"Babadag",
 
	"Bacãu",
 
	"Bacãu",
 
	"Baia Mare",
 
	"Bãile Herculane",
 
	"Bãilesti",
 
	"Bârlad",
 
	"Bãile Herculane",
 
	"Bãilesti",
 
	"Bârlad",
 
	"Bicaz",
 
	"Bistrita",
 
	"Blaj",
 
	"Borsec",
 
	"Botosani",
 
	"Brãila",
 
	"Brãila",
 
	"Brasov",
 
	"Bucuresti",
 
	"Buftea",
 
	"Buzãu",
 
	"Cãlãrasi",
 
	"Buzãu",
 
	"Cãlãrasi",
 
	"Caransebes",
 
	"Cernavodã",
 
	"Cernavodã",
 
	"Cluj-Napoca",
 
	"Constanta",
 
	"Covasna",
 
@@ -1953,29 +1953,29 @@ static const char *name_romanian_real[]=
 
	"Deva",
 
	"Dorohoi",
 
	"Dr.-Tr. Severin",
 
	"Drãgãsani",
 
	"Fãgãras",
 
	"Fãlticeni",
 
	"Drãgãsani",
 
	"Fãgãras",
 
	"Fãlticeni",
 
	"Fetesti",
 
	"Focsani",
 
	"Galati",
 
	"Gheorgheni",
 
	"Giurgiu",
 
	"Hârsova",
 
	"Hârsova",
 
	"Hunedoara",
 
	"Husi",
 
	"Iasi",
 
	"Isaccea",
 
	"Lugoj",
 
	"Mãcin",
 
	"Mãcin",
 
	"Mangalia",
 
	"Medgidia",
 
	"Medias",
 
	"Miercurea Ciuc",
 
	"Mizil",
 
	"Motru",
 
	"Nãsãud",
 
	"Nãvodari",
 
	"Nãsãud",
 
	"Nãvodari",
 
	"Odobesti",
 
	"Oltenita",
 
	"Onesti",
 
@@ -1986,14 +1986,14 @@ static const char *name_romanian_real[]=
 
	"Pitesti",
 
	"Ploiesti",
 
	"Predeal",
 
	"Râmnicu Vâlcea",
 
	"Râmnicu Vâlcea",
 
	"Reghin",
 
	"Resita",
 
	"Roman",
 
	"Rosiorii de Vede",
 
	"Satu Mare",
 
	"Sebes",
 
	"Sfântu Gheorghe",
 
	"Sfântu Gheorghe",
 
	"Sibiu",
 
	"Sighisoara",
 
	"Sinaia",
 
@@ -2002,21 +2002,21 @@ static const char *name_romanian_real[]=
 
	"Sovata",
 
	"Suceava",
 
	"Sulina",
 
	"Tãndãrei",
 
	"Târgoviste",
 
	"Târgu Jiu",
 
	"Târgu Mures",
 
	"Tãndãrei",
 
	"Târgoviste",
 
	"Târgu Jiu",
 
	"Târgu Mures",
 
	"Tecuci",
 
	"Timisoara",
 
	"Tulcea",
 
	"Turda",
 
	"Turnu Mãgurele",
 
	"Turnu Mãgurele",
 
	"Urziceni",
 
	"Vaslui",
 
	"Vatra Dornei",
 
	"Victoria",
 
	"Videle",
 
	"Zalãu"
 
	"Zalãu"
 
};
 

	
 
static const char *name_slovak_real[] = {
 
@@ -2112,12 +2112,12 @@ static const char *name_slovak_real[] = 
 
static const char *name_norwegian_1[] = {
 
	"Arna",
 
	"Aust",
 
	"Bjørk",
 
	"Bjørn",
 
	"Bjørk",
 
	"Bjørn",
 
	"Brand",
 
	"Bøver",
 
	"Bøver",
 
	"Drag",
 
	"Drø",
 
	"Drø",
 
	"Eids",
 
	"Egge",
 
	"Fager",
 
@@ -2130,12 +2130,12 @@ static const char *name_norwegian_1[] = 
 
	"Gaus",
 
	"Galte",
 
	"Geir",
 
	"Gløs",
 
	"Gløs",
 
	"Gran",
 
	"Grind",
 
	"Grims",
 
	"Grøn",
 
	"Grøt",
 
	"Grøn",
 
	"Grøt",
 
	"Gulle",
 
	"Haka",
 
	"Hammer",
 
@@ -2150,7 +2150,7 @@ static const char *name_norwegian_1[] = 
 
	"Kjerring",
 
	"Knatte",
 
	"Krok",
 
	"Køy",
 
	"Køy",
 
	"Lang",
 
	"Lauv",
 
	"Leir",
 
@@ -2158,7 +2158,7 @@ static const char *name_norwegian_1[] = 
 
	"Logn",
 
	"Lo",
 
	"Lyng",
 
	"Løn",
 
	"Løn",
 
	"Mesna",
 
	"Mel",
 
	"Mo",
 
@@ -2178,9 +2178,9 @@ static const char *name_norwegian_1[] = 
 
	"Sel",
 
	"Sol",
 
	"Sjur",
 
	"Skår",
 
	"Slått",
 
	"Stjør",
 
	"Skår",
 
	"Slått",
 
	"Stjør",
 
	"Stor",
 
	"Svart",
 
	"Svens",
 
@@ -2193,7 +2193,7 @@ static const char *name_norwegian_1[] = 
 
	"Vest",
 
	"Vesle",
 
	"Vik",
 
	"Våg"
 
	"Våg"
 
};
 

	
 
static const char *name_norwegian_2[] = {
 
@@ -2208,7 +2208,7 @@ static const char *name_norwegian_2[] = 
 
	"bugen",
 
	"by",
 
	"bygd",
 
	"bø",
 
	"bø",
 
	"dal",
 
	"egga",
 
	"eid",
 
@@ -2226,10 +2226,10 @@ static const char *name_norwegian_2[] = 
 
	"heim",
 
	"hella",
 
	"hovda",
 
	"høa",
 
	"høgda",
 
	"høa",
 
	"høgda",
 
	"kampen",
 
	"kjølen",
 
	"kjølen",
 
	"kollen",
 
	"kroken",
 
	"land",
 
@@ -2244,7 +2244,7 @@ static const char *name_norwegian_2[] = 
 
	"rud",
 
	"sand",
 
	"set",
 
	"sjøen",
 
	"sjøen",
 
	"skogen",
 
	"slette",
 
	"snipa",
 
@@ -2253,7 +2253,7 @@ static const char *name_norwegian_2[] = 
 
	"stulen",
 
	"sund",
 
	"svingen",
 
	"sætra",
 
	"sætra",
 
	"tinden",
 
	"tun",
 
	"vang",
 
@@ -2261,9 +2261,9 @@ static const char *name_norwegian_2[] = 
 
	"veid",
 
	"vik",
 
	"voll",
 
	"våg",
 
	"våg",
 
	"um",
 
	"åsen"
 
	"åsen"
 
};
 

	
 
static const char *name_norwegian_real[] = {
 
@@ -2271,12 +2271,12 @@ static const char *name_norwegian_real[]
 
	"Arendal",
 
	"Askim",
 
	"Bergen",
 
	"Bodø",
 
	"Bodø",
 
	"Brevik",
 
	"Bryne",
 
	"Brønnøysund",
 
	"Brønnøysund",
 
	"Drammen",
 
	"Drøbak",
 
	"Drøbak",
 
	"Egersund",
 
	"Elverum",
 
	"Farsund",
 
@@ -2284,10 +2284,10 @@ static const char *name_norwegian_real[]
 
	"Finnsnes",
 
	"Flekkefjord",
 
	"Flora",
 
	"Fosnavåg",
 
	"Fosnavåg",
 
	"Fredrikstad",
 
	"Førde",
 
	"Gjøvik",
 
	"Førde",
 
	"Gjøvik",
 
	"Grimstad",
 
	"Halden",
 
	"Hamar",
 
@@ -2296,13 +2296,13 @@ static const char *name_norwegian_real[]
 
	"Haugesund",
 
	"Holmestrand",
 
	"Horten",
 
	"Jørpeland",
 
	"Jørpeland",
 
	"Kirkenes",
 
	"Kolvereid",
 
	"Kongsberg",
 
	"Kongsvinger",
 
	"Kopervik",
 
	"Kragerø",
 
	"Kragerø",
 
	"Kristiansand",
 
	"Kristiansund",
 
	"Langesund",
 
@@ -2312,16 +2312,16 @@ static const char *name_norwegian_real[]
 
	"Levanger",
 
	"Lillehammer",
 
	"Lillesand",
 
	"Lillestrøm",
 
	"Lillestrøm",
 
	"Lyngdal",
 
	"Lørenskog",
 
	"Lørenskog",
 
	"Mandal",
 
	"Mo i Rana",
 
	"Molde",
 
	"Mosjøen",
 
	"Mosjøen",
 
	"Moss",
 
	"Mysen",
 
	"Måløy",
 
	"Måløy",
 
	"Namsos",
 
	"Narvik",
 
	"Notodden",
 
@@ -2330,11 +2330,11 @@ static const char *name_norwegian_real[]
 
	"Otta",
 
	"Porsgrunn",
 
	"Ringerike",
 
	"Risør",
 
	"Risør",
 
	"Rjukan",
 
	"Sandefjord",
 
	"Sandnes",
 
	"Sandnessjøen",
 
	"Sandnessjøen",
 
	"Sandvika",
 
	"Sarpsborg",
 
	"Sauda",
 
@@ -2345,152 +2345,152 @@ static const char *name_norwegian_real[]
 
	"Stathelle",
 
	"Stavanger",
 
	"Steinkjer",
 
	"Stjørdal",
 
	"Stjørdal",
 
	"Stokmarknes",
 
	"Stord",
 
	"Svelvik",
 
	"Svolvær",
 
	"Tromsø",
 
	"Svolvær",
 
	"Tromsø",
 
	"Trondheim",
 
	"Tvedestrand",
 
	"Tønsberg",
 
	"Tønsberg",
 
	"Ulsteinvik",
 
	"Vadsø",
 
	"Vardø",
 
	"Verdalsøra",
 
	"Åkrehamn",
 
	"Ålesund",
 
	"Åndalsnes"
 
	"Vadsø",
 
	"Vardø",
 
	"Verdalsøra",
 
	"Åkrehamn",
 
	"Ålesund",
 
	"Åndalsnes"
 
};
 

	
 
static const char *name_hungarian_1[] = {
 
	"Nagy-",
 
	"Kis-",
 
	"Felsõ-",
 
	"Alsó-",
 
	"Új-"
 
	"Felsõ-",
 
	"Alsó-",
 
	"Új-"
 
};
 

	
 
static const char *name_hungarian_2[] = {
 
	"Bodrog",
 
	"Dráva",
 
	"Dráva",
 
	"Duna",
 
	"Hejõ",
 
	"Hernád",
 
	"Rába",
 
	"Sajó",
 
	"Hejõ",
 
	"Hernád",
 
	"Rába",
 
	"Sajó",
 
	"Szamos",
 
	"Tisza",
 
	"Zala",
 
	"Balaton",
 
	"Fertõ",
 
	"Fertõ",
 
	"Bakony",
 
	"Cserhát",
 
	"Cserhát",
 
	"Bihar",
 
	"Hajdú",
 
	"Jász",
 
	"Hajdú",
 
	"Jász",
 
	"Kun",
 
	"Magyar",
 
	"Nógrád",
 
	"Nyír",
 
	"Nógrád",
 
	"Nyír",
 
	"Somogy",
 
	"Székely",
 
	"Székely",
 
	"Buda",
 
	"Gyõr",
 
	"Gyõr",
 
	"Pest",
 
	"Fehér",
 
	"Cserép",
 
	"Erdõ",
 
	"Fehér",
 
	"Cserép",
 
	"Erdõ",
 
	"Hegy",
 
	"Homok",
 
	"Mezõ",
 
	"Mezõ",
 
	"Puszta",
 
	"Sár",
 
	"Császár",
 
	"Sár",
 
	"Császár",
 
	"Herceg",
 
	"Király",
 
	"Király",
 
	"Nemes",
 
	"Püspök",
 
	"Püspök",
 
	"Szent",
 
	"Almás",
 
	"Szilvás",
 
	"Almás",
 
	"Szilvás",
 
	"Agg",
 
	"Aranyos",
 
	"Békés",
 
	"Egyházas",
 
	"Békés",
 
	"Egyházas",
 
	"Gagy",
 
	"Heves",
 
	"Kapos",
 
	"Tápió",
 
	"Tápió",
 
	"Torna",
 
	"Vas",
 
	"Vámos",
 
	"Vásáros"
 
	"Vámos",
 
	"Vásáros"
 
};
 

	
 
static const char *name_hungarian_3[] = {
 
	"apáti",
 
	"bába",
 
	"apáti",
 
	"bába",
 
	"bikk",
 
	"dob",
 
	"fa",
 
	"föld",
 
	"föld",
 
	"hegyes",
 
	"kak",
 
	"kereszt",
 
	"kürt",
 
	"ladány",
 
	"mérges",
 
	"kürt",
 
	"ladány",
 
	"mérges",
 
	"szalonta",
 
	"telek",
 
	"vas",
 
	"völgy"
 
	"völgy"
 
};
 

	
 
static const char *name_hungarian_4[] = {
 
	"alja",
 
	"egyháza",
 
	"háza",
 
	"úr",
 
	"vár"
 
	"egyháza",
 
	"háza",
 
	"úr",
 
	"vár"
 
};
 

	
 
static const char *name_hungarian_real[] = {
 
	"Ajka",
 
	"Aszód",
 
	"Aszód",
 
	"Badacsony",
 
	"Baja",
 
	"Budapest",
 
	"Debrecen",
 
	"Eger",
 
	"Fonyód",
 
	"Gödöllõ",
 
	"Gyõr",
 
	"Fonyód",
 
	"Gödöllõ",
 
	"Gyõr",
 
	"Gyula",
 
	"Karcag",
 
	"Kecskemét",
 
	"Kecskemét",
 
	"Keszthely",
 
	"Kisköre",
 
	"Kisköre",
 
	"Kocsord",
 
	"Komárom",
 
	"Kõszeg",
 
	"Makó",
 
	"Mohács",
 
	"Komárom",
 
	"Kõszeg",
 
	"Makó",
 
	"Mohács",
 
	"Miskolc",
 
	"Ózd",
 
	"Ózd",
 
	"Paks",
 
	"Pápa",
 
	"Pécs",
 
	"Polgár",
 
	"Pápa",
 
	"Pécs",
 
	"Polgár",
 
	"Sarkad",
 
	"Siófok",
 
	"Siófok",
 
	"Szeged",
 
	"Szentes",
 
	"Szolnok",
 
	"Tihany",
 
	"Tokaj",
 
	"Vác",
 
	"Záhony",
 
	"Vác",
 
	"Záhony",
 
	"Zirc"
 
};
 

	
 
@@ -2501,7 +2501,7 @@ static const char *name_swiss_real[] = {
 
	"Arosa",
 
	"Appenzell",
 
	"Arbon",
 
	"Altstätten",
 
	"Altstätten",
 
	"Baar",
 
	"Baden",
 
	"Bellinzona",
 
@@ -2512,20 +2512,20 @@ static const char *name_swiss_real[] = {
 
	"Burgdorf",
 
	"Bern",
 
	"Basel",
 
	"Bülach",
 
	"Bülach",
 
	"Carouge",
 
	"Cham",
 
	"Chiasso",
 
	"Chur",
 
	"Davos",
 
	"Delémont",
 
	"Delémont",
 
	"Dietikon",
 
	"Dübendorf",
 
	"Dübendorf",
 
	"Emmen",
 
	"Freienbach-Pfäffikon",
 
	"Freienbach-Pfäffikon",
 
	"Fribourg",
 
	"Frauenfeld",
 
	"Genève",
 
	"Genève",
 
	"Glarus",
 
	"Gossau",
 
	"Grenchen",
 
@@ -2537,9 +2537,9 @@ static const char *name_swiss_real[] = {
 
	"Jona",
 
	"Kriens",
 
	"Kloten",
 
	"Köniz",
 
	"Köniz",
 
	"Kreuzlingen",
 
	"Küsnacht",
 
	"Küsnacht",
 
	"Agen",
 
	"Lancy",
 
	"La Chaux-de-Fonds",
 
@@ -2556,7 +2556,7 @@ static const char *name_swiss_real[] = {
 
	"Lyss",
 
	"Luzern",
 
	"Martigny",
 
	"Münchenstein",
 
	"Münchenstein",
 
	"Meyrin",
 
	"Montreux",
 
	"Monthey",
 
@@ -2564,7 +2564,7 @@ static const char *name_swiss_real[] = {
 
	"Murten",
 
	"Moutier",
 
	"Muttenz",
 
	"Neuchâtel",
 
	"Neuchâtel",
 
	"Neuhausen am Rheinfall",
 
	"Nyon",
 
	"Olten",
 
@@ -2593,11 +2593,11 @@ static const char *name_swiss_real[] = {
 
	"St. Moritz",
 
	"Sion",
 
	"Spiez",
 
	"Stäfa",
 
	"Stäfa",
 
	"Sursee",
 
	"Schwyz",
 
	"Thalwil",
 
	"Thônex",
 
	"Thônex",
 
	"Thun",
 
	"Uster",
 
	"Uzwil",
 
@@ -2605,7 +2605,7 @@ static const char *name_swiss_real[] = {
 
	"Volketswil",
 
	"Versoix",
 
	"Vevey",
 
	"Wädenswil",
 
	"Wädenswil",
 
	"Wettingen",
 
	"Wil",
 
	"Wallisellen",
 
@@ -2616,7 +2616,7 @@ static const char *name_swiss_real[] = {
 
	"Yverdon-les-Bains",
 
	"Zollikon",
 
	"Zofingen",
 
	"Zürich",
 
	"Zürich",
 
	"Zug",
 
};
 

	
 
@@ -2626,12 +2626,12 @@ static const char *name_danish_1[] = {
 
	"Nye ",
 
	"Store ",
 
	"Kirke ",
 
	"Nørre ",
 
	"Nørre ",
 
	"Vester ",
 
	"Sønder ",
 
	"Øster ",
 
	"Sønder ",
 
	"Øster ",
 
	"Hvide ",
 
	"Høje ",
 
	"Høje ",
 
	"Kongens ",
 
};
 

	
 
@@ -2643,7 +2643,7 @@ static const char *name_danish_2[] = {
 
	"Bede",
 
	"Birke",
 
	"Bjerring",
 
	"Bjæver",
 
	"Bjæver",
 
	"Blommens",
 
	"Blok",
 
	"Bolder",
 
@@ -2656,7 +2656,7 @@ static const char *name_danish_2[] = {
 
	"Fredens",
 
	"Frederiks",
 
	"Fugle",
 
	"Fåre",
 
	"Fåre",
 
	"Gille",
 
	"Gis",
 
	"Givs",
 
@@ -2673,11 +2673,11 @@ static const char *name_danish_2[] = {
 
	"Hol",
 
	"Horn",
 
	"Humle",
 
	"Høj",
 
	"Hør",
 
	"Høj",
 
	"Hør",
 
	"Is",
 
	"Jyde",
 
	"Jægers",
 
	"Jægers",
 
	"Karls",
 
	"Klov",
 
	"Kokke",
 
@@ -2689,24 +2689,24 @@ static const char *name_danish_2[] = {
 
	"Ny",
 
	"Oks",
 
	"Ring",
 
	"Røde",
 
	"Røde",
 
	"Rung",
 
	"Rør",
 
	"Rør",
 
	"Rud",
 
	"Saks",
 
	"Salt",
 
	"Skam",
 
	"Silke",
 
	"Skod",
 
	"Skæl",
 
	"Skær",
 
	"Skæl",
 
	"Skær",
 
	"Sol",
 
	"Svend",
 
	"Svine",
 
	"Strand",
 
	"Stubbe",
 
	"Ting",
 
	"Tjære",
 
	"Tjære",
 
	"Tore",
 
	"Uger",
 
	"Ulf",
 
@@ -2714,9 +2714,9 @@ static const char *name_danish_2[] = {
 
	"Vand",
 
	"Vej",
 
	"Vor",
 
	"Vær",
 
	"Ør",
 
	"Ål"
 
	"Vær",
 
	"Ør",
 
	"Ål"
 
};
 

	
 
static const char *name_danish_3[] = {
 
@@ -2729,21 +2729,21 @@ static const char *name_danish_3[] = {
 
	"strup",
 
	"holm",
 
	"hus",
 
	"købing",
 
	"købing",
 
	"lund",
 
	"lunde",
 
	"sund",
 
	"ovre",
 
	"høj",
 
	"høj",
 
	"dal",
 
	"sted",
 
	"sten",
 
	"løse",
 
	"rød",
 
	"løse",
 
	"rød",
 
	"magle",
 
	"sø",
 
	"sø",
 
	"bjerg",
 
	"bæk",
 
	"bæk",
 
	"drup",
 
	"lev",
 
	"bo",
 
@@ -2753,17 +2753,17 @@ static const char *name_danish_3[] = {
 
};
 

	
 
static const char *name_turkish_prefix[] = {
 
	"Akça",
 
	"Akça",
 
	"Altin",
 
	"Bahçe",
 
	"Bahçe",
 
	"Boz",
 
	"Büyük",
 
	"Çay",
 
	"Büyük",
 
	"Çay",
 
	"Dogu",
 
	"Eski",
 
	"Güzel",
 
	"Güzel",
 
	"Kizil",
 
	"Küçük",
 
	"Küçük",
 
	"Orta",
 
	"Sari",
 
	"Sultan",
 
@@ -2772,9 +2772,9 @@ static const char *name_turkish_prefix[]
 
};
 

	
 
static const char *name_turkish_middle[] = {
 
	"agaç",
 
	"agaç",
 
	"ayva",
 
	"çam",
 
	"çam",
 
	"elma",
 
	"kurt",
 
	"pazar",
 
@@ -2787,10 +2787,10 @@ static const char *name_turkish_suffix[]
 
	"kale",
 
	"kaya",
 
	"kent",
 
	"köy",
 
	"köy",
 
	"ova",
 
	"özü",
 
	"ören",
 
	"özü",
 
	"ören",
 
	"pazar",
 
	"saray",
 
	"tepe",
 
@@ -2812,8 +2812,8 @@ static const char *name_turkish_real[] =
 
	"Bolu",
 
	"Burdur",
 
	"Bursa",
 
	"Çanakkale",
 
	"Çankiri",
 
	"Çanakkale",
 
	"Çankiri",
 
	"Denizli",
 
	"Diyarbakir",
 
	"Edirne",
 
@@ -2821,10 +2821,10 @@ static const char *name_turkish_real[] =
 
	"Erzurum",
 
	"Eskisehir",
 
	"Giresun",
 
	"Gümüshane",
 
	"Gümüshane",
 
	"Hatay",
 
	"Isparta",
 
	"içel",
 
	"içel",
 
	"istanbul",
 
	"izmir",
 
	"Kars",
 
@@ -2833,7 +2833,7 @@ static const char *name_turkish_real[] =
 
	"Kirklareli",
 
	"Kocaeli",
 
	"Konya",
 
	"Kütahya",
 
	"Kütahya",
 
	"Malatya",
 
	"Manisa",
 
	"Kahramanmaras",
 
@@ -2861,9 +2861,9 @@ static const char *name_turkish_real[] =
 
	"Ardahan",
 
	"Igdir",
 
	"Yalova",
 
	"Karabük",
 
	"Karabük",
 
	"Osmaniye",
 
	"Düzce"
 
	"Düzce"
 
};
 

	
 
static const char *name_italian_real[] = {
table/unicode.h
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 

	
 
typedef struct DefaultUnicodeMapping {
 
	WChar code; ///< Unicode value
 
	byte key;   ///< Character index of sprite
 
} DefaultUnicodeMapping;
 

	
 

	
 
/* Default unicode mapping table for sprite based glyphs.
 
 * This table allows us use unicode characters even though the glyphs don't
 
 * exist, or are in the wrong place, in the standard sprite fonts.
 
 * This is not used for FreeType rendering */
 

	
 
static DefaultUnicodeMapping _default_unicode_map[] = {
 
	{ 0x010D, 0x63 }, /* Small letter c with caron */
 
	{ 0x0160, 0xA6 }, /* Capital letter s with caron */
 
	{ 0x0161, 0xA8 }, /* Small letter s with caron */
 
	{ 0x017E, 0xB8 }, /* Small letter z with caron */
 
	{ 0x20AC, 0xA4 }, /* Euro symbol */
 
};
unix.c
Show inline comments
 
@@ -291,7 +291,7 @@ void CSleep(int milliseconds)
 
#include <errno.h>
 
#include "debug.h"
 

	
 
#define INTERNALCODE "ISO-8859-15"
 
#define INTERNALCODE "UTF-8"
 

	
 
/** Try and try to decipher the current locale from environmental
 
 * variables. MacOSX is hardcoded, other OS's are dynamic. If no suitable
variables.h
Show inline comments
 
@@ -323,12 +323,12 @@ VARDEF char _ini_videodriver[16], _ini_m
 
typedef struct {
 
	int num; // number of languages
 
	int curr; // currently selected language index
 
	char curr_file[32]; // currently selected language file
 
	StringID dropdown[32 + 1]; // used in settings dialog
 
	char curr_file[MAX_LANG]; // currently selected language file
 
	StringID dropdown[MAX_LANG + 1]; // used in settings dialog
 
	struct {
 
		char *name;
 
		char *file;
 
	} ent[32];
 
	} ent[MAX_LANG];
 
} DynamicLanguages;
 

	
 
VARDEF DynamicLanguages _dynlang;
video/win32_v.c
Show inline comments
 
@@ -349,14 +349,15 @@ static LRESULT CALLBACK WndProcGdi(HWND 
 
		case WM_KEYDOWN: {
 
			// this is the rewritten ascii input function
 
			// it disables windows deadkey handling --> more linux like :D
 
			WORD w = 0;
 
			wchar_t w = 0;
 
			byte ks[256];
 
			uint scancode;
 
			uint32 pressed_key;
 

	
 
			GetKeyboardState(ks);
 
			if (ToAscii(wParam, 0, ks, &w, 0) == 0) {
 
				w = 0; // no translation was possible
 
			if (ToUnicode(wParam, 0, ks, &w, 1, 0) == 0) {
 
				/* On win9x ToUnicode always fails, so fall back to ToAscii */
 
				if (ToAscii(wParam, 0, ks, &w, 0) == 0) w = 0; // no translation was possible
 
			}
 

	
 
			pressed_key = w | MapWindowsKey(wParam) << 16;
win32.c
Show inline comments
 
@@ -926,39 +926,67 @@ void DeterminePaths(void)
 
 */
 
bool InsertTextBufferClipboard(Textbuf *tb)
 
{
 
	if (IsClipboardFormatAvailable(CF_TEXT)) {
 
		HGLOBAL cbuf;
 
		const byte *data, *dataptr;
 
		uint16 width = 0;
 
		uint16 length = 0;
 
	HGLOBAL cbuf;
 
	char utf8_buf[512];
 
	const char *ptr;
 

	
 
	WChar c;
 
	uint16 width, length;
 

	
 
	if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
 
		int bytec;
 

	
 
		OpenClipboard(NULL);
 
		cbuf = GetClipboardData(CF_UNICODETEXT);
 

	
 
		ptr = GlobalLock(cbuf);
 
		bytec = WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)ptr, -1, utf8_buf, lengthof(utf8_buf), NULL, NULL);
 
		GlobalUnlock(cbuf);
 
		CloseClipboard();
 

	
 
		if (bytec == 0) {
 
			DEBUG(misc, 0) ("[utf8] Error converting '%s'. Errno %d", ptr, GetLastError());
 
			return false;
 
		}
 
	} else if (IsClipboardFormatAvailable(CF_TEXT)) {
 
		OpenClipboard(NULL);
 
		cbuf = GetClipboardData(CF_TEXT);
 
		data = GlobalLock(cbuf); // clipboard data
 
		dataptr = data;
 

	
 
		for (; IsValidAsciiChar(*dataptr, CS_ALPHANUMERAL) && (tb->length + length) < (tb->maxlength - 1) &&
 
				(tb->maxwidth == 0 || width + tb->width + GetCharacterWidth(FS_NORMAL, (byte)*dataptr) <= tb->maxwidth); dataptr++) {
 
					width += GetCharacterWidth(FS_NORMAL, (byte)*dataptr);
 
			length++;
 
		}
 

	
 
		if (length == 0) return false;
 

	
 
		memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos);
 
		memcpy(tb->buf + tb->caretpos, data, length);
 
		tb->width += width;
 
		tb->caretxoffs += width;
 

	
 
		tb->length += length;
 
		tb->caretpos += length;
 
		tb->buf[tb->length] = '\0'; // terminating zero
 

	
 
		ptr = GlobalLock(cbuf);
 
		ttd_strlcpy(utf8_buf, ptr, lengthof(utf8_buf));
 
		GlobalUnlock(cbuf);
 
		CloseClipboard();
 
		return true;
 
	} else {
 
		return false;
 
	}
 
	return false;
 

	
 
	width = length = 0;
 

	
 
	for (ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
 
		byte charwidth;
 

	
 
		if (!IsPrintable(c)) break;
 
		if (tb->length + length >= tb->maxlength - 1) break;
 
		charwidth = GetCharacterWidth(FS_NORMAL, c);
 

	
 
		if (tb->maxwidth != 0 && width + tb->width + charwidth > tb->maxwidth) break;
 

	
 
		width += charwidth;
 
		length += Utf8CharLen(c);
 
	}
 

	
 
	if (length == 0) return false;
 

	
 
	memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos);
 
	memcpy(tb->buf + tb->caretpos, utf8_buf, length);
 
	tb->width += width;
 
	tb->caretxoffs += width;
 

	
 
	tb->length += length;
 
	tb->caretpos += length;
 
	tb->buf[tb->length] = '\0'; // terminating zero
 

	
 
	return true;
 
}
 

	
 

	
window.c
Show inline comments
 
@@ -1422,7 +1422,7 @@ void HandleKeypress(uint32 key)
 

	
 
	// Setup event
 
	e.event = WE_KEYPRESS;
 
	e.we.keypress.ascii = GB(key, 0, 8);
 
	e.we.keypress.key     = GB(key,  0, 16);
 
	e.we.keypress.keycode = GB(key, 16, 16);
 
	e.we.keypress.cont = true;
 

	
window.h
Show inline comments
 
@@ -160,7 +160,7 @@ struct WindowEvent {
 

	
 
		struct {
 
			bool cont;     // continue the search? (default true)
 
			byte ascii;    // 8-bit ASCII-value of the key
 
			uint16 key;    // 16-bit Unicode value of the key
 
			uint16 keycode;// untranslated key (including shift-state)
 
		} keypress;
 

	
0 comments (0 inline, 0 general)