move some Windows code: windmain.c -> windsys.c
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "win10.h"
|
||||
#include "winos.h"
|
||||
#include <ShlObj.h>
|
||||
|
||||
#define NEED_VARARGS
|
||||
#include "hack.h"
|
||||
@@ -27,6 +28,7 @@
|
||||
|
||||
#ifdef WIN32
|
||||
#include <VersionHelpers.h>
|
||||
#include <UserEnv.h>
|
||||
|
||||
/*
|
||||
* The following WIN32 API routines are used in this file.
|
||||
@@ -40,6 +42,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
static char portable_device_path[MAX_PATH];
|
||||
|
||||
/* runtime cursor display control switch */
|
||||
boolean win32_cursorblink;
|
||||
|
||||
@@ -68,7 +72,17 @@ unsigned long sys_random_seed(void);
|
||||
static int max_filename(void);
|
||||
#endif
|
||||
|
||||
|
||||
int get_known_folder_path(const KNOWNFOLDERID *folder_id, char *path,
|
||||
size_t path_size);
|
||||
void create_directory(const char *path);
|
||||
int build_known_folder_path(const KNOWNFOLDERID *folder_id, char *path,
|
||||
size_t path_size, boolean versioned);
|
||||
void build_environment_path(const char *env_str, const char *folder,
|
||||
char *path, size_t path_size);
|
||||
boolean folder_file_exists(const char *folder, const char *file_name);
|
||||
boolean test_portable_config(const char *executable_path,
|
||||
char *portable_device_path,
|
||||
size_t portable_device_path_size);
|
||||
/* 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 consoletty.c]
|
||||
@@ -491,6 +505,20 @@ get_port_id(char *buf)
|
||||
extern void free_winmain_stuff(void);
|
||||
#endif
|
||||
|
||||
/* return TRUE if s contains a directory, not just a filespec */
|
||||
boolean
|
||||
contains_directory(const char *s)
|
||||
{
|
||||
int i, slen = strlen(s);
|
||||
const char *cp = s;
|
||||
|
||||
for (i = 0; i < slen; ++i) {
|
||||
if (*cp == '\\' || *cp == '/' || *cp == ':')
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nethack_exit(int code)
|
||||
{
|
||||
@@ -697,25 +725,6 @@ windows_early_options(const char *window_opt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a backslash to any name not ending in /, \ or : There must
|
||||
* be room for the \
|
||||
*/
|
||||
void
|
||||
append_slash(char *name)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!*name)
|
||||
return;
|
||||
ptr = name + (strlen(name) - 1);
|
||||
if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
|
||||
*++ptr = '\\';
|
||||
*++ptr = '\0';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#include <bcrypt.h> /* Windows Crypto Next Gen (CNG) */
|
||||
|
||||
#ifndef STATUS_SUCCESS
|
||||
@@ -786,6 +795,363 @@ nt_assert_failed(const char *expression, const char *filepath, int line)
|
||||
expression, filename, line);
|
||||
}
|
||||
|
||||
boolean
|
||||
get_user_home_folder(char *homebuf, size_t sz)
|
||||
{
|
||||
static char szHomeDirBuf[MAX_PATH] = { 0 };
|
||||
// We need a process with query permission set
|
||||
HANDLE hToken = 0;
|
||||
DWORD result =
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
|
||||
DWORD BufSize = MAX_PATH;
|
||||
|
||||
result = GetUserProfileDirectoryA(hToken, szHomeDirBuf, &BufSize);
|
||||
// Close handle opened via OpenProcessToken
|
||||
CloseHandle(hToken);
|
||||
|
||||
return (result != 0);
|
||||
}
|
||||
static char *get_executable_path(void);
|
||||
|
||||
static boolean path_buffer_set = FALSE;
|
||||
static char path_buffer[MAX_PATH];
|
||||
|
||||
char *
|
||||
get_executable_path(void)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
{
|
||||
TCHAR wbuf[BUFSZ];
|
||||
GetModuleFileName((HANDLE) 0, wbuf, BUFSZ);
|
||||
WideCharToMultiByte(CP_ACP, 0, wbuf, -1, path_buffer,
|
||||
sizeof(path_buffer), NULL, NULL);
|
||||
}
|
||||
#else
|
||||
DWORD length = GetModuleFileName((HANDLE) 0, path_buffer, MAX_PATH);
|
||||
if (length == ERROR_INSUFFICIENT_BUFFER)
|
||||
error("Unable to get module name");
|
||||
path_buffer[length] = '\0';
|
||||
#endif
|
||||
|
||||
char *seperator = strrchr(path_buffer, PATH_SEPARATOR);
|
||||
if (seperator)
|
||||
*seperator = '\0';
|
||||
|
||||
path_buffer_set = TRUE;
|
||||
return path_buffer;
|
||||
}
|
||||
|
||||
char *
|
||||
windows_exepath(void)
|
||||
{
|
||||
char *p = (char *) 0;
|
||||
|
||||
if (path_buffer_set)
|
||||
p = path_buffer;
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
translate_path_variables(const char *str, char *buf)
|
||||
{
|
||||
const char *src;
|
||||
char evar[BUFSZ], *dest, *envp, *eptr = (char *) 0;
|
||||
boolean in_evar;
|
||||
size_t ccount, ecount, destcount, slen = str ? strlen(str) : 0;
|
||||
|
||||
if (!slen || !buf) {
|
||||
if (buf)
|
||||
*buf = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
dest = buf;
|
||||
src = str;
|
||||
in_evar = FALSE;
|
||||
destcount = ecount = 0;
|
||||
for (ccount = 0;
|
||||
ccount < slen && destcount < (BUFSZ - 1) && ecount < (BUFSZ - 1);
|
||||
++ccount, ++src) {
|
||||
if (*src == '%') {
|
||||
if (in_evar) {
|
||||
*eptr = '\0';
|
||||
envp = nh_getenv(evar);
|
||||
if (envp) {
|
||||
size_t elen = strlen(envp);
|
||||
|
||||
if ((elen + destcount) < (size_t) (BUFSZ - 1)) {
|
||||
Strcpy(dest, envp);
|
||||
dest += elen;
|
||||
destcount += elen;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eptr = evar;
|
||||
ecount = 0;
|
||||
}
|
||||
in_evar = !in_evar;
|
||||
continue;
|
||||
}
|
||||
if (in_evar) {
|
||||
*eptr++ = *src;
|
||||
ecount++;
|
||||
} else {
|
||||
*dest++ = *src;
|
||||
destcount++;
|
||||
}
|
||||
}
|
||||
*dest = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
DISABLE_WARNING_UNREACHABLE_CODE
|
||||
|
||||
int
|
||||
get_known_folder_path(const KNOWNFOLDERID *folder_id, char *path,
|
||||
size_t path_size)
|
||||
{
|
||||
PWSTR wide_path;
|
||||
if (FAILED(SHGetKnownFolderPath(folder_id, 0, NULL, &wide_path))) {
|
||||
error("Unable to get known folder path");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
size_t converted;
|
||||
errno_t err;
|
||||
|
||||
err = wcstombs_s(&converted, path, path_size, wide_path, _TRUNCATE);
|
||||
|
||||
CoTaskMemFree(wide_path);
|
||||
|
||||
if (err == STRUNCATE || err == EILSEQ) {
|
||||
// silently handle this problem
|
||||
return FALSE;
|
||||
} else if (err != 0) {
|
||||
error(
|
||||
"Failed folder (%lu) path string conversion, unexpected err = %d",
|
||||
folder_id->Data1, err);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
create_directory(const char *path)
|
||||
{
|
||||
BOOL dres = CreateDirectoryA(path, NULL);
|
||||
|
||||
if (!dres) {
|
||||
DWORD dw = GetLastError();
|
||||
|
||||
if (dw != ERROR_ALREADY_EXISTS)
|
||||
error("Unable to create directory '%s'", path);
|
||||
}
|
||||
}
|
||||
|
||||
RESTORE_WARNING_UNREACHABLE_CODE
|
||||
|
||||
int
|
||||
build_known_folder_path(const KNOWNFOLDERID *folder_id, char *path,
|
||||
size_t path_size, boolean versioned)
|
||||
{
|
||||
if (!get_known_folder_path(folder_id, path, path_size))
|
||||
return FALSE;
|
||||
|
||||
strcat(path, "\\NetHack\\");
|
||||
create_directory(path);
|
||||
if (versioned) {
|
||||
Sprintf(eos(path), "%d.%d\\", VERSION_MAJOR, VERSION_MINOR);
|
||||
create_directory(path);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
build_environment_path(const char *env_str, const char *folder, char *path,
|
||||
size_t path_size)
|
||||
{
|
||||
path[0] = '\0';
|
||||
|
||||
const char *root_path = nh_getenv(env_str);
|
||||
|
||||
if (root_path == NULL)
|
||||
return;
|
||||
|
||||
strcpy_s(path, path_size, root_path);
|
||||
|
||||
char *colon = strchr(path, ';');
|
||||
if (colon != NULL)
|
||||
path[0] = '\0';
|
||||
|
||||
if (strlen(path) == 0)
|
||||
return;
|
||||
|
||||
append_slash(path);
|
||||
|
||||
if (folder != NULL) {
|
||||
strcat_s(path, path_size, folder);
|
||||
strcat_s(path, path_size, "\\");
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
folder_file_exists(const char *folder, const char *file_name)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
|
||||
if (folder[0] == '\0')
|
||||
return FALSE;
|
||||
|
||||
strcpy(path, folder);
|
||||
strcat(path, file_name);
|
||||
return file_exists(path);
|
||||
}
|
||||
|
||||
boolean
|
||||
file_exists(const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
/* Just see if it's there */
|
||||
if (stat(path, &sb)) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
set_default_prefix_locations(const char *programPath UNUSED)
|
||||
{
|
||||
static char executable_path[MAX_PATH];
|
||||
static char profile_path[MAX_PATH];
|
||||
static char versioned_profile_path[MAX_PATH];
|
||||
static char versioned_user_data_path[MAX_PATH];
|
||||
static char versioned_global_data_path[MAX_PATH];
|
||||
/* static char versioninfo[20] UNUSED; */
|
||||
|
||||
strcpy(executable_path, get_executable_path());
|
||||
append_slash(executable_path);
|
||||
|
||||
if (test_portable_config(executable_path, portable_device_path,
|
||||
sizeof portable_device_path)) {
|
||||
gf.fqn_prefix[SYSCONFPREFIX] = executable_path;
|
||||
gf.fqn_prefix[CONFIGPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[HACKPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[SAVEPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[LEVELPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[BONESPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[SCOREPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[LOCKPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[TROUBLEPREFIX] = portable_device_path;
|
||||
gf.fqn_prefix[DATAPREFIX] = executable_path;
|
||||
} else {
|
||||
if (!build_known_folder_path(&FOLDERID_Profile, profile_path,
|
||||
sizeof(profile_path), FALSE))
|
||||
strcpy(profile_path, executable_path);
|
||||
|
||||
if (!build_known_folder_path(&FOLDERID_Profile,
|
||||
versioned_profile_path,
|
||||
sizeof(profile_path), TRUE))
|
||||
strcpy(versioned_profile_path, executable_path);
|
||||
|
||||
if (!build_known_folder_path(&FOLDERID_LocalAppData,
|
||||
versioned_user_data_path,
|
||||
sizeof(versioned_user_data_path), TRUE))
|
||||
strcpy(versioned_user_data_path, executable_path);
|
||||
|
||||
if (!build_known_folder_path(
|
||||
&FOLDERID_ProgramData, versioned_global_data_path,
|
||||
sizeof(versioned_global_data_path), TRUE))
|
||||
strcpy(versioned_global_data_path, executable_path);
|
||||
|
||||
gf.fqn_prefix[SYSCONFPREFIX] = versioned_global_data_path;
|
||||
gf.fqn_prefix[CONFIGPREFIX] = profile_path;
|
||||
gf.fqn_prefix[HACKPREFIX] = versioned_profile_path;
|
||||
gf.fqn_prefix[SAVEPREFIX] = versioned_user_data_path;
|
||||
gf.fqn_prefix[LEVELPREFIX] = versioned_user_data_path;
|
||||
gf.fqn_prefix[BONESPREFIX] = versioned_global_data_path;
|
||||
gf.fqn_prefix[SCOREPREFIX] = versioned_global_data_path;
|
||||
gf.fqn_prefix[LOCKPREFIX] = versioned_global_data_path;
|
||||
gf.fqn_prefix[TROUBLEPREFIX] = versioned_profile_path;
|
||||
gf.fqn_prefix[DATAPREFIX] = executable_path;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a backslash to any name not ending in /, \ or : There must
|
||||
* be room for the \
|
||||
*/
|
||||
void
|
||||
append_slash(char *name)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!*name)
|
||||
return;
|
||||
ptr = name + (strlen(name) - 1);
|
||||
if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
|
||||
*++ptr = '\\';
|
||||
*++ptr = '\0';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void set_default_prefix_locations(const char *programPath);
|
||||
boolean
|
||||
test_portable_config(const char *executable_path, char *portable_device_path,
|
||||
size_t portable_device_path_size)
|
||||
{
|
||||
int lth = 0;
|
||||
const char *sysconf = "sysconf";
|
||||
char tmppath[MAX_PATH];
|
||||
boolean retval = FALSE,
|
||||
save_initoptions_noterminate = iflags.initoptions_noterminate;
|
||||
|
||||
if (portable_device_path
|
||||
&& folder_file_exists(executable_path, "sysconf")) {
|
||||
/*
|
||||
There is a sysconf file (not just sysconf.template) present in
|
||||
the exe path, which is not the way NetHack is initially
|
||||
distributed, so assume it means that the admin/installer wants to
|
||||
override something, perhaps set up for a fully-portable
|
||||
configuration that leaves no traces behind elsewhere on this
|
||||
computer's hard drive - delve into that...
|
||||
*/
|
||||
|
||||
*portable_device_path = '\0';
|
||||
lth = sizeof tmppath - strlen(sysconf);
|
||||
(void) strncpy(tmppath, executable_path, lth - 1);
|
||||
tmppath[lth - 1] = '\0';
|
||||
(void) strcat(tmppath, sysconf);
|
||||
|
||||
iflags.initoptions_noterminate = 1;
|
||||
/* assure_syscf_file(); */
|
||||
config_error_init(TRUE, tmppath, FALSE);
|
||||
/* ... and _must_ parse correctly. */
|
||||
if (read_config_file(tmppath, set_in_sysconf)
|
||||
&& sysopt.portable_device_paths)
|
||||
retval = TRUE;
|
||||
(void) config_error_done();
|
||||
iflags.initoptions_noterminate = save_initoptions_noterminate;
|
||||
sysopt_release(); /* the real sysconf processing comes later */
|
||||
}
|
||||
if (retval) {
|
||||
lth = strlen(executable_path);
|
||||
if (lth <= (int) portable_device_path_size - 1)
|
||||
Strcpy(portable_device_path, executable_path);
|
||||
else
|
||||
retval = FALSE;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
const char *
|
||||
get_portable_device(void)
|
||||
{
|
||||
return (const char *) portable_device_path;
|
||||
}
|
||||
|
||||
/* Windows helpers for CRASHREPORT etc */
|
||||
#ifdef CRASHREPORT
|
||||
struct CRctxt {
|
||||
|
||||
Reference in New Issue
Block a user