Back to home page

EIC code displayed by LXR

 
 

    


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

0001 #pragma once
0002 /**
0003 ssys.h
0004 ========
0005 
0006 Note that strings like "1e-9" parse ok into float/double.
0007 
0008 **/
0009 
0010 #include <cstdlib>
0011 #include <cassert>
0012 #include <cstring>
0013 #include <string>
0014 #include <regex>
0015 #include <sstream>
0016 #include <vector>
0017 #include <iostream>
0018 #include <iomanip>
0019 #include <map>
0020 #include <limits>
0021 #include <cstdint>
0022 
0023 #include "sstr.h"
0024 #include "spath.h"
0025 
0026 extern char **environ;
0027 
0028 struct ssys
0029 {
0030     static constexpr const bool VERBOSE = false ;
0031     static constexpr const char* GETENVVAR_PATH_PREFIX = "filepath:" ;
0032 
0033 
0034     static std::string popen(const char* cmd, bool chomp=true, int* rc=nullptr);
0035     static std::string popen(const char* cmda, const char* cmdb, bool chomp=true, int* rc=nullptr);
0036 
0037     static std::string uname(const char* args="-a");
0038     static std::string which(const char* script);
0039 
0040     static bool value_is_path_prefixed(const char* val );
0041     static const char* get_replacement_path(const char* val );
0042 
0043     static std::string getenviron(const char* q=nullptr);
0044     static bool is_under_ctest();
0045 
0046     static const char* getenvvar(const char* ekey );
0047     static const char* getenvvar(const char* ekey, const char* fallback);
0048     static const char* getenvvar(const char* ekey, const char* fallback, char q, char r );
0049 
0050 
0051     //static int getenv_ParseInt(const char* ekey, const char* fallback);
0052     //static std::vector<int>* getenv_ParseIntSpecList(const char* ekey, const char* fallback);
0053 
0054     static int64_t getenv_ParseInt64(const char* ekey, const char* fallback);
0055     static std::vector<int64_t>* getenv_ParseInt64SpecList(const char* ekey, const char* fallback);
0056 
0057     static unsigned long long getenvull(const char* ekey, unsigned long long fallback);
0058     static int getenvint(const char* ekey, int fallback);
0059     static int64_t getenvint64(const char* ekey, int64_t fallback);
0060     //static int getenvintspec( const char* ekey, const char* fallback);
0061     static int64_t  getenvint64spec( const char* ekey, const char* fallback);
0062     static uint64_t getenvuint64spec(const char* ekey, const char* fallback );
0063 
0064     static int getenvintpick( const char* ekey, const std::vector<std::string>& strs, int fallback );
0065 
0066     static unsigned getenvunsigned(const char* ekey, unsigned fallback);
0067     static unsigned getenvunsigned_fallback_max(const char* ekey );
0068 
0069 
0070 
0071     static double   getenvdouble(const char* ekey, double fallback);
0072     static float    getenvfloat(const char* ekey, float fallback);
0073     static bool     getenvbool(const char* ekey);
0074 
0075 
0076     static int countenv(const char* ekey, char delim=',');
0077 
0078     static bool hasenv_(const char* ekey);
0079     static bool hastoken_(const char* ekey);
0080     static char* _getenv(const char* ekey);
0081     static char* replace_envvar_token(const char* ekey);  // checks for token
0082     static char* _replace_envvar_token(const char* ekey); // MUST have token
0083     static char* _tokenized_getenv(const char* ekey);
0084 
0085 
0086     template<typename T>
0087     static T parse(const char* str);
0088 
0089 
0090     template<typename T>
0091     static T getenv_(const char* ekey, T fallback);
0092 
0093     template<typename T>
0094     static void getenv_(std::vector<std::pair<std::string, T>>& kv, const std::vector<std::string>& kk );
0095 
0096     template<typename T>
0097     static void getenv_(std::vector<std::pair<std::string, T>>& kv, const char* kk );
0098 
0099     template<typename T>
0100     static void fill_vec( std::vector<T>& vec, const char* line, char delim=',' );
0101 
0102     template<typename T>
0103     static void fill_evec( std::vector<T>& vec, const char* ekey, const char* fallback, char delim );
0104 
0105 
0106     template<typename T>
0107     static std::vector<T>* make_vec(const char* line, char delim=',');
0108 
0109     template<typename T>
0110     static std::vector<T>* getenv_vec(const char* ekey, const char* fallback, char delim=',');
0111 
0112     // THESE METHODS ARE TO ASSIST MIGRATION FROM THE OLD SSys.hh
0113     static std::vector<int>*   getenvintvec( const char* envkey, char delim=',');
0114     static void getenvintvec( const char* ekey, std::vector<int>& vec, char delim, const char* fallback ) ;
0115     static std::vector<float>* getenvfloatvec(const char* envkey, const char* fallback, char delim=',');
0116 
0117 
0118     template<typename T>
0119     static std::string desc_vec( const std::vector<T>* vec, unsigned edgeitems=5 );
0120 
0121     static int  idx_listed( const std::vector<std::string>* nn, const char* n );
0122     static bool  is_listed( const std::vector<std::string>* nn, const char* n );
0123     static int              listed_count(       std::vector<int>* ncount, const std::vector<std::string>* nn, const char* n );
0124     static std::string desc_listed_count( const std::vector<int>* ncount, const std::vector<std::string>* nn );
0125 
0126     static bool is_remote_session();
0127     static const char* username();
0128 
0129     static void Dump(const char* msg);
0130     static int run(const char* cmd);
0131 
0132     static int setenvvar( const char* ekey, const char* value, bool overwrite=true, char special_empty_token='\0' );
0133     static int setenvmap( const std::map<std::string, std::string>& env, bool overwrite=true , char special_empty_token='\0' );
0134 
0135     template<typename ... Args>
0136     static int setenvctx( Args ... args  );
0137 
0138     static std::string Desc();
0139     static std::string PWD();
0140 
0141     static void getenv_with_prefix(std::vector<std::pair<std::string,std::string>>& kvs, const char* prefix) ;
0142 
0143 
0144 };
0145 
0146 
0147 inline std::string ssys::popen(const char* cmd, bool chomp, int* rc)
0148 {
0149     std::stringstream ss ;
0150     FILE *fp = ::popen(cmd, "r");
0151     char line[512];
0152     while (fgets(line, sizeof(line), fp) != NULL)
0153     {
0154        if(chomp) line[strcspn(line, "\n")] = 0;
0155        ss << line ;
0156     }
0157 
0158     int retcode=0 ;
0159     int st = pclose(fp);
0160     if(WIFEXITED(st)) retcode=WEXITSTATUS(st);
0161 
0162     if(rc) *rc = retcode ;
0163 
0164     std::string s = ss.str();
0165     return s ;
0166 }
0167 
0168 inline std::string ssys::popen(const char* cmda, const char* cmdb, bool chomp, int* rc)
0169 {
0170     std::stringstream ss ;
0171     if(cmda) ss << cmda ;
0172     ss << " " ;
0173     if(cmdb) ss << cmdb ;
0174 
0175     std::string s = ss.str();
0176     return popen(s.c_str(), chomp, rc );
0177 }
0178 
0179 inline std::string ssys::uname(const char* args)
0180 {
0181     bool chomp = true ;
0182     int rc(0);
0183     std::string line = ssys::popen("uname", args, chomp, &rc );
0184     return rc == 0 ? line : "" ;
0185 }
0186 
0187 
0188 inline std::string ssys::which(const char* script)
0189 {
0190     bool chomp = true ;
0191     int rc(0);
0192     std::string path = ssys::popen("which 2>/dev/null", script, chomp, &rc );
0193 
0194     if(VERBOSE) std::cerr
0195          << " script " << script
0196          << " path " << path
0197          << " rc " << rc
0198          << std::endl
0199          ;
0200 
0201     std::string empty ;
0202     return rc == 0 ? path : empty ;
0203 }
0204 
0205 
0206 
0207 inline bool ssys::value_is_path_prefixed(const char* val )
0208 {
0209     return val && strlen(val) > strlen(GETENVVAR_PATH_PREFIX) && strncmp(val, GETENVVAR_PATH_PREFIX, strlen(GETENVVAR_PATH_PREFIX)) == 0 ;
0210 }
0211 
0212 inline const char* ssys::get_replacement_path(const char* val )
0213 {
0214     assert(value_is_path_prefixed(val)) ;
0215     return val ? strdup(val + strlen(GETENVVAR_PATH_PREFIX)) : nullptr ;
0216 }
0217 
0218 
0219 
0220 inline std::string ssys::getenviron(const char* q)
0221 {
0222     char** e = environ ;
0223     std::stringstream ss ;
0224     while(*e)
0225     {
0226         if( q == nullptr || strstr(*e, q)) ss << *e << "\n" ;
0227         e++ ;
0228     }
0229     std::string str = ss.str();
0230     return str;
0231 }
0232 
0233 inline bool ssys::is_under_ctest()
0234 {
0235     return countenv("DASHBOARD_TEST_FROM_CTEST,DART_TEST_FROM_DART", ',') > 0 ;
0236 }
0237 
0238 
0239 /**
0240 ssys::getenvvar
0241 ----------------
0242 
0243 For ekey with a comma such as "OPTICKS_ELV_SELECTION,ELV" the
0244 envvars are checked in order and the first to yield a value
0245 is returned.::
0246 
0247     OPTICKS_ELV_SELECTION=greetings ELV=hello ./ssys_test.sh
0248     test_getenvvar ekey OPTICKS_ELV_SELECTION,ELV val greetings
0249 
0250     OPTICKS_ELV_SELECTION_=greetings ELV=hello ./ssys_test.sh
0251     test_getenvvar ekey OPTICKS_ELV_SELECTION,ELV val hello
0252 
0253 
0254 If the string value of the envvar starts with GETENVVAR_PATH_PREFIX "filepath:"
0255 then the remainder of the string is intepreted as a file path which is loaded
0256 to replace the value or nullptr when no file is found.
0257 
0258 **/
0259 
0260 inline const char* ssys::getenvvar(const char* ekey)
0261 {
0262     std::vector<std::string> keys ;
0263     sstr::Split(ekey, ',', keys) ;
0264     char* val = getenv(ekey);
0265     for(unsigned i=0 ; i < keys.size() ; i++)
0266     {
0267         const char* key = keys[i].c_str();
0268         val = getenv(key) ;
0269         if( val != nullptr ) break ;
0270     }
0271 
0272     bool is_path_prefixed = value_is_path_prefixed(val) ;
0273 
0274     /*
0275     std::cout << "ssys::getenvvar "
0276               << " ekey " << ( ekey ? ekey : "-" )
0277               << " val  " << ( val ? val : "-" )
0278               << " is_path_prefixed " << is_path_prefixed
0279               << std::endl
0280               ;
0281     */
0282 
0283     if(is_path_prefixed)
0284     {
0285         const char* path = get_replacement_path(val) ;
0286 
0287         std::string txt ;
0288         bool path_exists = spath::Read( txt, path );
0289         val = path_exists ? strdup(txt.c_str()) : nullptr ;
0290 
0291         if(VERBOSE) std::cout
0292             << "ssys::getenvvar.is_path_prefixed "
0293             << " ekey " << ( ekey ? ekey : "-" )
0294             << " path " << ( path ? path : "-" )
0295             << " path_exists " << ( path_exists ? "YES" : "NO " )
0296             << " val " << ( val ? val : "-" )
0297             << std::endl
0298             ;
0299 
0300     }
0301     return val ;
0302 }
0303 inline const char* ssys::getenvvar(const char* ekey, const char* fallback)
0304 {
0305     const char* val = getenvvar(ekey);
0306     return ( val && strlen(val)>0) ? val : fallback ;   // 2024/12 "" => fallback
0307 }
0308 inline const char* ssys::getenvvar(const char* ekey, const char* fallback, char q, char r)
0309 {
0310      const char* v = getenvvar(ekey, fallback) ;
0311      char* vv = v ? strdup(v) : nullptr  ;
0312      for(int i=0 ; i < int(vv ? strlen(vv) : 0) ; i++) if(vv[i] == q ) vv[i] = r ;
0313      return vv ;
0314 }
0315 
0316 
0317 /*
0318 inline int ssys::getenv_ParseInt(const char* ekey, const char* fallback)
0319 {
0320     const char* spec = getenvvar(ekey, fallback);
0321     bool valid = spec != nullptr && strlen(spec) > 0 ;
0322     if(!valid)
0323     {
0324         std::cerr
0325             << "ssys::getenv_ParseInt"
0326             << " ekey " << ( ekey ? ekey : "-" )
0327             << " fallback " << ( fallback ? fallback : "-" )
0328             << " spec [" << ( spec ? spec :  "-" ) << "]"
0329             << " valid " << ( valid ? "YES" : "NO " )
0330             << "\n"
0331             ;
0332 
0333         return -1 ;
0334     }
0335     return sstr::ParseInt<int>(spec) ;
0336 }
0337 */
0338 
0339 
0340 inline int64_t ssys::getenv_ParseInt64(const char* ekey, const char* fallback)
0341 {
0342     const char* spec = getenvvar(ekey, fallback);
0343     bool valid = spec != nullptr && strlen(spec) > 0 ;
0344     if(!valid)
0345     {
0346         std::cerr
0347             << "ssys::getenv_ParseInt64"
0348             << " ekey " << ( ekey ? ekey : "-" )
0349             << " fallback " << ( fallback ? fallback : "-" )
0350             << " spec [" << ( spec ? spec :  "-" ) << "]"
0351             << " valid " << ( valid ? "YES" : "NO " )
0352             << "\n"
0353             ;
0354 
0355         return -1 ;
0356     }
0357     return sstr::ParseInt<int64_t>(spec) ;
0358 }
0359 
0360 
0361 
0362 
0363 
0364 
0365 
0366 
0367 
0368 
0369 
0370 
0371 
0372 
0373 
0374 
0375 
0376 
0377 
0378 
0379 inline std::vector<int64_t>* ssys::getenv_ParseInt64SpecList(const char* ekey, const char* fallback)
0380 {
0381     const char* spec = getenvvar(ekey, fallback);
0382     bool valid = spec != nullptr && strlen(spec) > 0 ;
0383     if(!valid) return nullptr ;
0384     return sstr::ParseIntSpecList<int64_t>( spec, ',' );
0385 }
0386 
0387 
0388 inline unsigned long long ssys::getenvull(const char* ekey, unsigned long long fallback)
0389 {
0390     char* val = getenv(ekey);
0391     return val ? std::atoll(val) : fallback ;
0392 }
0393 
0394 
0395 
0396 inline int ssys::getenvint(const char* ekey, int fallback)
0397 {
0398     char* val = getenv(ekey);
0399     return val ? std::atoi(val) : fallback ;
0400 }
0401 
0402 inline int64_t ssys::getenvint64(const char* ekey, int64_t fallback)
0403 {
0404     char* val = getenv(ekey);
0405     return val ? std::atol(val) : fallback ;
0406 }
0407 
0408 
0409 
0410 
0411 /**
0412 ssys::getenvintspec
0413 --------------------
0414 
0415 Uses sstr::ParseInt to convert spec like M1 M2 k10 to integers.
0416 
0417 
0418 inline int ssys::getenvintspec(const char* ekey, const char* fallback)
0419 {
0420     char* val = getenv(ekey);
0421     const char* spec = val ? val : fallback ;
0422     int ival = sstr::ParseInt<int>( spec ? spec : "0" );
0423     return ival ;
0424 }
0425 
0426 **/
0427 
0428 
0429 
0430 inline int64_t ssys::getenvint64spec(const char* ekey, const char* fallback)
0431 {
0432     char* val = getenv(ekey);
0433     const char* spec = val ? val : fallback ;
0434     int64_t ival = sstr::ParseInt<int64_t>( spec ? spec : "0" );
0435     return ival ;
0436 }
0437 
0438 inline uint64_t ssys::getenvuint64spec(const char* ekey, const char* fallback)
0439 {
0440     char* val = getenv(ekey);
0441     const char* spec = val ? val : fallback ;
0442     uint64_t ival = sstr::ParseInt<uint64_t>( spec ? spec : "0" );
0443     return ival ;
0444 }
0445 
0446 
0447 inline int ssys::getenvintpick(const char* ekey, const std::vector<std::string>& strs, int fallback )
0448 {
0449     char* v = getenv(ekey);
0450     if(v == nullptr) return fallback ;
0451 
0452     int pick = fallback ;
0453     int num_str = strs.size() ;
0454     for(int i=0 ; i < num_str ; i++)
0455     {
0456         const char* str = strs[i].c_str();
0457         if( str && v && strcmp(str, v) == 0 )
0458         {
0459             pick = i ;
0460             break ;
0461         }
0462     }
0463     return pick ;
0464 }
0465 
0466 
0467 
0468 
0469 
0470 
0471 
0472 inline unsigned ssys::getenvunsigned(const char* ekey, unsigned fallback)
0473 {
0474     int ival = getenvint(ekey, int(fallback));
0475     return ival > -1 ? ival : fallback ;
0476 }
0477 inline unsigned ssys::getenvunsigned_fallback_max(const char* ekey)
0478 {
0479     return getenvunsigned(ekey, std::numeric_limits<unsigned>::max() );
0480 }
0481 
0482 
0483 inline bool ssys::getenvbool( const char* ekey )
0484 {
0485     char* val = getenv(ekey);
0486     bool ival = val ? true : false ;
0487 
0488     /*
0489     // special casing a value indicating NO ?
0490     if(val)
0491     {
0492         if(strcmp(val,"NO") == 0) ival = false ;
0493         if(strcmp(val,"no") == 0) ival = false ;
0494         if(strcmp(val,"False") == 0) ival = false ;
0495         if(strcmp(val,"false") == 0) ival = false ;
0496         if(strcmp(val,"0") == 0) ival = false ;
0497     }
0498     */
0499 
0500     return ival ;
0501 }
0502 
0503 inline float  ssys::getenvfloat( const char* ekey, float  fallback){ return getenv_<float>(ekey,  fallback) ; }
0504 inline double ssys::getenvdouble(const char* ekey, double fallback){ return getenv_<double>(ekey, fallback) ; }
0505 
0506 
0507 /**
0508 ssys::countenv
0509 ---------------
0510 
0511 **/
0512 
0513 inline int ssys::countenv(const char* ekey, char delim)
0514 {
0515     std::vector<std::string> keys ;
0516     sstr::Split(ekey, delim, keys) ;
0517 
0518     int count = 0 ;
0519     char* val = nullptr ;
0520     for(unsigned i=0 ; i < keys.size() ; i++)
0521     {
0522         const char* key = keys[i].c_str();
0523         val = getenv(key) ;
0524         if( val != nullptr ) count += 1 ;
0525     }
0526     return count ;
0527 }
0528 
0529 
0530 inline bool ssys::hasenv_(const char* ekey)
0531 {
0532     return ekey != nullptr && ( getenv(ekey) != nullptr ) ;
0533 }
0534 
0535 inline bool ssys::hastoken_(const char* ekey)
0536 {
0537     return ekey != nullptr && strstr(ekey, "${") != nullptr && strstr(ekey, "}") != nullptr ;
0538 }
0539 
0540 /**
0541 ssys::_getenv
0542 ---------------
0543 
0544 This handles higher order ekey such as "${GEOM}_GEOMList" when the environmnent is::
0545 
0546     export GEOM=FewPMT
0547     export ${GEOM}_GEOMList=hamaLogicalPMT
0548 
0549 **/
0550 
0551 inline char* ssys::_getenv(const char* ekey)
0552 {
0553     if(ekey == nullptr) return nullptr ;
0554     return !hastoken_(ekey) ? getenv(ekey) : _tokenized_getenv(ekey ) ;
0555 }
0556 
0557 /**
0558 ssys::replace_envvar_token
0559 ----------------------------
0560 
0561 NB spath::Resolve provides much more flexible tokenization replacement
0562 
0563 1. extract VAR from head of string "${VAR}rest-of-string"
0564 2. construct string with the "${VAR}" replaced with its value obtained from envvar lookup,
0565    when the envvar does not exist returns eg "VARrest-of-string"
0566 
0567 **/
0568 
0569 inline char* ssys::replace_envvar_token(const char* ekey)
0570 {
0571     return !hastoken_(ekey) ? strdup(ekey) : _replace_envvar_token(ekey ) ;
0572 }
0573 inline char* ssys::_replace_envvar_token(const char* ekey)
0574 {
0575     std::stringstream ss ;
0576 
0577     char* ek = strdup(ekey) ;
0578     char* o = strstr(ek, "${" );
0579     char* c = strstr(ek, "}" );
0580     char* t = c ? c+1 : nullptr ;
0581 
0582     if( o != ek )  // chars before the token
0583     {
0584         *o = '\0' ; // temporily terminate at the '$'
0585         ss << ek ;
0586     }
0587 
0588     o += 2 ;    // advance past "${"
0589     *c = '\0' ; // terminate at position of "}"
0590 
0591     char* ov = getenv(o) ;
0592     ss << ( ov ? ov : o ) << t ;
0593     std::string str = ss.str();
0594 
0595     return strdup(str.c_str()) ;
0596 }
0597 
0598 
0599 /**
0600 ssys::_tokenized_getenv (hmm maybe second_order_getenv better name)
0601 ---------------------------------------------------------------------
0602 
0603 1. replace the envvar token of form ${VAR} in the ekey argument
0604 2. assuming the resulting string is in itself an envvar look that up,
0605    otherwise just return the unexpanded string
0606 
0607 **/
0608 
0609 inline char* ssys::_tokenized_getenv(const char* ekey)
0610 {
0611     std::string str = _replace_envvar_token(ekey) ;
0612     char* k = strdup(str.c_str()) ;
0613     char* kv = getenv(k) ;
0614     return kv ? kv : k ;
0615 }
0616 
0617 
0618 
0619 
0620 template<typename T>
0621 inline T ssys::parse(const char* str_)
0622 {
0623     std::string str(str_);
0624     std::istringstream iss(str);
0625     T tval ;
0626     iss >> tval ;
0627     return tval ;
0628 }
0629 
0630 // template specialization for T=std::string
0631 // otherwise the parsed value is truncated to the first element prior to any
0632 // whitespace within the source value
0633 template<>
0634 inline std::string ssys::parse(const char* str_)
0635 {
0636     std::string str( str_ ? str_ : "" ) ;
0637     return str ;
0638 }
0639 
0640 template int      ssys::parse(const char*);
0641 template unsigned ssys::parse(const char*);
0642 template float    ssys::parse(const char*);
0643 template double   ssys::parse(const char*);
0644 
0645 
0646 
0647 template<typename T>
0648 inline T ssys::getenv_(const char* ekey, T fallback)
0649 {
0650     char* v = getenv(ekey);
0651     int len = v ? strlen(v) : 0 ;
0652     return len == 0  ? fallback : parse<T>(v) ;
0653 }
0654 
0655 template int      ssys::getenv_(const char*, int );
0656 template unsigned ssys::getenv_(const char*, unsigned );
0657 template float    ssys::getenv_(const char*, float );
0658 template double   ssys::getenv_(const char*, double );
0659 template std::string ssys::getenv_(const char*, std::string );
0660 
0661 
0662 
0663 
0664 
0665 
0666 
0667 template<typename T>
0668 void ssys::getenv_(std::vector<std::pair<std::string, T>>& kv, const std::vector<std::string>& kk )
0669 {
0670     typedef typename std::pair<std::string,T> KV ;
0671     for(int i=0 ; i < int(kk.size()) ; i++)
0672     {
0673         const char* k = kk[i].c_str() ;
0674         const char* v_ = _getenv(k) ;   // supports higher level tokenized envvars like ${GEOM}_GEOMList
0675         if(v_ == nullptr) continue ;
0676 
0677         T v = parse<T>(v_) ;
0678         kv.push_back(KV(k,v)) ;
0679     }
0680 }
0681 
0682 template<typename T>
0683 void ssys::getenv_(std::vector<std::pair<std::string, T>>& kv, const char* kk_ )
0684 {
0685     std::vector<std::string> kk ;
0686     std::stringstream ss(kk_) ;
0687     std::string line ;
0688     while (std::getline(ss, line))  // newlines are swallowed by getline
0689     {
0690        if(line.empty()) continue ;
0691        line = std::regex_replace(line, std::regex(R"(^\s+|\s+$)"), "");
0692        if(line.empty()) continue ;
0693        kk.push_back(line);
0694     }
0695     getenv_(kv, kk );
0696 }
0697 
0698 
0699 
0700 template<typename T>
0701 inline void ssys::fill_vec( std::vector<T>& vec, const char* line, char delim )
0702 {
0703     std::stringstream ss;
0704     ss.str(line);
0705     std::string s;
0706     while (std::getline(ss, s, delim))
0707     {
0708         if(delim == '\n' && sstr::IsWhitespace(s)) continue ;
0709         std::istringstream iss(s);
0710         T t ;
0711         iss >> t ;
0712         vec.push_back(t) ;
0713     }
0714 }
0715 
0716 template void ssys::fill_vec( std::vector<int>&         , const char*, char );
0717 template void ssys::fill_vec( std::vector<unsigned>&    , const char*, char );
0718 template void ssys::fill_vec( std::vector<float>&       , const char*, char );
0719 template void ssys::fill_vec( std::vector<double>&      , const char*, char );
0720 template void ssys::fill_vec( std::vector<std::string>& , const char*, char );
0721 
0722 
0723 
0724 template<typename T>
0725 inline void ssys::fill_evec(std::vector<T>& vec, const char* ekey, const char* fallback, char delim )
0726 {
0727     assert(fallback);
0728     char* line_ = getenv(ekey);
0729     if(line_ == nullptr && fallback == nullptr) return ;
0730     const char* line = line_ ? line_ : fallback ;
0731     fill_vec<T>( vec, line, delim );
0732 }
0733 
0734 template void ssys::fill_evec( std::vector<int>&         , const char*, const char*, char );
0735 template void ssys::fill_evec( std::vector<unsigned>&    , const char*, const char*, char );
0736 template void ssys::fill_evec( std::vector<float>&       , const char*, const char*, char );
0737 template void ssys::fill_evec( std::vector<double>&      , const char*, const char*, char );
0738 template void ssys::fill_evec( std::vector<std::string>& , const char*, const char*, char );
0739 
0740 
0741 template<typename T>
0742 inline std::vector<T>* ssys::make_vec(const char* line, char delim )
0743 {
0744     if(line == nullptr) return nullptr ;
0745     std::vector<T>* vec = new std::vector<T>() ;
0746     fill_vec<T>( *vec, line, delim );
0747     return vec ;
0748 }
0749 
0750 
0751 
0752 /**
0753 ssys::getenv_vec
0754 -----------------
0755 
0756 With fallback:nullptr lack of the envvar yields a nullptr
0757 
0758 **/
0759 
0760 
0761 template<typename T>
0762 inline std::vector<T>* ssys::getenv_vec(const char* ekey, const char* fallback, char delim )
0763 {
0764     char* line = getenv(ekey);
0765     bool valid = line && strlen(line) > 0 ;  // blanks line are not valid
0766     return make_vec<T>( valid ? line : fallback, delim );
0767 }
0768 
0769 
0770 template std::vector<int>*      ssys::getenv_vec(const char*, const char*, char );
0771 template std::vector<unsigned>* ssys::getenv_vec(const char*, const char*, char );
0772 template std::vector<float>*    ssys::getenv_vec(const char*, const char*, char );
0773 template std::vector<double>*   ssys::getenv_vec(const char*, const char*, char );
0774 template std::vector<std::string>*   ssys::getenv_vec(const char*, const char*, char );
0775 
0776 
0777 inline std::vector<int>* ssys::getenvintvec(const char* envkey, char delim)
0778 {
0779     return getenv_vec<int>(envkey, nullptr, delim);
0780 }
0781 
0782 inline void ssys::getenvintvec( const char* ekey, std::vector<int>& vec, char delim, const char* fallback )
0783 {
0784     fill_evec<int>( vec, ekey, fallback, delim );
0785 }
0786 
0787 
0788 
0789 
0790 inline std::vector<float>* ssys::getenvfloatvec(const char* envkey, const char* fallback, char delim)
0791 {
0792     return getenv_vec<float>(envkey, fallback, delim);
0793 }
0794 
0795 
0796 
0797 
0798 
0799 
0800 template<typename T>
0801 inline std::string ssys::desc_vec( const std::vector<T>* vec, unsigned edgeitems  )
0802 {
0803     unsigned size = vec ? vec->size() : 0 ;
0804 
0805     std::stringstream ss ;
0806     ss << "(" ;
0807     for(unsigned i=0 ; i < size ; i++) if(i < edgeitems || i > size - edgeitems ) ss << (*vec)[i] << " " ;
0808     ss << ")" ;
0809 
0810     std::string s = ss.str();
0811     return s;
0812 }
0813 
0814 
0815 template std::string ssys::desc_vec(const std::vector<int>* , unsigned ) ;
0816 template std::string ssys::desc_vec(const std::vector<unsigned>* , unsigned ) ;
0817 template std::string ssys::desc_vec(const std::vector<float>* , unsigned ) ;
0818 template std::string ssys::desc_vec(const std::vector<double>* , unsigned ) ;
0819 template std::string ssys::desc_vec(const std::vector<std::string>* , unsigned ) ;
0820 
0821 
0822 /**
0823 ssys::idx_listed
0824 ------------------
0825 
0826 * if n is found within nn returns the index in range 0 to size-1 inclusive
0827 * if n is not found returns size
0828 * if nn is null return -1
0829 
0830 **/
0831 
0832 inline int ssys::idx_listed( const std::vector<std::string>* nn, const char* n ) // static
0833 {
0834     return nn ? std::distance( nn->begin(), std::find( nn->begin(), nn->end(), n ) ) : -1 ;
0835 }
0836 
0837 inline bool ssys::is_listed( const std::vector<std::string>* nn, const char* n ) // static
0838 {
0839     int sz = nn ? nn->size() : 0 ;
0840     int idx = idx_listed(nn, n) ;
0841     return idx > -1 && idx < sz ;
0842 }
0843 
0844 /**
0845 ssys::listed_count
0846 --------------------
0847 
0848 1. ncount vector is resized to match the size of nn
0849 2. index of the n within nn is found
0850 3. count for that index is accessed from ncount vector
0851 4. ncount entry for the index is incremented
0852 5. count is returned providing a 0-based occurrence index
0853 
0854 **/
0855 inline int ssys::listed_count( std::vector<int>* ncount, const std::vector<std::string>* nn, const char* n )
0856 {
0857     if(nn == nullptr || ncount == nullptr) return -1 ;
0858     int sz = nn->size() ;
0859     ncount->resize(sz);
0860     int idx = idx_listed(nn,n) ;
0861     if(idx >= sz) return -1 ;
0862     int count = ncount->at(idx) ;
0863     (*ncount)[idx] += 1 ;
0864     return count ;
0865 }
0866 
0867 
0868 inline std::string ssys::desc_listed_count( const std::vector<int>* ncount, const std::vector<std::string>* nn )
0869 {
0870     int ncount_sz = ncount ? int(ncount->size()) : -1 ;
0871     int nn_sz = nn ? int(nn->size()) : -1 ;
0872 
0873     std::stringstream ss ;
0874     ss << "ssys::desc_listed_count"
0875        << " ncount_sz " << ncount_sz
0876        << " nn_sz " << nn_sz
0877        << std::endl
0878        ;
0879 
0880     if( ncount_sz == nn_sz && nn_sz > -1 )
0881     {
0882         for(int i=0 ; i < nn_sz ; i++ ) ss << std::setw(3) << i << " : " << (*ncount)[i] << " : " << (*nn)[i] << std::endl ;
0883     }
0884     std::string str = ss.str();
0885     return str ;
0886 }
0887 
0888 
0889 /**
0890 ssys::is_remote_session
0891 -------------------------
0892 
0893 Returns true when the environment has one or more of the below envvars::
0894 
0895     SSH_CLIENT
0896     SSH_TTY
0897 
0898 **/
0899 
0900 
0901 inline bool ssys::is_remote_session()
0902 {
0903     char* ssh_client = getenv("SSH_CLIENT");
0904     char* ssh_tty = getenv("SSH_TTY");
0905     bool is_remote = ssh_client != nullptr || ssh_tty != nullptr ;
0906     return is_remote ;
0907 }
0908 
0909 
0910 
0911 inline const char* ssys::username()
0912 {
0913 #ifdef _MSC_VER
0914     const char* user = ssys::getenvvar("USERNAME", "no-USERNAME") ;
0915 #else
0916     const char* user = ssys::getenvvar("USER", "no-USER" ) ;
0917 #endif
0918     return user ? user : "ssys-username-undefined" ;
0919 }
0920 
0921 
0922 
0923 
0924 /**
0925 ssys::Dump
0926 ------------
0927 
0928 Dump the message using std::cout std::cerr printf and std::printf, used for testing stream redirection
0929 
0930 **/
0931 
0932 inline void ssys::Dump(const char* msg)
0933 {
0934     static int COUNT = -1 ;
0935     COUNT++ ;
0936     std::cout << std::setw(3) << COUNT << "[" << std::setw(20) << "std::cout" << "] " << msg << std::endl;
0937     std::cerr << std::setw(3) << COUNT << "[" << std::setw(20) << "std::cerr" << "] " << msg << std::endl;
0938     printf("%3d[%20s] %s \n", COUNT, "printf", msg );
0939     std::printf("%3d[%20s] %s \n", COUNT, "std::printf", msg );
0940     std::cerr << std::endl  ;
0941 }
0942 
0943 
0944 inline int ssys::run(const char* cmd)
0945 {
0946     int rc_raw = system(cmd);
0947     int rc =  WEXITSTATUS(rc_raw) ;
0948 
0949     std::cout
0950         << "ssys::run "
0951         <<  ( cmd ? cmd : "-" )
0952         << " rc_raw : " << rc_raw
0953         << " rc : " << rc
0954         << std::endl
0955         ;
0956 
0957     if(rc != 0) std::cout
0958         << "ssys::run"
0959         << " PATH ENVVAR MISCONFIGURED ? "
0960         << std::endl
0961         ;
0962     return rc ;
0963 }
0964 
0965 
0966 
0967 
0968 /**
0969 ssys::setenvvar
0970 -----------------
0971 
0972 overwrite:false
0973     preexisting envvar is not overridden.
0974 
0975 "value[0] == special_empty_token" and special_empty_token not default '\0' (eg use '-')
0976     indicates want value to be empty string, avoiding inconvenient shell
0977     handling of empty strings
0978 
0979 
0980 **/
0981 
0982 
0983 inline int ssys::setenvvar( const char* ekey, const char* value, bool overwrite, char special_empty_token)
0984 {
0985     std::stringstream ss ;
0986     ss << ekey << "=" ;
0987 
0988     if(value)
0989     {
0990         if(special_empty_token != '\0' && strlen(value) == 1 && value[0] == special_empty_token)
0991         {
0992             ss << "" ;
0993         }
0994         else
0995         {
0996             ss << value ;
0997         }
0998     }
0999 
1000     std::string ekv = ss.str();
1001     const char* prior = getenv(ekey) ;
1002 
1003     char* ekv_ = const_cast<char*>(strdup(ekv.c_str()));
1004 
1005     int rc = ( overwrite || !prior ) ? putenv(ekv_) : 0  ;
1006 
1007     const char* after = getenv(ekey) ;
1008 
1009     if(VERBOSE) std::cerr
1010         << "ssys::setenvvar"
1011         << " ekey " << ekey
1012         << " ekv " << ekv
1013         << " overwrite " << overwrite
1014         << " prior " << ( prior ? prior : "NULL" )
1015         << " value " << ( value ? value : "NULL" )
1016         << " after " << ( after ? after : "NULL" )
1017         << " rc " << rc
1018         << std::endl
1019         ;
1020 
1021     //std::raise(SIGINT);
1022     return rc ;
1023 }
1024 
1025 
1026 inline int ssys::setenvmap( const std::map<std::string, std::string>& env, bool overwrite, char special_empty_token )
1027 {
1028     typedef std::map<std::string, std::string>  MSS ;
1029     for(MSS::const_iterator it=env.begin() ; it != env.end() ; it++)
1030     {
1031         const std::string& key = it->first ;
1032         const std::string& val = it->second ;
1033         setenvvar(key.c_str(), val.c_str(), overwrite, special_empty_token );
1034     }
1035     return 0 ;
1036 }
1037 
1038 
1039 template<typename ... Args>
1040 inline int ssys::setenvctx( Args ... args_  )
1041 {
1042     std::vector<std::string> args = {args_...};
1043     std::vector<std::string> elem ;
1044 
1045     for(unsigned i=0 ; i < args.size() ; i++)
1046     {
1047         const std::string& arg = args[i] ;
1048         if(!arg.empty()) elem.push_back(arg);
1049     }
1050 
1051     unsigned num_elem = elem.size() ;
1052     assert( num_elem % 2 == 0 );
1053 
1054     bool overwrite = true ;
1055     char special_empty_token = '\0' ;
1056 
1057     for(unsigned i=0 ; i < num_elem/2 ; i++)
1058     {
1059         const std::string& key = elem[2*i+0] ;
1060         const std::string& val = elem[2*i+1] ;
1061         setenvvar(key.c_str(), val.c_str(), overwrite, special_empty_token );
1062     }
1063     return 0 ;
1064 }
1065 
1066 
1067 template int ssys::setenvctx(
1068           const char*, const char* );
1069 template int ssys::setenvctx(
1070           const char*, const char*,
1071           const char*, const char* );
1072 template int ssys::setenvctx(
1073           const char*, const char*,
1074           const char*, const char*,
1075           const char*, const char* );
1076 template int ssys::setenvctx(
1077           const char*, const char*,
1078           const char*, const char*,
1079           const char*, const char*,
1080           const char*, const char* );
1081 
1082 
1083 
1084 /**
1085 ssys::Desc
1086 -------------
1087 
1088 Generated with::
1089 
1090    ~/opticks/sysrap/ssys__Desc.sh
1091    ~/opticks/sysrap/ssys__Desc.sh | pbcopy
1092 
1093 Dump flags with::
1094 
1095     ssys_test
1096     QSimDescTest
1097 
1098 **/
1099 inline std::string ssys::Desc()  // static
1100 {
1101     std::stringstream ss ;
1102     ss << "ssys::Desc"
1103        << std::endl
1104 #ifdef CONFIG_Debug
1105        << "CONFIG_Debug"
1106 #else
1107        << "NOT:CONFIG_Debug"
1108 #endif
1109        << std::endl
1110 #ifdef CONFIG_Release
1111        << "CONFIG_Release"
1112 #else
1113        << "NOT:CONFIG_Release"
1114 #endif
1115        << std::endl
1116 #ifdef CONFIG_RelWithDebInfo
1117        << "CONFIG_RelWithDebInfo"
1118 #else
1119        << "NOT:CONFIG_RelWithDebInfo"
1120 #endif
1121        << std::endl
1122 #ifdef CONFIG_MinSizeRel
1123        << "CONFIG_MinSizeRel"
1124 #else
1125        << "NOT:CONFIG_MinSizeRel"
1126 #endif
1127        << std::endl
1128 #ifdef PRODUCTION
1129        << "PRODUCTION"
1130 #else
1131        << "NOT:PRODUCTION"
1132 #endif
1133        << std::endl
1134 #ifdef WITH_CHILD
1135        << "WITH_CHILD"
1136 #else
1137        << "NOT:WITH_CHILD"
1138 #endif
1139        << std::endl
1140 #ifdef WITH_CUSTOM4
1141        << "WITH_CUSTOM4"
1142 #else
1143        << "NOT:WITH_CUSTOM4"
1144 #endif
1145        << std::endl
1146 #ifdef PLOG_LOCAL
1147        << "PLOG_LOCAL"
1148 #else
1149        << "NOT:PLOG_LOCAL"
1150 #endif
1151        << std::endl
1152 #ifdef DEBUG_PIDX
1153        << "DEBUG_PIDX"
1154 #else
1155        << "NOT:DEBUG_PIDX"
1156 #endif
1157        << std::endl
1158 #ifdef DEBUG_TAG
1159        << "DEBUG_TAG"
1160 #else
1161        << "NOT:DEBUG_TAG"
1162 #endif
1163        << std::endl
1164        ;
1165     std::string str = ss.str() ;
1166     return str ;
1167 }
1168 
1169 inline std::string ssys::PWD()  // static
1170 {
1171     return getenvvar("PWD");    // note no newline
1172 }
1173 
1174 
1175 #ifdef _MSC_VER
1176 #else
1177 #include <unistd.h>
1178 extern char **environ;
1179 #endif
1180 
1181 
1182 inline void ssys::getenv_with_prefix(std::vector<std::pair<std::string,std::string>>& kvs, const char* prefix)
1183 {
1184 #ifdef _MSC_VER
1185 #else
1186     int i=0 ;
1187     char delim='=' ;
1188     while(environ[i])
1189     {
1190         std::string kv = environ[i++] ;
1191         size_t pos = kv.find(delim);
1192         if( pos == std::string::npos ) continue ;
1193         std::string k = kv.substr(0, pos);
1194         std::string v = kv.substr(pos+1);
1195         bool match_prefix = prefix ? sstr::StartsWith( k.c_str(), prefix ) : true ;
1196         //if(match_prefix) std::cout << "[" << k << "][" << v << "]" << ( match_prefix ? "YES" : "NO "  ) << std::endl ;
1197         if(!match_prefix) continue ;
1198         kvs.push_back( std::pair<std::string,std::string>( k, v ) );
1199     }
1200 #endif
1201 }
1202 
1203