Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:43

0001 /*
0002  * Copyright (c) 2019 Opticks Team. All Rights Reserved.
0003  *
0004  * This file is part of Opticks
0005  * (see https://bitbucket.org/simoncblyth/opticks).
0006  *
0007  * Licensed under the Apache License, Version 2.0 (the "License"); 
0008  * you may not use this file except in compliance with the License.  
0009  * You may obtain a copy of the License at
0010  *
0011  *   http://www.apache.org/licenses/LICENSE-2.0
0012  *
0013  * Unless required by applicable law or agreed to in writing, software 
0014  * distributed under the License is distributed on an "AS IS" BASIS, 
0015  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  
0016  * See the License for the specific language governing permissions and 
0017  * limitations under the License.
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 // Linux specific, but works on Darwin via some compat presumably  
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 ) // static
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)  // static 
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)  // static 
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)  // static 
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 SPath::Dirname
0083 -----------------
0084 
0085 ::
0086 
0087    SPath::Dirname("/some/path/with/some/last/elem") ->  "/some/path/with/some/last"
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  ) // static 
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 SPath::Resolve
0141 ---------------
0142 
0143 Resolves tokenized paths such as "$TOKEN/name.ext" or "$TOKEN" 
0144 where the TOKEN string is passed to SOpticksResource::Get("TOKEN") 
0145 for resolution. TOKEN strings matching standard keys : IDPath, CFBase, ... 
0146 yield the standard directories that are derived from the OPTICKS_KEY.  
0147 However these defaults may be overridden by setting envvars with keys 
0148 matching the standard keys. 
0149 
0150 When the SOpticksResource resolution does not yield a value a 
0151 default of the standard $TMP dir of form "/tmp/username/opticks" 
0152 is used for the prefix directory. 
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_);            // copy to allow modifications 
0168     char sep = '/' ; 
0169     char* spec_sep = strchr(spec, sep);    // pointer to first separator : so spec_sep is string starting from the first sep 
0170     char* spec_end = strchr(spec, '\0') ;  // pointer to null terminator
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' ;                 // temporarily null terminate at the first slash  
0185         const char* pfx = SOpticksResource::Get(spec+1);      // start one past the dollar terminated at first slash  
0186         *spec_sep = sep ;                  // put back the separator
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 SPath::CreateDirs
0212 --------------------
0213 
0214 mode:0 
0215     do nothing 
0216 
0217 mode:1
0218     create directories assuming the path argument is a file path by using SPath::Dirname 
0219     to extract the directory
0220 
0221 mode:2
0222     create directories assuming the path argumnent is a directory path 
0223 
0224 **/
0225 
0226 void SPath::CreateDirs(const char* path, int mode)  // static 
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 SPath::MakeDirs
0359 ----------------
0360 
0361 See sysrap/tests/mkdirp.cc
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++;                                 // advance past leading character, probably slash, and subsequent slashes the next line gets to  
0377         while(*p != '\0' && *p != '/') p++;  // advance p until subsequent slash 
0378         char v = *p;                         // store the slash      
0379         *p = '\0' ;                          // replace slash with string terminator
0380         //printf("%s\n", path );                   
0381         rc = mkdir(path, mode) == -1 && errno != EEXIST ? 1 : 0 ;  // set rc non-zero for mkdir errors other than exists already  
0382         *p = v;                              // put back the slash  
0383     }       
0384     free(path);
0385     return rc ;
0386 }
0387 
0388 void SPath::chdir(const char* path, int create_dirs)  // static
0389 {
0390     assert( create_dirs == 0 || create_dirs == 2 );   // 0:do nothing OR 2:dirpath
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()  // static
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_) // static 
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) // static 
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 SPath::mtime
0485 --------------
0486 
0487 This is used by STime::mtime which provides formatted time stamp strings. 
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)  // static
0511 {
0512     const char* sreal = SStr::FormatReal<T>(real, 6, 4, '0');
0513     int create_dirs = 2 ;  // 2:dirpath
0514     const char* fold = SPath::Resolve(prefix, reldir, sreal, create_dirs ); 
0515     const char* path = SPath::Resolve(fold, name, 0 ) ;  // 0:create_dirs nop
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 SPath::MakeName
0525 ------------------
0526 
0527 Form a name from the arguments::
0528 
0529     <stem><index><ext>
0530 
0531 stem
0532     can be null
0533 index
0534     ignored when < 0, otherwise yields %0.5d formatted string 
0535 ext 
0536     typically includes dot, eg ".jpg" or ".npy"
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 SPath::Make
0574 -------------
0575 
0576 Creates a path from the arguments::
0577 
0578     <base>/<reldir>/<stem><index><ext>
0579 
0580 * base and relname can be nullptr 
0581 * the stem index and ext are formatted using SPath::MakeName
0582 * directory is created 
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 SPath::Make
0596 -------------
0597 
0598     <base>/<reldir>/<reldir2>/<stem><index><ext>
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 SPath::SearchDirUpTreeWithFile
0613 -------------------------------
0614 
0615 Search up the directory tree starting from *startdir* for 
0616 a directory that contains an existing relative filepath *relf*  
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' ;  // move the null termination inwards from right, going up directory by directory 
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