Skip to content

Commit 401be1f

Browse files
committed
[windows] try to use APPDATA
1 parent 385c743 commit 401be1f

1 file changed

Lines changed: 109 additions & 23 deletions

File tree

src/base/paths.cc

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,118 @@
2727
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828
*/
2929

30-
#include "config.h"
30+
#include <filesystem>
3131

32-
#ifdef __CYGWIN__
33-
# include <algorithm>
34-
# include <iostream>
35-
# include <sstream>
36-
#endif
32+
#include "paths.hh"
3733

3834
#include <unistd.h>
3935

36+
#include "config.h"
4037
#include "fmt/format.h"
41-
#include "paths.hh"
38+
#include "opt_util.hh"
39+
40+
#ifdef _WIN32
41+
// Make sure we don't bring in all the extra junk with windows.h
42+
# ifndef WIN32_LEAN_AND_MEAN
43+
# define WIN32_LEAN_AND_MEAN
44+
# endif
45+
// stringapiset.h depends on this
46+
# include <windows.h>
47+
// For SUCCEEDED macro
48+
# include <winerror.h>
49+
// For WideCharToMultiByte
50+
# include <stringapiset.h>
51+
// For SHGetFolderPathW and various CSIDL "magic numbers"
52+
# include <shlobj.h>
53+
54+
namespace sago {
55+
namespace internal {
56+
57+
std::string
58+
win32_utf16_to_utf8(const wchar_t* wstr)
59+
{
60+
std::string res;
61+
// If the 6th parameter is 0 then WideCharToMultiByte returns the number of
62+
// bytes needed to store the result.
63+
int actualSize = WideCharToMultiByte(
64+
CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
65+
if (actualSize > 0) {
66+
// If the converted UTF-8 string could not be in the initial buffer.
67+
// Allocate one that can hold it.
68+
std::vector<char> buffer(actualSize);
69+
actualSize = WideCharToMultiByte(CP_UTF8,
70+
0,
71+
wstr,
72+
-1,
73+
&buffer[0],
74+
static_cast<int>(buffer.size()),
75+
nullptr,
76+
nullptr);
77+
res = buffer.data();
78+
}
79+
if (actualSize == 0) {
80+
// WideCharToMultiByte return 0 for errors.
81+
throw std::runtime_error("UTF16 to UTF8 failed with error code: "
82+
+ std::to_string(GetLastError()));
83+
}
84+
return res;
85+
}
4286

43-
namespace lnav::paths {
87+
} // namespace internal
88+
} // namespace sago
89+
90+
class FreeCoTaskMemory {
91+
LPWSTR pointer = NULL;
92+
93+
public:
94+
explicit FreeCoTaskMemory(LPWSTR pointer) : pointer(pointer) {};
95+
~FreeCoTaskMemory() { CoTaskMemFree(pointer); }
96+
};
4497

45-
#ifdef __CYGWIN__
46-
char*
47-
windows_to_unix_file_path(char* input)
98+
static std::string
99+
GetKnownWindowsFolder(REFKNOWNFOLDERID folderId, const char* errorMsg)
48100
{
49-
if (input == nullptr) {
50-
return nullptr;
101+
LPWSTR wszPath = NULL;
102+
HRESULT hr;
103+
hr = SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, NULL, &wszPath);
104+
FreeCoTaskMemory scopeBoundMemory(wszPath);
105+
106+
if (!SUCCEEDED(hr)) {
107+
throw std::runtime_error(errorMsg);
51108
}
109+
return sago::internal::win32_utf16_to_utf8(wszPath);
110+
}
111+
112+
static std::string
113+
GetAppData()
114+
{
115+
return GetKnownWindowsFolder(FOLDERID_RoamingAppData,
116+
"RoamingAppData could not be found");
117+
}
118+
119+
static std::string
120+
GetAppDataCommon()
121+
{
122+
return GetKnownWindowsFolder(FOLDERID_ProgramData,
123+
"ProgramData could not be found");
124+
}
125+
126+
static std::string
127+
GetAppDataLocal()
128+
{
129+
return GetKnownWindowsFolder(FOLDERID_LocalAppData,
130+
"LocalAppData could not be found");
131+
}
132+
#endif
133+
134+
namespace lnav::paths {
135+
136+
#ifdef _WIN32
137+
std::string
138+
windows_to_unix_file_path(const std::string& input)
139+
{
140+
static const auto CYGDRIVE = std::filesystem::path("cygdrive");
141+
52142
std::string file_path;
53143
file_path.assign(input);
54144

@@ -70,25 +160,21 @@ windows_to_unix_file_path(char* input)
70160
const auto remaining_path = file_path.substr(2, file_path.size() - 2);
71161
file_path = drive_letter + remaining_path;
72162

73-
std::stringstream stringstream;
74-
stringstream << "/cygdrive/";
75-
stringstream << file_path;
76-
77-
return const_cast<char*>(stringstream.str().c_str());
163+
return (CYGDRIVE / file_path).string();
78164
}
79165
#endif
80166

81167
std::filesystem::path
82168
dotlnav()
83169
{
84-
#ifdef __CYGWIN__
85-
auto home_env = windows_to_unix_file_path(getenv("APPDATA"));
170+
#ifdef _WIN32
171+
auto home_env = windows_to_unix_file_path(GetAppDataLocal());
86172
#else
87-
auto home_env = getenv("HOME");
173+
auto home_env = std::string(getenv_opt("HOME").value_or(""));
88174
#endif
89-
auto xdg_config_home = getenv("XDG_CONFIG_HOME");
175+
const auto* xdg_config_home = getenv("XDG_CONFIG_HOME");
90176

91-
if (home_env != nullptr) {
177+
if (!home_env.empty()) {
92178
auto home_path = std::filesystem::path(home_env);
93179

94180
if (std::filesystem::is_directory(home_path)) {

0 commit comments

Comments
 (0)