ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
path.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
9
10#if !DOXYGEN
14# if defined ( _WIN32 )
15# include <direct.h>
16# elif defined(__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
17# include <unistd.h>
18# include <dirent.h>
19# include <sys/stat.h>
20# include <pwd.h>
21# else
22# pragma message ("Unknown Platform in file: " __FILE__ )
23# endif
25# include <fstream>
26#endif // !DOXYGEN
27
28
29namespace alib::lang::system {
30
31#if !DOXYGEN
32//--------------- 2 SFINAE versions to load environment variables into a Path instance -------------
33namespace {
34
36template<typename TIf= PathCharType>
38loadEnvVar( const CString& name, AString& target, lang::CurrentData targetData =lang::CurrentData::Clear ) {
39 return EnvironmentVariables::Get( name, target, targetData );
40}
41
42template<typename TIf= PathCharType>
44loadEnvVar( const CString& name, Path& target, lang::CurrentData targetData =lang::CurrentData::Clear ) {
45 String256 buf;
46 auto result= EnvironmentVariables::Get( name, buf, targetData );
47 target.Reset( buf );
48 return result;
49}
51
52} // anonymous namespace
53
54#endif // !DOXYGEN
55
56// #################################################################################################
57// Static variables
58// #################################################################################################
61
62// #################################################################################################
63// Change
64// #################################################################################################
65//! @cond NO_DOX
66namespace {
67void createTempFolderInHomeDir( const PathString& folderName, Path& resultPath,
68 const NString& reasonMsg )
69{
70 // get home directory and set this as fallback result value
71 Path homeTemp( SystemFolders::Home );
72 resultPath.Reset( homeTemp );
73
74 // add given folder name and check if already exists
75 homeTemp._( DIRECTORY_SEPARATOR )._( folderName );
76 bool exists= homeTemp.IsDirectory();
77 if( !exists )
78 {
79 if( homeTemp.Create() == SystemErrors::OK )
80 {
81 exists= true;
82 NAString fileName( homeTemp ); fileName._( DIRECTORY_SEPARATOR )._( "readme.txt" );
83
84 std::ofstream file ( fileName );
85 if ( file.is_open() )
86 {
88 file << "This folder was created by \"" << pi.CmdLine
89 << "\"" << std::endl
90 << "to be used for temporary files." << std::endl;
91 file.write( reasonMsg.Buffer(), reasonMsg.Length() );
92 file << std::endl;
93 file.close();
94 }
95 }
96 }
97
98 // if existed or got created
99 if( exists )
100 resultPath.Reset( homeTemp );
101}
102} // anonymous namespace
103//! @endcond
104
106{
107 switch( special )
108 {
109 case SystemFolders::Root: _( DIRECTORY_SEPARATOR );
110 return true;
111
112 case SystemFolders::Current:
113 {
114 Reset();
115 nchar charBuf[FILENAME_MAX];
116
117 #if defined(__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
118 if ( ! getcwd( charBuf, sizeof(charBuf ) ) )
119 return false;
120 #elif defined ( _WIN32 )
121 if ( !_getcwd( charBuf, sizeof(charBuf ) ) )
122 return false;
123 #else
124 #pragma message ("Unknown Platform in file: " __FILE__ )
125 return false;
126 #endif
127
128 this ->_( static_cast<const nchar*>( charBuf ) );
129 return true;
130 }
131
132
133 case SystemFolders::Home:
134 {
135 #if defined (__unix__)
136 if ( !loadEnvVar( A_CHAR("HOME"), *this ) )
137 {
138 struct passwd* pwd = getpwuid(getuid());
139 Reset( pwd ? NString( pwd->pw_dir ) : "~/" );
140 }
141 return true;
142
143 #elif defined(__APPLE__)
144 macos::ALIB_APPLE_OC_NSHomeDirectory( *this );
145 if ( IsEmpty() )
146 {
147 struct passwd* pwd = getpwuid(getuid());
148 Reset( pwd ? NString( pwd->pw_dir ) : "~/" );
149 }
150 return true;
151
152
153 #elif defined(_WIN32)
154 if ( !loadEnvVar( A_CHAR("USERPROFILE"), *this ) || !IsDirectory() )
155 {
156 loadEnvVar( A_CHAR("HOMEDRIVE"), *this );
157 loadEnvVar( A_CHAR("HOMEPATH" ), *this, CurrentData::Keep );
158 }
159 return true;
160 #else
161 #pragma message ("Unknown Platform in file: " __FILE__ )
162 return false;
163 #endif
164 }
165
166
167 case SystemFolders::HomeConfig:
168 {
169 if( !Change( SystemFolders::Home ) )
170 return false;
171
172 // try ".config" and "AppData/Roaming" subdirectories.
173 #if defined (__unix__)
174 Change( A_PATH(".config") );
175 return true;
176 #elif defined(__APPLE__)
177 Change( A_PATH("Library/Preferences") );
178 return true;
179 #elif defined(_WIN32)
180 Change( Path(A_PATH("AppData")) << DIRECTORY_SEPARATOR << A_PATH("Roaming") );
181 return true;
182 #else
183 #pragma message ("Unknown Platform in file: " __FILE__ )
184 return false;
185 #endif
186 }
187
188 case SystemFolders::Module:
189 {
190 Reset( ProcessInfo::Current().ExecFilePath );
191 return true;
192 }
193
194 case SystemFolders::Temp:
195 {
198 {
199 #if defined (__unix__)
200 NString reasonMsg= "(The default temporary folder \"/tmp\" could not be found.)";
201 if ( Path(A_PATH("/tmp") ).IsDirectory() )
203
204
205 #elif defined(__APPLE__)
206 NString reasonMsg= "(The default temporary folder \"/tmp\" could not be found.)";
207 Path temp;
208 macos::ALIB_APPLE_OC_NSTemporaryDirectory( temp );
209 if ( temp.IsNotEmpty() )
211 else
212 {
213 temp.Reset( A_PATH("/tmp") );
214 if ( temp.IsDirectory() )
216 }
217
218
219 #elif defined(_WIN32)
220 NString reasonMsg= "(Environment variables TMP and TEMP either not set or not containing valid paths.)";
221 Path testDir;
222 if ( ( loadEnvVar( A_CHAR("TMP") , testDir ) && testDir.IsDirectory() )
223 || ( loadEnvVar( A_CHAR("TEMP"), testDir ) && testDir.IsDirectory() ) )
224 {
226 }
227 #else
228 #pragma message ("Unknown Platform in file: " __FILE__ )
229 #endif
230
231
233 {
234 Path homeTemp;
235 createTempFolderInHomeDir( A_PATH(".tmp"), homeTemp, reasonMsg );
236
237 // If this did not work, use home
238 if( homeTemp.IsNotEmpty() )
241 }
242 else
243 {
244 Change( SystemFolders::Home );
247 }
248 }
249 }
250 }
251
252 // set path to evaluated dir name
254 return true;
255
256 } // case SystemFolders::Temp:
257
258 case SystemFolders::VarTemp:
259 {
262 {
263 #if defined (__unix__)
264 NString reasonMsg= "(The default folder \"/var/tmp\" could not be found.)";
265
266 if ( Path( A_PATH("/var/tmp") ).IsDirectory() )
268
269 #elif defined(__APPLE__)
270 const NString reasonMsg= "(The default folder \"/private/var/tmp\" could not be found.)";
271
272 Path temp( A_PATH("/private/var/tmp") );
273 if ( temp.IsDirectory() )
275
276 #elif defined(_WIN32)
277 const NString reasonMsg= "(Environment variables TMP and TEMP either not set or not containing valid paths.)";
278 Path testDir;
279 if ( ( loadEnvVar( A_CHAR("TMP") , testDir ) && testDir.IsDirectory() )
280 || ( loadEnvVar( A_CHAR("TEMP"), testDir ) && testDir.IsDirectory() ) )
281 {
283 }
284 #else
285 #pragma message ("Unknown Platform in file: " __FILE__ )
286 #endif
287
288
290 {
291 Path varTemp;
292 createTempFolderInHomeDir( A_PATH(".var.tmp"), varTemp, reasonMsg );
293
294 // If this did not work, use home
295 if( varTemp.IsNotEmpty() )
298 }
299 else
300 {
301 Change( SystemFolders::Home );
304 }
305 }
306 }
307
308 }
309 // now path to evaluated dir name
311 return true;
312 }
313
314 default: ALIB_ERROR("Illegal switch state.")
315 return false;
316 } // switch ( special )
317}
318
319void Path::AddModuleName( const PathString& extension )
320{
323
325
326 #if defined(_WIN32)
327 if( EndsWith( A_PATH(".exe") ) )
328 DeleteEnd( 4 );
329 #endif
330
331 _( extension );
332}
333
334bool Path::Change( const PathString& ppath )
335{
336 // absolute addressing
337 Path path(ppath);
338 if( path.CharAtStart() == DIRECTORY_SEPARATOR )
339 {
340 if( !path.IsDirectory() )
341 return false;
342
343 Reset( path );
344 return true;
345 }
346
347
348 // relative addressing
349 integer origLength= Length();
350 _<NC>( DIRECTORY_SEPARATOR )._( path );
351
352 if( IsDirectory() )
353 return true;
354
355 ShortenTo( origLength );
356 return false;
357}
358
359
361{
362 #if defined (__GLIBC__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
363 ALIB_STRINGS_TO_NARROW(*this, nPath, 512)
364 DIR* dir= opendir( nPath );
365 if ( dir != nullptr )
366 {
367 closedir( dir );
368 return true;
369 }
370 return false;
371
372 #elif defined(_WIN32)
373
374 #if !ALIB_PATH_CHARACTERS_WIDE
375 DWORD dwAttrib = GetFileAttributesA( Terminate() );
376 #else
377 DWORD dwAttrib = GetFileAttributesW( Terminate() );
378 #endif
379 if( dwAttrib == INVALID_FILE_ATTRIBUTES )
380 return false;
381 if ( dwAttrib & FILE_ATTRIBUTE_DIRECTORY )
382 return true;
383 return false;
384
385 #else
386 #pragma message ("Unknown Platform in file: " __FILE__ )
387 #endif
388}
389
391
392 #if (defined(__GLIBCXX__) && !defined(__MINGW32__)) \
393 || defined(__APPLE__) \
394 || defined(__ANDROID_NDK__)
395
396 Path realPath;
397 if(!realpath(Terminate(), realPath.VBuffer() ) )
398 return SystemErrors(errno);
399
400 realPath.DetectLength();
401 Reset(realPath);
402 return SystemErrors::OK;
403
404 #else
405
406 namespace fs = std::filesystem;
407
408 std::error_code errorCode;
409 fs::path fsRealPath= fs::canonical(fs::path(std::basic_string_view<PathCharType>(Buffer(),
410 size_t(Length()))),
411 errorCode);
412 ALIB_DBG(if(errno==EINVAL && !errorCode) errno= 0;) // this happens!, we do not care, but clean up
413 ALIB_DBG(if(errno==ENOENT && !errorCode) errno= 0;)
414
415 if(errorCode)
416 return SystemErrors(errorCode.value());
417
418 Reset(fsRealPath.c_str());
419 return SystemErrors::OK;
420
421 #endif
422}
423SystemErrors Path::Create( const PathString& ppath ) // static
424{
425 if( Path::IsAbsolute(ppath) )
426 Reset( ppath );
427 else
428 (*this)._( DIRECTORY_SEPARATOR )._( ppath );
429
430 #if defined (__GLIBC__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
431 ALIB_STRINGS_TO_NARROW(*this,nPath,512)
432 int errCode= mkdir( nPath, S_IRWXU | S_IRGRP | S_IROTH
433 | S_IXGRP | S_IXOTH );
434
435 return SystemErrors(errCode);
436
437 #elif defined(_WIN32)
438 #if !ALIB_PATH_CHARACTERS_WIDE
439 BOOL result= CreateDirectoryA( Terminate(), NULL );
440 #else
441 BOOL result= CreateDirectoryW( Terminate(), NULL );
442 #endif
443
444
445 if( result )
446 return SystemErrors::OK;
447
448 return SystemErrors( GetLastError() );
449 #else
450 #pragma message ("Unknown Platform in file: " __FILE__ )
451 #endif
452}
453
454} // namespace [alib::lang::system]
ALIB_API bool Change(const PathString &path)
Definition path.cpp:334
int IsAbsolute() const
Definition path.hpp:347
static PathString tempDirEvaluatedOnce
Definition path.hpp:207
ALIB_API SystemErrors Create()
Definition path.hpp:279
ALIB_API SystemErrors MakeReal()
Definition path.cpp:390
PathString Name() const
Definition path.hpp:353
ALIB_API void AddModuleName(const PathString &extension)
Definition path.cpp:319
static PathString varTempDirEvaluatedOnce
Definition path.hpp:217
ALIB_API bool IsDirectory()
Definition path.cpp:360
static ALIB_API const ProcessInfo & Current()
constexpr const PathCharType * Terminate() const
Definition tastring.inl:821
TAString & _(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
TChar * VBuffer() const
Definition tastring.inl:843
constexpr bool IsNull() const
Definition string.hpp:364
constexpr bool IsEmpty() const
Definition string.hpp:383
void Allocate(TAllocator &allocator, const TString< TChar > &copy)
Definition string.hpp:2012
constexpr bool IsNotEmpty() const
Definition string.hpp:389
constexpr integer Length() const
Definition string.hpp:326
TChar CharAtStart() const
Definition string.hpp:466
bool EndsWith(const TString &needle) const
Definition string.hpp:854
constexpr const PathCharType * Buffer() const
Definition string.hpp:319
#define ATMP_BOOL_IF(Cond)
Definition tmp.hpp:48
#define A_CHAR(STR)
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_STRINGS_TO_NARROW( src, dest, bufSize)
#define ALIB_ERROR(...)
Definition alib.hpp:1267
#define A_PATH(literal)
Definition path.hpp:45
#define ATMP_EQ( T, TEqual)
Definition tmp.hpp:27
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition owner.hpp:457
#define ALIB_DBG(...)
Definition alib.hpp:390
#define ALIB_WARNINGS_IGNORE_UNUSED_FUNCTION
Definition alib.hpp:811
This is the reference documentation of sub-namespace system of module ALib BaseCamp.
Definition basecamp.cpp:75
strings::TString< PathCharType > PathString
The string-type used with this ALib Module.
Definition path.hpp:71
SystemErrors
Denotes result values returned by system functions (glibc, etc).
static constexpr PathCharType DIRECTORY_SEPARATOR
The standard path separator character. Defaults to '\' on Windows OS, '/' else.
Definition path.hpp:99
platform_specific integer
Definition integers.hpp:43
@ Keep
Chooses not no clear existing data.
@ Clear
Chooses to clear existing data.
ALIB_API MonoAllocator GLOBAL_ALLOCATOR
ALIB_API RecursiveLock GLOBAL_ALLOCATOR_LOCK
lang::system::ProcessInfo ProcessInfo
Type alias in namespace alib.
strings::TString< nchar > NString
Type alias in namespace alib.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
lang::system::Path Path
Type alias in namespace alib.
Definition path.hpp:409
strings::TCString< character > CString
Type alias in namespace alib.
LocalString< 256 > String256
Type alias name for TLocalString<character,256>.
characters::character character
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.
static ALIB_API bool Get(const CString &varName, AString &target, lang::CurrentData targetData=lang::CurrentData::Clear)