1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
// Copyright Epic Games, Inc. All Rights Reserved.
#include "browser_launcher.h"
#include <zenbase/zenbase.h>
#include <zencore/except_fmt.h>
#include <zencore/logging.h>
#include <stdexcept>
#include <string>
#if ZEN_PLATFORM_WINDOWS
# include <zencore/windows.h>
# include <shellapi.h>
#else
# include <spawn.h>
# include <sys/wait.h>
extern char** environ;
#endif
namespace zen {
void
LaunchBrowser(std::string_view Url)
{
if (Url.empty())
{
throw zen::runtime_error("Cannot launch browser with empty URL");
}
bool Success = false;
#if ZEN_PLATFORM_WINDOWS
std::string UrlZ(Url);
HINSTANCE Result = ShellExecuteA(nullptr, "open", UrlZ.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
Success = reinterpret_cast<intptr_t>(Result) > 32;
#else
# if ZEN_PLATFORM_MAC
const char* Program = "open";
# elif ZEN_PLATFORM_LINUX
const char* Program = "xdg-open";
# else
ZEN_NOT_IMPLEMENTED("Browser launching not implemented on this platform");
const char* Program = nullptr;
# endif
// Spawn directly via posix_spawnp to avoid the shell entirely, so URL contents
// cannot be interpreted as shell syntax regardless of what characters they contain.
std::string Url_c(Url);
char* const Argv[] = {const_cast<char*>(Program), Url_c.data(), nullptr};
pid_t Pid = 0;
const int SpawnRc = posix_spawnp(&Pid, Program, nullptr, nullptr, Argv, environ);
if (SpawnRc == 0)
{
int Status = 0;
if (waitpid(Pid, &Status, 0) == Pid)
{
Success = WIFEXITED(Status) && WEXITSTATUS(Status) == 0;
}
}
#endif
if (!Success)
{
throw zen::runtime_error("Failed to launch browser for '{}'", Url);
}
ZEN_CONSOLE("Web browser launched for '{}' successfully", Url);
}
} // namespace zen
|