From 3ebe43eb75806990a402aafd5858de615d5c1cca Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 2 Jun 2022 01:26:45 +0100 Subject: Solve the error logging situation --- TODO/.errmsg | 6 ++++ TODO/errmsg | 11 ------- compile | 8 ++++-- compile.bat | 66 ++++++++++++++++++++++++++---------------- src/autojump.c | 11 +++---- src/con_.c | 3 ++ src/demorec.c | 43 +++++++++++---------------- src/ent.c | 4 +-- src/errmsg.c | 23 +++++++++++++++ src/errmsg.h | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/fov.c | 8 ++++-- src/gameinfo.c | 29 +++++++++---------- src/hook.c | 10 +++++-- src/l4dwarp.c | 5 ++-- src/nosleep.c | 9 +++--- src/portalcolours.c | 6 ++-- src/rinput.c | 11 ++++--- src/sst.c | 36 +++++++++++------------ 18 files changed, 245 insertions(+), 127 deletions(-) create mode 100644 TODO/.errmsg delete mode 100644 TODO/errmsg create mode 100644 src/errmsg.c create mode 100644 src/errmsg.h diff --git a/TODO/.errmsg b/TODO/.errmsg new file mode 100644 index 0000000..aefe3fc --- /dev/null +++ b/TODO/.errmsg @@ -0,0 +1,6 @@ +Come up with a better error logging abstraction +==== +This is done, see errmsg.h. + +Because it's all format string nonsense to talk to the engine, it's mostly a +pile of macros, which is kind of wacky. But hey, it works. diff --git a/TODO/errmsg b/TODO/errmsg deleted file mode 100644 index 51b8aae..0000000 --- a/TODO/errmsg +++ /dev/null @@ -1,11 +0,0 @@ -Come up with a better error logging abstraction -==== -Something like the BSD err/warn/errx/warnx maybe, although taking into account -all the stupid Windows GetLastError differences too. As it stands, different -source files have different ways of prefixing messages, a lot of strings are -pretty redundant (would maybe be nice to have something closer to the DJB-style -concatenated string messages to solve that problem?), and almost nothing bothers -to include the actual system error string because doing so is currently doing -annoying. - -pls fix diff --git a/compile b/compile index d921b78..6948527 100755 --- a/compile +++ b/compile @@ -28,9 +28,12 @@ fi objs= cc() { objs="$objs .build/${1%%.c}.o" + _mn=" -DMODULE_NAME=${1%%.c}" + # ugly annoying special case + if [ "$_mn" = " -DMODULE_NAME=con_" ]; then _mn=" -DMODULE_NAME=con" + elif [ "$_mn" = "-DMODULE_NAME=sst" ]; then _mn=; fi $CC -m32 -c -flto -fpic $cflags $warnings -I.build/include \ - -D_FILE_OFFSET_BITS=64 -DFILE_BASENAME="${1%%.c}" \ - -o ".build/${1%%.c}.o" "src/$1" + -D_FILE_OFFSET_BITS=64$_mn -o ".build/${1%%.c}.o" "src/$1" } ld() { @@ -44,6 +47,7 @@ src="\ demorec.c engineapi.c ent.c + errmsg.c extmalloc.c fixes.c fov.c diff --git a/compile.bat b/compile.bat index 60372a1..fa631b1 100644 --- a/compile.bat +++ b/compile.bat @@ -30,47 +30,63 @@ goto :main :cc for /F %%b in ("%1") do set basename=%%~nb +set dmodname= -DMODULE_NAME=%basename% +:: ugly annoying special cases +if "%dmodname%"==" -DMODULE_NAME=con_" set dmodname= -DMODULE_NAME=con +if "%dmodname%"==" -DMODULE_NAME=sst" set dmodname= set objs=%objs% .build/%basename%.o %CC% -m32 -c -flto %cflags% %warnings% -I.build/include -D_CRT_SECURE_NO_WARNINGS -D_DLL ^ --DWIN32_LEAN_AND_MEAN -DNOMINMAX -DFILE_BASENAME=%basename% -o .build/%basename%.o %1 || exit /b +-DWIN32_LEAN_AND_MEAN -DNOMINMAX%dmodname% -o .build/%basename%.o %1 || exit /b +goto :eof + +:src goto :eof :main + +set src= +:: funny hack to build a list conveniently, lol. +setlocal EnableDelayedExpansion +for /f "tokens=2" %%f in ('findstr /B /C:":+ " "%~nx0"') do set src=!src! src/%%f +setlocal DisableDelayedExpansion +:+ autojump.c +:+ con_.c +:+ demorec.c +:+ engineapi.c +:+ ent.c +:+ errmsg.c +:+ extmalloc.c +:+ fixes.c +:+ fov.c +:+ gamedata.c +:+ gameinfo.c +:+ hook.c +:+ kv.c +:+ l4dwarp.c +:+ nosleep.c +:+ portalcolours.c +:+ rinput.c +:+ sst.c +:+ x86.c +:: just tack these on, whatever +if "%dbg%"=="1" ( + set src=%src% src/dbg.c + set src=%src% src/udis86.c +) + %HOSTCC% -municode -O2 %warnings% -D_CRT_SECURE_NO_WARNINGS ^ -o .build/codegen.exe src/build/codegen.c src/build/cmeta.c || exit /b %HOSTCC% -municode -O2 %warnings% -D_CRT_SECURE_NO_WARNINGS ^ -o .build/mkgamedata.exe src/build/mkgamedata.c src/kv.c || exit /b %HOSTCC% -municode -O2 %warnings% -D_CRT_SECURE_NO_WARNINGS -ladvapi32 ^ -o .build/mkentprops.exe src/build/mkentprops.c src/kv.c || exit /b -.build\codegen.exe src/autojump.c src/con_.c src/demorec.c src/engineapi.c src/ent.c src/extmalloc.c src/fixes.c src/fov.c ^ -src/gamedata.c src/gameinfo.c src/hook.c src/kv.c src/l4dwarp.c src/nosleep.c src/portalcolours.c src/rinput.c src/sst.c src/x86.c || exit /b +.build\codegen.exe%src% || exit /b .build\mkgamedata.exe gamedata/engine.kv gamedata/gamelib.kv gamedata/inputsystem.kv || exit /b .build\mkentprops.exe gamedata/entprops.kv || exit /b llvm-rc /FO .build\dll.res src\dll.rc || exit /b %CC% -shared -O0 -w -o .build/tier0.dll src/stubs/tier0.c %CC% -shared -O0 -w -o .build/vstdlib.dll src/stubs/vstdlib.c -call :cc src/autojump.c || exit /b -call :cc src/con_.c || exit /b -call :cc src/demorec.c || exit /b -call :cc src/engineapi.c || exit /b -call :cc src/ent.c || exit /b -call :cc src/extmalloc.c || exit /b -call :cc src/fixes.c || exit /b -call :cc src/fov.c || exit /b -call :cc src/gamedata.c || exit /b -call :cc src/gameinfo.c || exit /b -call :cc src/hook.c || exit /b -call :cc src/kv.c || exit /b -call :cc src/l4dwarp.c || exit /b -call :cc src/nosleep.c || exit /b -call :cc src/portalcolours.c || exit /b -call :cc src/rinput.c || exit /b -call :cc src/sst.c || exit /b -call :cc src/x86.c || exit /b -if "%dbg%"=="1" ( - call :cc src/dbg.c || exit /b - call :cc src/udis86.c || exit /b -) +for %%b in (%src%) do ( call :cc %%b || exit /b ) if "%dbg%"=="1" ( :: ugh, microsoft. set clibs=-lmsvcrtd -lvcruntimed -lucrtd diff --git a/src/autojump.c b/src/autojump.c index a8064da..e0b6a9f 100644 --- a/src/autojump.c +++ b/src/autojump.c @@ -18,6 +18,7 @@ #include "con_.h" #include "engineapi.h" +#include "errmsg.h" #include "gamedata.h" #include "intdefs.h" #include "hook.h" @@ -63,30 +64,30 @@ static bool unprot(void *gm) { void **vtable = *(void ***)gm; bool ret = os_mprot(vtable + vtidx_CheckJumpButton, sizeof(void *), PAGE_READWRITE); - if (!ret) con_warn("autojump: couldn't make memory writable\n"); + if (!ret) errmsg_errorsys("couldn't make virtual table writable"); return ret; } bool autojump_init(void) { // TODO(featgen): auto-check these factories if (!factory_client || !factory_server) { - con_warn("autojump: missing required factories\n"); + errmsg_warnx("missing required factories"); return false; } if (!has_vtidx_CheckJumpButton || !has_off_mv) { - con_warn("autojump: missing gamedata entries for this engine\n"); + errmsg_warnx("missing gamedata entries for this engine"); return false; } gmsv = factory_server("GameMovement001", 0); if (!gmsv) { - con_warn("autojump: couldn't get server-side game movement interface\n"); + errmsg_errorx("couldn't get server-side game movement interface"); return false; } if (!unprot(gmsv)) return false; gmcl = factory_client("GameMovement001", 0); if (!gmcl) { - con_warn("autojump: couldn't get client-side game movement interface\n"); + errmsg_errorx("couldn't get client-side game movement interface"); return false; } if (!unprot(gmcl)) return false; diff --git a/src/con_.c b/src/con_.c index 5cfe046..f259324 100644 --- a/src/con_.c +++ b/src/con_.c @@ -399,6 +399,9 @@ static void helpuserhelpus(int pluginver, char ifaceverchar) { con_msg("\n"); } +// note: for now at least, not using errmsg_*() macros here because it doesn't +// really make sense for these messages to be coming from "con" + static void warnoe(void) { con_warn("sst: error: this engine version is not yet supported\n"); } diff --git a/src/demorec.c b/src/demorec.c index dc9e899..156e7c6 100644 --- a/src/demorec.c +++ b/src/demorec.c @@ -22,6 +22,7 @@ #include "con_.h" #include "demorec.h" #include "engineapi.h" +#include "errmsg.h" #include "gamedata.h" #include "gameinfo.h" #include "hook.h" @@ -116,23 +117,19 @@ static void hook_record_cb(const struct con_cmdargs *args) { // we could use open(O_DIRECTORY), but that's not a thing on // windows, of course. struct os_stat s; + static const char *const errpfx = "ERROR: can't record demo: "; if (os_stat(dir, &s) == -1) { - con_warn("ERROR: can't record demo: "); if (errno == ENOENT) { - con_warn("subdirectory %.*s doesn't exist\n", + con_warn("%ssubdirectory %.*s doesn't exist\n", errpfx, argdirlen, arg); } else { - con_warn("%s\n", strerror(errno)); // guess this'll do. + con_warn("%s%s\n", errpfx, strerror(errno)); } return; } if (!S_ISDIR(s.st_mode)) { - // TODO(errmsg): duping this warning call to avoid duping - // the string data, very stupid, oh well. if/when we have - // New And Improved Logging this can be tidied up... - con_warn("ERROR: can't record demo: "); - con_warn("the path %.*s is not a directory\n", + con_warn("%spath %.*s is not a directory\n", errpfx, argdirlen, arg); return; } @@ -157,10 +154,10 @@ static void hook_stop_cb(const struct con_cmdargs *args) { // XXX: probably want some general foreach-instruction macro once we start doing // this kind of hackery in multiple different places -#define NEXT_INSN(p) do { \ +#define NEXT_INSN(p, tgt) do { \ int _len = x86_len(p); \ if (_len == -1) { \ - con_warn("demorec: %s: unknown or invalid instruction\n", __func__); \ + errmsg_errorx("unknown or invalid instruction looking for %s", tgt); \ return false; \ } \ (p) += _len; \ @@ -178,7 +175,7 @@ static inline bool find_demorecorder(struct con_cmd *cmd_stop) { demorecorder = *indirect; return true; } - NEXT_INSN(p); + NEXT_INSN(p, "demorecorder object"); } #else #warning TODO(linux): implement linux equivalent (cdecl!) @@ -202,7 +199,7 @@ static inline bool find_recmembers(void *stoprecording) { recording = mem_offset(demorecorder, mem_load32(p + 2)); } if (recording && demonum) return true; // blegh - NEXT_INSN(p); + NEXT_INSN(p, "state variables"); } #else // linux is probably different here idk #warning TODO(linux): implement linux equivalent (???) @@ -212,42 +209,34 @@ static inline bool find_recmembers(void *stoprecording) { bool demorec_init(void) { if (!has_vtidx_StopRecording) { - con_warn("demorec: missing gamedata entries for this engine\n"); + errmsg_warnx("missing gamedata entries for this engine"); return false; } cmd_record = con_findcmd("record"); if (!cmd_record) { // can *this* even happen? I hope not! - con_warn("demorec: couldn't find \"record\" command\n"); + errmsg_errorx("couldn't find \"record\" command"); return false; } orig_record_cb = con_getcmdcb(cmd_record); cmd_stop = con_findcmd("stop"); if (!cmd_stop) { - con_warn("demorec: couldn't find \"stop\" command\n"); + errmsg_errorx("couldn't find \"stop\" command"); return false; } orig_stop_cb = con_getcmdcb(cmd_stop); if (!find_demorecorder(cmd_stop)) { - con_warn("demorec: couldn't find demo recorder instance\n"); + errmsg_errorx("couldn't find demo recorder instance"); return false; } void **vtable = *(void ***)demorecorder; // XXX: 16 is totally arbitrary here! figure out proper bounds later if (!os_mprot(vtable, 16 * sizeof(void *), PAGE_READWRITE)) { - // TODO(errmsg): this is one of the only places I apparently bothered - // to properly log this stuff. really should solve this at some point -#ifdef _WIN32 - char err[128]; - OS_WINDOWS_ERROR(err); -#else - const char *err = strerror(errno); -#endif - con_warn("demorec: couldn't make memory writable: %s\n", err); + errmsg_errorsys("couldn't make virtual table writable"); return false; } if (!find_recmembers(vtable[vtidx_StopRecording])) { - con_warn("demorec: couldn't find m_bRecording and m_nDemoNumber\n"); + errmsg_errorx("couldn't find recording state variables"); return false; } @@ -357,7 +346,7 @@ DECL_VFUNC_DYN(int, GetEngineBuildNumber) bool demorec_custom_init(void) { if (!has_vtidx_GetEngineBuildNumber || !has_vtidx_RecordPacket) { - con_warn("demorec: custom: missing gamedata entries for this engine\n"); + errmsg_warnx("custom: missing gamedata entries for this engine"); return false; } diff --git a/src/ent.c b/src/ent.c index 2e47208..392fceb 100644 --- a/src/ent.c +++ b/src/ent.c @@ -16,8 +16,8 @@ #include -#include "con_.h" #include "engineapi.h" +#include "errmsg.h" #include "gamedata.h" #include "gametype.h" #include "intdefs.h" @@ -52,7 +52,7 @@ bool ent_init(void) { edicts = mem_offset(globalvars, off_edicts); return true; } - con_warn("ent: not implemented for this engine\n"); + errmsg_warnx("not implemented for this engine"); return false; } diff --git a/src/errmsg.c b/src/errmsg.c new file mode 100644 index 0000000..63af533 --- /dev/null +++ b/src/errmsg.c @@ -0,0 +1,23 @@ +/* + * Copyright © 2022 Michael Smith + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "con_.h" + +const char msg_note[] = "note: "; +const char msg_warn[] = "warning: "; +const char msg_error[] = "error: "; + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/errmsg.h b/src/errmsg.h new file mode 100644 index 0000000..17a4457 --- /dev/null +++ b/src/errmsg.h @@ -0,0 +1,83 @@ +/* + * Copyright © 2022 Michael Smith + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INC_ERRMSG_H +#define INC_ERRMSG_H + +#include "con_.h" +#include "os.h" + +extern const char msg_note[], msg_warn[], msg_error[]; + +#define _ERRMSG_STR1(x) #x +#define _ERRMSG_STR(x) _ERRMSG_STR1(x) + +#ifdef MODULE_NAME +#define _errmsg_msg(mod, msg, s, ...) \ + con_warn("sst: %s: %s" s ": %s\n", mod, msg, __VA_ARGS__) +// XXX: can we avoid using the ##__VA_ARGS__ extension here somehow? +#define _errmsg_msgx(mod, msg, s, ...) \ + con_warn("sst: %s: %s" s "\n", mod, msg, ##__VA_ARGS__) +#else +// dumb hack: we don't want sst.c to say "sst: sst:" - easier to just drop the +// module parameter here so all the stuff below can just remain the same +#define _errmsg_msg(ignored, msg, s, ...) \ + con_warn("sst: %s" s ": %s\n", msg, __VA_ARGS__) +#define _errmsg_msgx(ignored, msg, s, ...) \ + con_warn("sst: %s" s "\n", msg, ##__VA_ARGS__) +#endif + +#define _errmsg_std(msg, ...) \ + _errmsg_msg(_ERRMSG_STR(MODULE_NAME), msg, __VA_ARGS__, strerror(errno)) + +#define _errmsg_x(msg, ...) \ + _errmsg_msgx(_ERRMSG_STR(MODULE_NAME), msg, __VA_ARGS__) + +#ifdef _WIN32 +#define _errmsg_sys(msg, ...) do { \ + char _warnsys_buf[512]; \ + OS_WINDOWS_ERROR(_warnsys_buf); \ + _errmsg_msg(_ERRMSG_STR(MODULE_NAME), msg, __VA_ARGS__, _warnsys_buf); \ +} while (0) +#define _errmsg_dl _errmsg_sys +#else +#define _errmsg_sys _errmsg_std +static inline const char *_errmsg_dlerror(void) { + const char *e = dlerror(); + if (!e) return "Unknown error"; // just in case, better avoid weirdness! + return e; +} +#define _errmsg_dl(msg, ...) \ + _errmsg_msg(_ERRMSG_STR(MODULE_NAME), msg, __VA_ARGS__, _errmsg_dlerror()); +#endif + +// Reminder: will need add warnsock/errsock if we ever do stuff with sockets, +// because of Windows's WSAGetLastError() abomination. +#define errmsg_warnstd(...) _errmsg_std(msg_warn, __VA_ARGS__) +#define errmsg_warnsys(...) _errmsg_sys(msg_warn, __VA_ARGS__) +#define errmsg_warndl(...) _errmsg_dl(msg_warn, __VA_ARGS__) +#define errmsg_warnx(...) _errmsg_x(msg_warn, __VA_ARGS__) + +#define errmsg_errorstd(...) _errmsg_std(msg_error, __VA_ARGS__) +#define errmsg_errorsys(...) _errmsg_sys(msg_error, __VA_ARGS__) +#define errmsg_errordl(...) _errmsg_dl(msg_error, __VA_ARGS__) +#define errmsg_errorx(...) _errmsg_x(msg_error, __VA_ARGS__) + +#define errmsg_note(...) _errmsg_x(msg_note, __VA_ARGS__) + +#endif + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/fov.c b/src/fov.c index 151fa2e..c090651 100644 --- a/src/fov.c +++ b/src/fov.c @@ -21,6 +21,7 @@ #include "con_.h" #include "engineapi.h" +#include "errmsg.h" #include "ent.h" #include "gametype.h" #include "hook.h" @@ -57,7 +58,8 @@ static bool find_SetDefaultFOV(struct con_cmd *fov) { } int len = x86_len(p); if (len == -1) { - con_warn("fov: find_SetDefaultFOV: unknown or invalid instruction\n"); + errmsg_errorx("unknown or invalid instruction looking for %s", + "SetDefaultFOV"); return false; } p += len; @@ -100,13 +102,13 @@ bool fov_init(bool has_ent) { real_fov_desired = fov_desired; } if (!find_SetDefaultFOV(cmd_fov)) { - con_warn("fov: couldn't find SetDefaultFOV function\n"); + errmsg_errorx("couldn't find SetDefaultFOV function"); return false; } orig_SetDefaultFOV = (SetDefaultFOV_func)hook_inline( (void *)orig_SetDefaultFOV, (void *)&hook_SetDefaultFOV); if (!orig_SetDefaultFOV) { - con_warn("fov: couldn't hook SetDefaultFOV function\n"); + errmsg_errorsys("couldn't hook SetDefaultFOV function"); return false; } diff --git a/src/gameinfo.c b/src/gameinfo.c index 36c9402..8fe17d9 100644 --- a/src/gameinfo.c +++ b/src/gameinfo.c @@ -21,6 +21,7 @@ #include "con_.h" #include "engineapi.h" +#include "errmsg.h" #include "gametype.h" #include "intdefs.h" #include "kv.h" @@ -72,8 +73,7 @@ static void trygamelib(const os_char *path, os_char *outpath) { os_strcpy(outpath, path); } else if (errno != ENOENT) { - con_warn("gameinfo: failed to access %" fS ": %s\n", path, - strerror(errno)); + errmsg_warnstd("failed to access %" fS, path); } } @@ -132,7 +132,7 @@ static inline void dolibsearch(const char *p, uint len, bool isgamebin, int fmtspace = spaceleft - (sizeof("client" OS_DLSUFFIX) - 1); int ret = os_snprintf(outp, fmtspace, fmt, len, p); if (ret >= fmtspace) { -toobig: con_warn("gameinfo: skipping an overly long search path\n"); +toobig: errmsg_warnx("skipping an overly long search path"); return; } outp += ret; @@ -227,8 +227,7 @@ static void kv_cb(enum kv_token type, const char *p, uint len, void *_ctxt) { if (ctxt->dontcarelvl) --ctxt->dontcarelvl; else --ctxt->nestlvl; break; case KV_COND_PREFIX: case KV_COND_SUFFIX: - con_warn("gameinfo: warning: just ignoring conditional \"%.*s\"", - len, p); + errmsg_warnx("just ignoring conditional \"%.*s\"", len, p); } #undef MATCH } @@ -237,7 +236,7 @@ DECL_VFUNC_DYN(const char *, GetGameDirectory) bool gameinfo_init(void) { if (!has_vtidx_GetGameDirectory) { - con_warn("gameinfo: unsupported VEngineClient interface\n"); + errmsg_errorx("unsupported VEngineClient interface"); return false; } @@ -245,13 +244,12 @@ bool gameinfo_init(void) { // base dir is just cwd os_char cwd[PATH_MAX]; if (!os_getcwd(cwd, sizeof(cwd) / sizeof(*cwd))) { - con_warn("gameinfo: couldn't get working directory: %s\n", - strerror(errno)); + errmsg_errorstd("couldn't get working directory"); return false; } int len = os_strlen(cwd); if (len + sizeof("/bin") > sizeof(bindir) / sizeof(*bindir)) { - con_warn("gameinfo: working directory path is too long!\n"); + errmsg_errorx("working directory path is too long!"); return false; } memcpy(bindir, cwd, len * sizeof(*cwd)); @@ -261,7 +259,7 @@ bool gameinfo_init(void) { int gamedirlen = _snwprintf(gamedir, sizeof(gamedir) / sizeof(*gamedir), L"%S", VCALL(engclient, GetGameDirectory)); if (gamedirlen < 0) { // encoding error??? ugh... - con_warn("gameinfo: invalid game directory path!\n"); + errmsg_errorx("invalid game directory path!"); return false; } #else @@ -271,7 +269,7 @@ bool gameinfo_init(void) { #endif if (gamedirlen + sizeof("/gameinfo.txt") > sizeof(gamedir) / sizeof(*gamedir)) { - con_warn("gameinfo: game directory path is too long!\n"); + errmsg_errorx("game directory path is too long!"); return false; } os_char gameinfopath[PATH_MAX]; @@ -281,7 +279,7 @@ bool gameinfo_init(void) { 14 * sizeof(os_char)); int fd = os_open(gameinfopath, O_RDONLY); if (fd == -1) { - con_warn("gameinfo: couldn't open gameinfo.txt: %s\n", strerror(errno)); + errmsg_errorstd("couldn't open gameinfo.txt"); return false; } char buf[1024]; @@ -290,8 +288,7 @@ bool gameinfo_init(void) { int nread; while (nread = read(fd, buf, sizeof(buf))) { if (nread == -1) { - con_warn("gameinfo: couldn't read gameinfo.txt: %s\n", - strerror(errno)); + errmsg_errorstd("couldn't read gameinfo.txt"); goto e; } if (!kv_parser_feed(&kvp, buf, nread, &kv_cb, &ctxt)) goto ep; @@ -303,8 +300,8 @@ bool gameinfo_init(void) { if (GAMETYPE_MATCHES(L4DS)) gameinfo_title = "Left 4 Dead: Survivors"; return true; -ep: con_warn("gameinfo: couldn't parse gameinfo.txt (%d:%d): %s\n", - kvp.line, kvp.col, kvp.errmsg); +ep: errmsg_errorx("couldn't parse gameinfo.txt (%d:%d): %s", kvp.line, kvp.col, + kvp.errmsg); e: close(fd); return false; } diff --git a/src/hook.c b/src/hook.c index 9320636..bca226d 100644 --- a/src/hook.c +++ b/src/hook.c @@ -48,20 +48,24 @@ void *hook_inline(void *func_, void *target) { if (!os_mprot(func, 5, PAGE_EXECUTE_READWRITE)) return false; int len = 0; for (;;) { + // FIXME: these cases may result in somewhat dodgy error messaging. They + // shouldn't happen anyway though. Maybe if we're confident we just + // compile 'em out of release builds some day, but that sounds a little + // scary. For now prefering confusing messages over crashes, I guess. if (func[len] == X86_CALL) { con_warn("hook_inline: can't trampoline call instructions\n"); - return false; + return 0; } int ilen = x86_len(func + len); if (ilen == -1) { con_warn("hook_inline: unknown or invalid instruction\n"); - return false; + return 0; } len += ilen; if (len >= 5) break; if (func[len] == X86_JMPIW) { con_warn("hook_inline: can't trampoline jmp instructions\n"); - return false; + return 0; } } // for simplicity, just bump alloc the trampoline. no need to free anyway diff --git a/src/l4dwarp.c b/src/l4dwarp.c index 20f52a5..7a77427 100644 --- a/src/l4dwarp.c +++ b/src/l4dwarp.c @@ -20,6 +20,7 @@ #include "con_.h" #include "engineapi.h" +#include "errmsg.h" #include "ent.h" #include "gamedata.h" #include "gametype.h" @@ -34,7 +35,7 @@ DECL_VFUNC_DYN(void, Teleport, const struct vec3f *pos, const struct vec3f *ang, DEF_CCMD_HERE_UNREG(sst_l4d_testwarp, "Simulate a bot warping to you", CON_SERVERSIDE | CON_CHEAT) { struct edict *ed = ent_getedict(con_cmdclient + 1); - if (!ed) { con_warn("error: couldn't access player entity\n"); return; } + if (!ed) { errmsg_errorx("couldn't access player entity"); return; } void *e = VCALL(ed->ent_unknown, GetBaseEntity); // is this call required? struct vec3f *org = mem_offset(e, off_entpos); struct vec3f *ang = mem_offset(e, off_eyeang); @@ -50,7 +51,7 @@ DEF_CCMD_HERE_UNREG(sst_l4d_testwarp, "Simulate a bot warping to you", bool l4dwarp_init(void) { if (!GAMETYPE_MATCHES(L4Dx)) return false; if (!has_off_entpos || !has_off_eyeang || !has_vtidx_Teleport) { - con_warn("l4dwarp: missing gamedata entries for this engine\n"); + errmsg_warnx("missing gamedata entries for this engine"); return false; } con_reg(sst_l4d_testwarp); diff --git a/src/nosleep.c b/src/nosleep.c index c1c5a9b..c849f04 100644 --- a/src/nosleep.c +++ b/src/nosleep.c @@ -18,6 +18,7 @@ #include "con_.h" #include "engineapi.h" +#include "errmsg.h" #include "gamedata.h" #include "hook.h" #include "os.h" @@ -41,22 +42,22 @@ bool nosleep_init(void) { con_reg(engine_no_focus_sleep); // TODO(featgen): auto-check these factories if (!factory_inputsystem) { - con_warn("nosleep: missing required factories\n"); + errmsg_warnx("missing required factories"); return false; } if (!has_vtidx_SleepUntilInput) { - con_warn("nosleep: missing gamedata entries for this engine\n"); + errmsg_warnx("missing gamedata entries for this engine"); return false; } void *insys = factory_inputsystem("InputSystemVersion001", 0); if (!insys) { - con_warn("nosleep: couldn't get input system interface\n"); + errmsg_errorx("couldn't get input system interface"); return false; } vtable = *(void ***)insys; if (!os_mprot(vtable + vtidx_SleepUntilInput, sizeof(void *), PAGE_READWRITE)) { - con_warn("nosleep: couldn't make memory writable\n"); + errmsg_errorx("couldn't make virtual table writable"); return false; } orig_SleepUntilInput = (SleepUntilInput_func)hook_vtable(vtable, diff --git a/src/portalcolours.c b/src/portalcolours.c index 00eb96b..750ee19 100644 --- a/src/portalcolours.c +++ b/src/portalcolours.c @@ -19,7 +19,7 @@ #include "con_.h" #include "engineapi.h" -#include "extmalloc.h" +#include "errmsg.h" #include "gametype.h" #include "hook.h" #include "intdefs.h" @@ -123,13 +123,13 @@ bool portalcolours_init(void *clientlib) { // ... should libs be globals? if (!GAMETYPE_MATCHES(Portal)) return false; #ifdef _WIN32 if (!find_UTIL_Portal_Color(clientlib)) { - con_warn("portalcolours: error: couldn't find UTIL_Portal_Color\n"); + errmsg_errorx("couldn't find UTIL_Portal_Color"); return false; } orig_UTIL_Portal_Color = (UTIL_Portal_Color_func)hook_inline( (void *)orig_UTIL_Portal_Color, (void *)&hook_UTIL_Portal_Color); if (!orig_UTIL_Portal_Color) { - con_warn("portalcolours: error: couldn't hook UTIL_Portal_Color\n"); + errmsg_errorsys("couldn't hook UTIL_Portal_Color"); return false; } sst_portal_colour0->base.flags &= ~CON_HIDDEN; diff --git a/src/rinput.c b/src/rinput.c index 6286eda..1b81cf5 100644 --- a/src/rinput.c +++ b/src/rinput.c @@ -22,6 +22,7 @@ #include "con_.h" #include "hook.h" +#include "errmsg.h" #include "intdefs.h" // We reimplement m_rawinput by hooking cursor functions in the same way as @@ -31,8 +32,6 @@ // loaded. If m_rawinput already exists, we do nothing; people should use the // game's native raw input instead in that case. -#define ERR "rinput: error: " - #define USAGEPAGE_MOUSE 1 #define USAGE_MOUSE 2 @@ -106,18 +105,18 @@ bool rinput_init(void) { orig_GetCursorPos = (GetCursorPos_func)hook_inline((void *)&GetCursorPos, (void *)&hook_GetCursorPos); if (!orig_GetCursorPos) { - con_warn(ERR "couldn't hook GetCursorPos\n"); + errmsg_errorsys("couldn't hook %s", "GetCursorPos"); goto e0; } orig_SetCursorPos = (SetCursorPos_func)hook_inline((void *)&SetCursorPos, (void *)&hook_SetCursorPos); if (!orig_SetCursorPos) { - con_warn(ERR "couldn't hook SetCursorPos\n"); + errmsg_errorsys("couldn't hook %s", "SetCursorPos"); goto e1; } inwin = CreateWindowExW(0, L"RInput", L"RInput", 0, 0, 0, 0, 0, 0, 0, 0, 0); if (!inwin) { - con_warn(ERR " couldn't create input window\n"); + errmsg_errorsys("couldn't create input window"); goto e2; } RAWINPUTDEVICE rd = { @@ -126,7 +125,7 @@ bool rinput_init(void) { .usUsage = USAGE_MOUSE }; if (!RegisterRawInputDevices(&rd, 1, sizeof(rd))) { - con_warn(ERR " couldn't create raw mouse device\n"); + errmsg_errorsys("couldn't create raw mouse device"); goto e3; } diff --git a/src/sst.c b/src/sst.c index 39996c9..2ba4e9e 100644 --- a/src/sst.c +++ b/src/sst.c @@ -25,6 +25,7 @@ #include "con_.h" #include "demorec.h" #include "engineapi.h" +#include "errmsg.h" #include "ent.h" #include "fov.h" #include "fixes.h" @@ -80,14 +81,14 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) { os_char path[PATH_MAX]; if (!os_dlfile(ownhandle(), path, sizeof(path) / sizeof(*path))) { // hopefully by this point this won't happen, but, like, never know - con_warn("error: failed to get path to plugin\n"); + errmsg_errordl("failed to get path to plugin"); return; } os_char relpath[PATH_MAX]; #ifdef _WIN32 if (!PathRelativePathToW(relpath, searchdir, FILE_ATTRIBUTE_DIRECTORY, path, 0)) { - con_warn("error: couldn't compute a relative path for some reason\n"); + errmsg_errorsys("couldn't compute a relative path for some reason"); return; } // arbitrary aesthetic judgement @@ -98,13 +99,13 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) { int len = os_strlen(gameinfo_gamedir); if (len + sizeof("/addons/" VDFBASENAME ".vdf") > sizeof(path) / sizeof(*path)) { - con_warn("error: path to VDF is too long\n"); + errmsg_errorx("path to VDF is too long"); return; } memcpy(path, gameinfo_gamedir, len * sizeof(*gameinfo_gamedir)); memcpy(path + len, OS_LIT("/addons"), 8 * sizeof(os_char)); if (os_mkdir(path) == -1 && errno != EEXIST) { - con_warn("error: couldn't create %" fS ": %s\n", path, strerror(errno)); + errmsg_errorstd("couldn't create %" fS, path); return; } memcpy(path + len + sizeof("/addons") - 1, @@ -112,7 +113,7 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) { sizeof("/" VDFBASENAME ".vdf") * sizeof(os_char)); FILE *f = os_fopen(path, OS_LIT("wb")); if (!f) { - con_warn("error: couldn't open %" fS ": %s", path, strerror(errno)); + errmsg_errorstd("couldn't open %" fS, path); return; } // XXX: oh, crap, we're clobbering unicode again. welp, let's hope the @@ -120,7 +121,7 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) { // doesn't matter. if (fprintf(f, "Plugin { file \"%" fS "\" }\n", relpath) < 0 || fflush(f) == -1) { - con_warn("error: couldn't write to %" fS ": %s", path, strerror(errno)); + errmsg_errorstd("couldn't write to %" fS, path); } fclose(f); } @@ -130,14 +131,14 @@ DEF_CCMD_HERE(sst_autoload_disable, "Stop loading SST on game startup", 0) { int len = os_strlen(gameinfo_gamedir); if (len + sizeof("/addons/" VDFBASENAME ".vdf") > sizeof(path) / sizeof(*path)) { - con_warn("error: path to VDF is too long\n"); + errmsg_errorx("path to VDF is too long"); return; } memcpy(path, gameinfo_gamedir, len * sizeof(*gameinfo_gamedir)); memcpy(path + len, OS_LIT("/addons/") OS_LIT(VDFBASENAME) OS_LIT(".vdf"), sizeof("/addons/" VDFBASENAME ".vdf") * sizeof(os_char)); if (os_unlink(path) == -1 && errno != ENOENT) { - con_warn("warning: couldn't delete %" fS ":%s\n", path, strerror(errno)); + errmsg_warnstd("couldn't delete %" fS, path); } } @@ -248,14 +249,13 @@ static void VCALLCONV hook_VGuiConnect(void) { static void deferinit(void) { vgui = factory_engine("VEngineVGui001", 0); if (!vgui) { - con_warn("sst: warning: couldn't get VEngineVGui for deferred " - "feature setup\n"); + errmsg_warnx("couldn't get VEngineVGui for deferred feature setup"); goto e; } if (!os_mprot(*(void ***)vgui + vtidx_VGuiConnect, sizeof(void *), PAGE_READWRITE)) { - con_warn("sst: warning: couldn't unprotect CEngineVGui vtable for " - "deferred feature setup\n"); + errmsg_warnsys("couldn't make CEngineVGui vtable writable for deferred " + "feature setup"); goto e; } orig_VGuiConnect = (VGuiConnect_func)hook_vtable(*(void ***)vgui, @@ -295,11 +295,11 @@ static bool do_load(ifacefactory enginef, ifacefactory serverf) { clientlib = dlopen(gameinfo_clientlib, RTLD_NOW); #endif if (!clientlib) { - con_warn("sst: warning: couldn't get the game's client library\n"); + errmsg_warndl("couldn't get the game's client library"); } else if (!(factory_client = (ifacefactory)os_dlsym(clientlib, "CreateInterface"))) { - con_warn("sst: warning: couldn't get client's CreateInterface\n"); + errmsg_warndl("couldn't get client's CreateInterface"); } #ifdef _WIN32 void *inputsystemlib = GetModuleHandleW(L"inputsystem.dll"); @@ -311,11 +311,11 @@ static bool do_load(ifacefactory enginef, ifacefactory serverf) { if (inputsystemlib) dlclose(inputsystemlib); // blegh #endif if (!inputsystemlib) { - con_warn("sst: warning: couldn't get the input system library\n"); + errmsg_warndl("couldn't get the input system library"); } else if (!(factory_inputsystem = (ifacefactory)os_dlsym(inputsystemlib, "CreateInterface"))) { - con_warn("sst: warning: couldn't get input system's CreateInterface\n"); + errmsg_warndl("couldn't get input system's CreateInterface"); } // NOTE: this is technically redundant for early versions but I CBA writing @@ -324,8 +324,8 @@ static bool do_load(ifacefactory enginef, ifacefactory serverf) { void *kvs = KeyValuesSystem(); kvsvt = *(void ***)kvs; if (!os_mprot(kvsvt + 4, sizeof(void *), PAGE_READWRITE)) { - con_warn("sst: warning: couldn't unprotect KeyValuesSystem " - "vtable; won't be able to prevent nag message\n"); + errmsg_warnx("couldn't make KeyValuesSystem vtable writable"); + errmsg_note("won't be able to prevent any nag messages"); } else { orig_GetStringForSymbol = (GetStringForSymbol_func)hook_vtable( -- cgit v1.2.3