Back to home page

EIC code displayed by LXR

 
 

    


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

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 <cstdio>
0021 #include <cassert>
0022 #include <cstdlib>
0023 #include <cstring>
0024 #include <csignal>
0025 #include <sstream>
0026 #include <fstream>
0027 #include <iostream>
0028 #include <algorithm>
0029 
0030 #include <glm/glm.hpp>
0031 
0032 
0033 #include "SStr.hh"
0034 #include "SPath.hh"
0035 #include "spath.h"
0036 #include "SLOG.hh"
0037 
0038 
0039 const plog::Severity SStr::LEVEL = SLOG::EnvLevel("SStr", "DEBUG"); 
0040 
0041 
0042 /**
0043 
0044 In [15]: s = "hello"
0045 
0046 In [18]: encode_ = lambda s:sum(map(lambda ic:ord(ic[1]) << 8*ic[0], enumerate(s[:8]) ))
0047 
0048 In [19]: encode_(s)
0049 Out[19]: 478560413032
0050 
0051 In [40]: decode_ = lambda v:"".join(map( lambda c:str(unichr(c)), filter(None,map(lambda i:(v >> i*8) & 0xff, range(8))) ))
0052 
0053 In [41]: decode_(478560413032)
0054 Out[41]: 'hello'
0055 
0056 Hmm presumably base64 code might do this at a higher level ?
0057 
0058 **/
0059 
0060 
0061 
0062 
0063 void SStr::Save(const char* path_, const std::vector<std::string>& a, char delim )   // static
0064 {
0065     bool in_pwd = strchr(path_, '/' ) == nullptr ; 
0066     int create_dirs = in_pwd ? NOOP : FILEPATH ; 
0067     const char* path = SPath::Resolve(path_, create_dirs);  // 
0068     LOG(info) << "SPath::Resolve " << path_ << " to " << path ; 
0069     std::ofstream fp(path);
0070     for(std::vector<std::string>::const_iterator i = a.begin(); i != a.end(); ++i) fp << *i << delim ;
0071 }
0072 
0073 
0074 /**
0075 SStr::Save
0076 -----------
0077 
0078 Formerly when saving into PWD it was necessary to manually set create_dirs to 0 
0079 otherwise the file is not written but rather an empty directory was created and no file written.
0080 
0081 This issue has been fixed by checking for a "/" in the path and setting create_dirs accordingly.
0082 
0083 **/
0084 
0085 void SStr::Save(const char* path_, const char* txt )
0086 {
0087     bool in_pwd = strchr(path_, '/' ) == nullptr ; 
0088     int create_dirs = in_pwd ? NOOP : FILEPATH ; 
0089 
0090     const char* path = SPath::Resolve(path_, create_dirs );  
0091     LOG(LEVEL) << "SPath::Resolve " << path_ << " to " << path << " create_dirs " << create_dirs << " in_pwd " << in_pwd  ; 
0092     std::ofstream fp(path);
0093     fp << txt ;  
0094 }
0095 
0096 const char* SStr::Load(const char* path_ )
0097 {
0098     int create_dirs = 0 ; // 0:do nothing
0099     const char* path = SPath::Resolve(path_, create_dirs);  // 
0100     LOG(LEVEL) << "SPath::Resolve " << path_ << " to " << path ; 
0101     std::ifstream fp(path);
0102 
0103     std::stringstream ss ; 
0104     ss << fp.rdbuf() ; 
0105     std::string txt = ss.str(); 
0106     return strdup(txt.c_str()) ; 
0107 }
0108 
0109 /**
0110 SStr::LoadList
0111 ----------------
0112 
0113 Interprets the arg as either a filepath with lines to be loaded
0114 or a comma delimited string to be split into lines.   
0115 
0116 **/
0117 
0118 void SStr::LoadList(const char* arg, std::vector<std::string>& lines, char delim  )
0119 {
0120     if(arg == nullptr) return ; 
0121 
0122     if(spath::LooksLikePath(arg) && delim == '\n' )  // eg starts with slash
0123     {   
0124         std::ifstream ifs(arg);
0125         std::string line;
0126         while(std::getline(ifs, line)) lines.push_back(line) ; 
0127     }   
0128     else if( delim == ',' )
0129     {   
0130         SStr::Split( arg,  delim, lines );    
0131         LOG(LEVEL) << "split " << arg << " into " << lines.size()  ; 
0132     }   
0133     else
0134     {   
0135         lines.push_back(arg);
0136     }   
0137 }
0138 
0139 std::vector<std::string>* SStr::LoadList( const char* arg, char delim )
0140 {
0141     if(arg == nullptr) return nullptr ; 
0142     typedef std::vector<std::string> VS ; 
0143     VS* lines = new VS ; 
0144     LoadList(arg, *lines, delim ); 
0145     return lines ; 
0146 }
0147 
0148 
0149 
0150 
0151 
0152 
0153 
0154 
0155 
0156 void SStr::FillFromULL( char* dest, unsigned long long value, char unprintable)
0157 {
0158     dest[8] = '\0' ; 
0159     for( ULL w=0 ; w < 8 ; w++)
0160     {   
0161         ULL ullc = (value & (0xffull << w*8)) >> w*8 ;
0162         char c = static_cast<char>(ullc) ; 
0163         bool printable = c >= ' ' && c <= '~' ;
0164         dest[w] = printable ? c : unprintable ; 
0165     }       
0166 }
0167 
0168 const char* SStr::FromULL( unsigned long long value, char unprintable)
0169 {
0170     assert( sizeof(ULL) == 8 );
0171     char* s = new char[8+1] ; 
0172     FillFromULL(s, value, unprintable) ; 
0173     return s ; 
0174 }
0175 
0176 
0177 unsigned long long SStr::ToULL( const char* s )
0178 {
0179     assert( sizeof(ULL) == 8 );
0180 
0181     unsigned len = s ? strlen(s) : 0 ; 
0182     ULL mxw = len < 8 ? len : 8 ; 
0183 
0184     ULL v = 0ull ;   
0185     for(ULL w=0 ; w < mxw ; w++)
0186     {
0187         ULL c = s[w] ; 
0188         v |= ( c << 8ull*w ) ; 
0189     }
0190     return v ; 
0191 }
0192 
0193 
0194 
0195 
0196 template<size_t SIZE>
0197 const char* SStr::FormatInt( const char* fmt, int value )
0198 {
0199     char buf[SIZE]; 
0200     size_t cx = snprintf( buf, SIZE, fmt, value );   
0201     bool expect = cx < SIZE ;
0202     if(!expect) std::cerr << "SStr::FormatInt TRUNCATION " << std::endl; 
0203     assert( expect && "snprintf truncation detected" );  
0204     return strdup(buf);
0205 }
0206 
0207 template const char* SStr::FormatInt<8>( const char* , int  );
0208 template const char* SStr::FormatInt<64>( const char* , int  );
0209 
0210 
0211 const char* SStr::FormatIndex( int idx, bool prefix, int wid )
0212 {
0213     std::stringstream ss ;  
0214     if(prefix) ss << ( idx == 0 ? "z" : ( idx < 0 ? "n" : "p" ) ) ; 
0215     ss << std::setfill('0') << std::setw(wid) << std::abs(idx) ; 
0216     std::string s = ss.str(); 
0217     return strdup(s.c_str()); 
0218 }
0219 
0220 
0221 
0222 
0223 template<size_t SIZE>
0224 const char* SStr::Format1( const char* fmt, const char* value )
0225 {
0226     char buf[SIZE]; 
0227     size_t cx = snprintf( buf, SIZE, fmt, value );   
0228     bool expect = cx < SIZE ;
0229     if(!expect) std::cerr << "SStr::Format1 TRUNCATION " << std::endl; 
0230     assert( expect && "snprintf truncation detected" );  
0231     return strdup(buf);
0232 }
0233 
0234 template<size_t SIZE>
0235 const char* SStr::Format2( const char* fmt, const char* value1, const char* value2 )
0236 {
0237     char buf[SIZE]; 
0238     size_t cx = snprintf( buf, SIZE, fmt, value1, value2 );   
0239     bool expect = cx < SIZE ;
0240     if(!expect) std::cerr << "SStr::Format2 TRUNCATION " << std::endl; 
0241     assert( expect && "snprintf truncation detected" );  
0242     return strdup(buf);
0243 }
0244 
0245 template<size_t SIZE>
0246 const char* SStr::Format3( const char* fmt, const char* value1, const char* value2, const char* value3 )
0247 {
0248     char buf[SIZE]; 
0249     size_t cx = snprintf( buf, SIZE, fmt, value1, value2, value3 );   
0250     bool expect = cx < SIZE ;
0251     if(!expect) std::cerr << "SStr::Format3 TRUNCATION " << std::endl; 
0252     assert( expect && "snprintf truncation detected" );  
0253     return strdup(buf);
0254 }
0255 
0256 
0257 
0258 template const char* SStr::Format1<256>( const char* , const char* );
0259 template const char* SStr::Format2<256>( const char* , const char*, const char* );
0260 template const char* SStr::Format3<256>( const char* , const char*, const char* , const char* );
0261 
0262 template const char* SStr::Format1<16>( const char* , const char* );
0263 
0264 
0265 template<typename T>
0266 const char* SStr::FormatReal(const T value, int w, int p, char fill )
0267 {
0268     std::stringstream ss ; 
0269     ss << std::fixed << std::setfill(fill) << std::setw(w) << std::setprecision(p) << value ; 
0270     std::string s = ss.str(); 
0271     return strdup(s.c_str()) ; 
0272 } 
0273 
0274 template const char* SStr::FormatReal<float>(const float, int, int, char );
0275 template const char* SStr::FormatReal<double>(const double, int, int, char );
0276 
0277 
0278 template<typename ... Args>
0279 std::string SStr::Format_( const char* fmt, Args ... args )
0280 {
0281     // see sysrap/tests/StringFormatTest.cc
0282     int sz = std::snprintf( nullptr, 0, fmt, args ... ) + 1; // +1 for null termination
0283     assert( sz > 0 );  
0284     std::vector<char> buf(sz) ;   
0285     std::snprintf( buf.data(), sz, fmt, args ... );
0286     return std::string( buf.begin(), buf.begin() + sz - 1 );  // exclude null termination 
0287 }
0288 
0289 template std::string SStr::Format_( const char*, const char* ); 
0290 template std::string SStr::Format_( const char* , int, double ); 
0291 template std::string SStr::Format_( const char* , int ); 
0292 template std::string SStr::Format_( const char* , int, const char* ); 
0293 template std::string SStr::Format_( const char* , unsigned ); 
0294 template std::string SStr::Format_( const char*, const char* , const char* ); 
0295 template std::string SStr::Format_( const char*, const char* , int, const char* ); 
0296 
0297 
0298 template<typename ... Args>
0299 const char* SStr::Format( const char* fmt, Args ... args )
0300 {
0301     std::string s = Format_(fmt, args...) ; 
0302     return strdup(s.c_str()); 
0303 }
0304 
0305 template const char* SStr::Format( const char*, const char* ); 
0306 template const char* SStr::Format( const char* , int, double ); 
0307 template const char* SStr::Format( const char* , int ); 
0308 template const char* SStr::Format( const char* , int, const char* ); 
0309 template const char* SStr::Format( const char* , unsigned ); 
0310 template const char* SStr::Format( const char*, const char* , const char* ); 
0311 template const char* SStr::Format( const char*, const char* , int, const char* ); 
0312 
0313 
0314 
0315 /**
0316 
0317 replace with spath::Name
0318 
0319 template<typename ... Args>
0320 const char* SStr::Name( Args ... elem_ )
0321 {
0322     std::vector<std::string> elem = {elem_...};
0323     std::stringstream ss ; 
0324     for(unsigned i=0 ; i < elem.size() ; i++)  ss << elem[i] ; 
0325     std::string s = ss.str(); 
0326     return strdup(s.c_str()) ; 
0327 }
0328 
0329 template const char* SStr::Name( const char* ); 
0330 template const char* SStr::Name( const char*, const char*  ); 
0331 template const char* SStr::Name( const char*, const char*, const char* ); 
0332 
0333 **/
0334 
0335 
0336 
0337 bool SStr::Blank( const char* s )
0338 {
0339    unsigned n = strlen(s) ; 
0340    return n == 0 || All(s, ' ') ; 
0341 }
0342 
0343 bool SStr::All( const char* s , char q )
0344 {
0345    unsigned n = strlen(s) ; 
0346    return n > 0 && Count(s, q) == n ; 
0347 
0348 }
0349 unsigned SStr::Count( const char* s , char q )
0350 {
0351    unsigned n = strlen(s) ; 
0352    unsigned count = 0 ; 
0353    for(unsigned i=0 ; i < n ; i++) if( s[i] == q ) count += 1 ; 
0354    return count ;  
0355 }
0356 
0357 bool SStr::Contains( const char* s_ , const char* q_ )
0358 {
0359     std::string s(s_); 
0360     std::string q(q_); 
0361     return s.find(q) != std::string::npos ;
0362 }
0363 
0364 /**
0365 SStr::EndsWith
0366 ---------------
0367 
0368 eg::
0369 
0370     SStr::EndsWith("name.npy", ".npy") == true 
0371 
0372 
0373 **/
0374 bool SStr::EndsWith( const char* s, const char* q)
0375 {
0376     int pos = strlen(s) - strlen(q) ;
0377     return pos > 0 && strncmp(s + pos, q, strlen(q)) == 0 ;
0378 }
0379 
0380 const char* SStr::StripPrefix_(const char* s, const char* pfx )
0381 {
0382     const char* ss = pfx && StartsWith(s, pfx ) ? s + strlen(pfx) : s ;
0383     return strdup(ss); 
0384 }
0385 
0386 
0387 
0388 
0389 const char* SStr::StripPrefix(const char* s, const char* pfx0, const char* pfx1, const char* pfx2 )
0390 {
0391     if(      pfx0 && StartsWith(s,pfx0) )  return StripPrefix_(s, pfx0) ; 
0392     else if( pfx1 && StartsWith(s,pfx1) )  return StripPrefix_(s, pfx1) ;
0393     else if( pfx2 && StartsWith(s,pfx2) )  return StripPrefix_(s, pfx2) ;
0394     return strdup(s); 
0395 }
0396 
0397 const char* SStr::MaterialBaseName(const char* s )
0398 {
0399     return StripPrefix(s, "/dd/Materials/", "_dd_Materials_" );  
0400 }
0401 
0402 /**
0403 SStr::StartsWith
0404 ------------------
0405 
0406 The 2nd query string must be less than or equal to the length of the first string and 
0407 all the characters of the query string must match with the first string in order 
0408 to return true.
0409 
0410 **/
0411 
0412 bool SStr::StartsWith( const char* s, const char* q)
0413 {
0414     return s && q && strlen(q) <= strlen(s) && strncmp(s, q, strlen(q)) == 0 ;
0415 }
0416 
0417 
0418 
0419 
0420 const char* SStr::AZaz = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ; 
0421 
0422 bool SStr::StartsWithLetterAZaz(const char* q )
0423 {
0424    const char* p = q != nullptr && strlen(q) > 0 ? strchr(AZaz, q[0]) : nullptr ; 
0425    return p != nullptr ;  
0426 }
0427 
0428 
0429 
0430 
0431 
0432 /**
0433 SStr::SimpleMatch
0434 ---------------------
0435 
0436 Return if the argument string s matches the query string q 
0437 If q ends with '$' require a full match otherwise allow
0438 StartsWith match.
0439 
0440 **/
0441 bool SStr::SimpleMatch(const char* s, const char* q )
0442 {
0443     unsigned ls = strlen(s); 
0444     unsigned lq = strlen(q); 
0445 
0446     if(ls == 0 ) return false ; 
0447     if(lq == 0 ) return false ; 
0448 
0449     bool qed = q[lq-1] == '$' || q[lq-1] == '@' ; 
0450     bool qed_match = 0 == strncmp(s, q, lq - 1) && ls == lq - 1 ;   // exact match up to the dollar 
0451     return qed ? qed_match : StartsWith(s, q) ;
0452 }
0453 
0454 
0455 
0456 /** 
0457 SStr::Match
0458 -------------
0459 
0460 Based on https://www.geeksforgeeks.org/wildcard-character-matching/
0461 
0462 See tests/match.cc
0463 
0464 
0465 The second argument string can contain wildcard tokens:
0466     
0467 `*` 
0468      matches with 0 or more of any char (NB '**' not supported)
0469 `?`   
0470      matches any one character.
0471 `$` or '@'
0472      when appearing at end of q requires the end of s to match  
0473    
0474 **/ 
0475     
0476 bool SStr::Match(const char* s, const char* q) 
0477 {
0478     if (*q == '\0' && *s == '\0') return true;
0479 
0480     if (*q == '*' && *(q+1) != '\0' && *s == '\0') return false;  // reached end of s but still q chars coming 
0481 
0482     if ( (*q == '$' || *q == '@') && *(q+1) == '\0' && *s == '\0' ) return true ; 
0483     
0484     if (*q == '?' || *q == *s) return SStr::Match(s+1, q+1);  // on to next char
0485 
0486     if (*q == '*') return SStr::Match(s, q+1) || SStr::Match(s+1, q);   // '*' can match nothing or anything in s, including literal '*'
0487           
0488     return false;
0489 }         
0490 
0491 /**
0492 
0493 SStr::HasPointerSuffix
0494 -----------------------
0495 
0496 Typically see 12 hexdigit pointers, as even though have 64 bits it is normal to only use 48 bits in an address space
0497     0x7ff46e500520 
0498 
0499 But with G4 are seeing only 9 hexdigits ??
0500 
0501 
0502 **/
0503 
0504 bool SStr::HasPointerSuffix( const char* name, unsigned hexdigits )
0505 {
0506    // eg Det0x110d9a820      why 9 hex digits vs
0507    //       0x7ff46e500520    
0508    //
0509     std::string s(name); 
0510     unsigned l = s.size() ; 
0511     if(l < hexdigits+2 ) return false ;
0512  
0513     for(unsigned i=0 ; i < hexdigits+2 ; i++)
0514     {
0515         char c = s[l-11+i] ; 
0516         bool ok = false ; 
0517         switch(i)
0518         {
0519             case 0: ok = c == '0' ; break ; 
0520             case 1: ok = c == 'x' ; break ; 
0521             default:  ok = ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'f' ) ; break ;   
0522         }
0523         if(!ok) return false ; 
0524     }
0525     return true  ; 
0526 }
0527 
0528 
0529 /**
0530 SStr::GetPointerSuffixDigits
0531 ------------------------------
0532 
0533 Check for hexdigits backwards, until reach first non-hexdigit the 'x'::
0534 
0535    World0x7fc10641cbb0  -> 12 
0536      Det0x110fa38b0     ->  9
0537      Hello              -> -1
0538 
0539 **/
0540 
0541 int SStr::GetPointerSuffixDigits( const char* name )
0542 {
0543     if( name == NULL ) return -1 ; 
0544     int l = strlen(name) ; 
0545     int num = 0 ; 
0546     for(int i=0 ; i < l ; i++ )  
0547     {
0548          char c = *(name + l - 1 - i) ;  // reverse order chars
0549          bool hexdigit = ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'f' ) ; 
0550          if(!hexdigit) break ;  
0551          num += 1 ; 
0552     } 
0553     //std::cout << std::endl ; 
0554     if(l - num - 1 < 0 )  return -1 ; 
0555     if(l - num - 2 < 0 )  return -1 ; 
0556 
0557     char c1 = *(name + l - num - 1);
0558     char c2 = *(name + l - num - 2);
0559 
0560     return  c1 == 'x' && c2 == '0'  ?  num : -1 ; 
0561 }
0562 
0563 /**
0564 SStr::HasPointerSuffix
0565 ------------------------
0566 
0567 Returns true when the number of hex digits is within the inclusive min-max range.
0568 
0569 **/
0570 
0571 bool SStr::HasPointerSuffix( const char* name, unsigned min_hexdigits, unsigned max_hexdigits )
0572 {    
0573     int num_hexdigits = GetPointerSuffixDigits( name ); 
0574     return  num_hexdigits > -1 && num_hexdigits >= int(min_hexdigits) && num_hexdigits <= int(max_hexdigits) ; 
0575 }
0576 
0577 /**
0578 SStr::TrimPointerSuffix
0579 -------------------------
0580 
0581 For an input name such as "SomeName0xdeadbeef"  returns "SomeName"
0582 
0583 **/
0584 const char* SStr::TrimPointerSuffix( const char* name )
0585 {
0586     int num_hexdigits = GetPointerSuffixDigits( name ); // char-by-char look back  
0587     char* trim = strdup(name); 
0588 
0589     if( num_hexdigits >= 6 && num_hexdigits <= 12 )   // sanity check for the pointer suffix
0590     {
0591         int ip = strlen(name) - num_hexdigits - 2 ;  // offset to land on the '0' of "SomeName0xdeadbeef"
0592         assert( ip >= 0 ); 
0593         char* p = trim + ip ; 
0594         assert( *p == '0' ); 
0595         *p = '\0' ;    // terminate string chopping off the suffix eg "0xdeadbeef"
0596     }    
0597     return trim ; 
0598 }
0599 
0600 
0601 
0602 const char* SStr::TrimLeading(const char* s)
0603 {
0604     char* p = strdup(s); 
0605     while( *p && ( *p == ' ' || *p == '\n' )) p++ ; 
0606     return p ; 
0607 }
0608 const char* SStr::TrimTrailing(const char* s)
0609 {
0610     char* p = strdup(s); 
0611     char* e = p + strlen(p) - 1 ; 
0612     while(e > p && ( *e == ' ' || *e == '\n' )) e-- ;
0613     e[1] = '\0' ;
0614     return p ; 
0615 }
0616 const char* SStr::Trim(const char* s)  // trim leading and trailing whitespace 
0617 {
0618     char* p = strdup(s); 
0619     char* e = p + strlen(p) - 1 ; 
0620     while(e > p && ( *e == ' ' || *e == '\n' )) e-- ;
0621     *(e+1) = '\0' ;
0622     while( *p && ( *p == ' ' || *p == '\n')) p++ ; 
0623     return p ; 
0624 }
0625 
0626 /**
0627 SStr::HeadFirst
0628 -----------------
0629 
0630 Returns string up until the first occurence of the char
0631 or the entire string of the char does not occur. 
0632 
0633 For example::
0634 
0635     SStr::HeadFirst("AltXJFixtureConstruction_XZ", '_') -> "AltXJFixtureConstruction" 
0636 
0637 **/
0638 
0639 const char* SStr::HeadFirst(const char* s_, char c )
0640 {
0641     char* s = strdup(s_); 
0642     char* p = strchr(s, c ); 
0643     if(p) *p = '\0' ;  // terminate string at first occurence of c   
0644     return s ; 
0645 }
0646 
0647 /**
0648 SStr::HeadLast
0649 -----------------
0650 
0651 Returns string up until the last occurence of the char
0652 or the entire string of the char does not occur. 
0653 
0654 For example::
0655 
0656     SStr::HeadLast("AltXJFixtureConstruction_OtherSuffix_XZ", '_') -> "AltXJFixtureConstruction_OtherSuffix" 
0657 
0658 **/
0659 
0660 const char* SStr::HeadLast(const char* s_, char c )
0661 {
0662     char* s = strdup(s_); 
0663     char* p = strrchr(s, c ); 
0664     if(p) *p = '\0' ;  // terminate string at last occurence of c   
0665     return s ; 
0666 }
0667 
0668 
0669 
0670 const char* SStr::Concat( const char* a, const char* b, const char* c  )
0671 {
0672     std::stringstream ss ; 
0673     if(a) ss << a ; 
0674     if(b) ss << b ; 
0675     if(c) ss << c ; 
0676     std::string s = ss.str();
0677     return strdup(s.c_str());
0678 }
0679 
0680 const char* SStr::Concat( const char* a, unsigned b, const char* c  )
0681 {
0682     std::stringstream ss ; 
0683     if(a) ss << a ; 
0684     ss << b ; 
0685     if(c) ss << c ; 
0686     std::string s = ss.str();
0687     return strdup(s.c_str());
0688 }
0689 
0690 const char* SStr::Concat( const char* a, unsigned b, const char* c, unsigned d, const char* e  )
0691 {
0692     std::stringstream ss ; 
0693 
0694     if(a) ss << a ; 
0695     ss << b ; 
0696     if(c) ss << c ; 
0697     ss << d ; 
0698     if(e) ss << e ; 
0699 
0700     std::string s = ss.str();
0701     return strdup(s.c_str());
0702 }
0703 
0704 
0705 template<typename T>
0706 const char* SStr::Concat_( const char* a, T b, const char* c  )
0707 {
0708     std::stringstream ss ; 
0709     if(a) ss << a ; 
0710     ss << b ; 
0711     if(c) ss << c ; 
0712     std::string s = ss.str();
0713     return strdup(s.c_str());
0714 }
0715 
0716 
0717 
0718 const char* SStr::Replace( const char* s,  char a, char b )
0719 {
0720     std::stringstream ss ; 
0721     for(unsigned i=0 ; i < strlen(s) ; i++)
0722     {
0723         char c = *(s+i) ;   
0724         ss << ( c == a ? b : c ) ;  
0725     }
0726     std::string r = ss.str(); 
0727     return strdup(r.c_str());
0728 }
0729 
0730 
0731 /**
0732 SStr::ReplaceEnd
0733 ------------------
0734 
0735 String s is required to have ending q.
0736 New string n is returned with the ending q replaced with r.
0737 
0738 **/
0739 
0740 const char* SStr::ReplaceEnd( const char* s, const char* q, const char* r  )
0741 {
0742     int pos = strlen(s) - strlen(q) ;
0743     assert( pos > 0 && strncmp(s + pos, q, strlen(q)) == 0 );
0744 
0745     std::stringstream ss ; 
0746     for(int i=0 ; i < pos ; i++) ss << *(s+i) ;  
0747     ss << r ; 
0748 
0749     std::string n = ss.str(); 
0750     return strdup(n.c_str());
0751 }
0752 
0753 
0754 
0755 
0756 
0757 
0758 void SStr::Split( const char* str, char delim,   std::vector<std::string>& elem )
0759 {
0760     std::stringstream ss; 
0761     ss.str(str)  ;
0762     std::string s;
0763     while (std::getline(ss, s, delim)) elem.push_back(s) ; 
0764 }
0765 
0766 /**
0767 SStr::ISplit
0768 -------------
0769 
0770 Usage::
0771 
0772     std::vector<int> pos ; 
0773     SStr::ISplit( spec_, pos, ',' );  
0774 
0775 Replace with::
0776 
0777     sstr::split<int>( pos,  spec_ , ',' )
0778 
0779 **/
0780 
0781 int SStr::ISplit( const char* line, std::vector<int>& ivec, char delim )
0782 {
0783     std::stringstream ss; 
0784     ss.str(line)  ;
0785 
0786     std::string s;
0787     while (std::getline(ss, s, delim)) ivec.push_back(std::atoi(s.c_str())) ; 
0788     
0789     return ivec.size(); 
0790 }
0791 
0792 std::vector<int>* SStr::ISplit( const char* line, char delim )
0793 {
0794     std::vector<int>* ivec = new std::vector<int>() ; 
0795     ISplit(line, *ivec, delim ); 
0796     return ivec ; 
0797 }
0798 
0799 
0800 
0801 template const char* SStr::Concat_<unsigned>(           const char* , unsigned           , const char*  );
0802 template const char* SStr::Concat_<unsigned long long>( const char* , unsigned long long , const char*  );
0803 template const char* SStr::Concat_<int>(                const char* , int                , const char*  );
0804 template const char* SStr::Concat_<long>(               const char* , long               , const char*  );
0805 
0806 
0807 
0808 
0809 void SStr::ParseGridSpec(  std::array<int,9>& grid, const char* spec)  // static 
0810 {
0811     int idx = 0 ; 
0812     std::stringstream ss(spec); 
0813     std::string s;
0814     while (std::getline(ss, s, ',')) 
0815     {   
0816         std::stringstream tt(s); 
0817         std::string t;
0818         while (std::getline(tt, t, ':')) grid[idx++] = std::atoi(t.c_str()) ; 
0819     }   
0820 
0821     std::stringstream uu ; 
0822     uu << spec << " : " ;
0823     for(int i=0 ; i < 9 ; i++) uu << grid[i] << " " ; 
0824     uu << std::endl ; 
0825 
0826     std::string u = ss.str(); 
0827     LOG(info) << u ;  
0828 }
0829 
0830 
0831 void SStr::DumpGrid(const std::array<int,9>& cl)
0832 {   
0833     int i0 = cl[0] ;
0834     int i1 = cl[1] ;
0835     int is = cl[2] ;
0836     int j0 = cl[3] ;
0837     int j1 = cl[4] ;
0838     int js = cl[5] ;
0839     int k0 = cl[6] ;
0840     int k1 = cl[7] ;
0841     int ks = cl[8] ; 
0842 
0843     unsigned num = 0 ; 
0844     for(int i=i0 ; i < i1 ; i+=is ) 
0845     for(int j=j0 ; j < j1 ; j+=js ) 
0846     for(int k=k0 ; k < k1 ; k+=ks ) 
0847     {
0848         std::cout << std::setw(2) << num << " (i,j,k) " << "(" << i << "," << j << "," << k << ") " << std::endl ; 
0849         num += 1 ; 
0850     }
0851 }
0852 
0853 
0854 
0855 
0856 
0857 
0858 template <typename T>
0859 void SStr::GetEVector(std::vector<T>& vec, const char* key, const char* fallback )
0860 {
0861     const char* sval = getenv(key); 
0862     std::stringstream ss(sval ? sval : fallback); 
0863     std::string s ; 
0864     while(getline(ss, s, ',')) vec.push_back(ato_<T>(s.c_str()));   
0865 }  
0866 
0867 template void  SStr::GetEVector<unsigned>(std::vector<unsigned>& vec, const char* key, const char* fallback  );
0868 template void  SStr::GetEVector<float>(std::vector<float>& vec, const char* key, const char* fallback  );
0869 
0870 void SStr::GetEVec(glm::vec3& v, const char* key, const char* fallback )
0871 {   
0872     std::vector<float> vec ; 
0873     SStr::GetEVector<float>(vec, key, fallback);
0874     std::cout << key << SStr::Present(vec) << std::endl ; 
0875     assert( vec.size() == 3 ); 
0876     for(int i=0 ; i < 3 ; i++) v[i] = vec[i] ;
0877 }   
0878     
0879 void SStr::GetEVec(glm::vec4& v, const char* key, const char* fallback )
0880 {   
0881     std::vector<float> vec ;
0882     SStr::GetEVector<float>(vec, key, fallback);
0883     std::cout << key << SStr::Present(vec) << std::endl ;
0884     assert( vec.size() == 4 );
0885     for(int i=0 ; i < 4 ; i++) v[i] = vec[i] ; 
0886 }
0887 
0888 
0889 
0890 
0891 template <typename T>
0892 std::string SStr::Present(std::vector<T>& vec)
0893 {   
0894     std::stringstream ss ; 
0895     for(unsigned i=0 ; i < vec.size() ; i++) ss << vec[i] << " " ;
0896     return ss.str();
0897 }
0898 
0899 
0900 template std::string SStr::Present<float>(std::vector<float>& );
0901 template std::string SStr::Present<unsigned>(std::vector<unsigned>& );
0902 template std::string SStr::Present<int>(std::vector<int>& );
0903 
0904 
0905 
0906 template <typename T>
0907 T SStr::GetEValue(const char* key, T fallback) // static 
0908 {   
0909     const char* sval = getenv(key); 
0910     T val = sval ? ato_<T>(sval) : fallback ;
0911     return val ;
0912 }
0913 
0914 
0915 
0916 unsigned SStr::Encode4(const char* s) // static 
0917 {
0918     unsigned u4 = 0u ; 
0919     for(unsigned i=0 ; i < std::min(4ul, strlen(s)) ; i++ )
0920     {
0921         unsigned u = unsigned(s[i]) ;
0922         u4 |= ( u << (i*8) ) ;
0923     }
0924     return u4 ;
0925 }
0926 
0927 
0928 template float       SStr::GetEValue<float>(const char* key, float fallback);
0929 template int         SStr::GetEValue<int>(const char* key,   int  fallback);
0930 template unsigned    SStr::GetEValue<unsigned>(const char* key,   unsigned  fallback);
0931 template std::string SStr::GetEValue<std::string>(const char* key,  std::string  fallback);
0932 template bool        SStr::GetEValue<bool>(const char* key,  bool  fallback);
0933 
0934 
0935 /**
0936 Str::PTXPath
0937 -------------
0938 
0939 Instead can use::
0940 
0941    spath::Resolve("$OPTICKS_PREFIX/ptx/CSGOptiX_generated_CSGOptiX7.cu.ptx")  
0942 
0943 
0944 const char* SStr::PTXPath( const char* install_prefix, const char* cmake_target, const char* cu_stem, const char* cu_ext ) // static
0945 {   
0946     std::stringstream ss ;
0947     ss << install_prefix
0948        << "/ptx/"
0949        << cmake_target
0950        << "_generated_"
0951        << cu_stem
0952        << cu_ext
0953        << ".ptx"
0954        ;
0955     std::string path = ss.str();
0956     return strdup(path.c_str());
0957 }
0958 **/
0959 
0960 
0961 
0962 
0963 template <typename T>
0964 T SStr::ato_( const char* a )   // static 
0965 {   
0966     std::string s(a);
0967     std::istringstream iss(s);
0968     T v ;  
0969     iss >> v ;
0970     return v ;
0971 }
0972 
0973 
0974 template double   SStr::ato_<double>( const char* ); 
0975 template float    SStr::ato_<float>( const char* ); 
0976 template int      SStr::ato_<int>( const char* ); 
0977 template unsigned SStr::ato_<unsigned>( const char* ); 
0978 
0979 
0980 void SStr::GridMinMax(const std::array<int,9>& grid, glm::ivec3&mn, glm::ivec3& mx)  // static 
0981 {   
0982     mn.x = grid[0] ; mx.x = grid[1] ;
0983     mn.y = grid[3] ; mx.y = grid[4] ;
0984     mn.z = grid[6] ; mx.z = grid[7] ;
0985 }
0986 
0987 void SStr::GridMinMax(const std::array<int,9>& grid, int&mn, int& mx)  // static 
0988 {   
0989     for(int a=0 ; a < 3 ; a++)
0990     for(int i=grid[a*3+0] ; i < grid[a*3+1] ; i+=grid[a*3+2] )
0991     {   
0992         if( i > mx ) mx = i ;
0993         if( i < mn ) mn = i ;
0994     }
0995     std::cout << "SStr::GridMinMax " << mn << " " << mx << std::endl ;
0996 }
0997 
0998 
0999 
1000 int SStr::AsInt(const char* arg, int fallback )
1001 {
1002     char* end ;   
1003     char** endptr = &end ; 
1004     int base = 10 ;   
1005     unsigned long ul = strtoul(arg, endptr, base); 
1006     bool end_points_to_terminator = end == arg + strlen(arg) ;   
1007     return end_points_to_terminator ? int(ul) : fallback ;  
1008 }
1009 
1010 
1011 int SStr::ExtractInt(const char* arg, int start, unsigned num, int fallback)
1012 {
1013     unsigned pos = start < 0 ? strlen(arg) + start : start  ; 
1014     unsigned len = strlen(arg) ; 
1015     if(pos > len) return fallback ; 
1016     if(pos + num > len) return fallback ; 
1017 
1018     std::string s(arg+pos,num) ; 
1019     return SStr::AsInt(s.c_str(), fallback);
1020 }
1021 
1022 
1023 /**
1024 SStr::ReplaceChars
1025 --------------------
1026 
1027 Duplicate the input string and change all occurences of *repl* chars within the string into *to*
1028 
1029 **/
1030 
1031 const char* SStr::ReplaceChars(const char* str, const char* repl, char to ) 
1032 {
1033     char* s = strdup(str); 
1034     for(unsigned i=0 ; i < strlen(s) ; i++) if(strchr(repl, s[i]) != nullptr) s[i] = to ;  
1035     return s ; 
1036 }
1037 
1038 long SStr::ExtractLong( const char* s, long fallback )
1039 {
1040     std::vector<long> vals;
1041     Extract(vals, s); 
1042     return vals.size() == 1 ? vals[0] : fallback ; 
1043 }
1044 
1045 
1046 /**
1047 SStr::Extract OBSOLETE : REPLACE WITH sstr::Extract
1048 -------------------------------------------------------
1049 
1050 Some str with other uses of + - would trip this up.
1051 
1052 
1053 **/
1054 void SStr::Extract( std::vector<long>& vals, const char* s )
1055 {
1056     char* s0 = strdup(s); 
1057     char* p = s0 ; 
1058     while (*p) 
1059     {
1060         if( (*p >= '0' && *p <= '9') || *p == '+' || *p == '-') vals.push_back(strtol(p, &p, 10)) ; 
1061         else p++ ;
1062     }
1063     free(s0); 
1064 }
1065 
1066 void SStr::Extract_( std::vector<long>& vals, const char* s )
1067 {
1068     char* p = const_cast<char*>(s) ; 
1069     while (*p) 
1070     {
1071         if( (*p >= '0' && *p <= '9') || *p == '+' || *p == '-') vals.push_back(strtol(p, &p, 10)) ; 
1072         else p++ ;
1073     }
1074 }
1075 
1076 void SStr::Extract_( std::vector<float>& vals, const char* s )
1077 {
1078     char* p = const_cast<char*>(s) ; 
1079     while (*p) 
1080     {
1081         if( (*p >= '0' && *p <= '9') || *p == '+' || *p == '-' || *p == '.') vals.push_back(strtof(p, &p)) ; 
1082         else p++ ;
1083     }
1084 }
1085 
1086 
1087 
1088 
1089 int SStr::ekv_split( std::vector<std::pair<std::string, std::string> > & ekv, const char* line_, char edelim, char kvdelim)
1090 {
1091     int err = 0 ; 
1092     bool warn = true ; 
1093     const char* line = strdup(line_);
1094     typedef std::pair<std::string,std::string> KV ;   
1095     std::istringstream f(line);
1096     std::string s;
1097     while (getline(f, s, edelim))
1098     {   
1099         std::vector<std::string> kv ;
1100         SStr::Split( s.c_str(), kvdelim, kv );    
1101 
1102         if(kv.size() == 2)
1103         {   
1104             ekv.push_back(KV(kv[0],kv[1]));
1105         }   
1106         else
1107         {   
1108             if(warn)
1109             {   
1110                 LOG(error) << "ignoring malformed kv [" << s.c_str() << "]" ; 
1111                 LOG(error) << "line [" << line << "]" ; 
1112             }   
1113             err++ ; 
1114             std::raise(SIGINT);
1115         }   
1116     }   
1117     return err ; 
1118 }
1119 
1120 
1121 
1122 
1123 const char* SStr::ParseStringIntInt( const char* triplet, int& y, int& z, char delim )
1124 {
1125     std::stringstream ss; 
1126     ss.str(triplet)  ;
1127     std::string s;
1128     std::vector<std::string> elem ; 
1129     while (std::getline(ss, s, delim)) elem.push_back(s) ; 
1130     assert(elem.size() == 3 ); 
1131     y = AsInt( elem[1].c_str() ); 
1132     z = AsInt( elem[2].c_str() ); 
1133     return strdup(elem[0].c_str()); 
1134 }
1135 
1136