diff --git a/Makefile.am b/Makefile.am index ff0de9f8..2ce79ff1 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 93928603..fa20d597 100644 --- a/compat.h +++ b/compat.h @@ -77,6 +77,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 @@ -106,10 +111,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 @@ -479,4 +480,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 98b67a4d..6f04718d 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 4cd147e1..7c895170 100644 --- a/popup.c +++ b/popup.c @@ -778,7 +778,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; @@ -810,7 +810,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 0753cb27..ff3f0fda 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;