File indexing completed on 2026-04-09 07:49:43
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <string>
0021 #include <cstring>
0022 #include <csignal>
0023 #include <cassert>
0024 #include <sstream>
0025 #include <fstream>
0026 #include <iostream>
0027
0028
0029 #include <cstring>
0030 #include <cstdlib>
0031 #include <cstdio>
0032 #include <errno.h>
0033
0034
0035 #include <sys/stat.h>
0036 #include <unistd.h> // for chdir
0037
0038
0039 #include "SStr.hh"
0040 #include "SPath.hh"
0041 #include "SOpticksResource.hh"
0042 #include "SLOG.hh"
0043
0044
0045 const plog::Severity SPath::LEVEL = SLOG::EnvLevel("SPath", "DEBUG");
0046
0047
0048 const char* SPath::Stem( const char* name )
0049 {
0050 std::string arg = name ;
0051 std::string base = arg.substr(0, arg.find_last_of(".")) ;
0052 return strdup( base.c_str() ) ;
0053 }
0054
0055 bool SPath::IsReadable(const char* base, const char* name)
0056 {
0057 std::stringstream ss ;
0058 ss << base << "/" << name ;
0059 std::string s = ss.str();
0060 return IsReadable(s.c_str());
0061 }
0062 bool SPath::IsReadable(const char* path)
0063 {
0064 std::ifstream fp(path, std::ios::in|std::ios::binary);
0065 bool readable = !fp.fail();
0066 fp.close();
0067 return readable ;
0068 }
0069
0070 const char* SPath::GetHomePath(const char* rel)
0071 {
0072 char* home = getenv("HOME");
0073 assert(home);
0074 std::stringstream ss ;
0075 ss << home ;
0076 if(rel != NULL) ss << "/" << rel ;
0077 std::string path = ss.str();
0078 return strdup(path.c_str()) ;
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091 const char* SPath::Dirname(const char* path)
0092 {
0093 std::string p = path ;
0094 std::size_t pos = p.find_last_of("/");
0095 std::string dir = pos == std::string::npos ? p : p.substr(0,pos) ;
0096 return strdup( dir.c_str() ) ;
0097 }
0098
0099
0100 const char* SPath::ChangeName(const char* srcpath, const char* name)
0101 {
0102 const char* dir = Dirname(srcpath);
0103 std::stringstream ss ;
0104 ss << dir << "/" << name ;
0105 free((void*)dir) ;
0106 std::string path = ss.str();
0107 return strdup( path.c_str() );
0108 }
0109
0110
0111 const char* SPath::Basename(const char* path)
0112 {
0113 std::string p = path ;
0114 std::size_t pos = p.find_last_of("/");
0115 std::string base = pos == std::string::npos ? p : p.substr(pos+1) ;
0116 return strdup( base.c_str() ) ;
0117 }
0118
0119 const char* SPath::UserTmpDir(const char* pfx, const char* user_envvar, const char* sub, char sep )
0120 {
0121 char* user = getenv(user_envvar);
0122 std::stringstream ss ;
0123 ss << pfx
0124 << sep
0125 << user
0126 << sep
0127 << sub
0128 ;
0129 std::string s = ss.str();
0130 return strdup(s.c_str());
0131 }
0132
0133 const char* SPath::Resolve(int create_dirs)
0134 {
0135 assert( create_dirs == NOOP || create_dirs == DIRPATH );
0136 return SPath::Resolve("$DefaultOutputDir", create_dirs);
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156 const char* SPath::Resolve(const char* spec_, int create_dirs)
0157 {
0158 assert( create_dirs == NOOP || create_dirs == DIRPATH || create_dirs == FILEPATH );
0159
0160 LOG(LEVEL)
0161 << " spec_ [" << spec_ << "]"
0162 << " create_dirs [" << create_dirs << "]"
0163 ;
0164
0165 if(!spec_) return nullptr ;
0166
0167 char* spec = strdup(spec_);
0168 char sep = '/' ;
0169 char* spec_sep = strchr(spec, sep);
0170 char* spec_end = strchr(spec, '\0') ;
0171
0172 LOG(LEVEL)
0173 << " spec " << spec
0174 << " spec_sep " << spec_sep
0175 << " spec_end " << spec_end
0176 ;
0177
0178 bool tok_rel = spec[0] == '$' && spec_sep && spec_end && spec_sep != spec_end ;
0179 bool tok_only = spec[0] == '$' && spec_sep == nullptr ;
0180
0181 std::stringstream ss ;
0182 if(tok_rel)
0183 {
0184 *spec_sep = '\0' ;
0185 const char* pfx = SOpticksResource::Get(spec+1);
0186 *spec_sep = sep ;
0187 const char* prefix = pfx ? pfx : UserTmpDir() ;
0188 ss << prefix << spec_sep ;
0189 }
0190 else if(tok_only)
0191 {
0192 const char* pfx = SOpticksResource::Get(spec+1);
0193 const char* prefix = pfx ? pfx : UserTmpDir() ;
0194 ss << prefix ;
0195 }
0196 else
0197 {
0198 ss << spec ;
0199 }
0200 std::string s = ss.str();
0201
0202 const char* path = s.c_str();
0203
0204 CreateDirs(path, create_dirs );
0205
0206 return strdup(path) ;
0207 }
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226 void SPath::CreateDirs(const char* path, int mode)
0227 {
0228 if(mode == 0) return ;
0229 const char* dirname = mode == 1 ? Dirname(path) : path ;
0230 int rc = MakeDirs(dirname) ;
0231
0232 if( rc != 0 ) std::cerr
0233 << "SPath::CreateDirs ERROR "
0234 << " path " << ( path ? path : "-" )
0235 << " mode " << mode
0236 << " dirname " << ( dirname ? dirname : "-" )
0237 << " rc " << rc
0238 << std::endl
0239 ;
0240
0241 assert( rc == 0 );
0242 }
0243
0244
0245
0246 const char* SPath::Resolve(const char* dir, const char* name, int create_dirs)
0247 {
0248 LOG(LEVEL)
0249 << " dir [" << dir << "]"
0250 << " name [" << ( name ? name : "-" )<< "]"
0251 << " create_dirs [" << create_dirs << "]"
0252 ;
0253
0254 std::stringstream ss ;
0255 if(dir) ss << dir ;
0256 if(name) ss << "/" << name ;
0257
0258 std::string s = ss.str();
0259 return Resolve(s.c_str(), create_dirs);
0260 }
0261
0262 const char* SPath::Resolve(const char* dir, const char* reldir, const char* name, int create_dirs)
0263 {
0264 LOG(LEVEL)
0265 << " dir [" << dir << "]"
0266 << " reldir [" << reldir << "]"
0267 << " name [" << name << "]"
0268 << " create_dirs [" << create_dirs << "]"
0269 ;
0270
0271 std::stringstream ss ;
0272 if(dir) ss << dir ;
0273 if(reldir) ss << "/" << reldir ;
0274 if(name) ss << "/" << name ;
0275
0276 std::string s = ss.str();
0277 return Resolve(s.c_str(), create_dirs);
0278 }
0279
0280 const char* SPath::Resolve(const char* dir, const char* reldir, const char* rel2dir, const char* name, int create_dirs)
0281 {
0282 LOG(LEVEL)
0283 << " dir [" << dir << "]"
0284 << " reldir [" << reldir << "]"
0285 << " rel2dir [" << rel2dir << "]"
0286 << " name [" << name << "]"
0287 << " create_dirs [" << create_dirs << "]"
0288 ;
0289
0290 std::stringstream ss ;
0291 if(dir) ss << dir ;
0292 if(reldir) ss << "/" << reldir ;
0293 if(rel2dir) ss << "/" << rel2dir ;
0294 if(name) ss << "/" << name ;
0295 std::string s = ss.str();
0296 return Resolve(s.c_str(), create_dirs);
0297 }
0298
0299
0300
0301 const char* SPath::Resolve(const char* dir, const char* reldir, const char* rel2dir, const char* rel3dir, const char* name, int create_dirs)
0302 {
0303 LOG(LEVEL)
0304 << " dir [" << dir << "]"
0305 << " reldir [" << reldir << "]"
0306 << " rel2dir [" << rel2dir << "]"
0307 << " rel3dir [" << rel3dir << "]"
0308 << " name [" << name << "]"
0309 << " create_dirs [" << create_dirs << "]"
0310 ;
0311
0312 std::stringstream ss ;
0313 if(dir) ss << dir ;
0314 if(reldir) ss << "/" << reldir ;
0315 if(rel2dir) ss << "/" << rel2dir ;
0316 if(rel3dir) ss << "/" << rel3dir ;
0317 if(name) ss << "/" << name ;
0318
0319 std::string s = ss.str();
0320 return Resolve(s.c_str(), create_dirs);
0321 }
0322
0323
0324
0325 const char* SPath::Resolve(const char* dir, int idx, int create_dirs)
0326 {
0327 bool prefix = true ;
0328 return SPath::Resolve(dir, SStr::FormatIndex(idx, prefix), create_dirs);
0329 }
0330 const char* SPath::Resolve(const char* dir, const char* name, int idx, int create_dirs)
0331 {
0332 bool prefix = true ;
0333 return SPath::Resolve(dir, name, SStr::FormatIndex(idx, prefix), create_dirs);
0334 }
0335 const char* SPath::Resolve(const char* dir, const char* reldir, const char* name, int idx, int create_dirs)
0336 {
0337 bool prefix = true ;
0338 return SPath::Resolve(dir, reldir, name, SStr::FormatIndex(idx, prefix), create_dirs);
0339 }
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350 bool SPath::LooksLikePath(const char* path)
0351 {
0352 if(!path) return false ;
0353 if(strlen(path) < 2) return false ;
0354 return path[0] == '/' || path[0] == '$' ;
0355 }
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365 int SPath::MakeDirs( const char* path_, int mode_ )
0366 {
0367 mode_t default_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ;
0368 mode_t mode = mode_ == 0 ? default_mode : mode_ ;
0369
0370 char* path = strdup(path_);
0371 char* p = path ;
0372 int rc = 0 ;
0373
0374 while (*p != '\0' && rc == 0)
0375 {
0376 p++;
0377 while(*p != '\0' && *p != '/') p++;
0378 char v = *p;
0379 *p = '\0' ;
0380
0381 rc = mkdir(path, mode) == -1 && errno != EEXIST ? 1 : 0 ;
0382 *p = v;
0383 }
0384 free(path);
0385 return rc ;
0386 }
0387
0388 void SPath::chdir(const char* path, int create_dirs)
0389 {
0390 assert( create_dirs == 0 || create_dirs == 2 );
0391
0392 const char* p = SPath::Resolve(path, create_dirs);
0393
0394 int rc = ::chdir(p) ;
0395 std::cout << "SPath::chdir " << p << " rc " << rc << std::endl ;
0396
0397 assert( rc == 0 );
0398 }
0399
0400 const char* SPath::getcwd()
0401 {
0402 char path[100] ;
0403 char* ret = ::getcwd(path, 100);
0404 return ret == nullptr ? nullptr : strdup(path);
0405 }
0406
0407 void SPath::MakeEmpty(const char* path_)
0408 {
0409 const char* path = SPath::Resolve(path_, FILEPATH);
0410 std::ofstream fp(path);
0411 }
0412
0413 bool SPath::Exists(const char* path_)
0414 {
0415 const char* path = SPath::Resolve(path_, FILEPATH);
0416 std::ifstream fp(path, std::ios::in|std::ios::binary);
0417 return fp.fail() ? false : true ;
0418 }
0419
0420 bool SPath::Exists(const char* base, const char* relf)
0421 {
0422 const char* path = SPath::Resolve(base, relf, FILEPATH);
0423 std::ifstream fp(path, std::ios::in|std::ios::binary);
0424 return fp.fail() ? false : true ;
0425 }
0426
0427
0428
0429
0430
0431 const char* SPath::PickFirstExisting(const char* path0, const char* path1, const char* path2 )
0432 {
0433 if(SPath::Exists(path0)) return path0 ;
0434 if(SPath::Exists(path1)) return path1 ;
0435 if(SPath::Exists(path2)) return path2 ;
0436 return nullptr ;
0437 }
0438
0439
0440 int SPath::Remove(const char* path_)
0441 {
0442 const char* path = SPath::Resolve(path_, FILEPATH);
0443 assert( strlen(path) > 2 );
0444 return remove(path);
0445 }
0446
0447
0448 void SPath::Copy( const char* dst__, const char* src__ )
0449 {
0450 const char* src_ = SPath::Resolve( src__, NOOP );
0451 const char* dst_ = SPath::Resolve( dst__, FILEPATH );
0452
0453 bool same = strcmp(dst_, src_) == 0 ;
0454 if(same) std::cerr << "SPath::Copy : ERR SAME " << std::endl ;
0455 if(same) std::raise(SIGINT) ;
0456 assert( same == false );
0457
0458 std::ifstream src(src_, std::ios::binary);
0459 std::ofstream dst(dst_, std::ios::binary);
0460 dst << src.rdbuf();
0461 }
0462
0463 void SPath::Copy( const char* dstname, const char* srcname, const char* dir )
0464 {
0465 const char* src_ = SPath::Resolve( dir, srcname, NOOP );
0466 const char* dst_ = SPath::Resolve( dir, dstname, FILEPATH );
0467
0468 bool same = strcmp(dst_, src_) == 0 ;
0469 if(same) std::cerr << "SPath::Copy : ERR SAME " << std::endl ;
0470 if(same) std::raise(SIGINT) ;
0471 assert( same == false );
0472
0473 std::ifstream src(src_, std::ios::binary);
0474 std::ofstream dst(dst_, std::ios::binary);
0475 dst << src.rdbuf();
0476 }
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491 int SPath::mtime(const char* base, const char* name)
0492 {
0493 std::stringstream ss ;
0494 ss << base << "/" << name ;
0495 std::string s = ss.str();
0496 return mtime(s.c_str());
0497 }
0498
0499 int SPath::mtime(const char* path)
0500 {
0501 struct stat st;
0502 int ierr = stat(path, &st );
0503 int mtime = st.st_mtime;
0504 return ierr == 0 ? mtime : 0 ;
0505 }
0506
0507
0508
0509 template<typename T>
0510 const char* SPath::MakePath( const char* prefix, const char* reldir, const T real, const char* name)
0511 {
0512 const char* sreal = SStr::FormatReal<T>(real, 6, 4, '0');
0513 int create_dirs = 2 ;
0514 const char* fold = SPath::Resolve(prefix, reldir, sreal, create_dirs );
0515 const char* path = SPath::Resolve(fold, name, 0 ) ;
0516 return path ;
0517 }
0518
0519 template const char* SPath::MakePath<float>( const char*, const char*, const float, const char* );
0520 template const char* SPath::MakePath<double>( const char*, const char*, const double, const char* );
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541 std::string SPath::MakeName( const char* stem, int index, const char* ext )
0542 {
0543 std::string name ;
0544 if( index > -1 )
0545 {
0546 if( stem && ext )
0547 {
0548 name = SStr::Format("%s%0.5d%s", stem, index, ext ) ;
0549 }
0550 else if( stem == nullptr && ext )
0551 {
0552 name = SStr::Format("%0.5d%s", index, ext ) ;
0553 }
0554 }
0555 else
0556 {
0557 if( stem && ext )
0558 {
0559 std::stringstream ss ;
0560 ss << stem << ext ;
0561 name = ss.str();
0562 }
0563 else if( stem == nullptr && ext )
0564 {
0565 name = ext ;
0566 }
0567 }
0568 return name ;
0569 }
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586 const char* SPath::Make( const char* base, const char* reldir, const char* stem, int index, const char* ext, int create_dirs )
0587 {
0588 assert( create_dirs == NOOP || create_dirs == FILEPATH );
0589 std::string name = MakeName(stem, index, ext);
0590 const char* path = SPath::Resolve(base, reldir, name.c_str(), create_dirs ) ;
0591 return path ;
0592 }
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602 const char* SPath::Make( const char* base, const char* reldir, const char* reldir2, const char* stem, int index, const char* ext, int create_dirs )
0603 {
0604 assert( create_dirs == NOOP || create_dirs == FILEPATH );
0605 std::string name = MakeName(stem, index, ext);
0606 const char* path = SPath::Resolve(base, reldir, reldir2, name.c_str(), create_dirs ) ;
0607 return path ;
0608 }
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620 const char* SPath::SearchDirUpTreeWithFile( const char* startdir, const char* relf )
0621 {
0622 if(startdir == nullptr || relf == nullptr) return nullptr ;
0623 char* dir = strdup(startdir) ;
0624 while(dir && strlen(dir) > 1)
0625 {
0626 if(SPath::Exists(dir, relf)) break ;
0627 char* last = strrchr(dir, '/');
0628 *last = '\0' ;
0629 }
0630 return ( dir && strlen(dir) > 1 ) ? strdup(dir) : nullptr ;
0631 }
0632
0633
0634
0635
0636 template<typename ... Args>
0637 std::string SPath::Join_( Args ... args_ )
0638 {
0639 std::vector<std::string> args = {args_...};
0640 std::vector<std::string> elem ;
0641
0642 for(unsigned i=0 ; i < args.size() ; i++)
0643 {
0644 const std::string& arg = args[i] ;
0645 if(!arg.empty()) elem.push_back(arg);
0646 }
0647
0648 unsigned num_elem = elem.size() ;
0649 std::stringstream ss ;
0650 for(unsigned i=0 ; i < num_elem ; i++)
0651 {
0652 const std::string& ele = elem[i] ;
0653 ss << ele << ( i < num_elem - 1 ? "/" : "" ) ;
0654 }
0655 std::string s = ss.str();
0656 return s ;
0657 }
0658
0659 template std::string SPath::Join_( const char*, const char* );
0660 template std::string SPath::Join_( const char*, const char*, const char* );
0661 template std::string SPath::Join_( const char*, const char*, const char*, const char* );
0662
0663 template<typename ... Args>
0664 const char* SPath::Join( Args ... args )
0665 {
0666 std::string s = Join_(args...) ;
0667 return strdup(s.c_str()) ;
0668 }
0669
0670 template const char* SPath::Join( const char*, const char* );
0671 template const char* SPath::Join( const char*, const char*, const char* );
0672 template const char* SPath::Join( const char*, const char*, const char*, const char* );
0673
0674
0675