openspades/Sources/Core/ShellApi.cpp
2020-07-28 19:03:50 +00:00

151 lines
4.7 KiB
C++

/*
Copyright (c) 2016 yvt
This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cerrno> // errno
#include <cstdlib> // system
#include <cstring> // strerror
#include "ShellApi.h"
#include <Core/Debug.h>
#include <Core/Strings.h>
#ifdef WIN32
#include <Imports/SDL.h>
#include <windows.h>
namespace {
static std::wstring WStringFromUtf8(const char *s) {
auto *ws = (wchar_t *)SDL_iconv_string("UCS-2-INTERNAL", "UTF-8", s, strlen(s) + 1);
if (!ws)
return L"";
std::wstring wss(ws);
SDL_free(ws);
return wss;
}
}
#else
#include <sys/wait.h> // WIFSIGNALED, ...
#endif
namespace spades {
#if defined(__APPLE__)
// macOS version of ShowDirectoryInShell is defined in ShellApi.mm.
#elif defined(WIN32)
bool ShowDirectoryInShell(const std::string &directoryPath) {
std::wstring widePath = WStringFromUtf8(directoryPath.c_str());
// "The return value is cast as an HINSTANCE for backward compatibility with 16-bit Windows
// applications. It is not a true HINSTANCE, however. It can be cast only to an int and
// compared to either 32 or the following error codes below." --- MSDN Library
//
// Cast it to INT_PTR instead of int to get rid of "pointer truncation" warning.
INT_PTR result = reinterpret_cast<INT_PTR>(
ShellExecuteW(nullptr, L"explore", widePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL));
// "If the function succeeds, it returns a value greater than 32."
if (result > 32) {
return true;
} else {
SPLog("ShellExecuteW returned %u while trying to open '%s' with Explorer.",
static_cast<unsigned int>(result), directoryPath.c_str());
return false;
}
}
bool OpenURLInBrowser(const std::string &url) {
std::wstring widePath = WStringFromUtf8(url.c_str());
// "The return value is cast as an HINSTANCE for backward compatibility with 16-bit Windows
// applications. It is not a true HINSTANCE, however. It can be cast only to an int and
// compared to either 32 or the following error codes below." --- MSDN Library
//
// Cast it to INT_PTR instead of int to get rid of "pointer truncation" warning.
INT_PTR result = reinterpret_cast<INT_PTR>(
ShellExecuteW(nullptr, L"open", widePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL));
// "If the function succeeds, it returns a value greater than 32."
if (result > 32) {
return true;
} else {
SPLog("ShellExecuteW returned %u while trying to open '%s' with a browser.",
static_cast<unsigned int>(result), url.c_str());
return false;
}
}
#elif (__unix || __unix__) || defined(__HAIKU__)
bool ShowDirectoryInShell(const std::string &directoryPath) {
// FIXME: escape single quotes
if (directoryPath.find("'") != std::string::npos) {
SPLog("Cannot launch xdg-open (currently): the directory path '%s' contains a single "
"quotation mark",
directoryPath.c_str());
return false;
}
// Assumption: system() uses the Bourne or any compatible shell internally.
// system() behaves like that of GNU C Library.
int result = std::system(Format("xdg-open '{0}'", directoryPath).c_str());
if (result == -1) {
int no = errno;
SPLog("system() failed while executing xdg-open '%s': %s", directoryPath.c_str(),
std::strerror(no));
return false;
}
int status = WEXITSTATUS(result);
if (status) {
SPLog("xdg-open failed with the exit code %d.", status);
return false;
}
return true;
}
bool OpenURLInBrowser(const std::string &url) {
// FIXME: escape single quotes
if (url.find("'") != std::string::npos) {
SPLog("Cannot launch xdg-open (currently): the URL '%s' contains a single quotation mark",
url.c_str());
return false;
}
// Assumption: system() uses the Bourne or any compatible shell internally.
// system() behaves like that of GNU C Library.
int result = std::system(Format("xdg-open '{0}'", url).c_str());
if (result == -1) {
int no = errno;
SPLog("system() failed while executing xdg-open '%s': %s", url.c_str(),
std::strerror(no));
return false;
}
int status = WEXITSTATUS(result);
if (status) {
SPLog("xdg-open failed with the exit code %d.", status);
return false;
}
return true;
}
#endif
}