File indexing completed on 2026-04-09 07:49:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <sstream>
0021 #include <iostream>
0022 #include <iomanip>
0023 #include <cstdlib>
0024 #include <cstring>
0025 #include <csignal>
0026 #include <cmath>
0027 #include <math.h>
0028
0029 #include <cassert>
0030 #include <cstdio>
0031 #include <fstream>
0032
0033 #include <sys/wait.h>
0034
0035 #include "SSys.hh"
0036 #include "SStr.hh"
0037 #include "SLOG.hh"
0038
0039 #include "scuda.h"
0040
0041
0042 extern char **environ;
0043
0044 const plog::Severity SSys::LEVEL = SLOG::EnvLevel("SSys", "DEBUG") ;
0045
0046 const char* SSys::OS = "Linux" ;
0047
0048
0049 void SSys::DumpEnv(const char* pfx )
0050 {
0051 int i = 1;
0052 for (char* s = *environ ; s; i++)
0053 {
0054 if(pfx == NULL || strncmp(s, pfx, strlen(pfx)) == 0) printf("%s\n", s);
0055 s = *(environ+i);
0056 }
0057 }
0058
0059
0060 const unsigned SSys::SIGNBIT32 = 0x80000000 ;
0061 const unsigned SSys::OTHERBIT32 = 0x7fffffff ;
0062
0063
0064 bool SSys::IsNegativeZero(float f)
0065 {
0066 return std::signbit(f) && f == -0.f ;
0067 }
0068
0069
0070 const char* SSys::fmt(const char* tmpl, unsigned val)
0071 {
0072 char buf[100] ;
0073 snprintf(buf, 100, tmpl, val );
0074 return strdup(buf);
0075 }
0076
0077
0078 int SSys::exec(const char* exe, const char* arg1, const char* arg2)
0079 {
0080 std::stringstream ss ;
0081 ss << exe << " " ;
0082 if(arg1) ss << arg1 << " " ;
0083 if(arg2) ss << arg2 << " " ;
0084
0085 std::string cmd = ss.str();
0086 return SSys::run(cmd.c_str());
0087 }
0088
0089 int SSys::run(const char* cmd)
0090 {
0091 int rc_raw = system(cmd);
0092 int rc = WEXITSTATUS(rc_raw) ;
0093
0094 LOG(info) << cmd
0095 << " rc_raw : " << rc_raw
0096 << " rc : " << rc
0097 ;
0098
0099 if(rc != 0)
0100 {
0101 LOG(error)
0102 << "FAILED with "
0103 << " cmd " << cmd
0104 << " RC " << rc
0105 ;
0106 LOG(verbose) << " possibly you need to set export PATH=$OPTICKS_HOME/ana:$OPTICKS_HOME/bin:/usr/local/opticks/lib:$PATH " ;
0107 }
0108 return rc ;
0109 }
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119 std::string SSys::Which(const char* script)
0120 {
0121 bool chomp = true ;
0122
0123 int rc(0);
0124 std::string path = SSys::POpen("which 2>/dev/null", script, chomp, rc );
0125 LOG(LEVEL)
0126 << " script " << script
0127 << " path " << path
0128 << " rc " << rc
0129 ;
0130
0131 std::string empty ;
0132 return rc == 0 ? path : empty ;
0133 }
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 std::string SSys::POpen(const char* cmd, bool chomp, int& rc)
0146 {
0147 LOG(LEVEL) << "[ " << cmd ;
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
0156 ss << line ;
0157 }
0158
0159 rc=0 ;
0160 int st = pclose(fp);
0161 if(WIFEXITED(st)) rc=WEXITSTATUS(st);
0162 LOG(LEVEL) << "] " << cmd << " rc " << rc ;
0163
0164 return ss.str() ;
0165 }
0166
0167 std::string SSys::POpen(const char* cmda, const char* cmdb, bool chomp, int& rc)
0168 {
0169 std::stringstream ss ;
0170 if(cmda) ss << cmda ;
0171 ss << " " ;
0172 if(cmdb) ss << cmdb ;
0173
0174 std::string s = ss.str();
0175 return POpen(s.c_str(), chomp, rc );
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186 int SSys::npdump(const char* path, const char* nptype, const char* postview, const char* printoptions)
0187 {
0188 if(!printoptions) printoptions = "suppress=True,precision=3" ;
0189
0190 std::stringstream ss ;
0191 ss << "python -c 'import sys, os, numpy as np ;"
0192 << " np.set_printoptions(" << printoptions << ") ;"
0193 << " a=np.load(os.path.expandvars(\"" << path << "\")) ;"
0194 << " print(a.shape);"
0195 << " print(a.view(" << nptype << ")" << ( postview ? postview : "" ) << ") ;"
0196 << " sys.exit(0) ' "
0197 ;
0198
0199 std::string cmd = ss.str();
0200 return run(cmd.c_str());
0201 }
0202
0203
0204 void SSys::xxdump(char* buf, int num_bytes, int width, char non_printable )
0205 {
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 for(int i=0 ; i < num_bytes ; i++)
0219 {
0220 char c = buf[i] ;
0221 bool printable = c >= ' ' && c <= '~' ;
0222 std::cout << ( printable ? c : non_printable ) ;
0223 if((i+1) % width == 0 ) std::cout << "\n" ;
0224 }
0225 }
0226
0227
0228 std::string SSys::xxd( char* buf, int num_bytes, int width, char non_printable )
0229 {
0230 std::stringstream ss ;
0231 for(int i=0 ; i < num_bytes ; i++)
0232 {
0233 char c = buf[i] ;
0234 bool printable = c >= ' ' && c <= '~' ;
0235 ss << ( printable ? c : non_printable ) ;
0236 if((i+1) % width == 0 ) ss << "\n" ;
0237 }
0238 return ss.str();
0239 }
0240
0241
0242
0243 std::string SSys::hexlify(const void* obj, size_t size, bool reverse)
0244 {
0245 const unsigned char * const bytes = static_cast<const unsigned char *>(obj);
0246 std::stringstream ss ;
0247 for(size_t i=0 ; i < size ; i++) ss << std::setw(2) << std::hex << std::setfill('0') << unsigned(bytes[reverse ? size - 1 - i : i]) ;
0248 return ss.str();
0249 }
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276 int SSys::GetInteractivityLevel()
0277 {
0278 char* dtmd = getenv("DART_TEST_FROM_DART");
0279 char* cidm = getenv("CTEST_INTERACTIVE_DEBUG_MODE");
0280
0281 int level = 2 ;
0282 if(dtmd && dtmd[0] == '1')
0283 {
0284 level = 0 ;
0285 }
0286 else if(IsRemoteSession())
0287 {
0288 level = 0 ;
0289 }
0290 else if(cidm && cidm[0] == '1')
0291 {
0292 level = 1 ;
0293 }
0294 else if(cidm && cidm[0] == '0')
0295 {
0296 level = 0 ;
0297 }
0298 else
0299 {
0300 level = 2 ;
0301 }
0302 return level ;
0303 }
0304
0305
0306
0307 bool SSys::IsCTestRunning()
0308 {
0309 char* dtmd = getenv("DART_TEST_FROM_DART");
0310 char* cidm = getenv("CTEST_INTERACTIVE_DEBUG_MODE");
0311 return dtmd || cidm ;
0312 }
0313
0314
0315 bool SSys::IsENVVAR(const char* envvar)
0316 {
0317 char* e = getenv(envvar);
0318 return e != NULL ;
0319 }
0320
0321 bool SSys::IsVERBOSE() { return IsENVVAR("VERBOSE") ; }
0322 bool SSys::IsHARIKARI() { return IsENVVAR("HARIKARI") ; }
0323
0324
0325
0326 bool SSys::IsRemoteSession()
0327 {
0328 char* ssh_client = getenv("SSH_CLIENT");
0329 char* ssh_tty = getenv("SSH_TTY");
0330
0331 bool is_remote = ssh_client != NULL || ssh_tty != NULL ;
0332
0333 LOG(verbose) << "SSys::IsRemoteSession"
0334 << " ssh_client " << ssh_client
0335 << " ssh_tty " << ssh_tty
0336 << " is_remote " << is_remote
0337 ;
0338
0339 return is_remote ;
0340 }
0341
0342
0343 void SSys::WaitForInput(const char* msg)
0344 {
0345 LOG(info) << "SSys::WaitForInput " << msg ;
0346 int c = '\0' ;
0347 do
0348 {
0349 c = std::cin.get() ;
0350
0351 } while(c != '\n' );
0352
0353 LOG(info) << "SSys::WaitForInput DONE " ;
0354 }
0355
0356 int SSys::getenvint( const char* envkey, int fallback )
0357 {
0358 char* val = getenv(envkey);
0359 int ival = val ? atoi_(val) : fallback ;
0360 return ival ;
0361 }
0362
0363 char SSys::getenvchar( const char* envkey, char fallback )
0364 {
0365 char* val = getenv(envkey);
0366 char c = val ? val[0] : fallback ;
0367 return c ;
0368 }
0369
0370 unsigned SSys::getenvunsigned_fallback_max( const char* envkey)
0371 {
0372 return SSys::getenvunsigned(envkey, std::numeric_limits<unsigned>::max() );
0373 }
0374
0375 unsigned SSys::getenvunsigned( const char* envkey, unsigned fallback )
0376 {
0377 char* val = getenv(envkey);
0378 unsigned uval = val ? atoi_(val) : fallback ;
0379 return uval ;
0380 }
0381
0382 float SSys::getenvfloat( const char* envkey, float fallback )
0383 {
0384 char* val = getenv(envkey);
0385 float fval = val ? atof_(val) : fallback ;
0386 return fval ;
0387 }
0388
0389 double SSys::getenvdouble( const char* envkey, double fallback )
0390 {
0391 char* val = getenv(envkey);
0392 double fval = val ? atod_(val) : fallback ;
0393 return fval ;
0394 }
0395
0396 bool SSys::getenvbool( const char* envkey )
0397 {
0398 char* val = getenv(envkey);
0399 bool ival = val ? true : false ;
0400 return ival ;
0401 }
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 std::vector<int>* SSys::getenvintvec(const char* envkey, char delim)
0414 {
0415 if(getenv(envkey) == nullptr) return nullptr ;
0416
0417 std::vector<int>* ivec = new std::vector<int>() ;
0418
0419 int nitem = getenvintvec(envkey, *ivec, delim, "" );
0420
0421 LOG(LEVEL) << " nitem " << nitem ;
0422
0423 return ivec ;
0424 }
0425
0426
0427 int SSys::getenvintvec( const char* envkey, std::vector<int>& ivec, char delim, const char* fallback )
0428 {
0429 char* line = getenv(envkey);
0430 std::stringstream ss;
0431 ss.str(line ? line : fallback) ;
0432 std::string s;
0433 while (std::getline(ss, s, delim)) ivec.push_back(atoi_(s.c_str())) ;
0434 return ivec.size();
0435 }
0436
0437 std::string SSys::Desc(const std::vector<int>* ivec)
0438 {
0439 std::stringstream ss ;
0440 if(ivec == nullptr) ss << "ivec null" ;
0441 else for(unsigned i=0 ; i < ivec->size() ; i++ ) ss << std::setw(7) << (*ivec)[i] << " " ;
0442 std::string s = ss.str();
0443 return s ;
0444 }
0445
0446
0447
0448 std::vector<float>* SSys::getenvfloatvec(const char* envkey, const char* fallback, char delim )
0449 {
0450 std::vector<float>* fvec = new std::vector<float>() ;
0451 int nitem = getenvfloatvec(envkey, *fvec,fallback, delim );
0452 LOG(LEVEL) << " nitem " << nitem ;
0453 return fvec ;
0454 }
0455
0456
0457
0458
0459 int SSys::getenvfloatvec( const char* envkey, std::vector<float>& fvec, const char* fallback, char delim )
0460 {
0461 char* line = getenv(envkey);
0462 std::stringstream ss;
0463 ss.str(line ? line : fallback) ;
0464 std::string s;
0465 while (std::getline(ss, s, delim)) fvec.push_back(atof_(s.c_str())) ;
0466 return fvec.size();
0467 }
0468
0469 float3 SSys::getenvfloat3( const char* envkey, const char* fallback, char delim )
0470 {
0471 std::vector<float> fvec ;
0472 getenvfloatvec(envkey, fvec, fallback, delim );
0473 return make_float3(
0474 fvec.size() > 0 ? fvec[0] : 0.f ,
0475 fvec.size() > 1 ? fvec[1] : 0.f ,
0476 fvec.size() > 2 ? fvec[2] : 0.f
0477 );
0478 }
0479
0480 float3 SSys::getenvfloat3norm( const char* envkey, const char* fallback, char delim )
0481 {
0482 float3 v = getenvfloat3(envkey, fallback, delim);
0483 return normalize(v);
0484 }
0485
0486
0487 float4 SSys::getenvfloat4( const char* envkey, const char* fallback, char delim )
0488 {
0489 std::vector<float> fvec ;
0490 getenvfloatvec(envkey, fvec, fallback, delim );
0491 return make_float4(
0492 fvec.size() > 0 ? fvec[0] : 0.f ,
0493 fvec.size() > 1 ? fvec[1] : 0.f ,
0494 fvec.size() > 2 ? fvec[2] : 0.f ,
0495 fvec.size() > 3 ? fvec[3] : 0.f
0496 );
0497 }
0498
0499
0500 std::string SSys::Desc(const std::vector<float>* fvec)
0501 {
0502 std::stringstream ss ;
0503 if(fvec == nullptr) ss << "fvec null" ;
0504 else for(unsigned i=0 ; i < fvec->size() ; i++ ) ss << std::setw(10) << std::fixed << std::setprecision(4) << (*fvec)[i] << " " ;
0505 std::string s = ss.str();
0506 return s ;
0507 }
0508
0509
0510
0511 int SSys::atoi_( const char* a )
0512 {
0513 std::string s(a);
0514 std::istringstream iss(s);
0515 int i ;
0516 iss >> i ;
0517 return i ;
0518 }
0519
0520
0521 float SSys::atof_( const char* a )
0522 {
0523 std::string s(a);
0524 std::istringstream iss(s);
0525 float f ;
0526 iss >> f ;
0527 return f ;
0528 }
0529
0530 double SSys::atod_( const char* a )
0531 {
0532 std::string s(a);
0533 std::istringstream iss(s);
0534 double f ;
0535 iss >> f ;
0536 return f ;
0537 }
0538
0539
0540
0541
0542
0543 void SSys::split(std::vector<std::string>& elem, const char* str, char delim )
0544 {
0545 if(strchr(str, delim) == nullptr )
0546 {
0547 elem.push_back(str);
0548 }
0549 else
0550 {
0551 std::stringstream ss;
0552 ss.str(str) ;
0553 std::string s;
0554 while (std::getline(ss, s, delim)) elem.push_back(s) ;
0555 }
0556 }
0557
0558
0559 bool SSys::hasenvvar( const char* ekey )
0560 {
0561 return getenv(ekey) != nullptr ;
0562 }
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574 const char* SSys::getenvvar( const char* envvar )
0575 {
0576 std::vector<std::string> evars ;
0577 split(evars, envvar, ',');
0578 const char* evalue = nullptr ;
0579 for(unsigned i=0 ; i < evars.size() ; i++)
0580 {
0581 const char* ekey = evars[i].c_str();
0582 evalue = getenv(ekey);
0583 if(evalue) break ;
0584 }
0585 return evalue ;
0586 }
0587
0588 const char* SSys::getenvvar( const char* envkey, const char* fallback )
0589 {
0590 const char* evalue = getenvvar(envkey) ;
0591 return evalue ? evalue : fallback ;
0592 }
0593
0594 const char* SSys::username()
0595 {
0596 #ifdef _MSC_VER
0597 const char* user = SSys::getenvvar("USERNAME") ;
0598 #else
0599 const char* user = SSys::getenvvar("USER") ;
0600 #endif
0601 return user ? user : "SSys-username-undefined" ;
0602 }
0603
0604
0605 #ifdef _MSC_VER
0606 const char* SSys::hostname()
0607 {
0608
0609 return NULL ;
0610 }
0611 #else
0612
0613 #ifndef HOST_NAME_MAX
0614 # if defined(_POSIX_HOST_NAME_MAX)
0615 # define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
0616 # elif defined(MAXHOSTNAMELEN)
0617 # define HOST_NAME_MAX MAXHOSTNAMELEN
0618 # endif
0619 #endif
0620
0621
0622 #include <unistd.h>
0623 #include <limits.h>
0624 const char* SSys::hostname()
0625 {
0626 char hostname[HOST_NAME_MAX];
0627 hostname[0] = '\0' ;
0628 gethostname(hostname, HOST_NAME_MAX);
0629 return hostname[0] == '\0' ? "SSys-hostname-undefined" : strdup(hostname) ;
0630 }
0631 #endif
0632
0633 int SSys::unsetenv( const char* ekey )
0634 {
0635 return ::unsetenv(ekey);
0636 }
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649 int SSys::setenvvar( const char* ekey, const char* value, bool overwrite, char special_empty_token)
0650 {
0651 std::stringstream ss ;
0652 ss << ekey << "=" ;
0653
0654 if(value)
0655 {
0656 if(special_empty_token != '\0' && strlen(value) == 1 && value[0] == special_empty_token)
0657 {
0658 ss << "" ;
0659 }
0660 else
0661 {
0662 ss << value ;
0663 }
0664 }
0665
0666 std::string ekv = ss.str();
0667 const char* prior = getenv(ekey) ;
0668
0669 char* ekv_ = const_cast<char*>(strdup(ekv.c_str()));
0670
0671 int rc = ( overwrite || !prior ) ? putenv(ekv_) : 0 ;
0672
0673 const char* after = getenv(ekey) ;
0674
0675 LOG(debug)
0676 << " ekey " << ekey
0677 << " ekv " << ekv
0678 << " overwrite " << overwrite
0679 << " prior " << ( prior ? prior : "NULL" )
0680 << " value " << ( value ? value : "NULL" )
0681 << " after " << ( after ? after : "NULL" )
0682 << " rc " << rc
0683 ;
0684
0685
0686 return rc ;
0687 }
0688
0689 unsigned SSys::COUNT = 0 ;
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699 void SSys::Dump_(const char* msg)
0700 {
0701 std::cout << std::setw(3) << COUNT << "[" << std::setw(20) << "std::cout" << "] " << msg << std::endl;
0702 std::cerr << std::setw(3) << COUNT << "[" << std::setw(20) << "std::cerr" << "] " << msg << std::endl;
0703 printf("%3d[%20s] %s \n", COUNT, "printf", msg );
0704 std::printf("%3d[%20s] %s \n", COUNT, "std::printf", msg );
0705 }
0706 void SSys::Dump(const char* msg)
0707 {
0708 Dump_(msg);
0709 std::cerr << std::endl ;
0710 COUNT++ ;
0711 }
0712
0713
0714
0715 const char* SSys::ResolveExecutable(const char* envvar_key, const char* default_executable)
0716 {
0717 const char* ev = SSys::getenvvar(envvar_key, default_executable) ;
0718 if(ev && ev[0] == '/') return strdup(ev) ;
0719 std::string path = SSys::Which(ev);
0720 return strdup(path.c_str());
0721 }
0722 const char* SSys::ResolvePython()
0723 {
0724 return SSys::ResolveExecutable("OPTICKS_PYTHON", "python");
0725 }
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741 int SSys::RunPythonScript(const char* script)
0742 {
0743 std::string script_path = SSys::Which(script);
0744 const char* python_executable = SSys::ResolvePython() ;
0745 LOG(info)
0746 << " script " << script
0747 << " script_path " << script_path
0748 << " python_executable " << python_executable
0749 ;
0750
0751 int RC = script_path.empty() ? 101 : SSys::exec(python_executable,script_path.c_str()) ;
0752 LOG(info) << " RC " << RC ;
0753 LOG_IF(error, RC != 0) << std::endl << RunPythonScript_NOTES ;
0754
0755 return RC ;
0756 }
0757
0758 const char* SSys::RunPythonScript_NOTES = R"LITERAL(
0759 SSys::RunPythonScript_NOTES
0760 ------------------------------
0761
0762 Common causes of error when running python scripts via SSys::RunPythonScript are:
0763
0764 1. using a python which does not have the *numpy* module
0765 2. not configuring PYTHONPATH such that the *opticks* modules can be found
0766 3. not configuring PATH to allow SSys::Which to find the python scripts
0767
0768 Example settings of envvars to configure within .bash_profile or .bashrc which
0769 control the python that opticks C++ will use with SSys::RunPythonScript are::
0770
0771 export OPTICKS_PYTHON=/Users/blyth/miniconda3/bin/python
0772 export PYTHONPATH=$PYTHONPATH:$(opticks-fold)
0773 export PATH=$PATH:$(opticks-home)/bin
0774
0775 Note that opticks-fold is the directory above opticks-home "/home/blyth/opticks"
0776 so that will often be the HOME directory, eg /home/blyth
0777
0778 )LITERAL";
0779
0780
0781
0782 int SSys::RunPythonCode(const char* code)
0783 {
0784 const char* python_executable = SSys::ResolvePython() ;
0785 LOG(info)
0786 << " code [" << code << "]"
0787 << " python_executable " << python_executable
0788 ;
0789
0790 const char* arg1 = "-c" ;
0791 const char* arg2 = SStr::Concat("'", code, "'") ;
0792
0793 int RC = code == NULL ? 101 : SSys::exec(python_executable,arg1, arg2) ;
0794 LOG(info) << " RC " << RC ;
0795 return RC ;
0796 }
0797
0798
0799 void SSys::Exit(int rc)
0800 {
0801 LOG(fatal) << " rc " << rc ;
0802 std::raise(SIGINT) ;
0803 }
0804
0805
0806
0807