Changes to be committed: modified: include/winprocs.h modified: src/options.c modified: sys/share/pcmain.c new file: sys/share/safeproc.c modified: sys/winnt/Makefile.msc modified: sys/winnt/stubs.c new file: sys/winnt/windmain.c modified: sys/winnt/winnt.c modified: win/win32/vs2017/NetHack.vcxproj modified: win/win32/vs2017/NetHackW.vcxproj modified: win/win32/winhack.c Because multiple window ports are supported on Windows now, even in the same executable and selectable via config file in some cases, some adjustments became necessary. There will likely be some further refining of this over the next day or two. List of changes: Move Windows startup from sys/share/pcmain.c and into its own sys/winnt/windmain.c so that it can be modified to fix some current breakage, and allow altering the order of some things. There is startup processing code that is common to all of the Windows WindowPorts, but that startup processing code needs to have no dependency on any one of those WindowPorts. Yet, during startup processing, some of the initialization routines can end up calling NetHack functions that expect an active Window port underneath, and if there isn't one, routines like pline, impossible, panic can end up invoking null function pointers. Place a new file sys/share/safeproc.c, in which a complete window port is available for early startup processing purposes. It's WindowPort name field is set to "safe-startup" just for reference. The prototypes in include/winprocs.h require that SAFEPROCS be Usage: windowprocs = get_safe_procs(0); initializes a set of winprocs function pointers that ensure none of the function pointers are left null, but that's all it does. windowprocs = get_safe_procs(1); initializes a set of winprocs functions pointers that ensure none of the function pointers are left null, but also provides some basic output and input functionality using nothing other than C stdio routines (no platform or OS specific code). The conditional code related to WIN32 has been removed from sys/share/pcmain.c The code common to all of the Windows WindowPorts calls get_safe_procs() almost immediately to ensure that there is a set of WindowPort winprocs available.
616 lines
16 KiB
C
616 lines
16 KiB
C
/* NetHack 3.6 winnt.c $NHDT-Date: 1524321419 2018/04/21 14:36:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.30 $ */
|
|
/* Copyright (c) NetHack PC Development Team 1993, 1994 */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
/*
|
|
* WIN32 system functions.
|
|
*
|
|
* Included in both console and window based clients on the windows platform.
|
|
*
|
|
* Initial Creation: Michael Allison - January 31/93
|
|
*
|
|
*/
|
|
|
|
#include "winos.h"
|
|
|
|
#define NEED_VARARGS
|
|
#include "hack.h"
|
|
#include <dos.h>
|
|
#ifndef __BORLANDC__
|
|
#include <direct.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#ifdef TTY_GRAPHICS
|
|
#include "wintty.h"
|
|
#endif
|
|
#ifdef WIN32
|
|
|
|
/*
|
|
* The following WIN32 API routines are used in this file.
|
|
*
|
|
* GetDiskFreeSpace
|
|
* GetVolumeInformation
|
|
* GetUserName
|
|
* FindFirstFile
|
|
* FindNextFile
|
|
* FindClose
|
|
*
|
|
*/
|
|
|
|
/* runtime cursor display control switch */
|
|
boolean win32_cursorblink;
|
|
|
|
/* globals required within here */
|
|
HANDLE ffhandle = (HANDLE) 0;
|
|
WIN32_FIND_DATA ffd;
|
|
|
|
typedef HWND(WINAPI *GETCONSOLEWINDOW)();
|
|
static HWND GetConsoleHandle(void);
|
|
static HWND GetConsoleHwnd(void);
|
|
#if !defined(TTY_GRAPHICS)
|
|
extern void NDECL(backsp);
|
|
#endif
|
|
|
|
/* The function pointer nt_kbhit contains a kbhit() equivalent
|
|
* which varies depending on which window port is active.
|
|
* For the tty port it is tty_kbhit() [from nttty.c]
|
|
* For the win32 port it is win32_kbhit() [from winmain.c]
|
|
* It is initialized to point to def_kbhit [in here] for safety.
|
|
*/
|
|
|
|
int def_kbhit(void);
|
|
int (*nt_kbhit)() = def_kbhit;
|
|
|
|
char
|
|
switchar()
|
|
{
|
|
/* Could not locate a WIN32 API call for this- MJA */
|
|
return '-';
|
|
}
|
|
|
|
long
|
|
freediskspace(path)
|
|
char *path;
|
|
{
|
|
char tmppath[4];
|
|
DWORD SectorsPerCluster = 0;
|
|
DWORD BytesPerSector = 0;
|
|
DWORD FreeClusters = 0;
|
|
DWORD TotalClusters = 0;
|
|
|
|
tmppath[0] = *path;
|
|
tmppath[1] = ':';
|
|
tmppath[2] = '\\';
|
|
tmppath[3] = '\0';
|
|
GetDiskFreeSpace(tmppath, &SectorsPerCluster, &BytesPerSector,
|
|
&FreeClusters, &TotalClusters);
|
|
return (long) (SectorsPerCluster * BytesPerSector * FreeClusters);
|
|
}
|
|
|
|
/*
|
|
* Functions to get filenames using wildcards
|
|
*/
|
|
int
|
|
findfirst(path)
|
|
char *path;
|
|
{
|
|
if (ffhandle) {
|
|
FindClose(ffhandle);
|
|
ffhandle = (HANDLE) 0;
|
|
}
|
|
ffhandle = FindFirstFile(path, &ffd);
|
|
return (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1;
|
|
}
|
|
|
|
int
|
|
findnext()
|
|
{
|
|
return FindNextFile(ffhandle, &ffd) ? 1 : 0;
|
|
}
|
|
|
|
char *
|
|
foundfile_buffer()
|
|
{
|
|
return &ffd.cFileName[0];
|
|
}
|
|
|
|
long
|
|
filesize(file)
|
|
char *file;
|
|
{
|
|
if (findfirst(file)) {
|
|
return ((long) ffd.nFileSizeLow);
|
|
} else
|
|
return -1L;
|
|
}
|
|
|
|
/*
|
|
* Chdrive() changes the default drive.
|
|
*/
|
|
void
|
|
chdrive(str)
|
|
char *str;
|
|
{
|
|
char *ptr;
|
|
char drive;
|
|
if ((ptr = index(str, ':')) != (char *) 0) {
|
|
drive = toupper((uchar) *(ptr - 1));
|
|
_chdrive((drive - 'A') + 1);
|
|
}
|
|
}
|
|
|
|
static int
|
|
max_filename()
|
|
{
|
|
DWORD maxflen;
|
|
int status = 0;
|
|
|
|
status = GetVolumeInformation((LPTSTR) 0, (LPTSTR) 0, 0, (LPDWORD) 0,
|
|
&maxflen, (LPDWORD) 0, (LPTSTR) 0, 0);
|
|
if (status)
|
|
return maxflen;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
def_kbhit()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Strip out troublesome file system characters.
|
|
*/
|
|
|
|
void nt_regularize(s) /* normalize file name */
|
|
register char *s;
|
|
{
|
|
register unsigned char *lp;
|
|
|
|
for (lp = s; *lp; lp++)
|
|
if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/'
|
|
|| *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|'
|
|
|| *lp == ':' || (*lp > 127))
|
|
*lp = '_';
|
|
}
|
|
|
|
/*
|
|
* This is used in nhlan.c to implement some of the LAN_FEATURES.
|
|
*/
|
|
char *
|
|
get_username(lan_username_size)
|
|
int *lan_username_size;
|
|
{
|
|
static TCHAR username_buffer[BUFSZ];
|
|
unsigned int status;
|
|
DWORD i = BUFSZ - 1;
|
|
|
|
/* i gets updated with actual size */
|
|
status = GetUserName(username_buffer, &i);
|
|
if (status)
|
|
username_buffer[i] = '\0';
|
|
else
|
|
Strcpy(username_buffer, "NetHack");
|
|
if (lan_username_size)
|
|
*lan_username_size = strlen(username_buffer);
|
|
return username_buffer;
|
|
}
|
|
|
|
#if 0
|
|
char *getxxx()
|
|
{
|
|
char szFullPath[MAX_PATH] = "";
|
|
HMODULE hInst = NULL; /* NULL gets the filename of this module */
|
|
|
|
GetModuleFileName(hInst, szFullPath, sizeof(szFullPath));
|
|
return &szFullPath[0];
|
|
}
|
|
#endif
|
|
|
|
/* fatal error */
|
|
/*VARARGS1*/
|
|
void error
|
|
VA_DECL(const char *, s)
|
|
{
|
|
char buf[BUFSZ];
|
|
VA_START(s);
|
|
VA_INIT(s, const char *);
|
|
/* error() may get called before tty is initialized */
|
|
if (iflags.window_inited)
|
|
end_screen();
|
|
if (WINDOWPORT("tty")) {
|
|
buf[0] = '\n';
|
|
(void) vsprintf(&buf[1], s, VA_ARGS);
|
|
Strcat(buf, "\n");
|
|
msmsg(buf);
|
|
} else {
|
|
(void) vsprintf(buf, s, VA_ARGS);
|
|
Strcat(buf, "\n");
|
|
raw_printf(buf);
|
|
}
|
|
VA_END();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void
|
|
Delay(int ms)
|
|
{
|
|
(void) Sleep(ms);
|
|
}
|
|
|
|
void
|
|
win32_abort()
|
|
{
|
|
boolean is_tty = FALSE;
|
|
|
|
#ifdef TTY_GRAPHICS
|
|
is_tty = WINDOWPORT("tty");
|
|
#endif
|
|
if (wizard) {
|
|
int c, ci, ct;
|
|
|
|
if (!iflags.window_inited)
|
|
c = 'n';
|
|
ct = 0;
|
|
msmsg("Execute debug breakpoint wizard?");
|
|
while ((ci = nhgetch()) != '\n') {
|
|
if (ct > 0) {
|
|
if (is_tty)
|
|
backsp(); /* \b is visible on NT console */
|
|
(void) putchar(' ');
|
|
if (is_tty)
|
|
backsp();
|
|
ct = 0;
|
|
c = 'n';
|
|
}
|
|
if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') {
|
|
ct = 1;
|
|
c = ci;
|
|
msmsg("%c", c);
|
|
}
|
|
}
|
|
if (c == 'y')
|
|
DebugBreak();
|
|
}
|
|
abort();
|
|
}
|
|
|
|
static char interjection_buf[INTERJECTION_TYPES][1024];
|
|
static int interjection[INTERJECTION_TYPES];
|
|
|
|
void
|
|
interject_assistance(num, interjection_type, ptr1, ptr2)
|
|
int num;
|
|
int interjection_type;
|
|
genericptr_t ptr1;
|
|
genericptr_t ptr2;
|
|
{
|
|
switch (num) {
|
|
case 1: {
|
|
char *panicmsg = (char *) ptr1;
|
|
char *datadir = (char *) ptr2;
|
|
char *tempdir = nh_getenv("TEMP");
|
|
interjection_type = INTERJECT_PANIC;
|
|
interjection[INTERJECT_PANIC] = 1;
|
|
/*
|
|
* ptr1 = the panic message about to be delivered.
|
|
* ptr2 = the directory prefix of the dungeon file
|
|
* that failed to open.
|
|
* Check to see if datadir matches tempdir or a
|
|
* common windows temp location. If it does, inform
|
|
* the user that they are probably trying to run the
|
|
* game from within their unzip utility, so the required
|
|
* files really don't exist at the location. Instruct
|
|
* them to unpack them first.
|
|
*/
|
|
if (panicmsg && datadir) {
|
|
if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15)
|
|
|| strstri(datadir, "TEMP")
|
|
|| (tempdir && strstri(datadir, tempdir))) {
|
|
(void) strncpy(
|
|
interjection_buf[INTERJECT_PANIC],
|
|
"\nOne common cause of this error is attempting to "
|
|
"execute\n"
|
|
"the game by double-clicking on it while it is "
|
|
"displayed\n"
|
|
"inside an unzip utility.\n\n"
|
|
"You have to unzip the contents of the zip file into a\n"
|
|
"folder on your system, and then run \"NetHack.exe\" or "
|
|
"\n"
|
|
"\"NetHackW.exe\" from there.\n\n"
|
|
"If that is not the situation, you are encouraged to\n"
|
|
"report the error as shown above.\n\n",
|
|
1023);
|
|
}
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
|
|
void
|
|
interject(interjection_type)
|
|
int interjection_type;
|
|
{
|
|
if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES)
|
|
msmsg(interjection_buf[interjection_type]);
|
|
}
|
|
|
|
#ifdef RUNTIME_PASTEBUF_SUPPORT
|
|
|
|
void port_insert_pastebuf(buf)
|
|
char *buf;
|
|
{
|
|
/* This implementation will utilize the windows clipboard
|
|
* to accomplish this.
|
|
*/
|
|
|
|
char *tmp = buf;
|
|
HGLOBAL hglbCopy;
|
|
WCHAR *w, w2[2];
|
|
int cc, rc, abytes;
|
|
LPWSTR lpwstrCopy;
|
|
HANDLE hresult;
|
|
|
|
if (!buf)
|
|
return;
|
|
|
|
cc = strlen(buf);
|
|
/* last arg=0 means "tell me the size of the buffer that I need" */
|
|
rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w2, 0);
|
|
if (!rc) return;
|
|
|
|
abytes = rc * sizeof(WCHAR);
|
|
w = (WCHAR *)alloc(abytes);
|
|
/* Housekeeping need: +free(w) */
|
|
|
|
rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w, rc);
|
|
if (!rc) {
|
|
free(w);
|
|
return;
|
|
}
|
|
if (!OpenClipboard(NULL)) {
|
|
free(w);
|
|
return;
|
|
}
|
|
/* Housekeeping need: +CloseClipboard(), free(w) */
|
|
|
|
EmptyClipboard();
|
|
|
|
/* allocate global mem obj to hold the text */
|
|
|
|
hglbCopy = GlobalAlloc(GMEM_MOVEABLE, abytes);
|
|
if (hglbCopy == NULL) {
|
|
CloseClipboard();
|
|
free(w);
|
|
return;
|
|
}
|
|
/* Housekeeping need: +GlobalFree(hglbCopy), CloseClipboard(), free(w) */
|
|
|
|
lpwstrCopy = (LPWSTR)GlobalLock(hglbCopy);
|
|
/* Housekeeping need: +GlobalUnlock(hglbCopy), GlobalFree(hglbCopy),
|
|
CloseClipboard(), free(w) */
|
|
|
|
memcpy(lpwstrCopy, w, abytes);
|
|
GlobalUnlock(hglbCopy);
|
|
/* Housekeeping need: GlobalFree(hglbCopy), CloseClipboard(), free(w) */
|
|
|
|
/* put it on the clipboard */
|
|
hresult = SetClipboardData(CF_UNICODETEXT, hglbCopy);
|
|
if (!hresult) {
|
|
raw_printf("Error copying to clipboard.\n");
|
|
GlobalFree(hglbCopy); /* only needed if clipboard didn't accept data */
|
|
}
|
|
/* Housekeeping need: CloseClipboard(), free(w) */
|
|
|
|
CloseClipboard();
|
|
free(w);
|
|
return;
|
|
}
|
|
|
|
static HWND
|
|
GetConsoleHandle(void)
|
|
{
|
|
HMODULE hMod = GetModuleHandle("kernel32.dll");
|
|
GETCONSOLEWINDOW pfnGetConsoleWindow =
|
|
(GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
|
|
if (pfnGetConsoleWindow)
|
|
return pfnGetConsoleWindow();
|
|
else
|
|
return GetConsoleHwnd();
|
|
}
|
|
|
|
static HWND
|
|
GetConsoleHwnd(void)
|
|
{
|
|
int iterations = 0;
|
|
HWND hwndFound = 0;
|
|
char OldTitle[1024], NewTitle[1024], TestTitle[1024];
|
|
|
|
/* Get current window title */
|
|
GetConsoleTitle(OldTitle, sizeof OldTitle);
|
|
|
|
(void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
|
|
GetCurrentProcessId());
|
|
SetConsoleTitle(NewTitle);
|
|
|
|
GetConsoleTitle(TestTitle, sizeof TestTitle);
|
|
while (strcmp(TestTitle, NewTitle) != 0) {
|
|
iterations++;
|
|
/* sleep(0); */
|
|
GetConsoleTitle(TestTitle, sizeof TestTitle);
|
|
}
|
|
hwndFound = FindWindow(NULL, NewTitle);
|
|
SetConsoleTitle(OldTitle);
|
|
/* printf("%d iterations\n", iterations); */
|
|
return hwndFound;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef RUNTIME_PORT_ID
|
|
/*
|
|
* _M_IX86 is Defined for x86 processors. This is not defined for x64
|
|
* processors.
|
|
* _M_X64 is Defined for x64 processors.
|
|
* _M_IA64 is Defined for Itanium Processor Family 64-bit processors.
|
|
* _WIN64 is Defined for applications for Win64.
|
|
*/
|
|
#ifndef _M_IX86
|
|
#ifdef _M_X64
|
|
#define TARGET_PORT "x64"
|
|
#endif
|
|
#ifdef _M_IA64
|
|
#define TARGET_PORT "IA64"
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef TARGET_PORT
|
|
#define TARGET_PORT "x86"
|
|
#endif
|
|
|
|
char *
|
|
get_port_id(buf)
|
|
char *buf;
|
|
{
|
|
Strcpy(buf, TARGET_PORT);
|
|
return buf;
|
|
}
|
|
#endif /* RUNTIME_PORT_ID */
|
|
|
|
/* nhassert_failed is called when an nhassert's condition is false */
|
|
void nhassert_failed(const char * exp, const char * file, int line)
|
|
{
|
|
char message[128];
|
|
_snprintf(message, sizeof(message),
|
|
"NHASSERT(%s) in '%s' at line %d\n", exp, file, line);
|
|
|
|
if (IsDebuggerPresent()) {
|
|
OutputDebugStringA(message);
|
|
DebugBreak();
|
|
}
|
|
|
|
// strip off the newline
|
|
message[strlen(message) - 1] = '\0';
|
|
error(message);
|
|
}
|
|
|
|
/* nethack_enter_winnt() is the first thing called from main */
|
|
void nethack_enter_winnt()
|
|
{
|
|
#ifdef TTY_GRAPHICS
|
|
nethack_enter_nttty();
|
|
#endif
|
|
}
|
|
|
|
/* CP437 to Unicode mapping according to the Unicode Consortium */
|
|
const WCHAR cp437[256] = {
|
|
0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
|
|
0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
|
|
0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
|
|
0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
|
|
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
|
|
0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
|
|
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
|
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
|
|
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
|
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
|
|
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
|
|
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
|
|
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
|
0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
|
|
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
|
|
0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
|
|
0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
|
|
0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
|
|
0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
|
|
0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
|
|
0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
|
|
0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
|
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
|
|
0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
|
|
0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
|
|
0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
|
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
|
|
0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
|
|
0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
|
|
0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
|
|
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
|
|
0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
|
|
};
|
|
|
|
WCHAR *
|
|
winos_ascii_to_wide_str(const unsigned char * src, WCHAR * dst, size_t dstLength)
|
|
{
|
|
size_t i = 0;
|
|
while(i < dstLength - 1 && src[i] != 0)
|
|
dst[i++] = cp437[src[i]];
|
|
dst[i] = 0;
|
|
return dst;
|
|
}
|
|
|
|
WCHAR
|
|
winos_ascii_to_wide(const unsigned char c)
|
|
{
|
|
return cp437[c];
|
|
}
|
|
|
|
BOOL winos_font_support_cp437(HFONT hFont)
|
|
{
|
|
BOOL allFound = FALSE;
|
|
HDC hdc = GetDC(NULL);
|
|
HFONT oldFont = SelectObject(hdc, hFont);
|
|
|
|
DWORD size = GetFontUnicodeRanges(hdc, NULL);
|
|
GLYPHSET *glyphSet = (GLYPHSET *) malloc(size);
|
|
|
|
if (glyphSet != NULL) {
|
|
GetFontUnicodeRanges(hdc, glyphSet);
|
|
|
|
allFound = TRUE;
|
|
for (int i = 0; i < 256 && allFound; i++) {
|
|
WCHAR wc = cp437[i];
|
|
BOOL found = FALSE;
|
|
for (DWORD j = 0; j < glyphSet->cRanges && !found; j++) {
|
|
WCHAR first = glyphSet->ranges[j].wcLow;
|
|
WCHAR last = first + glyphSet->ranges[j].cGlyphs - 1;
|
|
|
|
if (wc >= first && wc <= last)
|
|
found = TRUE;
|
|
}
|
|
if (!found)
|
|
allFound = FALSE;
|
|
}
|
|
|
|
free(glyphSet);
|
|
}
|
|
|
|
SelectObject(hdc, oldFont);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
return allFound;
|
|
}
|
|
|
|
int
|
|
windows_early_options(window_opt)
|
|
const char *window_opt;
|
|
{
|
|
/*
|
|
* If you return 2, the game will exit before it begins.
|
|
* Return 1, to say the option parsed okay.
|
|
* Return 0, to say the option was bad.
|
|
*/
|
|
|
|
if (match_optname(window_opt, "cursorblink", 5, FALSE)) {
|
|
win32_cursorblink = TRUE;
|
|
return 1;
|
|
} else {
|
|
raw_printf(
|
|
"-%swindows:cursorblink is the only supported option.\n");
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* WIN32 */
|
|
|
|
/*winnt.c*/
|