From 37b27d2eef381b2443942039759230aeb37401c7 Mon Sep 17 00:00:00 2001 From: Rafael Kitover <rkitover@gmail.com> Date: Sat, 24 Aug 2024 05:44:45 +0000 Subject: [PATCH] Support use as a Windows program outside of Cygwin If `getenv("SHELL")` is `NULL`, use the function `win32_setenv_shell()` added to `osdep-win32-cpp.cpp` to set it using the command line of the parent process, which is retrieved using WMI WIN32 API. This is a C++ file because the OLE/WMI API is only available for C++. Adjust the autotools code to add this file and link the necessary Windows DLLs. Include some fixed/missing MINGW headers necessary to compile this file. This will be fixed in the relevant places and they will be removed. Add a new macro WIN32_PLATFORM for Windows specific functionality, currently Cygwin and MSYS2, in the future for the native port as well. When spawning commands using the shell, check for cmd.exe on Windows and use the `/c` switch, otherwise use `-c` which works for PowerShell, MSYS2, Cygwin and Git Bash etc.. Adjust code that uses `/tmp/` to use `$env:USERPROFILE/AppData/Local/Temp/` outside of a Cygwin virtual filesystem when `/tmp/` is not available, add the function `win32_get_tmpdir()` and related functions to `osdep-win32.c` for this. Use `getenv("USERPROFILE")` when `getenv("HOME")` is `NULL`. When outside of a Cygwin virtual filesystem, use `C:\ProgramData\tmux\tmux.conf:$USERPROFILE\.tmux.conf:$LOCALAPPDATA\tmux\tmux.conf` as the config search order. Use the ncurses term-driver with `TERM="#win32con"` when a terminfo database is not available. This will require patches to ncurses as well as MSYS2 and Cygwin to work. Signed-off-by: Rafael Kitover <rkitover@gmail.com> --- Makefile.am | 15 +- compat.h | 54 +- configure.ac | 251 +++--- osdep-win32-cpp.cpp | 87 ++ osdep-win32.c | 101 +++ popup.c | 4 +- spawn.c | 2 +- third_party/mingw_headers/comutil.h | 1233 +++++++++++++++++++++++++++ third_party/mingw_headers/new.h | 45 + tmux.c | 6 +- tmux.h | 3 - tty-term.c | 21 +- 12 files changed, 1683 insertions(+), 139 deletions(-) create mode 100644 osdep-win32-cpp.cpp create mode 100644 osdep-win32.c create mode 100644 third_party/mingw_headers/comutil.h create mode 100644 third_party/mingw_headers/new.h diff --git a/Makefile.am b/Makefile.am index 6c7d2d3f..1bbdfd56 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,10 +11,15 @@ dist_EXTRA_tmux_SOURCES = compat/*.[ch] # Preprocessor flags. AM_CPPFLAGS += @XOPEN_DEFINES@ \ -DTMUX_VERSION='"@VERSION@"' \ - -DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \ -DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \ -DTMUX_TERM='"@DEFAULT_TERM@"' +AM_CPPFLAGS += -DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' + +if TARGET_WIN32 +AM_CPPFLAGS += -DTMUX_CONF_WIN32='"/c/ProgramData/tmux/tmux.conf:~/.tmux.conf:$$LOCALAPPDATA/tmux/tmux.conf"' +endif + # Additional object files. LDADD = $(LIBOBJS) @@ -67,7 +72,7 @@ AM_CPPFLAGS += -D_BSD_SOURCE endif # Set flags for Cygwin. -if IS_CYGWIN +if TARGET_WIN32 AM_CPPFLAGS += -DTMUX_SOCK_PERM=0 endif @@ -227,6 +232,12 @@ if ENABLE_SIXEL dist_tmux_SOURCES += image.c image-sixel.c endif +# Windows-specific support. +if TARGET_WIN32 +dist_tmux_SOURCES += osdep-win32.c osdep-win32-cpp.cpp +LDADD += -lole32 -loleaut32 -lwbemuuid +endif + if NEED_FUZZING check_PROGRAMS = fuzz/input-fuzzer fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS) diff --git a/compat.h b/compat.h index f33dcf1a..4856c442 100644 --- a/compat.h +++ b/compat.h @@ -69,6 +69,11 @@ #define __weak __attribute__ ((__weak__)) #endif +#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__) +#define WIN32_PLATFORM +#define TTY_OVER_SOCKET +#endif + #ifndef ECHOPRT #define ECHOPRT 0 #endif @@ -98,10 +103,6 @@ void warnx(const char *, ...); #define _PATH_BSHELL "/bin/sh" #endif -#ifndef _PATH_TMP -#define _PATH_TMP "/tmp/" -#endif - #ifndef _PATH_DEVNULL #define _PATH_DEVNULL "/dev/null" #endif @@ -471,4 +472,49 @@ int BSDgetopt(int, char *const *, const char *); #define optreset BSDoptreset #define optarg BSDoptarg +#ifndef WIN32_PLATFORM + +#ifndef TMUX_CONF_WIN32 +#define TMUX_CONF_WIN32 "/c/ProgramData/tmux/tmux.conf:~/.tmux.conf" +#endif + +#define SHELL_CMD_SWITCH(shell) "-c" +#define TMPDIR() "/tmp/" + +#ifndef TMUX_SOCK +#define TMUX_SOCK "$TMUX_TMPDIR:" TMPDIR +#endif + +#define TMPFILE_TEMPLATE() TMPDIR() "tmux.XXXXXXXX" + +#define GETENV_HOME() getenv("HOME") +#define GETENV_SHELL() getenv("SHELL") + +#define TMUX_CONF_SEARCH_PATH() TMUX_CONF + +#else + +void win32_setenv_shell(void); +const char *win32_get_tmpdir(void); +const char *win32_get_tmpfile_template(void); +const char *win32_get_socket_dir_search_path(void); +const char *win32_get_conf_search_path(void); +const char *win32_get_shell_cmd_switch(const char *); + +#define SHELL_CMD_SWITCH(shell) win32_get_shell_cmd_switch(shell) +#define TMPDIR() win32_get_tmpdir() + +#ifndef TMUX_SOCK +#define TMUX_SOCK win32_get_socket_dir_search_path() +#endif + +#define TMPFILE_TEMPLATE() win32_get_tmpfile_template() + +#define GETENV_HOME() (getenv("HOME") ? getenv("HOME") : getenv("USERPROFILE")) +#define GETENV_SHELL() (getenv("SHELL") ? getenv("SHELL") : (win32_setenv_shell(), getenv("SHELL"))) + +#define TMUX_CONF_SEARCH_PATH() win32_get_conf_search_path() + +#endif + #endif /* COMPAT_H */ diff --git a/configure.ac b/configure.ac index 4f90fcd5..9c121dd2 100644 --- a/configure.ac +++ b/configure.ac @@ -3,12 +3,13 @@ AC_INIT([tmux], next-3.6) AC_PREREQ([2.60]) +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + AC_CONFIG_AUX_DIR(etc) AC_CONFIG_LIBOBJ_DIR(compat) AM_INIT_AUTOMAKE([foreign subdir-objects]) -AC_CANONICAL_HOST - # When CFLAGS isn't set at this stage and gcc is detected by the macro below, # autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an # empty default. @@ -41,10 +42,136 @@ if test "x$enable_fuzzing" = xyes; then AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address" fi +AC_ARG_ENABLE( + utf8proc, + AS_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed) +) + +# Figure out the platform. +AC_MSG_CHECKING(platform) +case "$target_os" in + *aix*) + AC_MSG_RESULT(aix) + PLATFORM=aix + ;; + *darwin*) + AC_MSG_RESULT(darwin) + PLATFORM=darwin + # + # macOS uses __dead2 instead of __dead, like FreeBSD. But it defines + # __dead away so it needs to be removed before we can replace it. + # + AC_DEFINE(BROKEN___DEAD) + # + # macOS CMSG_FIRSTHDR is broken, so redefine it with a working one. + # daemon works but has some stupid side effects, so use our internal + # version which has a workaround. + # + AC_DEFINE(BROKEN_CMSG_FIRSTHDR) + AC_LIBOBJ(daemon) + AC_LIBOBJ(daemon-darwin) + # + # macOS wcwidth(3) is bad, so complain and suggest using utf8proc + # instead. + # + if test "x$enable_utf8proc" = x; then + AC_MSG_NOTICE([]) + AC_MSG_NOTICE([ macOS library support for Unicode is very poor,]) + AC_MSG_NOTICE([ particularly for complex codepoints like emojis;]) + AC_MSG_NOTICE([ to use these correctly, configuring with]) + AC_MSG_NOTICE([ --enable-utf8proc is recommended. To build]) + AC_MSG_NOTICE([ without anyway, use --disable-utf8proc]) + AC_MSG_NOTICE([]) + AC_MSG_ERROR([must give --enable-utf8proc or --disable-utf8proc]) + fi + ;; + *dragonfly*) + AC_MSG_RESULT(dragonfly) + PLATFORM=dragonfly + ;; + *linux*) + AC_MSG_RESULT(linux) + PLATFORM=linux + ;; + *freebsd*) + AC_MSG_RESULT(freebsd) + PLATFORM=freebsd + ;; + *netbsd*) + AC_MSG_RESULT(netbsd) + PLATFORM=netbsd + ;; + *openbsd*) + AC_MSG_RESULT(openbsd) + PLATFORM=openbsd + ;; + *sunos*) + AC_MSG_RESULT(sunos) + PLATFORM=sunos + ;; + *solaris*) + AC_MSG_RESULT(sunos) + PLATFORM=sunos + case `/usr/bin/nroff --version 2>&1` in + *GNU*) + # Solaris 11.4 and later use GNU groff. + MANFORMAT=mdoc + ;; + *) + if test `uname -o 2>/dev/null` = illumos; then + # Illumos uses mandoc. + MANFORMAT=mdoc + else + # Solaris 2.0 to 11.3 use AT&T nroff. + MANFORMAT=man + fi + ;; + esac + ;; + *hpux*) + AC_MSG_RESULT(hpux) + PLATFORM=hpux + ;; + *cygwin*|*msys*) + AC_MSG_RESULT(cygwin) + PLATFORM=cygwin + TARGET_WIN32=yes + AC_DEFINE(TARGET_WIN32) + AM_CONDITIONAL(TARGET_WIN32, test "x$TARGET_WIN32" = xyes) + ;; + *haiku*) + AC_MSG_RESULT(haiku) + PLATFORM=haiku + ;; + *) + AC_MSG_RESULT(unknown) + PLATFORM=unknown + ;; +esac +AC_SUBST(PLATFORM) +AM_CONDITIONAL(IS_AIX, test "x$PLATFORM" = xaix) +AM_CONDITIONAL(IS_DARWIN, test "x$PLATFORM" = xdarwin) +AM_CONDITIONAL(IS_DRAGONFLY, test "x$PLATFORM" = xdragonfly) +AM_CONDITIONAL(IS_LINUX, test "x$PLATFORM" = xlinux) +AM_CONDITIONAL(IS_FREEBSD, test "x$PLATFORM" = xfreebsd) +AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd) +AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd) +AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos) +AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux) +AM_CONDITIONAL(IS_CYGWIN, test "x$PLATFORM" = xcygwin) +AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku) +AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown) + + # Set up the compiler in two different ways and say yes we may want to install. -AC_PROG_CC -AM_PROG_CC_C_O m4_version_prereq(2.70, [AC_PROG_CC], [AC_PROG_CC_C99]) + +if test "x$TARGET_WIN32" = xyes; then + AC_PROG_CXX + CFLAGS="$CFLAGS -isystem $(dirname $(readlink -f $0))/third_party/mingw_headers" + CXXFLAGS="$CXXFLAGS -std=c++17 -isystem $(dirname $(readlink -f $0))/third_party/mingw_headers -O2 -fpermissive -Wno-write-strings -Wno-class-conversion" +fi + AC_PROG_CPP AC_PROG_EGREP AC_PROG_INSTALL @@ -381,10 +508,6 @@ if test "x$enable_utempter" = xyes; then fi # Look for utf8proc. -AC_ARG_ENABLE( - utf8proc, - AS_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed) -) if test "x$enable_utf8proc" = xyes; then PKG_CHECK_MODULES( LIBUTF8PROC, @@ -874,118 +997,6 @@ AC_SUBST(DEFAULT_TERM) MANFORMAT=mdoc AC_SUBST(MANFORMAT) -# Figure out the platform. -AC_MSG_CHECKING(platform) -case "$host_os" in - *aix*) - AC_MSG_RESULT(aix) - PLATFORM=aix - ;; - *darwin*) - AC_MSG_RESULT(darwin) - PLATFORM=darwin - # - # macOS uses __dead2 instead of __dead, like FreeBSD. But it defines - # __dead away so it needs to be removed before we can replace it. - # - AC_DEFINE(BROKEN___DEAD) - # - # macOS CMSG_FIRSTHDR is broken, so redefine it with a working one. - # daemon works but has some stupid side effects, so use our internal - # version which has a workaround. - # - AC_DEFINE(BROKEN_CMSG_FIRSTHDR) - AC_LIBOBJ(daemon) - AC_LIBOBJ(daemon-darwin) - # - # macOS wcwidth(3) is bad, so complain and suggest using utf8proc - # instead. - # - if test "x$enable_utf8proc" = x; then - AC_MSG_NOTICE([]) - AC_MSG_NOTICE([ macOS library support for Unicode is very poor,]) - AC_MSG_NOTICE([ particularly for complex codepoints like emojis;]) - AC_MSG_NOTICE([ to use these correctly, configuring with]) - AC_MSG_NOTICE([ --enable-utf8proc is recommended. To build]) - AC_MSG_NOTICE([ without anyway, use --disable-utf8proc]) - AC_MSG_NOTICE([]) - AC_MSG_ERROR([must give --enable-utf8proc or --disable-utf8proc]) - fi - ;; - *dragonfly*) - AC_MSG_RESULT(dragonfly) - PLATFORM=dragonfly - ;; - *linux*) - AC_MSG_RESULT(linux) - PLATFORM=linux - ;; - *freebsd*) - AC_MSG_RESULT(freebsd) - PLATFORM=freebsd - ;; - *netbsd*) - AC_MSG_RESULT(netbsd) - PLATFORM=netbsd - ;; - *openbsd*) - AC_MSG_RESULT(openbsd) - PLATFORM=openbsd - ;; - *sunos*) - AC_MSG_RESULT(sunos) - PLATFORM=sunos - ;; - *solaris*) - AC_MSG_RESULT(sunos) - PLATFORM=sunos - case `/usr/bin/nroff --version 2>&1` in - *GNU*) - # Solaris 11.4 and later use GNU groff. - MANFORMAT=mdoc - ;; - *) - if test `uname -o 2>/dev/null` = illumos; then - # Illumos uses mandoc. - MANFORMAT=mdoc - else - # Solaris 2.0 to 11.3 use AT&T nroff. - MANFORMAT=man - fi - ;; - esac - ;; - *hpux*) - AC_MSG_RESULT(hpux) - PLATFORM=hpux - ;; - *cygwin*|*msys*) - AC_MSG_RESULT(cygwin) - PLATFORM=cygwin - ;; - *haiku*) - AC_MSG_RESULT(haiku) - PLATFORM=haiku - ;; - *) - AC_MSG_RESULT(unknown) - PLATFORM=unknown - ;; -esac -AC_SUBST(PLATFORM) -AM_CONDITIONAL(IS_AIX, test "x$PLATFORM" = xaix) -AM_CONDITIONAL(IS_DARWIN, test "x$PLATFORM" = xdarwin) -AM_CONDITIONAL(IS_DRAGONFLY, test "x$PLATFORM" = xdragonfly) -AM_CONDITIONAL(IS_LINUX, test "x$PLATFORM" = xlinux) -AM_CONDITIONAL(IS_FREEBSD, test "x$PLATFORM" = xfreebsd) -AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd) -AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd) -AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos) -AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux) -AM_CONDITIONAL(IS_CYGWIN, test "x$PLATFORM" = xcygwin) -AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku) -AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown) - # Set the default lock command DEFAULT_LOCK_CMD="lock -np" AC_MSG_CHECKING(lock-command) diff --git a/osdep-win32-cpp.cpp b/osdep-win32-cpp.cpp new file mode 100644 index 00000000..fb9c26ec --- /dev/null +++ b/osdep-win32-cpp.cpp @@ -0,0 +1,87 @@ +#include <cwchar> + +#define WIN32_LEAN_AND_MEAN +#define _WIN32_DCOM + +#define sprintf_s sprintf + +#include <windows.h> +#include <comutil.h> +#include <stringapiset.h> +#include <tlhelp32.h> +#include <wbemidl.h> + +void +win32_setenv_shell_impl(void); + +void +win32_setenv_shell_impl(void) +{ + unsigned pid = GetCurrentProcessId(); + int ppid = -1; + HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32 pe = { 0 }; + IWbemLocator* wbem_locator = nullptr; + IWbemServices* wbem_services = nullptr; + IEnumWbemClassObject* enum_wbem = nullptr; + + pe.dwSize = sizeof(PROCESSENTRY32); + + if (Process32First(h, &pe)) { + do { + if (pe.th32ProcessID == pid) + ppid = pe.th32ParentProcessID; + } while (Process32Next(h, &pe)); + } + + CloseHandle(h); + + CoInitializeEx(0, COINIT_MULTITHREADED); + CoInitializeSecurity(nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr); + CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&wbem_locator); + + wbem_locator->ConnectServer(L"ROOT\\CIMV2", nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbem_services); + wchar_t* query = new wchar_t[4096]; + swprintf(query, 4096, L"select commandline from win32_process where processid = %d", ppid); + wbem_services->ExecQuery(L"WQL", query, WBEM_FLAG_FORWARD_ONLY, nullptr, &enum_wbem); + delete[] query; + + if (enum_wbem) { + IWbemClassObject *result = nullptr; + ULONG returned_count = 0; + + if(enum_wbem->Next(WBEM_INFINITE, 1, &result, &returned_count) == S_OK) { + VARIANT process_id; + VARIANT command_line; + + result->Get(L"CommandLine", 0, &command_line, 0, 0); + + wchar_t* command_line_utf16 = command_line.bstrVal; + size_t size = WideCharToMultiByte(CP_UTF8, 0, command_line_utf16, -1, nullptr, 0, nullptr, nullptr) + 1; + char* command_line_utf8 = new char[size]; + + WideCharToMultiByte(CP_UTF8, 0, command_line_utf16, -1, command_line_utf8, size, nullptr, nullptr); + + SysFreeString(command_line_utf16); + + setenv("SHELL", command_line_utf8, 1); + + delete[] command_line_utf8; + + result->Release(); + } + } +} + +extern "C" { + +void +win32_setenv_shell(void); + +void +win32_setenv_shell(void) +{ + win32_setenv_shell_impl(); +} + +} diff --git a/osdep-win32.c b/osdep-win32.c new file mode 100644 index 00000000..e8ea6316 --- /dev/null +++ b/osdep-win32.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "tmux.h" +#include "xmalloc.h" + +static int in_cygwin_virtual_filesystem(void); + +#define PROFILE_TMPDIR "/AppData/Local/Temp/" + +static char tmpdir[4096] = {0}; +static char socket_dir[4096] = {0}; +static char tmpfile_template[4096] = {0}; +static int in_cygwin_fs = -1; + +static int +in_cygwin_virtual_filesystem(void) +{ + if (in_cygwin_fs != -1) + return in_cygwin_fs; + + in_cygwin_fs = 0; + + if ( + (access("/bin/sh", F_OK) == 0) && + (access("/usr", F_OK) == 0) && + (access("/home", F_OK) == 0) && + (access("/proc", F_OK) == 0) && + (access("/var", F_OK) == 0) && + (access("/tmp", F_OK) == 0) && + (access("/dev/null", F_OK) == 0) && + (access("/dev/random", F_OK) == 0) && + (access("/dev/stdout", F_OK) == 0) && + (access("/proc/stat", F_OK) == 0) + ) { + in_cygwin_fs = 1; + } + + return in_cygwin_fs; +} + +const char * +win32_get_tmpdir(void) +{ + char *profile_dir = NULL; + + if (*tmpdir) + return tmpdir; + + if (in_cygwin_virtual_filesystem()) { + strncpy(tmpdir, "/tmp/", 4096); + return tmpdir; + } + + if ((profile_dir = getenv("USERPROFILE"))) + snprintf(tmpdir, 4096, "%s%s", profile_dir, PROFILE_TMPDIR); + + return tmpdir; +} + +const char * +win32_get_socket_dir_search_path(void) +{ + if (*socket_dir) + return socket_dir; + + snprintf(socket_dir, 4096, "$TMUX_TMPDIR:%s", win32_get_tmpdir()); + + return socket_dir; +} + +const char * +win32_get_conf_search_path(void) +{ + if (in_cygwin_virtual_filesystem()) + return TMUX_CONF; + + return TMUX_CONF_WIN32; +} + +const char * +win32_get_tmpfile_template(void) +{ + if (*tmpfile_template) + return tmpfile_template; + + snprintf(tmpfile_template, 4096, "%s/tmux.XXXXXXXX", win32_get_tmpdir()); + + return tmpfile_template; +} + +const char * +win32_get_shell_cmd_switch(const char *shell) +{ + if (strstr(shell, "cmd.exe") != NULL) + return "/c"; + else + return "-c"; +} diff --git a/popup.c b/popup.c index 97f532c0..78ce0880 100644 --- a/popup.c +++ b/popup.c @@ -775,7 +775,7 @@ popup_editor(struct client *c, const char *buf, size_t len, int fd; FILE *f; char *cmd; - char path[] = _PATH_TMP "tmux.XXXXXXXX"; + char *path = (char *)TMPFILE_TEMPLATE(); const char *editor; u_int px, py, sx, sy; @@ -807,7 +807,7 @@ popup_editor(struct client *c, const char *buf, size_t len, xasprintf(&cmd, "%s %s", editor, path); if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, BOX_LINES_DEFAULT, - NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, NULL, c, NULL, + NULL, px, py, sx, sy, NULL, cmd, 0, NULL, TMPDIR(), NULL, c, NULL, NULL, NULL, popup_editor_close_cb, pe) != 0) { popup_editor_free(pe); free(cmd); diff --git a/spawn.c b/spawn.c index d321dba4..559a7f4f 100644 --- a/spawn.c +++ b/spawn.c @@ -456,7 +456,7 @@ spawn_pane(struct spawn_context *sc, char **cause) xasprintf(&argv0, "%s", cp + 1); else xasprintf(&argv0, "%s", new_wp->shell); - execl(new_wp->shell, argv0, "-c", tmp, (char *)NULL); + execl(new_wp->shell, argv0, SHELL_CMD_SWITCH(new_wp->shell), tmp, (char *)NULL); _exit(1); } if (cp != NULL && cp[1] != '\0') diff --git a/third_party/mingw_headers/comutil.h b/third_party/mingw_headers/comutil.h new file mode 100644 index 00000000..ddb09063 --- /dev/null +++ b/third_party/mingw_headers/comutil.h @@ -0,0 +1,1233 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#ifndef _INC_COMUTIL +#define _INC_COMUTIL + +#include <ole2.h> +#include <stdio.h> + +#ifndef _COM_ASSERT +#define _COM_ASSERT(x) ((void)0) +#endif + +#define _COM_MEMCPY_S(dest,destsize,src,count) memcpy(dest,src,count) + +/* Use of wsprintf might be impossible, if strsafe.h is included. */ +#ifndef __STDC_SECURE_LIB__ +#define _COM_PRINTF_S_1(dest,destsize,format,arg1) wsprintf(dest,format,arg1) +#elif defined(UNICODE) +#define _COM_PRINTF_S_1(dest,destsize,format,arg1) swprintf_s(dest,destsize,format,arg1) +#else +#define _COM_PRINTF_S_1(dest,destsize,format,arg1) sprintf_s(dest,destsize,format,arg1) +#endif + +#ifdef __cplusplus + +#pragma push_macro("new") +#undef new + +#ifndef WINAPI +#if defined(_ARM_) +#define WINAPI +#else +#define WINAPI __stdcall +#endif +#endif + +class _com_error; + +void WINAPI _com_issue_error(HRESULT); + +class _bstr_t; +class _variant_t; + +namespace _com_util { + inline void CheckError(HRESULT hr) { + if(FAILED(hr)) { _com_issue_error(hr); } + } +} + +namespace _com_util { + BSTR WINAPI ConvertStringToBSTR(const char *pSrc); + char *WINAPI ConvertBSTRToString(BSTR pSrc); +} + +class _bstr_t { +public: + _bstr_t() throw(); + _bstr_t(const _bstr_t &s) throw(); + _bstr_t(const char *s); + _bstr_t(const wchar_t *s); + _bstr_t(const _variant_t &var); + _bstr_t(BSTR bstr,bool fCopy); + ~_bstr_t() throw(); + _bstr_t &operator=(const _bstr_t &s) throw(); + _bstr_t &operator=(const char *s); + _bstr_t &operator=(const wchar_t *s); + _bstr_t &operator=(const _variant_t &var); + _bstr_t &operator+=(const _bstr_t &s); + _bstr_t operator+(const _bstr_t &s) const; + friend _bstr_t operator+(const char *s1,const _bstr_t &s2); + friend _bstr_t operator+(const wchar_t *s1,const _bstr_t &s2); + operator const wchar_t *() const throw(); + operator wchar_t *() const throw(); + operator const char *() const; + operator char *() const; + bool operator!() const throw(); + bool operator==(const _bstr_t &str) const throw(); + bool operator!=(const _bstr_t &str) const throw(); + bool operator<(const _bstr_t &str) const throw(); + bool operator>(const _bstr_t &str) const throw(); + bool operator<=(const _bstr_t &str) const throw(); + bool operator>=(const _bstr_t &str) const throw(); + BSTR copy(bool fCopy = true) const; + unsigned int length() const throw(); + void Assign(BSTR s); + BSTR &GetBSTR(); + BSTR *GetAddress(); + void Attach(BSTR s); + BSTR Detach() throw(); +private: + class Data_t { + public: + Data_t(const char *s); + Data_t(const wchar_t *s); + Data_t(BSTR bstr,bool fCopy); + Data_t(const _bstr_t &s1,const _bstr_t &s2); + unsigned __LONG32 AddRef() throw(); + unsigned __LONG32 Release() throw(); + unsigned __LONG32 RefCount() const throw(); + operator const wchar_t *() const throw(); + operator const char *() const; + const wchar_t *GetWString() const throw(); + wchar_t *&GetWString() throw(); + const char *GetString() const; + BSTR Copy() const; + void Assign(BSTR s); + void Attach(BSTR s) throw(); + unsigned int Length() const throw(); + int Compare(const Data_t &str) const throw(); + void *operator new(size_t sz); + private: + BSTR m_wstr; + mutable char *m_str; + unsigned __LONG32 m_RefCount; + Data_t() throw(); + Data_t(const Data_t &s) throw(); + ~Data_t() throw(); + void _Free() throw(); + }; +private: + Data_t *m_Data; +private: + void _AddRef() throw(); + void _Free() throw(); + int _Compare(const _bstr_t &str) const throw(); +}; + +inline _bstr_t::_bstr_t() throw() : m_Data(NULL) { } + +inline _bstr_t::_bstr_t(const _bstr_t &s) throw() : m_Data(s.m_Data) { _AddRef(); } + +inline _bstr_t::_bstr_t(const char *s) : m_Data(new Data_t(s)) { + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } +} + +inline _bstr_t::_bstr_t(const wchar_t *s) : m_Data(new Data_t(s)) { + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } +} + +inline _bstr_t::_bstr_t(BSTR bstr,bool fCopy) : m_Data(new Data_t(bstr,fCopy)) { + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } +} + +inline _bstr_t::~_bstr_t() throw() { _Free(); } + +inline _bstr_t &_bstr_t::operator=(const _bstr_t &s) throw() { + if(this!=&s) { + _Free(); + m_Data = s.m_Data; + _AddRef(); + } + return *this; +} + +inline _bstr_t &_bstr_t::operator=(const char *s) { + _COM_ASSERT(!s || static_cast<const char *>(*this)!=s); + if(!s || static_cast<const char *>(*this)!=s) { + _Free(); + m_Data = new Data_t(s); + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } + } + return *this; +} + +inline _bstr_t &_bstr_t::operator=(const wchar_t *s) { + _COM_ASSERT(!s || static_cast<const wchar_t *>(*this)!=s); + if(!s || static_cast<const wchar_t *>(*this)!=s) { + _Free(); + m_Data = new Data_t(s); + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } + } + return *this; +} + +inline _bstr_t &_bstr_t::operator+=(const _bstr_t &s) { + Data_t *newData = new Data_t(*this,s); + if(!newData) { _com_issue_error(E_OUTOFMEMORY); } + else { + _Free(); + m_Data = newData; + } + return *this; +} + +inline _bstr_t _bstr_t::operator+(const _bstr_t &s) const { + _bstr_t b = *this; + b += s; + return b; +} + +inline _bstr_t operator+(const char *s1,const _bstr_t &s2) { + _bstr_t b = s1; + b += s2; + return b; +} + +inline _bstr_t operator+(const wchar_t *s1,const _bstr_t &s2) { + _bstr_t b = s1; + b += s2; + return b; +} + +inline _bstr_t::operator const wchar_t *() const throw() { return (m_Data!=NULL) ? m_Data->GetWString() : NULL; } +inline _bstr_t::operator wchar_t *() const throw() { return const_cast<wchar_t *>((m_Data!=NULL) ? m_Data->GetWString() : NULL); } +inline _bstr_t::operator const char *() const { return (m_Data!=NULL) ? m_Data->GetString() : NULL; } +inline _bstr_t::operator char *() const { return const_cast<char *>((m_Data!=NULL) ? m_Data->GetString() : NULL); } +inline bool _bstr_t::operator!() const throw() { return (m_Data!=NULL) ? !m_Data->GetWString() : true; } +inline bool _bstr_t::operator==(const _bstr_t &str) const throw() { return _Compare(str)==0; } +inline bool _bstr_t::operator!=(const _bstr_t &str) const throw() { return _Compare(str)!=0; } +inline bool _bstr_t::operator<(const _bstr_t &str) const throw() { return _Compare(str)<0; } +inline bool _bstr_t::operator>(const _bstr_t &str) const throw() { return _Compare(str)>0; } +inline bool _bstr_t::operator<=(const _bstr_t &str) const throw() { return _Compare(str)<=0; } +inline bool _bstr_t::operator>=(const _bstr_t &str) const throw() { return _Compare(str)>=0; } +inline BSTR _bstr_t::copy(bool fCopy) const { return (m_Data!=NULL) ? (fCopy ? m_Data->Copy() : m_Data->GetWString()) : NULL; } +inline unsigned int _bstr_t::length() const throw() { return (m_Data!=NULL) ? m_Data->Length() : 0; } +inline void _bstr_t::Assign(BSTR s) { + _COM_ASSERT(!s || !m_Data || m_Data->GetWString()!=s); + if(!s || !m_Data || m_Data->GetWString()!=s) { + _Free(); + m_Data = new Data_t(s,TRUE); + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } + } +} + +inline BSTR &_bstr_t::GetBSTR() { + if(!m_Data) { + m_Data = new Data_t(0,FALSE); + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } + } + return m_Data->GetWString(); +} + +inline BSTR *_bstr_t::GetAddress() { + Attach(0); + return &m_Data->GetWString(); +} + +inline void _bstr_t::Attach(BSTR s) { + _Free(); + m_Data = new Data_t(s,FALSE); + if(!m_Data) { _com_issue_error(E_OUTOFMEMORY); } +} + +inline BSTR _bstr_t::Detach() throw () { + _COM_ASSERT(m_Data!=NULL && m_Data->RefCount()==1); + if(m_Data!=NULL && m_Data->RefCount()==1) { + BSTR b = m_Data->GetWString(); + m_Data->GetWString() = NULL; + _Free(); + return b; + } else { + _com_issue_error(E_POINTER); + return NULL; + } +} + +inline void _bstr_t::_AddRef() throw() { + if(m_Data!=NULL) m_Data->AddRef(); +} + +inline void _bstr_t::_Free() throw() { + if(m_Data!=NULL) { + m_Data->Release(); + m_Data = NULL; + } +} + +inline int _bstr_t::_Compare(const _bstr_t &str) const throw() { + if(m_Data==str.m_Data) return 0; + if(!m_Data) return -1; + if(!str.m_Data) return 1; + return m_Data->Compare(*str.m_Data); +} + +inline _bstr_t::Data_t::Data_t(const char *s) : m_str(NULL),m_RefCount(1) { + m_wstr = _com_util::ConvertStringToBSTR(s); +} + +inline _bstr_t::Data_t::Data_t(const wchar_t *s) : m_str(NULL),m_RefCount(1) { + m_wstr = ::SysAllocString(s); + if(!m_wstr && s!=NULL) { _com_issue_error(E_OUTOFMEMORY); } +} + +inline _bstr_t::Data_t::Data_t(BSTR bstr,bool fCopy) : m_str(NULL),m_RefCount(1) { + if(fCopy && bstr!=NULL) { + m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr)); + if(!m_wstr) { _com_issue_error(E_OUTOFMEMORY); } + } else m_wstr = bstr; +} + +inline _bstr_t::Data_t::Data_t(const _bstr_t &s1,const _bstr_t &s2) : m_str(NULL),m_RefCount(1) { + const unsigned int l1 = s1.length(); + const unsigned int l2 = s2.length(); + m_wstr = ::SysAllocStringByteLen(NULL,(l1 + l2) *sizeof(wchar_t)); + if(!m_wstr) { + _com_issue_error(E_OUTOFMEMORY); + return; + } + const wchar_t *wstr1 = static_cast<const wchar_t *>(s1); + if(wstr1!=NULL) { + _COM_MEMCPY_S(m_wstr,(l1 + l2 + 1) *sizeof(wchar_t),wstr1,(l1 + 1) *sizeof(wchar_t)); + } + const wchar_t *wstr2 = static_cast<const wchar_t *>(s2); + if(wstr2!=NULL) { + _COM_MEMCPY_S(m_wstr + l1,(l2 + 1) *sizeof(wchar_t),wstr2,(l2 + 1) *sizeof(wchar_t)); + } +} + +inline unsigned __LONG32 _bstr_t::Data_t::AddRef() throw() { + InterlockedIncrement(reinterpret_cast<LONG*>(&m_RefCount)); + return m_RefCount; +} + +inline unsigned __LONG32 _bstr_t::Data_t::Release() throw() { + unsigned __LONG32 cRef = InterlockedDecrement(reinterpret_cast<LONG*>(&m_RefCount)); + if(cRef==0) delete this; + return cRef; +} + +inline unsigned __LONG32 _bstr_t::Data_t::RefCount() const throw() { return m_RefCount; } +inline _bstr_t::Data_t::operator const wchar_t *() const throw() { return m_wstr; } +inline _bstr_t::Data_t::operator const char *() const { return GetString(); } +inline const wchar_t *_bstr_t::Data_t::GetWString() const throw() { return m_wstr; } +inline wchar_t *&_bstr_t::Data_t::GetWString() throw() { return m_wstr; } +inline const char *_bstr_t::Data_t::GetString() const { + if(!m_str) m_str = _com_util::ConvertBSTRToString(m_wstr); + return m_str; +} +inline BSTR _bstr_t::Data_t::Copy() const { + if(m_wstr!=NULL) { + BSTR bstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(m_wstr),::SysStringByteLen(m_wstr)); + if(!bstr) { _com_issue_error(E_OUTOFMEMORY); } + return bstr; + } + return NULL; +} +inline void _bstr_t::Data_t::Assign(BSTR s) { + _Free(); + if(s!=NULL) { + m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char *>(s),::SysStringByteLen(s)); + m_str = 0; + } +} +inline void _bstr_t::Data_t::Attach(BSTR s) throw() { + _Free(); + m_wstr = s; + m_str = 0; + m_RefCount = 1; +} +inline unsigned int _bstr_t::Data_t::Length() const throw() { return m_wstr ? ::SysStringLen(m_wstr) : 0; } +inline int _bstr_t::Data_t::Compare(const _bstr_t::Data_t &str) const throw() { + if(!m_wstr) return str.m_wstr ? -1 : 0; + if(!str.m_wstr) return 1; + const unsigned int l1 = ::SysStringLen(m_wstr); + const unsigned int l2 = ::SysStringLen(str.m_wstr); + unsigned int len = l1; + if(len>l2) len = l2; + BSTR bstr1 = m_wstr; + BSTR bstr2 = str.m_wstr; + while (len-->0) { + if(*bstr1++!=*bstr2++) return bstr1[-1] - bstr2[-1]; + } + return (l1<l2) ? -1 : (l1==l2) ? 0 : 1; +} + +#ifdef _COM_OPERATOR_NEW_THROWS +inline void *_bstr_t::Data_t::operator new(size_t sz) { + try { + return ::operator new(sz); + } catch (...) { + return NULL; + } +} +#else +inline void *_bstr_t::Data_t::operator new(size_t sz) { + return ::operator new(sz); +} +#endif + +inline _bstr_t::Data_t::~Data_t() throw() { _Free(); } +inline void _bstr_t::Data_t::_Free() throw() { + if(m_wstr!=NULL) ::SysFreeString(m_wstr); + if(m_str!=NULL) delete [] m_str; +} + +class _variant_t : public ::tagVARIANT { +public: + _variant_t() throw(); + _variant_t(const VARIANT &varSrc); + _variant_t(const VARIANT *pSrc); + _variant_t(const _variant_t &varSrc); + _variant_t(VARIANT &varSrc,bool fCopy); + _variant_t(short sSrc,VARTYPE vtSrc = VT_I2); + _variant_t(__LONG32 lSrc,VARTYPE vtSrc = VT_I4); + _variant_t(float fltSrc) throw(); + _variant_t(double dblSrc,VARTYPE vtSrc = VT_R8); + _variant_t(const CY &cySrc) throw(); + _variant_t(const _bstr_t &bstrSrc); + _variant_t(const wchar_t *pSrc); + _variant_t(const char *pSrc); + _variant_t(IDispatch *pSrc,bool fAddRef = true) throw(); + _variant_t(bool boolSrc) throw(); + _variant_t(IUnknown *pSrc,bool fAddRef = true) throw(); + _variant_t(const DECIMAL &decSrc) throw(); + _variant_t(BYTE bSrc) throw(); + _variant_t(char cSrc) throw(); + _variant_t(unsigned short usSrc) throw(); + _variant_t(unsigned __LONG32 ulSrc) throw(); +#ifndef __CYGWIN__ + _variant_t(int iSrc) throw(); + _variant_t(unsigned int uiSrc) throw(); +#endif + __MINGW_EXTENSION _variant_t(__int64 i8Src) throw(); + __MINGW_EXTENSION _variant_t(unsigned __int64 ui8Src) throw(); + ~_variant_t() throw(); + operator short() const; + operator __LONG32() const; + operator float() const; + operator double() const; + operator CY() const; + operator _bstr_t() const; + operator IDispatch*() const; + operator bool() const; + operator IUnknown*() const; + operator DECIMAL() const; + operator BYTE() const; + operator VARIANT() const throw(); + operator char() const; + operator unsigned short() const; + operator unsigned __LONG32() const; +#ifndef __CYGWIN__ + operator int() const; + operator unsigned int() const; +#endif + __MINGW_EXTENSION operator __int64() const; + __MINGW_EXTENSION operator unsigned __int64() const; + _variant_t &operator=(const VARIANT &varSrc); + _variant_t &operator=(const VARIANT *pSrc); + _variant_t &operator=(const _variant_t &varSrc); + _variant_t &operator=(short sSrc); + _variant_t &operator=(__LONG32 lSrc); + _variant_t &operator=(float fltSrc); + _variant_t &operator=(double dblSrc); + _variant_t &operator=(const CY &cySrc); + _variant_t &operator=(const _bstr_t &bstrSrc); + _variant_t &operator=(const wchar_t *pSrc); + _variant_t &operator=(const char *pSrc); + _variant_t &operator=(IDispatch *pSrc); + _variant_t &operator=(bool boolSrc); + _variant_t &operator=(IUnknown *pSrc); + _variant_t &operator=(const DECIMAL &decSrc); + _variant_t &operator=(BYTE bSrc); + _variant_t &operator=(char cSrc); + _variant_t &operator=(unsigned short usSrc); + _variant_t &operator=(unsigned __LONG32 ulSrc); +#ifndef __CYGWIN__ + _variant_t &operator=(int iSrc); + _variant_t &operator=(unsigned int uiSrc); +#endif + __MINGW_EXTENSION _variant_t &operator=(__int64 i8Src); + __MINGW_EXTENSION _variant_t &operator=(unsigned __int64 ui8Src); + bool operator==(const VARIANT &varSrc) const throw(); + bool operator==(const VARIANT *pSrc) const throw(); + bool operator!=(const VARIANT &varSrc) const throw(); + bool operator!=(const VARIANT *pSrc) const throw(); + void Clear(); + void Attach(VARIANT &varSrc); + VARIANT Detach(); + VARIANT &GetVARIANT() throw(); + VARIANT *GetAddress(); + void ChangeType(VARTYPE vartype,const _variant_t *pSrc = NULL); + void SetString(const char *pSrc); +}; + +inline _variant_t::_variant_t() throw() { ::VariantInit(this); } +inline _variant_t::_variant_t(const VARIANT &varSrc) { + ::VariantInit(this); + _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(&varSrc))); +} +inline _variant_t::_variant_t(const VARIANT *pSrc) { + if(!pSrc) { _com_issue_error(E_POINTER); } + else { + ::VariantInit(this); + _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(pSrc))); + } +} +inline _variant_t::_variant_t(const _variant_t &varSrc) { + ::VariantInit(this); + _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(static_cast<const VARIANT*>(&varSrc)))); +} +inline _variant_t::_variant_t(VARIANT &varSrc,bool fCopy) { + if(fCopy) { + ::VariantInit(this); + _com_util::CheckError(::VariantCopy(this,&varSrc)); + } else { + _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc)); + V_VT(&varSrc) = VT_EMPTY; + } +} +inline _variant_t::_variant_t(short sSrc,VARTYPE vtSrc) { + if((vtSrc!=VT_I2) && (vtSrc!=VT_BOOL)) { + _com_issue_error(E_INVALIDARG); + return; + } + if(vtSrc==VT_BOOL) { + V_VT(this) = VT_BOOL; + V_BOOL(this) = (sSrc ? VARIANT_TRUE : VARIANT_FALSE); + } else { + V_VT(this) = VT_I2; + V_I2(this) = sSrc; + } +} +inline _variant_t::_variant_t(__LONG32 lSrc,VARTYPE vtSrc) { + if((vtSrc!=VT_I4) && (vtSrc!=VT_ERROR) && (vtSrc!=VT_BOOL)) { + _com_issue_error(E_INVALIDARG); + return; + } + if(vtSrc==VT_ERROR) { + V_VT(this) = VT_ERROR; + V_ERROR(this) = lSrc; + } else if(vtSrc==VT_BOOL) { + V_VT(this) = VT_BOOL; + V_BOOL(this) = (lSrc ? VARIANT_TRUE : VARIANT_FALSE); + } else { + V_VT(this) = VT_I4; + V_I4(this) = lSrc; + } +} +inline _variant_t::_variant_t(float fltSrc) throw() { + V_VT(this) = VT_R4; + V_R4(this) = fltSrc; +} + +inline _variant_t::_variant_t(double dblSrc,VARTYPE vtSrc) { + if((vtSrc!=VT_R8) && (vtSrc!=VT_DATE)) { + _com_issue_error(E_INVALIDARG); + return; + } + if(vtSrc==VT_DATE) { + V_VT(this) = VT_DATE; + V_DATE(this) = dblSrc; + } else { + V_VT(this) = VT_R8; + V_R8(this) = dblSrc; + } +} +inline _variant_t::_variant_t(const CY &cySrc) throw() { + V_VT(this) = VT_CY; + V_CY(this) = cySrc; +} +inline _variant_t::_variant_t(const _bstr_t &bstrSrc) { + V_VT(this) = VT_BSTR; + BSTR bstr = static_cast<wchar_t *>(bstrSrc); + if(!bstr) V_BSTR(this) = NULL; + else { + V_BSTR(this) = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr)); + if(!(V_BSTR(this))) { _com_issue_error(E_OUTOFMEMORY); } + } +} +inline _variant_t::_variant_t(const wchar_t *pSrc) { + V_VT(this) = VT_BSTR; + V_BSTR(this) = ::SysAllocString(pSrc); + if(!(V_BSTR(this)) && pSrc!=NULL) { _com_issue_error(E_OUTOFMEMORY); } +} +inline _variant_t::_variant_t(const char *pSrc) { + V_VT(this) = VT_BSTR; + V_BSTR(this) = _com_util::ConvertStringToBSTR(pSrc); +} +inline _variant_t::_variant_t(IDispatch *pSrc,bool fAddRef) throw() { + V_VT(this) = VT_DISPATCH; + V_DISPATCH(this) = pSrc; + if(fAddRef && V_DISPATCH(this)!=NULL) V_DISPATCH(this)->AddRef(); +} +inline _variant_t::_variant_t(bool boolSrc) throw() { + V_VT(this) = VT_BOOL; + V_BOOL(this) = (boolSrc ? VARIANT_TRUE : VARIANT_FALSE); +} +inline _variant_t::_variant_t(IUnknown *pSrc,bool fAddRef) throw() { + V_VT(this) = VT_UNKNOWN; + V_UNKNOWN(this) = pSrc; + if(fAddRef && V_UNKNOWN(this)!=NULL) V_UNKNOWN(this)->AddRef(); +} +inline _variant_t::_variant_t(const DECIMAL &decSrc) throw() { + V_DECIMAL(this) = decSrc; + V_VT(this) = VT_DECIMAL; +} +inline _variant_t::_variant_t(BYTE bSrc) throw() { + V_VT(this) = VT_UI1; + V_UI1(this) = bSrc; +} +inline _variant_t::_variant_t(char cSrc) throw() { + V_VT(this) = VT_I1; + V_I1(this) = cSrc; +} +inline _variant_t::_variant_t(unsigned short usSrc) throw() { + V_VT(this) = VT_UI2; + V_UI2(this) = usSrc; +} +inline _variant_t::_variant_t(unsigned __LONG32 ulSrc) throw() { + V_VT(this) = VT_UI4; + V_UI4(this) = ulSrc; +} +#ifndef __CYGWIN__ +inline _variant_t::_variant_t(int iSrc) throw() { + V_VT(this) = VT_INT; + V_INT(this) = iSrc; +} +inline _variant_t::_variant_t(unsigned int uiSrc) throw() { + V_VT(this) = VT_UINT; + V_UINT(this) = uiSrc; +} +#endif +__MINGW_EXTENSION inline _variant_t::_variant_t(__int64 i8Src) throw() { + V_VT(this) = VT_I8; + V_I8(this) = i8Src; +} +__MINGW_EXTENSION inline _variant_t::_variant_t(unsigned __int64 ui8Src) throw() { + V_VT(this) = VT_UI8; + V_UI8(this) = ui8Src; +} +inline _variant_t::operator short() const { + if(V_VT(this)==VT_I2) return V_I2(this); + _variant_t varDest; + varDest.ChangeType(VT_I2,this); + return V_I2(&varDest); +} +inline _variant_t::operator __LONG32() const { + if(V_VT(this)==VT_I4) return V_I4(this); + _variant_t varDest; + varDest.ChangeType(VT_I4,this); + return V_I4(&varDest); +} + +inline _variant_t::operator float() const { + if(V_VT(this)==VT_R4) return V_R4(this); + _variant_t varDest; + varDest.ChangeType(VT_R4,this); + return V_R4(&varDest); +} + +inline _variant_t::operator double() const { + if(V_VT(this)==VT_R8) return V_R8(this); + _variant_t varDest; + varDest.ChangeType(VT_R8,this); + return V_R8(&varDest); +} + +inline _variant_t::operator CY() const { + if(V_VT(this)==VT_CY) return V_CY(this); + _variant_t varDest; + varDest.ChangeType(VT_CY,this); + return V_CY(&varDest); +} + +inline _variant_t::operator _bstr_t() const { + if(V_VT(this)==VT_BSTR) return V_BSTR(this); + _variant_t varDest; + varDest.ChangeType(VT_BSTR,this); + return V_BSTR(&varDest); +} + +inline _variant_t::operator IDispatch*() const { + if(V_VT(this)==VT_DISPATCH) { + if(V_DISPATCH(this)!=NULL) V_DISPATCH(this)->AddRef(); + return V_DISPATCH(this); + } + _variant_t varDest; + varDest.ChangeType(VT_DISPATCH,this); + if(V_DISPATCH(&varDest)!=NULL) V_DISPATCH(&varDest)->AddRef(); + return V_DISPATCH(&varDest); +} +inline _variant_t::operator bool() const { + if(V_VT(this)==VT_BOOL) return V_BOOL(this) ? true : false; + _variant_t varDest; + varDest.ChangeType(VT_BOOL,this); + return (V_BOOL(&varDest)==VARIANT_TRUE) ? true : false; +} + +inline _variant_t::operator IUnknown*() const { + if(V_VT(this)==VT_UNKNOWN) { + if(V_UNKNOWN(this)!=NULL) V_UNKNOWN(this)->AddRef(); + return V_UNKNOWN(this); + } + _variant_t varDest; + varDest.ChangeType(VT_UNKNOWN,this); + if(V_UNKNOWN(&varDest)!=NULL) V_UNKNOWN(&varDest)->AddRef(); + return V_UNKNOWN(&varDest); +} +inline _variant_t::operator DECIMAL() const { + if(V_VT(this)==VT_DECIMAL) return V_DECIMAL(this); + _variant_t varDest; + varDest.ChangeType(VT_DECIMAL,this); + return V_DECIMAL(&varDest); +} +inline _variant_t::operator BYTE() const { + if(V_VT(this)==VT_UI1) return V_UI1(this); + _variant_t varDest; + varDest.ChangeType(VT_UI1,this); + return V_UI1(&varDest); +} +inline _variant_t::operator VARIANT() const throw() { return *(VARIANT*) this; } +inline _variant_t::operator char() const { + if(V_VT(this)==VT_I1) return V_I1(this); + _variant_t varDest; + varDest.ChangeType(VT_I1,this); + return V_I1(&varDest); +} + +inline _variant_t::operator unsigned short() const { + if(V_VT(this)==VT_UI2) return V_UI2(this); + _variant_t varDest; + varDest.ChangeType(VT_UI2,this); + return V_UI2(&varDest); +} + +inline _variant_t::operator unsigned __LONG32() const { + if(V_VT(this)==VT_UI4) return V_UI4(this); + _variant_t varDest; + varDest.ChangeType(VT_UI4,this); + return V_UI4(&varDest); +} +#ifndef __CYGWIN__ +inline _variant_t::operator int() const { + if(V_VT(this)==VT_INT) return V_INT(this); + _variant_t varDest; + varDest.ChangeType(VT_INT,this); + return V_INT(&varDest); +} +inline _variant_t::operator unsigned int() const { + if(V_VT(this)==VT_UINT) return V_UINT(this); + _variant_t varDest; + varDest.ChangeType(VT_UINT,this); + return V_UINT(&varDest); +} +#endif +__MINGW_EXTENSION inline _variant_t::operator __int64() const { + if(V_VT(this)==VT_I8) return V_I8(this); + _variant_t varDest; + varDest.ChangeType(VT_I8,this); + return V_I8(&varDest); +} +__MINGW_EXTENSION inline _variant_t::operator unsigned __int64() const { + if(V_VT(this)==VT_UI8) return V_UI8(this); + _variant_t varDest; + varDest.ChangeType(VT_UI8,this); + return V_UI8(&varDest); +} +inline _variant_t &_variant_t::operator=(const VARIANT &varSrc) { + _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(&varSrc))); + return *this; +} +inline _variant_t &_variant_t::operator=(const VARIANT *pSrc) { + if(!pSrc) { _com_issue_error(E_POINTER); } + else { _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(pSrc))); } + return *this; +} +inline _variant_t &_variant_t::operator=(const _variant_t &varSrc) { + _com_util::CheckError(::VariantCopy(this,const_cast<VARIANT*>(static_cast<const VARIANT*>(&varSrc)))); + return *this; +} +inline _variant_t &_variant_t::operator=(short sSrc) { + if(V_VT(this)==VT_I2) V_I2(this) = sSrc; + else if(V_VT(this)==VT_BOOL) V_BOOL(this) = (sSrc ? VARIANT_TRUE : VARIANT_FALSE); + else { + Clear(); + V_VT(this) = VT_I2; + V_I2(this) = sSrc; + } + return *this; +} +inline _variant_t &_variant_t::operator=(__LONG32 lSrc) { + if(V_VT(this)==VT_I4) V_I4(this) = lSrc; + else if(V_VT(this)==VT_ERROR) V_ERROR(this) = lSrc; + else if(V_VT(this)==VT_BOOL) V_BOOL(this) = (lSrc ? VARIANT_TRUE : VARIANT_FALSE); + else { + Clear(); + V_VT(this) = VT_I4; + V_I4(this) = lSrc; + } + return *this; +} +inline _variant_t &_variant_t::operator=(float fltSrc) { + if(V_VT(this)!=VT_R4) { + Clear(); + V_VT(this) = VT_R4; + } + V_R4(this) = fltSrc; + return *this; +} + +inline _variant_t &_variant_t::operator=(double dblSrc) +{ + if(V_VT(this)==VT_R8) { + V_R8(this) = dblSrc; + } + else if(V_VT(this)==VT_DATE) { + V_DATE(this) = dblSrc; + } + else { + + Clear(); + + V_VT(this) = VT_R8; + V_R8(this) = dblSrc; + } + + return *this; +} + +inline _variant_t &_variant_t::operator=(const CY &cySrc) +{ + if(V_VT(this)!=VT_CY) { + + Clear(); + + V_VT(this) = VT_CY; + } + + V_CY(this) = cySrc; + + return *this; +} + +inline _variant_t &_variant_t::operator=(const _bstr_t &bstrSrc) +{ + _COM_ASSERT(V_VT(this)!=VT_BSTR || !((BSTR) bstrSrc) || V_BSTR(this)!=(BSTR) bstrSrc); + + Clear(); + + V_VT(this) = VT_BSTR; + + if(!bstrSrc) { + V_BSTR(this) = NULL; + } + else { + BSTR bstr = static_cast<wchar_t *>(bstrSrc); + V_BSTR(this) = ::SysAllocStringByteLen(reinterpret_cast<char *>(bstr),::SysStringByteLen(bstr)); + + if(!(V_BSTR(this))) { + _com_issue_error(E_OUTOFMEMORY); + } + } + + return *this; +} + +inline _variant_t &_variant_t::operator=(const wchar_t *pSrc) +{ + _COM_ASSERT(V_VT(this)!=VT_BSTR || !pSrc || V_BSTR(this)!=pSrc); + + Clear(); + + V_VT(this) = VT_BSTR; + + if(!pSrc) { + V_BSTR(this) = NULL; + } + else { + V_BSTR(this) = ::SysAllocString(pSrc); + + if(!(V_BSTR(this))) { + _com_issue_error(E_OUTOFMEMORY); + } + } + + return *this; +} + +inline _variant_t &_variant_t::operator=(const char *pSrc) +{ + _COM_ASSERT(V_VT(this)!=(VT_I1 | VT_BYREF) || !pSrc || V_I1REF(this)!=pSrc); + + Clear(); + + V_VT(this) = VT_BSTR; + V_BSTR(this) = _com_util::ConvertStringToBSTR(pSrc); + + return *this; +} + +inline _variant_t &_variant_t::operator=(IDispatch *pSrc) +{ + _COM_ASSERT(V_VT(this)!=VT_DISPATCH || pSrc==0 || V_DISPATCH(this)!=pSrc); + + Clear(); + + V_VT(this) = VT_DISPATCH; + V_DISPATCH(this) = pSrc; + + if(V_DISPATCH(this)!=NULL) { + + V_DISPATCH(this)->AddRef(); + } + + return *this; +} + +inline _variant_t &_variant_t::operator=(bool boolSrc) +{ + if(V_VT(this)!=VT_BOOL) { + + Clear(); + + V_VT(this) = VT_BOOL; + } + + V_BOOL(this) = (boolSrc ? VARIANT_TRUE : VARIANT_FALSE); + + return *this; +} + +inline _variant_t &_variant_t::operator=(IUnknown *pSrc) +{ + _COM_ASSERT(V_VT(this)!=VT_UNKNOWN || !pSrc || V_UNKNOWN(this)!=pSrc); + + Clear(); + + V_VT(this) = VT_UNKNOWN; + V_UNKNOWN(this) = pSrc; + + if(V_UNKNOWN(this)!=NULL) { + + V_UNKNOWN(this)->AddRef(); + } + + return *this; +} + +inline _variant_t &_variant_t::operator=(const DECIMAL &decSrc) +{ + if(V_VT(this)!=VT_DECIMAL) { + + Clear(); + } + + V_DECIMAL(this) = decSrc; + V_VT(this) = VT_DECIMAL; + + return *this; +} + +inline _variant_t &_variant_t::operator=(BYTE bSrc) +{ + if(V_VT(this)!=VT_UI1) { + + Clear(); + + V_VT(this) = VT_UI1; + } + + V_UI1(this) = bSrc; + + return *this; +} + +inline _variant_t &_variant_t::operator=(char cSrc) +{ + if(V_VT(this)!=VT_I1) { + + Clear(); + + V_VT(this) = VT_I1; + } + + V_I1(this) = cSrc; + + return *this; +} + +inline _variant_t &_variant_t::operator=(unsigned short usSrc) +{ + if(V_VT(this)!=VT_UI2) { + + Clear(); + + V_VT(this) = VT_UI2; + } + + V_UI2(this) = usSrc; + + return *this; +} + +inline _variant_t &_variant_t::operator=(unsigned __LONG32 ulSrc) +{ + if(V_VT(this)!=VT_UI4) { + + Clear(); + + V_VT(this) = VT_UI4; + } + + V_UI4(this) = ulSrc; + + return *this; +} + +#ifndef __CYGWIN__ +inline _variant_t &_variant_t::operator=(int iSrc) +{ + if(V_VT(this)!=VT_INT) { + + Clear(); + + V_VT(this) = VT_INT; + } + + V_INT(this) = iSrc; + + return *this; +} + +inline _variant_t &_variant_t::operator=(unsigned int uiSrc) +{ + if(V_VT(this)!=VT_UINT) { + + Clear(); + + V_VT(this) = VT_UINT; + } + + V_UINT(this) = uiSrc; + + return *this; +} +#endif + +__MINGW_EXTENSION inline _variant_t &_variant_t::operator=(__int64 i8Src) { + if(V_VT(this)!=VT_I8) { + + Clear(); + + V_VT(this) = VT_I8; + } + + V_I8(this) = i8Src; + + return *this; +} + +__MINGW_EXTENSION inline _variant_t &_variant_t::operator=(unsigned __int64 ui8Src) { + if(V_VT(this)!=VT_UI8) { + + Clear(); + + V_VT(this) = VT_UI8; + } + + V_UI8(this) = ui8Src; + + return *this; +} + +inline bool _variant_t::operator==(const VARIANT &varSrc) const throw() { + return *this==&varSrc; +} + +inline bool _variant_t::operator==(const VARIANT *pSrc) const throw() +{ + if(!pSrc) { + return false; + } + + if(this==pSrc) { + return true; + } + + if(V_VT(this)!=V_VT(pSrc)) { + return false; + } + + switch (V_VT(this)) { +case VT_EMPTY: +case VT_NULL: + return true; + +case VT_I2: + return V_I2(this)==V_I2(pSrc); + +case VT_I4: + return V_I4(this)==V_I4(pSrc); + +case VT_R4: + return V_R4(this)==V_R4(pSrc); + +case VT_R8: + return V_R8(this)==V_R8(pSrc); + +case VT_CY: + return memcmp(&(V_CY(this)),&(V_CY(pSrc)),sizeof(CY))==0; + +case VT_DATE: + return V_DATE(this)==V_DATE(pSrc); + +case VT_BSTR: + return (::SysStringByteLen(V_BSTR(this))==::SysStringByteLen(V_BSTR(pSrc))) && + (memcmp(V_BSTR(this),V_BSTR(pSrc),::SysStringByteLen(V_BSTR(this)))==0); + +case VT_DISPATCH: + return V_DISPATCH(this)==V_DISPATCH(pSrc); + +case VT_ERROR: + return V_ERROR(this)==V_ERROR(pSrc); + +case VT_BOOL: + return V_BOOL(this)==V_BOOL(pSrc); + +case VT_UNKNOWN: + return V_UNKNOWN(this)==V_UNKNOWN(pSrc); + +case VT_DECIMAL: + return memcmp(&(V_DECIMAL(this)),&(V_DECIMAL(pSrc)),sizeof(DECIMAL))==0; + +case VT_UI1: + return V_UI1(this)==V_UI1(pSrc); + +case VT_I1: + return V_I1(this)==V_I1(pSrc); + +case VT_UI2: + return V_UI2(this)==V_UI2(pSrc); + +case VT_UI4: + return V_UI4(this)==V_UI4(pSrc); + +case VT_INT: + return V_INT(this)==V_INT(pSrc); + +case VT_UINT: + return V_UINT(this)==V_UINT(pSrc); + +case VT_I8: + return V_I8(this)==V_I8(pSrc); + +case VT_UI8: + return V_UI8(this)==V_UI8(pSrc); + +default: + _com_issue_error(E_INVALIDARG); + + } + + return false; +} + +inline bool _variant_t::operator!=(const VARIANT &varSrc) const throw() +{ + return !(*this==&varSrc); +} + +inline bool _variant_t::operator!=(const VARIANT *pSrc) const throw() +{ + return !(*this==pSrc); +} + +inline void _variant_t::Clear() +{ + _com_util::CheckError(::VariantClear(this)); +} + +inline void _variant_t::Attach(VARIANT &varSrc) +{ + + Clear(); + + _COM_MEMCPY_S(this,sizeof(varSrc),&varSrc,sizeof(varSrc)); + V_VT(&varSrc) = VT_EMPTY; +} + +inline VARIANT _variant_t::Detach() +{ + VARIANT varResult = *this; + V_VT(this) = VT_EMPTY; + + return varResult; +} + +inline VARIANT &_variant_t::GetVARIANT() throw() +{ + return *(VARIANT*) this; +} + +inline VARIANT *_variant_t::GetAddress() { + Clear(); + return (VARIANT*) this; +} +inline void _variant_t::ChangeType(VARTYPE vartype,const _variant_t *pSrc) { + if(!pSrc) pSrc = this; + if((this!=pSrc) || (vartype!=V_VT(this))) { + _com_util::CheckError(::VariantChangeType(static_cast<VARIANT*>(this),const_cast<VARIANT*>(static_cast<const VARIANT*>(pSrc)),0,vartype)); + } +} +inline void _variant_t::SetString(const char *pSrc) { operator=(pSrc); } +inline _variant_t::~_variant_t() throw() { ::VariantClear(this); } +inline _bstr_t::_bstr_t(const _variant_t &var) : m_Data(NULL) { + if(V_VT(&var)==VT_BSTR) { + *this = V_BSTR(&var); + return; + } + _variant_t varDest; + varDest.ChangeType(VT_BSTR,&var); + *this = V_BSTR(&varDest); +} +inline _bstr_t &_bstr_t::operator=(const _variant_t &var) { + if(V_VT(&var)==VT_BSTR) { + *this = V_BSTR(&var); + return *this; + } + _variant_t varDest; + varDest.ChangeType(VT_BSTR,&var); + *this = V_BSTR(&varDest); + return *this; +} + +extern _variant_t vtMissing; + +#ifndef _USE_RAW +#define bstr_t _bstr_t +#define variant_t _variant_t +#endif + +#pragma pop_macro("new") + +/* We use _com_issue_error here, but we only provide its inline version in comdef.h, + * so we need to make sure that it's included as well. */ +#include <comdef.h> + +#endif /* __cplusplus */ + +#endif diff --git a/third_party/mingw_headers/new.h b/third_party/mingw_headers/new.h new file mode 100644 index 00000000..f3c70971 --- /dev/null +++ b/third_party/mingw_headers/new.h @@ -0,0 +1,45 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#ifndef _INC_NEW +#define _INC_NEW + +#ifdef __cplusplus + +#include <new> + +#include <crtdefs.h> + +#pragma push_macro("new") +#undef new + +#ifndef __NOTHROW_T_DEFINED +#define __NOTHROW_T_DEFINED +#endif + +#ifndef __PLACEMENT_NEW_INLINE +#define __PLACEMENT_NEW_INLINE +#endif + +_CRTIMP int __cdecl _query_new_mode(void); +_CRTIMP int __cdecl _set_new_mode(int _NewMode); + +#ifndef _PNH_DEFINED +typedef int (__cdecl *_PNH)(size_t); +#define _PNH_DEFINED +#endif + +_CRTIMP _PNH __cdecl _query_new_handler(void); +_CRTIMP _PNH __cdecl _set_new_handler(_PNH _NewHandler); + +#ifndef _NO_ANSI_NH_DEFINED +#define _NO_ANSI_NEW_HANDLER ((new_handler)-1) +#define _NO_ANSI_NEW_HANDLER_M ((_new_handler_m)-1) +#define _NO_ANSI_NH_DEFINED +#endif + +#pragma pop_macro("new") +#endif +#endif diff --git a/tmux.c b/tmux.c index 6659e1c3..a24818ae 100644 --- a/tmux.c +++ b/tmux.c @@ -65,7 +65,7 @@ getshell(void) struct passwd *pw; const char *shell; - shell = getenv("SHELL"); + shell = GETENV_SHELL(); if (checkshell(shell)) return (shell); @@ -328,7 +328,7 @@ find_home(void) if (home != NULL) return (home); - home = getenv("HOME"); + home = GETENV_HOME(); if (home == NULL || *home == '\0') { pw = getpwuid(getuid()); if (pw != NULL) @@ -377,7 +377,7 @@ main(int argc, char **argv) environ_put(global_environ, *var, 0); if ((cwd = find_cwd()) != NULL) environ_set(global_environ, "PWD", 0, "%s", cwd); - expand_paths(TMUX_CONF, &cfg_files, &cfg_nfiles, 1); + expand_paths(TMUX_CONF_SEARCH_PATH(), &cfg_files, &cfg_nfiles, 1); while ((opt = getopt(argc, argv, "2c:CDdf:lL:NqS:T:uUvV")) != -1) { switch (opt) { diff --git a/tmux.h b/tmux.h index 4db4b670..00b0f715 100644 --- a/tmux.h +++ b/tmux.h @@ -81,9 +81,6 @@ struct winlink; #ifndef TMUX_CONF #define TMUX_CONF "/etc/tmux.conf:~/.tmux.conf" #endif -#ifndef TMUX_SOCK -#define TMUX_SOCK "$TMUX_TMPDIR:" _PATH_TMP -#endif #ifndef TMUX_SOCK_PERM #define TMUX_SOCK_PERM (7 /* o+rwx */) #endif diff --git a/tty-term.c b/tty-term.c index d4223497..e79c33bb 100644 --- a/tty-term.c +++ b/tty-term.c @@ -683,8 +683,9 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps, u_int i; const char *s; char tmp[11]; + int retval = ERR; - if (setupterm((char *)name, fd, &error) != OK) { + if ((retval = setupterm((char *)name, fd, &error)) != OK) { switch (error) { case 1: xasprintf(cause, "can't use hardcopy terminal: %s", @@ -695,13 +696,25 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps, name); break; case -1: - xasprintf(cause, "can't find terminfo database"); - break; +#ifdef WIN32_PLATFORM + if ((retval = setupterm("#win32con", fd, &error)) != OK) + { + xasprintf(cause, "can't set up Win32 console"); + break; + } +#else + { + xasprintf(cause, "can't find terminfo database"); + break; + } +#endif default: xasprintf(cause, "unknown error"); break; } - return (-1); + + if (retval != OK) + return (-1); } *ncaps = 0;