Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
WellKnownLocations.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
6#if qStroika_Foundation_Common_Platform_Windows
7#include <shlobj.h>
8#include <windows.h>
9#elif qPlatoform_POSIX
10#include <cstdlib>
11#endif
12
13#include "Stroika/Foundation/Execution/Throw.h"
14#if qStroika_Foundation_Common_Platform_Windows
15#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
16#endif
17
18#include "FileUtils.h"
19
20#include "WellKnownLocations.h"
21
22using namespace Stroika::Foundation;
23using namespace Stroika::Foundation::Execution;
24using namespace Stroika::Foundation::IO;
26
29
30/*
31 ********************************************************************************
32 ************ FileSystem::WellKnownLocations::GetMyDocuments ********************
33 ********************************************************************************
34 */
35filesystem::path FileSystem::WellKnownLocations::GetMyDocuments (bool createIfNotPresent)
36{
37#if qStroika_Foundation_Common_Platform_POSIX
38 // @todo NYI createIfNotPresent - not sure we want/should???
39
40 // Cacheable because the environment variables should be set externally.
41 // This has the defect that it misses setenv calls, but that SB so rare,
42 // and not clearly a bug we ignore subsequent changes...
43 static const filesystem::path kCachedResult_ = [] () -> filesystem::path {
44 // http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html
45 const char* pPath = ::getenv ("HOME");
46 if (pPath != nullptr) {
47 return pPath;
48 }
49 return filesystem::path{};
50 }();
51 return kCachedResult_;
52#elif qStroika_Foundation_Common_Platform_Windows
53 // @todo DO overlaod with no args, so we can CACHE - like we do for POSIX!
54
55 wchar_t fileBuf[MAX_PATH]{};
56 // note - https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/nf-shlobj_core-shgetspecialfolderpathw not clear this properly sets GetLastError ()
57 Execution::Platform::Windows::ThrowIfZeroGetLastError (::SHGetSpecialFolderPathW (nullptr, fileBuf, CSIDL_PERSONAL, createIfNotPresent));
58 filesystem::path result = fileBuf;
59 // Assure non-empty result
60 if (result.empty ()) {
61 result = path{"c:"sv}; // shouldn't happen
62 }
63 Ensure (not createIfNotPresent or filesystem::is_directory (result));
64 return result;
65#else
67 return filesystem::path ();
68#endif
69}
70
71/*
72 ********************************************************************************
73 ********* FileSystem::WellKnownLocations::GetSpoolDirectory ********************
74 ********************************************************************************
75 */
77{
78#if qStroika_Foundation_Common_Platform_POSIX
79 static const filesystem::path kVarSpool_{"/var/spool/"sv};
80 return kVarSpool_;
81#elif qStroika_Foundation_Common_Platform_Windows
82 /// Not sure what better than FOLDERID_ProgramData / "Spool"???
83 SDKChar fileBuf[MAX_PATH]{};
84 Verify (::SHGetSpecialFolderPath (nullptr, fileBuf, CSIDL_COMMON_APPDATA, false));
85 filesystem::path result = fileBuf;
86 // Assure non-empty result
87 if (result.empty ()) {
88 result = filesystem::path ("c:"); // shouldn't happen
89 }
90 if (filesystem::is_directory (filesystem::path (result))) {
91 return filesystem::path (result);
92 }
93 else {
94 return filesystem::path{};
95 }
96#else
98 return String{};
99#endif
100}
101
102/*
103 ********************************************************************************
104 ******** FileSystem::WellKnownLocations::GetApplicationData ********************
105 ********************************************************************************
106 */
107filesystem::path FileSystem::WellKnownLocations::GetApplicationData (bool createIfNotPresent)
108{
109#if qStroika_Foundation_Common_Platform_POSIX
110 // USED UNTIL STROIKA v2.0a207 - so watch out for older apps - backward compat - static String kVarLib_ = String_Constant{ L"/var/lib/" };
111 static const filesystem::path kVarLib_{"/var/opt/"};
112 return kVarLib_;
113#elif qStroika_Foundation_Common_Platform_Windows
114 SDKChar fileBuf[MAX_PATH]{};
115 Verify (::SHGetSpecialFolderPath (nullptr, fileBuf, CSIDL_COMMON_APPDATA, createIfNotPresent));
116 filesystem::path result = fileBuf;
117 // Assure non-empty result
118 if (result.empty ()) {
119 result = filesystem::path{"c:"}; // shouldn't happen
120 }
121 Ensure (not createIfNotPresent or filesystem::is_directory (result));
122 return result;
123#else
125 return String{};
126#endif
127}
128
129/*
130 ********************************************************************************
131 ******** FileSystem::WellKnownLocations::GetRuntimeVariableData ****************
132 ********************************************************************************
133 */
135{
136#if qStroika_Foundation_Common_Platform_POSIX
137 static const filesystem::path kResult_{"/var/run/"sv};
138 return kResult_;
139#elif qStroika_Foundation_Common_Platform_Windows
140 return GetTemporary ();
141#else
143 return String{};
144#endif
145}
146
147#if qStroika_Foundation_Common_Platform_Windows
148/*
149 ********************************************************************************
150 ************** FileSystem::WellKnownLocations::GetWinSxS ***********************
151 ********************************************************************************
152 */
153filesystem::path FileSystem::WellKnownLocations::GetWinSxS ()
154{
155 wchar_t fileBuf[MAX_PATH]{};
156 Verify (::SHGetSpecialFolderPathW (nullptr, fileBuf, CSIDL_WINDOWS, false));
157 filesystem::path result = fileBuf;
158 // Assure non-empty result
159 if (result.empty ()) {
160 return result;
161 }
162 result /= "WinSxS";
163 if (not filesystem::is_directory (result)) {
164 result.clear ();
165 }
166 Ensure (result.empty () or filesystem::is_directory (result));
167 return result;
168}
169#endif
170
171/*
172 ********************************************************************************
173 ************* FileSystem::WellKnownLocations::GetTemporary *********************
174 ********************************************************************************
175 */
176namespace {
177 SDKString AssureDirectoryPathSlashTerminated_ (const SDKString& dirPath)
178 {
179 if (dirPath.empty ()) {
180 AssertNotReached (); // not sure if this is an error or not. Not sure how code used.
181 // put assert in there to find out... Probably should THROW!
182 // -- LGP 2009-05-12
183 SDKChar tmp = filesystem::path::preferred_separator;
184 return SDKString (&tmp, &tmp + 1);
185 }
186 else {
187 SDKChar lastChar = dirPath[dirPath.size () - 1];
188 if (lastChar == filesystem::path::preferred_separator) {
189 return dirPath;
190 }
191 SDKString result = dirPath;
192 result += filesystem::path::preferred_separator;
193 return result;
194 }
195 }
196 SDKString GetTemporary_ ()
197 {
198#if qStroika_Foundation_Common_Platform_POSIX
199 // http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html
200 const char* pPath = ::getenv ("TMPDIR");
201 if (pPath != nullptr) {
202 return AssureDirectoryPathSlashTerminated_ (pPath);
203 }
204 return "/tmp/";
205#elif qStroika_Foundation_Common_Platform_Windows
206 // NB: internally GetTempPath looks at ENV VAR TMP, then TEMP, etc...
207 SDKChar buf[4 * 1024];
208 if (::GetTempPath (static_cast<DWORD> (Memory::NEltsOf (buf)), buf) == 0) {
209 return SDKSTR ("c:\\Temp\\");
210 }
211 else {
212 return AssureDirectoryPathSlashTerminated_ (buf);
213 }
214#else
216 return SDKSTR (L"/tmp/");
217#endif
218 }
219}
220
222{
223 // Cacheable because the environment variables should be set externally.
224 // This has the defect that it misses setenv calls, but that SB so rare,
225 // and not clearly a bug we ignore subsequent changes...
226 static const filesystem::path kCachedResult_ = [] () -> filesystem::path {
227#if qStroika_Foundation_Common_Platform_POSIX
228 // http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html
229 const char* pPath = ::getenv ("TMPDIR");
230 if (pPath != nullptr) {
231 return AssureDirectoryPathSlashTerminated_ (pPath);
232 }
233 return "/tmp/";
234#elif qStroika_Foundation_Common_Platform_Windows
235 // NB: internally GetTempPath looks at ENV VAR TMP, then TEMP, etc...
236 SDKChar buf[4 * 1024];
237 if (::GetTempPath (static_cast<DWORD> (Memory::NEltsOf (buf)), buf) == 0) {
238 return SDKSTR ("c:\\Temp\\");
239 }
240 else {
241 return buf;
242 }
243#else
245 return SDKSTR (L"/tmp/");
246#endif
247 }();
248 return kCachedResult_;
249}
#define AssertNotImplemented()
Definition Assertions.h:401
#define AssertNotReached()
Definition Assertions.h:355
#define Verify(c)
Definition Assertions.h:419
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
conditional_t< qTargetPlatformSDKUseswchar_t, wchar_t, char > SDKChar
Definition SDKChar.h:71
basic_string< SDKChar > SDKString
Definition SDKString.h:38
filesystem::path GetApplicationData(bool createIfNotPresent=true)