File indexing completed on 2026-04-09 07:49:43
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <cassert>
0013 #include <cstdlib>
0014 #include <cstring>
0015 #include <string>
0016 #include <sstream>
0017 #include <fstream>
0018 #include <vector>
0019 #include <iostream>
0020 #include <unistd.h>
0021
0022
0023 #include "sproc.h"
0024 #include "sdirectory.h"
0025 #include "sstamp.h"
0026
0027 struct spath
0028 {
0029 friend struct spath_test ;
0030 static constexpr const bool VERBOSE = false ;
0031 static constexpr const bool DUMP = false ;
0032
0033 private:
0034 static std::string _ResolvePath(const char* spec);
0035 static std::string _ResolvePathGeneralized(const char* spec_);
0036
0037
0038 static char* ResolvePath(const char* spec);
0039 static char* ResolvePathGeneralized(const char* spec);
0040
0041 static char* DefaultTMP();
0042 static constexpr const char* _DefaultOutputDir = "$TMP/GEOM/$GEOM/$ExecutableName" ;
0043
0044 public:
0045 static char* DefaultOutputDir();
0046 static std::string DefaultOutputName(const char* stem, int index, const char* ext);
0047 static const char* DefaultOutputPath(const char* stem, int index, const char* ext, bool unique);
0048
0049
0050 private:
0051 static char* ResolveToken(const char* token);
0052 static char* _ResolveToken(const char* token);
0053 static bool IsTokenWithFallback(const char* token);
0054 static bool IsToken(const char* token);
0055 static char* _ResolveTokenWithFallback(const char* token);
0056
0057 template<typename ... Args>
0058 static std::string _Resolve(Args ... args );
0059
0060 public:
0061 template<typename ... Args>
0062 static const char* Resolve(Args ... args );
0063
0064
0065 static bool LooksUnresolved( const char* path , const char* _path );
0066 static bool LooksUnresolved0( const char* path , const char* _path );
0067 static const char* ResolveTopLevel( const char* spec );
0068
0069
0070 static bool StartsWith( const char* s, const char* q);
0071 static bool EndsWith( const char* path, const char* q);
0072 static int SplitExt0(std::string& dir, std::string& stem, std::string& ext, const char* path );
0073 static int SplitExt(std::string& dir, std::string& stem, std::string& ext, const char* path );
0074
0075 private:
0076 template<typename ... Args>
0077 static std::string _Join( Args ... args_ );
0078
0079 template<typename ... Args>
0080 static std::string _Check( char method, Args ... args_ );
0081
0082 template<typename ... Args>
0083 static std::string _Name( Args ... args_ );
0084
0085 public:
0086 template<typename ... Args>
0087 static const char* Join( Args ... args );
0088
0089 template<typename ... Args>
0090 static const char* Name( Args ... args );
0091
0092 template<typename ... Args>
0093 static char* Name_( Args ... args );
0094
0095
0096
0097
0098 template<typename ... Args>
0099 static bool Exists( Args ... args );
0100
0101
0102 static bool LooksLikePath(const char* arg);
0103 static const char* Dirname(const char* path);
0104 static const char* Basename(const char* path);
0105
0106 static int Remove(const char* path_);
0107
0108 static const char* SearchDirUpTreeWithFile( const char* startdir, const char* relf );
0109
0110 static bool Read( std::string& str , const char* path );
0111 static bool Read( std::vector<char>&, const char* path );
0112
0113
0114 static bool Write(const char* txt, const char* base, const char* name );
0115 static bool Write(const char* txt, const char* path );
0116 private:
0117 static bool Write_( const char* str , const char* path );
0118 public:
0119 static void MakeDirsForFile(const char* path);
0120
0121 static long Filesize(const char* dir, const char* name);
0122 static long Filesize(const char* path);
0123
0124 static char* CWD();
0125
0126
0127 static const char* GEOM(const char* _geom=nullptr);
0128 static const char* GEOM_Aux(const char* geom, const char* aux);
0129 static const char* GEOMSub(const char* _geom=nullptr);
0130 static const char* GEOMWrap(const char* _geom=nullptr);
0131 static const char* GEOMList(const char* _geom=nullptr);
0132
0133
0134 static char* CFBaseFromGEOM(const char* _geom=nullptr);
0135 static bool has_CFBaseFromGEOM(const char* _geom=nullptr);
0136
0137 static char* GDMLPathFromGEOM(const char* _geom=nullptr);
0138
0139 static bool is_readable(const char* base, const char* name);
0140 static bool is_readable(const char* path );
0141
0142 static int64_t last_write_time(const char* path, bool dump=false);
0143
0144
0145 };
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160 inline std::string spath::_ResolvePath(const char* spec_)
0161 {
0162 if(spec_ == nullptr) return "" ;
0163 char* spec = strdup(spec_);
0164
0165 std::stringstream ss ;
0166 int speclen = int(strlen(spec)) ;
0167 char* end = strchr(spec, '\0' );
0168 int i = 0 ;
0169
0170 if(VERBOSE) std::cout << " spec " << spec << " speclen " << speclen << std::endl ;
0171
0172 while( i < speclen )
0173 {
0174 if(VERBOSE) std::cout << " i " << i << " spec[i] " << spec[i] << std::endl ;
0175 if( spec[i] == '$' )
0176 {
0177 char* p = spec + i ;
0178 char* sep = strchr( p, '/' ) ;
0179 bool tok_plus = sep && end && sep != end ;
0180 if(tok_plus) *sep = '\0' ;
0181 char* val = ResolveToken(p+1) ;
0182 int toklen = int(strlen(p)) ;
0183 if(VERBOSE) std::cout << " toklen " << toklen << std::endl ;
0184 if(val == nullptr)
0185 {
0186 std::cerr
0187 << "spath::_ResolvePath token ["
0188 << p+1
0189 << "] does not resolve "
0190 << std::endl
0191 ;
0192 ss << "UNRESOLVED_TOKEN_" << (p+1) ;
0193 }
0194 else
0195 {
0196 ss << val ;
0197 }
0198 if(tok_plus) *sep = '/' ;
0199 i += toklen ;
0200 }
0201 else
0202 {
0203 ss << spec[i] ;
0204 i += 1 ;
0205 }
0206 }
0207 std::string str = ss.str();
0208 return str ;
0209 }
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226 inline std::string spath::_ResolvePathGeneralized(const char* spec_)
0227 {
0228 if(spec_ == nullptr) return "" ;
0229 char* spec = strdup(spec_);
0230
0231 std::stringstream ss ;
0232 int speclen = int(strlen(spec)) ;
0233 int speclen1 = speclen - 1 ;
0234 char* end = strchr(spec, '\0' );
0235 int i = 0 ;
0236
0237 while( i < speclen )
0238 {
0239 char* p = spec + i ;
0240 if( i < speclen1 && *p == '$' && *(p+1) != '{' )
0241 {
0242 char* sep = strchr( p, '/' ) ;
0243 bool tok_plus = sep && end && sep != end ;
0244 if(tok_plus) *sep = '\0' ;
0245 char* val = ResolveToken(p+1) ;
0246 int toklen = int(strlen(p)) ;
0247 ss << ( val ? val : p+1 ) ;
0248 if(tok_plus) *sep = '/' ;
0249 i += toklen ;
0250 }
0251 else if( i < speclen1 && *p == '$' && *(p+1) == '{' )
0252 {
0253 char* sep = strchr(p, '}' ) + 1 ;
0254 char keep = *sep ;
0255 bool tok_plus = sep && end && sep != end ;
0256 if(tok_plus) *sep = '\0' ;
0257 char* val = ResolveToken(p+1) ;
0258 int toklen = int(strlen(p)) ;
0259 ss << ( val ? val : p+1 ) ;
0260 if(tok_plus) *sep = keep ;
0261 i += toklen ;
0262 }
0263 else
0264 {
0265 ss << *p ;
0266 i += 1 ;
0267 }
0268 }
0269 std::string str = ss.str();
0270 return str ;
0271 }
0272
0273
0274
0275
0276 inline char* spath::ResolvePath(const char* spec_)
0277 {
0278 std::string path = _ResolvePath(spec_) ;
0279 return strdup(path.c_str()) ;
0280 }
0281 inline char* spath::ResolvePathGeneralized(const char* spec_)
0282 {
0283 std::string path = _ResolvePathGeneralized(spec_) ;
0284 return strdup(path.c_str()) ;
0285 }
0286
0287
0288
0289
0290 inline char* spath::DefaultTMP()
0291 {
0292 char* user = getenv("USER") ;
0293 std::stringstream ss ;
0294 ss << "/tmp/" << ( user ? user : "MISSING_USER" ) << "/" << "opticks" ;
0295 std::string str = ss.str();
0296 return strdup(str.c_str());
0297 }
0298
0299 inline char* spath::DefaultOutputDir()
0300 {
0301 return (char*)_DefaultOutputDir ;
0302 }
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325 inline std::string spath::DefaultOutputName(const char* _stem, int index, const char* ext)
0326 {
0327 std::string stem = sstamp::FormatTimeStem(_stem, 0, false) ;
0328 std::stringstream ss ;
0329 ss << stem << std::setfill('0') << std::setw(5) << index << ext ;
0330 std::string str = ss.str();
0331 return str ;
0332 }
0333
0334 inline const char* spath::DefaultOutputPath(const char* stem, int index, const char* ext, bool unique)
0335 {
0336 const char* outfold = DefaultOutputDir();
0337 std::string outname = DefaultOutputName(stem, index, ext);
0338 const char* outpath = Resolve(outfold, outname );
0339 if(unique)
0340 {
0341
0342 int offset = 0 ;
0343 while( Exists(outpath) && offset < 100 )
0344 {
0345 offset += 1 ;
0346 outname = DefaultOutputName(stem, index+offset, ext);
0347 outpath = Resolve( outfold, outname.c_str() );
0348 }
0349 }
0350 return outpath ;
0351 }
0352
0353
0354
0355 inline char* spath::ResolveToken(const char* token)
0356 {
0357 bool is_twf = IsTokenWithFallback(token) ;
0358
0359 char* result0 = is_twf
0360 ?
0361 _ResolveTokenWithFallback(token)
0362 :
0363 _ResolveToken(token)
0364 ;
0365
0366 bool is_still_token = IsToken(result0) && strcmp(token, result0) != 0 ;
0367 char* result1 = is_still_token ? ResolvePath(result0) : result0 ;
0368
0369 if(DUMP) std::cout
0370 << "spath::ResolveToken.DUMP" << std::endl
0371 << " token [" << ( token ? token : "-" ) << "]"
0372 << " is_twf " << ( is_twf ? "YES" : "NO " )
0373 << " result0 [" << ( result0 ? result0 : "-" ) << "]"
0374 << " result1 [" << ( result1 ? result1 : "-" ) << "]"
0375 << std::endl
0376 ;
0377
0378 return result1 ;
0379 }
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 inline char* spath::_ResolveToken(const char* token)
0404 {
0405 char* tok = strdup(token) ;
0406
0407 if( tok && strlen(tok) > 0 && tok[0] == '$') tok += 1 ;
0408 if( tok && strlen(tok) > 0 && tok[0] == '{' && tok[strlen(tok)-1] == '}')
0409 {
0410 tok += 1 ;
0411 tok[strlen(tok)-1] = '\0' ;
0412 }
0413
0414 char* val = getenv(tok) ;
0415 if( val == nullptr && strcmp(tok, "TMP") == 0) val = DefaultTMP() ;
0416 if( val == nullptr && strcmp(tok, "ExecutableName") == 0) val = sproc::ExecutableName() ;
0417 if( val == nullptr && strcmp(tok, "DefaultOutputDir") == 0) val = DefaultOutputDir() ;
0418 if( val == nullptr && strcmp(tok, "CFBaseFromGEOM") == 0) val = CFBaseFromGEOM() ;
0419 return val ;
0420 }
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435 inline bool spath::IsTokenWithFallback(const char* token)
0436 {
0437 return token && strlen(token) > 0 && token[0] == '{' && token[strlen(token)-1] == '}' && strstr(token,":-") != nullptr ;
0438 }
0439 inline bool spath::IsToken(const char* token)
0440 {
0441 return token && strlen(token) > 0 && strstr(token,"$") != nullptr ;
0442 }
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459 inline char* spath::_ResolveTokenWithFallback(const char* token_)
0460 {
0461 char* token = strdup(token_);
0462 if(token && strlen(token) > 0 && token[0] == '$') token += 1 ;
0463
0464 bool is_twf = IsTokenWithFallback(token) ;
0465 if(!is_twf) std::cerr << "spath::_ResolveTokenWithFallback"
0466 << " ERROR NOT-IsTokenWithFallback "
0467 << " token_ [" << ( token_ ? token_ : "-" ) << "]"
0468 << " token [" << ( token ? token : "-" ) << "]"
0469 << std::endl
0470 ;
0471 assert(is_twf);
0472
0473 token[strlen(token)-1] = '\0' ;
0474
0475 const char* delim = ":-" ;
0476 char* split = strstr(token, delim) ;
0477
0478 bool dump = false ;
0479
0480 if(dump) std::cout
0481 << "spath::ResolveTokenWithFallback"
0482 << std::endl
0483 << " token " << ( token ? token : "-" )
0484 << std::endl
0485 << " split " << ( split ? split : "-" )
0486 << std::endl
0487 ;
0488
0489 assert( split );
0490 char* tok1 = split + strlen(delim) ;
0491
0492 split[0] = '\0' ;
0493 char* tok0 = token + 1 ;
0494
0495 if(dump) std::cout
0496 << "spath::ResolveTokenWithFallback"
0497 << std::endl
0498 << " tok0 " << ( tok0 ? tok0 : "-" )
0499 << std::endl
0500 << " tok1 " << ( tok1 ? tok1 : "-" )
0501 << std::endl
0502 ;
0503
0504 char* val = _ResolveToken(tok0) ;
0505 if(val == nullptr) val = ResolvePath(tok1) ;
0506 return val ;
0507 }
0508
0509
0510
0511
0512 template<typename ... Args>
0513 inline std::string spath::_Resolve( Args ... args )
0514 {
0515 std::string spec = _Join(std::forward<Args>(args)... );
0516 return _ResolvePath(spec.c_str());
0517 }
0518
0519 template std::string spath::_Resolve( const char* );
0520 template std::string spath::_Resolve( const char*, const char* );
0521 template std::string spath::_Resolve( const char*, const char*, const char* );
0522 template std::string spath::_Resolve( const char*, const char*, const char*, const char* );
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540 template<typename ... Args>
0541 inline const char* spath::Resolve( Args ... args )
0542 {
0543 std::string spec = _Join(std::forward<Args>(args)... );
0544
0545
0546 std::string path = _ResolvePathGeneralized(spec.c_str());
0547
0548 return strdup(path.c_str()) ;
0549 }
0550
0551 template const char* spath::Resolve( const char* );
0552 template const char* spath::Resolve( const char*, const char* );
0553 template const char* spath::Resolve( const char*, const char*, const char* );
0554 template const char* spath::Resolve( const char*, const char*, const char*, const char* );
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 inline bool spath::LooksUnresolved( const char* path , const char* _path )
0577 {
0578 bool _path_starts_with_dollar = _path && strlen(_path) > 1 && _path[0] == '$' ;
0579 if(!_path_starts_with_dollar) return false ;
0580 return StartsWith( path, _path + 1 );
0581 }
0582
0583
0584 inline bool spath::LooksUnresolved0( const char* path , const char* _path )
0585 {
0586 bool _path_starts_with_dollar = _path && strlen(_path) > 1 && _path[0] == '$' ;
0587 bool path_is_same_without_dollar = path && strlen(path) > 1 && strcmp(_path+1, path) == 0 ;
0588 return _path_starts_with_dollar && path_is_same_without_dollar ;
0589 }
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603
0604 inline const char* spath::ResolveTopLevel( const char* spec )
0605 {
0606 const char* path = spath::Resolve(spec) ;
0607 bool path_unresolved = spath::LooksUnresolved(path, spec);
0608 if(path_unresolved)
0609 {
0610 std::cout
0611 << "spath::ResolveTopLevel"
0612 << " ABORT as missing envvars path, see for example spath::CFBaseFromGEOM \n"
0613 << " spec [" << ( spec ? spec : "-" ) << "]\n"
0614 << " path [" << ( path ? path : "-" ) << "]\n"
0615 ;
0616 }
0617 return path_unresolved ? nullptr : path ;
0618 }
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637 inline bool spath::StartsWith( const char* s, const char* q)
0638 {
0639 return s && q && strlen(q) <= strlen(s) && strncmp(s, q, strlen(q)) == 0 ;
0640 }
0641
0642
0643
0644
0645 inline bool spath::EndsWith( const char* path, const char* q)
0646 {
0647 const char* s = Resolve(path);
0648 int pos = strlen(s) - strlen(q) ;
0649 return pos > 0 && strncmp(s + pos, q, strlen(q)) == 0 ;
0650 }
0651
0652 inline int spath::SplitExt0(std::string& dir, std::string& stem, std::string& ext, const char* _path )
0653 {
0654 std::string path = _path ;
0655 std::size_t pos0 = path.find_last_of("/");
0656 std::string name = pos0 == std::string::npos ? path : path.substr(pos0+1) ;
0657 dir = pos0 == std::string::npos ? "" : path.substr(0, pos0) ;
0658
0659 std::size_t pos1 = name.find_last_of(".");
0660 ext = pos1 == std::string::npos ? "" : name.substr(pos1) ;
0661 stem = pos1 == std::string::npos ? name : name.substr(0, pos1) ;
0662
0663 bool ok = strlen(dir.c_str())>0 && strlen(stem.c_str()) > 0 && strlen(ext.c_str()) > 0 ;
0664 return ok ? 0 : 1 ;
0665 }
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681 #if __cplusplus < 201703
0682 inline int spath::SplitExt(std::string& dir, std::string& stem, std::string& ext, const char* _path )
0683 {
0684 return SplitExt0(dir, stem, ext, _path );
0685 }
0686 #else
0687 #include <filesystem>
0688 inline int spath::SplitExt(std::string& dir, std::string& stem, std::string& ext, const char* _path )
0689 {
0690 std::filesystem::path path(_path);
0691 dir = path.parent_path().string() ;
0692 stem = path.stem().string() ;
0693 ext = path.extension().string() ;
0694 bool ok = strlen(dir.c_str())>0 && strlen(stem.c_str()) > 0 && strlen(ext.c_str()) > 0 ;
0695 return ok ? 0 : 1 ;
0696 }
0697 #endif
0698
0699
0700
0701
0702 template<typename ... Args>
0703 inline std::string spath::_Join( Args ... args_ )
0704 {
0705 std::vector<std::string> args = {args_...};
0706 std::vector<std::string> elem ;
0707
0708 for(unsigned i=0 ; i < args.size() ; i++)
0709 {
0710 const std::string& arg = args[i] ;
0711 if(!arg.empty()) elem.push_back(arg);
0712 }
0713
0714 unsigned num_elem = elem.size() ;
0715 std::stringstream ss ;
0716 for(unsigned i=0 ; i < num_elem ; i++)
0717 {
0718 const std::string& ele = elem[i] ;
0719 ss << ele << ( i < num_elem - 1 ? "/" : "" ) ;
0720 }
0721 std::string s = ss.str();
0722 return s ;
0723 }
0724
0725 template std::string spath::_Join( const char* );
0726 template std::string spath::_Join( const char*, const char* );
0727 template std::string spath::_Join( const char*, const char*, const char* );
0728 template std::string spath::_Join( const char*, const char*, const char*, const char* );
0729
0730 template<typename ... Args>
0731 inline const char* spath::Join( Args ... args )
0732 {
0733 std::string s = _Join(std::forward<Args>(args)...) ;
0734 return strdup(s.c_str()) ;
0735 }
0736
0737 template const char* spath::Join( const char* );
0738 template const char* spath::Join( const char*, const char* );
0739 template const char* spath::Join( const char*, const char*, const char* );
0740 template const char* spath::Join( const char*, const char*, const char*, const char* );
0741
0742
0743
0744
0745 template<typename ... Args>
0746 inline std::string spath::_Check( char method, Args ... args_ )
0747 {
0748 std::vector<std::string> args = {args_...};
0749 std::stringstream ss ;
0750 ss << method << ":" ;
0751
0752 for(int i=0 ; i < int(args.size()) ; i++)
0753 {
0754 const std::string& arg = args[i] ;
0755 if(arg.empty()) continue ;
0756 ss << arg << " " ;
0757 }
0758 std::string str = ss.str();
0759 return str ;
0760 }
0761
0762
0763 template std::string spath::_Check( char, const char* );
0764 template std::string spath::_Check( char, const char*, const char* );
0765 template std::string spath::_Check( char, const char*, const char*, const char* );
0766 template std::string spath::_Check( char, const char*, const char*, const char*, const char* );
0767
0768
0769
0770
0771
0772 template<typename ... Args>
0773 inline std::string spath::_Name( Args ... args_ )
0774 {
0775 std::vector<std::string> args = {args_...};
0776 std::vector<std::string> elem ;
0777
0778 for(unsigned i=0 ; i < args.size() ; i++)
0779 {
0780 const std::string& arg = args[i] ;
0781 if(!arg.empty()) elem.push_back(arg);
0782 }
0783
0784 const char* delim = "" ;
0785
0786 unsigned num_elem = elem.size() ;
0787 std::stringstream ss ;
0788 for(unsigned i=0 ; i < num_elem ; i++)
0789 {
0790 const std::string& ele = elem[i] ;
0791 ss << ele << ( i < num_elem - 1 ? delim : "" ) ;
0792 }
0793 std::string s = ss.str();
0794 return s ;
0795 }
0796
0797 template std::string spath::_Name( const char* );
0798 template std::string spath::_Name( const char*, const char* );
0799 template std::string spath::_Name( const char*, const char*, const char* );
0800 template std::string spath::_Name( const char*, const char*, const char*, const char* );
0801
0802 template std::string spath::_Name( char* );
0803 template std::string spath::_Name( char*, char* );
0804 template std::string spath::_Name( char*, char*, char* );
0805 template std::string spath::_Name( char*, char*, char*, char* );
0806
0807
0808
0809
0810 template<typename ... Args>
0811 inline const char* spath::Name( Args ... args )
0812 {
0813 std::string s = _Name(std::forward<Args>(args)...) ;
0814 return strdup(s.c_str()) ;
0815 }
0816
0817 template const char* spath::Name( const char* );
0818 template const char* spath::Name( const char*, const char* );
0819 template const char* spath::Name( const char*, const char*, const char* );
0820 template const char* spath::Name( const char*, const char*, const char*, const char* );
0821
0822
0823
0824 template<typename ... Args>
0825 inline char* spath::Name_( Args ... args )
0826 {
0827 std::string s = _Name(std::forward<Args>(args)...) ;
0828 return strdup(s.c_str()) ;
0829 }
0830
0831 template char* spath::Name_( char* );
0832 template char* spath::Name_( char*, char* );
0833 template char* spath::Name_( char*, char*, char* );
0834 template char* spath::Name_( char*, char*, char*, char* );
0835
0836
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846
0847
0848
0849
0850
0851
0852
0853
0854 template<typename ... Args>
0855 inline bool spath::Exists(Args ... args)
0856 {
0857 std::string path = _Resolve(std::forward<Args>(args)...) ;
0858 std::ifstream fp(path.c_str(), std::ios::in|std::ios::binary);
0859 return fp.fail() ? false : true ;
0860 }
0861
0862 template bool spath::Exists( const char* );
0863 template bool spath::Exists( const char*, const char* );
0864 template bool spath::Exists( const char*, const char*, const char* );
0865 template bool spath::Exists( const char*, const char*, const char*, const char* );
0866
0867
0868
0869
0870
0871
0872
0873 inline bool spath::LooksLikePath(const char* arg)
0874 {
0875 if(!arg) return false ;
0876 if(strlen(arg) < 2) return false ;
0877 return arg[0] == '/' || arg[0] == '$' ;
0878 }
0879
0880
0881 inline const char* spath::Dirname(const char* path)
0882 {
0883 std::string p = path ;
0884 std::size_t pos = p.find_last_of("/");
0885 std::string fold = pos == std::string::npos ? "" : p.substr(0, pos) ;
0886 return strdup( fold.c_str() ) ;
0887 }
0888
0889 inline const char* spath::Basename(const char* path)
0890 {
0891 std::string p = path ;
0892 std::size_t pos = p.find_last_of("/");
0893 std::string base = pos == std::string::npos ? p : p.substr(pos+1) ;
0894 return strdup( base.c_str() ) ;
0895 }
0896
0897
0898 inline int spath::Remove(const char* path_)
0899 {
0900 const char* path = spath::Resolve(path_);
0901 assert( strlen(path) > 2 );
0902 return remove(path);
0903 }
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915 inline const char* spath::SearchDirUpTreeWithFile( const char* startdir, const char* relf )
0916 {
0917 if(startdir == nullptr || relf == nullptr) return nullptr ;
0918 char* dir = strdup(startdir) ;
0919 while(dir && strlen(dir) > 1)
0920 {
0921 if(spath::Exists(dir, relf)) break ;
0922 char* last = strrchr(dir, '/');
0923 *last = '\0' ;
0924 }
0925 return ( dir && strlen(dir) > 1 ) ? strdup(dir) : nullptr ;
0926 }
0927
0928
0929 inline bool spath::Read( std::string& str , const char* path_ )
0930 {
0931 const char* path = Resolve(path_);
0932 std::ifstream fp(path);
0933 bool good = fp.good() ;
0934 if( good )
0935 {
0936 std::stringstream content ;
0937 content << fp.rdbuf();
0938 str = content.str();
0939 }
0940 return good ;
0941 }
0942
0943 inline bool spath::Read( std::vector<char>& data, const char* path_ )
0944 {
0945 const char* path = Resolve(path_);
0946 std::ifstream fp(path, std::ios::binary);
0947 bool good = fp.good() ;
0948 if( good )
0949 {
0950 fp.seekg(0, fp.end);
0951 std::streamsize size = fp.tellg();
0952 fp.seekg(0, fp.beg);
0953
0954 if(size <= 0 ) std::cerr << "spath::Read ERROR stream size " << size << " for path " << ( path ? path : "-" ) << "\n" ;
0955 if(size <= 0) return false ;
0956
0957 data.resize(size);
0958 fp.read(data.data(), size );
0959 bool fail = fp.fail();
0960
0961 if(fail) std::cerr << "spath::Read ERROR failed to read size " << size << " bytes from path " << ( path ? path : "-" ) << "\n" ;
0962 if(fail) return false ;
0963 }
0964 return good ;
0965 }
0966
0967
0968 inline bool spath::Write( const char* str , const char* base, const char* name )
0969 {
0970 const char* path = base == nullptr ? Resolve(name) : Resolve(base, name);
0971 return Write_(str, path );
0972 }
0973 inline bool spath::Write( const char* str , const char* path_ )
0974 {
0975 const char* path = Resolve(path_);
0976 return Write_(str, path );
0977 }
0978 inline bool spath::Write_( const char* str , const char* path )
0979 {
0980 sdirectory::MakeDirsForFile(path) ;
0981 std::ofstream fp(path);
0982 bool good = fp.good() ;
0983 if( good ) fp << str ;
0984 return good ;
0985 }
0986
0987 inline void spath::MakeDirsForFile(const char* path)
0988 {
0989 sdirectory::MakeDirsForFile(path) ;
0990 }
0991
0992
0993 inline long spath::Filesize(const char* dir, const char* name)
0994 {
0995 const char* path = Resolve(dir, name);
0996 return Filesize(path);
0997 }
0998
0999 inline long spath::Filesize(const char* path)
1000 {
1001 FILE *fp = fopen(path,"rb");
1002
1003 bool failed = fp == nullptr ;
1004 if(failed) std::cerr << "spath::Filesize unable to open file [" << path << "]\n" ;
1005 assert(!failed);
1006
1007 fseek(fp, 0L, SEEK_END);
1008 long file_size = ftell(fp);
1009 rewind(fp);
1010 fclose(fp);
1011
1012 return file_size ;
1013 }
1014
1015 inline char* spath::CWD()
1016 {
1017 char path[256] ;
1018 char* ret = getcwd(path, 256);
1019 return ret == nullptr ? nullptr : strdup(path);
1020 }
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035 inline const char* spath::GEOM(const char* _geom){ return _geom ? _geom : getenv("GEOM") ; }
1036 inline const char* spath::GEOM_Aux(const char* _geom, const char* aux)
1037 {
1038 const char* geom = _geom ? _geom : GEOM() ;
1039 const char* name = spath::Name(geom, aux) ;
1040 return geom == nullptr ? nullptr : getenv(name) ;
1041 }
1042
1043 inline const char* spath::GEOMSub( const char* _geom){ return GEOM_Aux( _geom, "_GEOMSub" ); }
1044 inline const char* spath::GEOMWrap(const char* _geom){ return GEOM_Aux( _geom, "_GEOMWrap" ); }
1045 inline const char* spath::GEOMList(const char* _geom){ return GEOM_Aux( _geom, "_GEOMList" ); }
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064 inline char* spath::CFBaseFromGEOM(const char* _geom)
1065 {
1066 const char* geom = GEOM(_geom);
1067 char* name = spath::Name_(geom ? geom : "MISSING_GEOM", "_CFBaseFromGEOM") ;
1068 char* path = geom == nullptr ? nullptr : getenv(name) ;
1069
1070 if(VERBOSE) std::cout
1071 << "spath::CFBaseFromGEOM"
1072 << " geom " << ( geom ? geom : "-" )
1073 << " name " << ( name ? name : "-" )
1074 << " path " << ( path ? path : "-" )
1075 << "\n"
1076 ;
1077 return path ;
1078 }
1079
1080 inline bool spath::has_CFBaseFromGEOM(const char* _geom)
1081 {
1082 char* cfb = CFBaseFromGEOM(_geom);
1083 return cfb != nullptr ;
1084 }
1085
1086
1087 inline char* spath::GDMLPathFromGEOM(const char* _geom)
1088 {
1089 char* cfb = CFBaseFromGEOM(_geom);
1090 return cfb ? spath::Name_(cfb, "/origin.gdml") : nullptr ;
1091 }
1092
1093
1094 inline bool spath::is_readable(const char* base, const char* name)
1095 {
1096 std::stringstream ss ;
1097 if( base && name )
1098 {
1099 ss << base << "/" << name ;
1100 }
1101 else if( name )
1102 {
1103 ss << name ;
1104 }
1105 std::string s = ss.str();
1106 return is_readable(s.c_str());
1107 }
1108 inline bool spath::is_readable(const char* path_)
1109 {
1110 const char* path = path_ ? spath::Resolve(path_) : nullptr ;
1111 if( path == nullptr ) return false ;
1112 std::ifstream fp(path, std::ios::in|std::ios::binary);
1113 bool readable = !fp.fail();
1114 fp.close();
1115 return readable ;
1116 }
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132 inline int64_t spath::last_write_time(const char* path, bool dump)
1133 {
1134 int64_t lwt = 0 ;
1135
1136 #ifdef WITH_FILESYSTEM_NOT_WORKING
1137 std::filesystem::path p(path);
1138 std::filesystem::file_time_type ftt = std::filesystem::last_write_time(p);
1139
1140
1141
1142
1143
1144
1145 using namespace std::chrono;
1146 auto sys_now = system_clock::now();
1147 auto fil_now = decltype(ftt)::clock::now();
1148
1149 int64_t t_sys = duration_cast<microseconds>(sys_now.time_since_epoch()).count() ;
1150 int64_t t_fil = duration_cast<microseconds>(fil_now.time_since_epoch()).count() ;
1151 int64_t t_ftt = duration_cast<microseconds>(ftt.time_since_epoch()).count() ;
1152
1153
1154
1155
1156 std::cout
1157 << " t_sys [" << t_sys << "]\n"
1158 << " t_fil [" << t_fil << "]\n"
1159 << " t_ftt [" << t_fil << "]\n"
1160 ;
1161 #else
1162
1163 struct stat fs;
1164 int rc = stat(path, &fs) ;
1165 std::time_t mtime = rc == 0 ? fs.st_mtime : 0 ;
1166
1167 if(dump)
1168 {
1169 char* str = std::asctime(std::localtime(&mtime));
1170 std::cout << "spath::last_write_time str [" << str << "]\n" ;
1171 }
1172
1173 using namespace std::chrono;
1174 const auto from = system_clock::from_time_t(mtime);
1175 lwt = duration_cast<microseconds>(from.time_since_epoch()).count();
1176 #endif
1177 return lwt ;
1178 }
1179
1180
1181
1182