/src/core/pystring/pystring.cpp

http://github.com/imageworks/OpenColorIO · C++ · 1658 lines · 1104 code · 291 blank · 263 comment · 305 complexity · 5aa8bc88b9bb4a0c4413994c75579fea MD5 · raw file

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) 2008-2010, Sony Pictures Imageworks Inc
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // Redistributions of source code must retain the above copyright notice,
  10. // this list of conditions and the following disclaimer.
  11. // Redistributions in binary form must reproduce the above copyright
  12. // notice, this list of conditions and the following disclaimer in the
  13. // documentation and/or other materials provided with the distribution.
  14. // Neither the name of the organization Sony Pictures Imageworks nor the
  15. // names of its contributors
  16. // may be used to endorse or promote products derived from this software
  17. // without specific prior written permission.
  18. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. // "AS
  20. // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  21. // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  22. // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER
  24. // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL,
  26. // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28. // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29. // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30. // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. ///////////////////////////////////////////////////////////////////////////////
  33. #include <OpenColorIO/OpenColorIO.h>
  34. #include "pystring.h"
  35. #include <algorithm>
  36. #include <cctype>
  37. #include <cstring>
  38. #include <iostream>
  39. #include <sstream>
  40. OCIO_NAMESPACE_ENTER
  41. {
  42. namespace pystring
  43. {
  44. #if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
  45. #ifndef WINDOWS
  46. #define WINDOWS
  47. #endif
  48. #endif
  49. // This definition codes from configure.in in the python src.
  50. // Strictly speaking this limits us to str sizes of 2**31.
  51. // Should we wish to handle this limit, we could use an architecture
  52. // specific #defines and read from ssize_t (unistd.h) if the header exists.
  53. // But in the meantime, the use of int assures maximum arch compatibility.
  54. // This must also equal the size used in the end = MAX_32BIT_INT default arg.
  55. typedef int Py_ssize_t;
  56. /* helper macro to fixup start/end slice values */
  57. #define ADJUST_INDICES(start, end, len) \
  58. if (end > len) \
  59. end = len; \
  60. else if (end < 0) { \
  61. end += len; \
  62. if (end < 0) \
  63. end = 0; \
  64. } \
  65. if (start < 0) { \
  66. start += len; \
  67. if (start < 0) \
  68. start = 0; \
  69. }
  70. namespace {
  71. //////////////////////////////////////////////////////////////////////////////////////////////
  72. /// why doesn't the std::reverse work?
  73. ///
  74. void reverse_strings( std::vector< std::string > & result)
  75. {
  76. for (std::vector< std::string >::size_type i = 0; i < result.size() / 2; i++ )
  77. {
  78. std::swap(result[i], result[result.size() - 1 - i]);
  79. }
  80. }
  81. //////////////////////////////////////////////////////////////////////////////////////////////
  82. ///
  83. ///
  84. void split_whitespace( const std::string & str, std::vector< std::string > & result, int maxsplit )
  85. {
  86. std::string::size_type i, j, len = str.size();
  87. for (i = j = 0; i < len; )
  88. {
  89. while ( i < len && ::isspace( str[i] ) ) i++;
  90. j = i;
  91. while ( i < len && ! ::isspace( str[i]) ) i++;
  92. if (j < i)
  93. {
  94. if ( maxsplit-- <= 0 ) break;
  95. result.push_back( str.substr( j, i - j ));
  96. while ( i < len && ::isspace( str[i])) i++;
  97. j = i;
  98. }
  99. }
  100. if (j < len)
  101. {
  102. result.push_back( str.substr( j, len - j ));
  103. }
  104. }
  105. //////////////////////////////////////////////////////////////////////////////////////////////
  106. ///
  107. ///
  108. void rsplit_whitespace( const std::string & str, std::vector< std::string > & result, int maxsplit )
  109. {
  110. std::string::size_type len = str.size();
  111. std::string::size_type i, j;
  112. for (i = j = len; i > 0; )
  113. {
  114. while ( i > 0 && ::isspace( str[i - 1] ) ) i--;
  115. j = i;
  116. while ( i > 0 && ! ::isspace( str[i - 1]) ) i--;
  117. if (j > i)
  118. {
  119. if ( maxsplit-- <= 0 ) break;
  120. result.push_back( str.substr( i, j - i ));
  121. while ( i > 0 && ::isspace( str[i - 1])) i--;
  122. j = i;
  123. }
  124. }
  125. if (j > 0)
  126. {
  127. result.push_back( str.substr( 0, j ));
  128. }
  129. //std::reverse( result, result.begin(), result.end() );
  130. reverse_strings( result );
  131. }
  132. } //anonymous namespace
  133. //////////////////////////////////////////////////////////////////////////////////////////////
  134. ///
  135. ///
  136. void split( const std::string & str, std::vector< std::string > & result, const std::string & sep, int maxsplit )
  137. {
  138. result.clear();
  139. if ( maxsplit < 0 ) maxsplit = MAX_32BIT_INT;//result.max_size();
  140. if ( sep.size() == 0 )
  141. {
  142. split_whitespace( str, result, maxsplit );
  143. return;
  144. }
  145. std::string::size_type i,j, len = str.size(), n = sep.size();
  146. i = j = 0;
  147. while ( i+n <= len )
  148. {
  149. if ( str[i] == sep[0] && str.substr( i, n ) == sep )
  150. {
  151. if ( maxsplit-- <= 0 ) break;
  152. result.push_back( str.substr( j, i - j ) );
  153. i = j = i + n;
  154. }
  155. else
  156. {
  157. i++;
  158. }
  159. }
  160. result.push_back( str.substr( j, len-j ) );
  161. }
  162. //////////////////////////////////////////////////////////////////////////////////////////////
  163. ///
  164. ///
  165. void rsplit( const std::string & str, std::vector< std::string > & result, const std::string & sep, int maxsplit )
  166. {
  167. if ( maxsplit < 0 )
  168. {
  169. split( str, result, sep, 0 );
  170. return;
  171. }
  172. result.clear();
  173. if ( sep.size() == 0 )
  174. {
  175. rsplit_whitespace( str, result, maxsplit );
  176. return;
  177. }
  178. std::string::size_type i,j, len = str.size(), n = sep.size();
  179. i = j = len;
  180. while ( i > n )
  181. {
  182. if ( str[i - 1] == sep[n - 1] && str.substr( i - n, n ) == sep )
  183. {
  184. if ( maxsplit-- <= 0 ) break;
  185. result.push_back( str.substr( i, j - i ) );
  186. i = j = i - n;
  187. }
  188. else
  189. {
  190. i--;
  191. }
  192. }
  193. result.push_back( str.substr( 0, j ) );
  194. reverse_strings( result );
  195. }
  196. //////////////////////////////////////////////////////////////////////////////////////////////
  197. ///
  198. ///
  199. #define LEFTSTRIP 0
  200. #define RIGHTSTRIP 1
  201. #define BOTHSTRIP 2
  202. //////////////////////////////////////////////////////////////////////////////////////////////
  203. ///
  204. ///
  205. std::string do_strip( const std::string & str, int striptype, const std::string & chars )
  206. {
  207. Py_ssize_t len = (Py_ssize_t) str.size(), i, j, charslen = (Py_ssize_t) chars.size();
  208. if ( charslen == 0 )
  209. {
  210. i = 0;
  211. if ( striptype != RIGHTSTRIP )
  212. {
  213. while ( i < len && ::isspace( str[i] ) )
  214. {
  215. i++;
  216. }
  217. }
  218. j = len;
  219. if ( striptype != LEFTSTRIP )
  220. {
  221. do
  222. {
  223. j--;
  224. }
  225. while (j >= i && ::isspace(str[j]));
  226. j++;
  227. }
  228. }
  229. else
  230. {
  231. const char * sep = chars.c_str();
  232. i = 0;
  233. if ( striptype != RIGHTSTRIP )
  234. {
  235. while ( i < len && memchr(sep, str[i], charslen) )
  236. {
  237. i++;
  238. }
  239. }
  240. j = len;
  241. if (striptype != LEFTSTRIP)
  242. {
  243. do
  244. {
  245. j--;
  246. }
  247. while (j >= i && memchr(sep, str[j], charslen) );
  248. j++;
  249. }
  250. }
  251. if ( i == 0 && j == len )
  252. {
  253. return str;
  254. }
  255. else
  256. {
  257. return str.substr( i, j - i );
  258. }
  259. }
  260. //////////////////////////////////////////////////////////////////////////////////////////////
  261. ///
  262. ///
  263. void partition( const std::string & str, const std::string & sep, std::vector< std::string > & result )
  264. {
  265. result.resize(3);
  266. int index = find( str, sep );
  267. if ( index < 0 )
  268. {
  269. result[0] = str;
  270. result[1] = "";
  271. result[2] = "";
  272. }
  273. else
  274. {
  275. result[0] = str.substr( 0, index );
  276. result[1] = sep;
  277. result[2] = str.substr( index + sep.size(), str.size() );
  278. }
  279. }
  280. //////////////////////////////////////////////////////////////////////////////////////////////
  281. ///
  282. ///
  283. void rpartition( const std::string & str, const std::string & sep, std::vector< std::string > & result )
  284. {
  285. result.resize(3);
  286. int index = rfind( str, sep );
  287. if ( index < 0 )
  288. {
  289. result[0] = "";
  290. result[1] = "";
  291. result[2] = str;
  292. }
  293. else
  294. {
  295. result[0] = str.substr( 0, index );
  296. result[1] = sep;
  297. result[2] = str.substr( index + sep.size(), str.size() );
  298. }
  299. }
  300. //////////////////////////////////////////////////////////////////////////////////////////////
  301. ///
  302. ///
  303. std::string strip( const std::string & str, const std::string & chars )
  304. {
  305. return do_strip( str, BOTHSTRIP, chars );
  306. }
  307. //////////////////////////////////////////////////////////////////////////////////////////////
  308. ///
  309. ///
  310. std::string lstrip( const std::string & str, const std::string & chars )
  311. {
  312. return do_strip( str, LEFTSTRIP, chars );
  313. }
  314. //////////////////////////////////////////////////////////////////////////////////////////////
  315. ///
  316. ///
  317. std::string rstrip( const std::string & str, const std::string & chars )
  318. {
  319. return do_strip( str, RIGHTSTRIP, chars );
  320. }
  321. //////////////////////////////////////////////////////////////////////////////////////////////
  322. ///
  323. ///
  324. std::string join( const std::string & str, const std::vector< std::string > & seq )
  325. {
  326. std::vector< std::string >::size_type seqlen = seq.size(), i;
  327. if ( seqlen == 0 ) return "";
  328. if ( seqlen == 1 ) return seq[0];
  329. std::string result( seq[0] );
  330. for ( i = 1; i < seqlen; ++i )
  331. {
  332. result += str + seq[i];
  333. }
  334. return result;
  335. }
  336. //////////////////////////////////////////////////////////////////////////////////////////////
  337. ///
  338. ///
  339. namespace
  340. {
  341. /* Matches the end (direction >= 0) or start (direction < 0) of self
  342. * against substr, using the start and end arguments. Returns
  343. * -1 on error, 0 if not found and 1 if found.
  344. */
  345. int _string_tailmatch(const std::string & self, const std::string & substr,
  346. Py_ssize_t start, Py_ssize_t end,
  347. int direction)
  348. {
  349. Py_ssize_t len = (Py_ssize_t) self.size();
  350. Py_ssize_t slen = (Py_ssize_t) substr.size();
  351. const char* sub = substr.c_str();
  352. const char* str = self.c_str();
  353. ADJUST_INDICES(start, end, len);
  354. if (direction < 0) {
  355. // startswith
  356. if (start+slen > len)
  357. return 0;
  358. } else {
  359. // endswith
  360. if (end-start < slen || start > len)
  361. return 0;
  362. if (end-slen > start)
  363. start = end - slen;
  364. }
  365. if (end-start >= slen)
  366. return (!std::memcmp(str+start, sub, slen));
  367. return 0;
  368. }
  369. }
  370. bool endswith( const std::string & str, const std::string & suffix, int start, int end )
  371. {
  372. int result = _string_tailmatch(str, suffix,
  373. (Py_ssize_t) start, (Py_ssize_t) end, +1);
  374. //if (result == -1) // TODO: Error condition
  375. return static_cast<bool>(result);
  376. }
  377. bool startswith( const std::string & str, const std::string & prefix, int start, int end )
  378. {
  379. int result = _string_tailmatch(str, prefix,
  380. (Py_ssize_t) start, (Py_ssize_t) end, -1);
  381. //if (result == -1) // TODO: Error condition
  382. return static_cast<bool>(result);
  383. }
  384. //////////////////////////////////////////////////////////////////////////////////////////////
  385. ///
  386. ///
  387. bool isalnum( const std::string & str )
  388. {
  389. std::string::size_type len = str.size(), i;
  390. if ( len == 0 ) return false;
  391. if( len == 1 )
  392. {
  393. return ::isalnum( str[0] );
  394. }
  395. for ( i = 0; i < len; ++i )
  396. {
  397. if ( !::isalnum( str[i] ) ) return false;
  398. }
  399. return true;
  400. }
  401. //////////////////////////////////////////////////////////////////////////////////////////////
  402. ///
  403. ///
  404. bool isalpha( const std::string & str )
  405. {
  406. std::string::size_type len = str.size(), i;
  407. if ( len == 0 ) return false;
  408. if( len == 1 ) return ::isalpha( (int) str[0] );
  409. for ( i = 0; i < len; ++i )
  410. {
  411. if ( !::isalpha( (int) str[i] ) ) return false;
  412. }
  413. return true;
  414. }
  415. //////////////////////////////////////////////////////////////////////////////////////////////
  416. ///
  417. ///
  418. bool isdigit( const std::string & str )
  419. {
  420. std::string::size_type len = str.size(), i;
  421. if ( len == 0 ) return false;
  422. if( len == 1 ) return ::isdigit( str[0] );
  423. for ( i = 0; i < len; ++i )
  424. {
  425. if ( ! ::isdigit( str[i] ) ) return false;
  426. }
  427. return true;
  428. }
  429. //////////////////////////////////////////////////////////////////////////////////////////////
  430. ///
  431. ///
  432. bool islower( const std::string & str )
  433. {
  434. std::string::size_type len = str.size(), i;
  435. if ( len == 0 ) return false;
  436. if( len == 1 ) return ::islower( str[0] );
  437. for ( i = 0; i < len; ++i )
  438. {
  439. if ( !::islower( str[i] ) ) return false;
  440. }
  441. return true;
  442. }
  443. //////////////////////////////////////////////////////////////////////////////////////////////
  444. ///
  445. ///
  446. bool isspace( const std::string & str )
  447. {
  448. std::string::size_type len = str.size(), i;
  449. if ( len == 0 ) return false;
  450. if( len == 1 ) return ::isspace( str[0] );
  451. for ( i = 0; i < len; ++i )
  452. {
  453. if ( !::isspace( str[i] ) ) return false;
  454. }
  455. return true;
  456. }
  457. //////////////////////////////////////////////////////////////////////////////////////////////
  458. ///
  459. ///
  460. bool istitle( const std::string & str )
  461. {
  462. std::string::size_type len = str.size(), i;
  463. if ( len == 0 ) return false;
  464. if ( len == 1 ) return ::isupper( str[0] );
  465. bool cased = false, previous_is_cased = false;
  466. for ( i = 0; i < len; ++i )
  467. {
  468. if ( ::isupper( str[i] ) )
  469. {
  470. if ( previous_is_cased )
  471. {
  472. return false;
  473. }
  474. previous_is_cased = true;
  475. cased = true;
  476. }
  477. else if ( ::islower( str[i] ) )
  478. {
  479. if (!previous_is_cased)
  480. {
  481. return false;
  482. }
  483. previous_is_cased = true;
  484. cased = true;
  485. }
  486. else
  487. {
  488. previous_is_cased = false;
  489. }
  490. }
  491. return cased;
  492. }
  493. //////////////////////////////////////////////////////////////////////////////////////////////
  494. ///
  495. ///
  496. bool isupper( const std::string & str )
  497. {
  498. std::string::size_type len = str.size(), i;
  499. if ( len == 0 ) return false;
  500. if( len == 1 ) return ::isupper( str[0] );
  501. for ( i = 0; i < len; ++i )
  502. {
  503. if ( !::isupper( str[i] ) ) return false;
  504. }
  505. return true;
  506. }
  507. //////////////////////////////////////////////////////////////////////////////////////////////
  508. ///
  509. ///
  510. std::string capitalize( const std::string & str )
  511. {
  512. std::string s( str );
  513. std::string::size_type len = s.size(), i;
  514. if ( len > 0)
  515. {
  516. if (::islower(s[0])) s[0] = (char) ::toupper( s[0] );
  517. }
  518. for ( i = 1; i < len; ++i )
  519. {
  520. if (::isupper(s[i])) s[i] = (char) ::tolower( s[i] );
  521. }
  522. return s;
  523. }
  524. //////////////////////////////////////////////////////////////////////////////////////////////
  525. ///
  526. ///
  527. std::string lower( const std::string & str )
  528. {
  529. std::string s( str );
  530. std::string::size_type len = s.size(), i;
  531. for ( i = 0; i < len; ++i )
  532. {
  533. if ( ::isupper( s[i] ) ) s[i] = (char) ::tolower( s[i] );
  534. }
  535. return s;
  536. }
  537. //////////////////////////////////////////////////////////////////////////////////////////////
  538. ///
  539. ///
  540. std::string upper( const std::string & str )
  541. {
  542. std::string s( str ) ;
  543. std::string::size_type len = s.size(), i;
  544. for ( i = 0; i < len; ++i )
  545. {
  546. if ( ::islower( s[i] ) ) s[i] = (char) ::toupper( s[i] );
  547. }
  548. return s;
  549. }
  550. //////////////////////////////////////////////////////////////////////////////////////////////
  551. ///
  552. ///
  553. std::string swapcase( const std::string & str )
  554. {
  555. std::string s( str );
  556. std::string::size_type len = s.size(), i;
  557. for ( i = 0; i < len; ++i )
  558. {
  559. if ( ::islower( s[i] ) ) s[i] = (char) ::toupper( s[i] );
  560. else if (::isupper( s[i] ) ) s[i] = (char) ::tolower( s[i] );
  561. }
  562. return s;
  563. }
  564. //////////////////////////////////////////////////////////////////////////////////////////////
  565. ///
  566. ///
  567. std::string title( const std::string & str )
  568. {
  569. std::string s( str );
  570. std::string::size_type len = s.size(), i;
  571. bool previous_is_cased = false;
  572. for ( i = 0; i < len; ++i )
  573. {
  574. int c = s[i];
  575. if ( ::islower(c) )
  576. {
  577. if ( !previous_is_cased )
  578. {
  579. s[i] = (char) ::toupper(c);
  580. }
  581. previous_is_cased = true;
  582. }
  583. else if ( ::isupper(c) )
  584. {
  585. if ( previous_is_cased )
  586. {
  587. s[i] = (char) ::tolower(c);
  588. }
  589. previous_is_cased = true;
  590. }
  591. else
  592. {
  593. previous_is_cased = false;
  594. }
  595. }
  596. return s;
  597. }
  598. //////////////////////////////////////////////////////////////////////////////////////////////
  599. ///
  600. ///
  601. std::string translate( const std::string & str, const std::string & table, const std::string & deletechars )
  602. {
  603. std::string s;
  604. std::string::size_type len = str.size(), dellen = deletechars.size();
  605. if ( table.size() != 256 )
  606. {
  607. // TODO : raise exception instead
  608. return str;
  609. }
  610. //if nothing is deleted, use faster code
  611. if ( dellen == 0 )
  612. {
  613. s = str;
  614. for ( std::string::size_type i = 0; i < len; ++i )
  615. {
  616. s[i] = table[ s[i] ];
  617. }
  618. return s;
  619. }
  620. int trans_table[256];
  621. for ( int i = 0; i < 256; i++)
  622. {
  623. trans_table[i] = table[i];
  624. }
  625. for ( std::string::size_type i = 0; i < dellen; i++)
  626. {
  627. trans_table[(int) deletechars[i] ] = -1;
  628. }
  629. for ( std::string::size_type i = 0; i < len; ++i )
  630. {
  631. if ( trans_table[ (int) str[i] ] != -1 )
  632. {
  633. s += table[ str[i] ];
  634. }
  635. }
  636. return s;
  637. }
  638. //////////////////////////////////////////////////////////////////////////////////////////////
  639. ///
  640. ///
  641. std::string zfill( const std::string & str, int width )
  642. {
  643. int len = (int)str.size();
  644. if ( len >= width )
  645. {
  646. return str;
  647. }
  648. std::string s( str );
  649. int fill = width - len;
  650. s = std::string( fill, '0' ) + s;
  651. if ( s[fill] == '+' || s[fill] == '-' )
  652. {
  653. s[0] = s[fill];
  654. s[fill] = '0';
  655. }
  656. return s;
  657. }
  658. //////////////////////////////////////////////////////////////////////////////////////////////
  659. ///
  660. ///
  661. std::string ljust( const std::string & str, int width )
  662. {
  663. std::string::size_type len = str.size();
  664. if ( (( int ) len ) >= width ) return str;
  665. return str + std::string( width - len, ' ' );
  666. }
  667. //////////////////////////////////////////////////////////////////////////////////////////////
  668. ///
  669. ///
  670. std::string rjust( const std::string & str, int width )
  671. {
  672. std::string::size_type len = str.size();
  673. if ( (( int ) len ) >= width ) return str;
  674. return std::string( width - len, ' ' ) + str;
  675. }
  676. //////////////////////////////////////////////////////////////////////////////////////////////
  677. ///
  678. ///
  679. std::string center( const std::string & str, int width )
  680. {
  681. int len = (int) str.size();
  682. int marg, left;
  683. if ( len >= width ) return str;
  684. marg = width - len;
  685. left = marg / 2 + (marg & width & 1);
  686. return std::string( left, ' ' ) + str + std::string( marg - left, ' ' );
  687. }
  688. //////////////////////////////////////////////////////////////////////////////////////////////
  689. ///
  690. ///
  691. std::string slice( const std::string & str, int start, int end )
  692. {
  693. ADJUST_INDICES(start, end, (int) str.size());
  694. if ( start >= end ) return "";
  695. return str.substr( start, end - start );
  696. }
  697. //////////////////////////////////////////////////////////////////////////////////////////////
  698. ///
  699. ///
  700. int find( const std::string & str, const std::string & sub, int start, int end )
  701. {
  702. ADJUST_INDICES(start, end, (int) str.size());
  703. std::string::size_type result = str.find( sub, start );
  704. // If we cannot find the string, or if the end-point of our found substring is past
  705. // the allowed end limit, return that it can't be found.
  706. if( result == std::string::npos ||
  707. (result + sub.size() > (std::string::size_type)end) )
  708. {
  709. return -1;
  710. }
  711. return (int) result;
  712. }
  713. //////////////////////////////////////////////////////////////////////////////////////////////
  714. ///
  715. ///
  716. int index( const std::string & str, const std::string & sub, int start, int end )
  717. {
  718. return find( str, sub, start, end );
  719. }
  720. //////////////////////////////////////////////////////////////////////////////////////////////
  721. ///
  722. ///
  723. int rfind( const std::string & str, const std::string & sub, int start, int end )
  724. {
  725. ADJUST_INDICES(start, end, (int) str.size());
  726. std::string::size_type result = str.rfind( sub, end );
  727. if( result == std::string::npos ||
  728. result < (std::string::size_type)start ||
  729. (result + sub.size() > (std::string::size_type)end))
  730. return -1;
  731. return (int)result;
  732. }
  733. //////////////////////////////////////////////////////////////////////////////////////////////
  734. ///
  735. ///
  736. int rindex( const std::string & str, const std::string & sub, int start, int end )
  737. {
  738. return rfind( str, sub, start, end );
  739. }
  740. //////////////////////////////////////////////////////////////////////////////////////////////
  741. ///
  742. ///
  743. std::string expandtabs( const std::string & str, int tabsize )
  744. {
  745. std::string s( str );
  746. std::string::size_type len = str.size(), i = 0;
  747. int offset = 0;
  748. int j = 0;
  749. for ( i = 0; i < len; ++i )
  750. {
  751. if ( str[i] == '\t' )
  752. {
  753. if ( tabsize > 0 )
  754. {
  755. int fillsize = tabsize - (j % tabsize);
  756. j += fillsize;
  757. s.replace( i + offset, 1, std::string( fillsize, ' ' ));
  758. offset += fillsize - 1;
  759. }
  760. else
  761. {
  762. s.replace( i + offset, 1, "" );
  763. offset -= 1;
  764. }
  765. }
  766. else
  767. {
  768. j++;
  769. if (str[i] == '\n' || str[i] == '\r')
  770. {
  771. j = 0;
  772. }
  773. }
  774. }
  775. return s;
  776. }
  777. //////////////////////////////////////////////////////////////////////////////////////////////
  778. ///
  779. ///
  780. int count( const std::string & str, const std::string & substr, int start, int end )
  781. {
  782. int nummatches = 0;
  783. int cursor = start;
  784. while ( 1 )
  785. {
  786. cursor = find( str, substr, cursor, end );
  787. if ( cursor < 0 ) break;
  788. cursor += (int) substr.size();
  789. nummatches += 1;
  790. }
  791. return nummatches;
  792. }
  793. //////////////////////////////////////////////////////////////////////////////////////////////
  794. ///
  795. ///
  796. std::string replace( const std::string & str, const std::string & oldstr, const std::string & newstr, int count )
  797. {
  798. int sofar = 0;
  799. int cursor = 0;
  800. std::string s( str );
  801. std::string::size_type oldlen = oldstr.size(), newlen = newstr.size();
  802. while ( ( cursor = find( s, oldstr, cursor ) ) != -1 )
  803. {
  804. if ( count > -1 && sofar >= count )
  805. {
  806. break;
  807. }
  808. s.replace( cursor, oldlen, newstr );
  809. cursor += (int) newlen;
  810. ++sofar;
  811. }
  812. return s;
  813. }
  814. //////////////////////////////////////////////////////////////////////////////////////////////
  815. ///
  816. ///
  817. void splitlines( const std::string & str, std::vector< std::string > & result, bool keepends )
  818. {
  819. result.clear();
  820. std::string::size_type len = str.size(), i, j, eol;
  821. for (i = j = 0; i < len; )
  822. {
  823. while (i < len && str[i] != '\n' && str[i] != '\r') i++;
  824. eol = i;
  825. if (i < len)
  826. {
  827. if (str[i] == '\r' && i + 1 < len && str[i+1] == '\n')
  828. {
  829. i += 2;
  830. }
  831. else
  832. {
  833. i++;
  834. }
  835. if (keepends)
  836. eol = i;
  837. }
  838. result.push_back( str.substr( j, eol - j ) );
  839. j = i;
  840. }
  841. if (j < len)
  842. {
  843. result.push_back( str.substr( j, len - j ) );
  844. }
  845. }
  846. //////////////////////////////////////////////////////////////////////////////////////////////
  847. ///
  848. ///
  849. std::string mul( const std::string & str, int n )
  850. {
  851. // Early exits
  852. if (n <= 0) return "";
  853. if (n == 1) return str;
  854. std::ostringstream os;
  855. for(int i=0; i<n; ++i)
  856. {
  857. os << str;
  858. }
  859. return os.str();
  860. }
  861. namespace os
  862. {
  863. namespace path
  864. {
  865. //////////////////////////////////////////////////////////////////////////////////////////////
  866. ///
  867. ///
  868. /// These functions are C++ ports of the python2.6 versions of os.path,
  869. /// and come from genericpath.py, ntpath.py, posixpath.py
  870. /// Split a pathname into drive and path specifiers.
  871. /// Returns drivespec, pathspec. Either part may be empty.
  872. void splitdrive_nt(std::string & drivespec, std::string & pathspec,
  873. const std::string & p)
  874. {
  875. if(pystring::slice(p, 1, 2) == ":")
  876. {
  877. std::string path = p; // In case drivespec == p
  878. drivespec = pystring::slice(path, 0, 2);
  879. pathspec = pystring::slice(path, 2);
  880. }
  881. else
  882. {
  883. drivespec = "";
  884. pathspec = p;
  885. }
  886. }
  887. // On Posix, drive is always empty
  888. void splitdrive_posix(std::string & drivespec, std::string & pathspec,
  889. const std::string & path)
  890. {
  891. drivespec = "";
  892. pathspec = path;
  893. }
  894. void splitdrive(std::string & drivespec, std::string & pathspec,
  895. const std::string & path)
  896. {
  897. #ifdef WINDOWS
  898. return splitdrive_nt(drivespec, pathspec, path);
  899. #else
  900. return splitdrive_posix(drivespec, pathspec, path);
  901. #endif
  902. }
  903. //////////////////////////////////////////////////////////////////////////////////////////////
  904. ///
  905. ///
  906. // Test whether a path is absolute
  907. // In windows, if the character to the right of the colon
  908. // is a forward or backslash it's absolute.
  909. bool isabs_nt(const std::string & path)
  910. {
  911. std::string drivespec, pathspec;
  912. splitdrive_nt(drivespec, pathspec, path);
  913. if(pathspec.empty()) return false;
  914. return ((pathspec[0] == '/') || (pathspec[0] == '\\'));
  915. }
  916. bool isabs_posix(const std::string & s)
  917. {
  918. return pystring::startswith(s, "/");
  919. }
  920. bool isabs(const std::string & path)
  921. {
  922. #ifdef WINDOWS
  923. return isabs_nt(path);
  924. #else
  925. return isabs_posix(path);
  926. #endif
  927. }
  928. //////////////////////////////////////////////////////////////////////////////////////////////
  929. ///
  930. ///
  931. std::string abspath_nt(const std::string & path, const std::string & cwd)
  932. {
  933. std::string p = path;
  934. if(!isabs_nt(p)) p = join_nt(cwd, p);
  935. return normpath_nt(p);
  936. }
  937. std::string abspath_posix(const std::string & path, const std::string & cwd)
  938. {
  939. std::string p = path;
  940. if(!isabs_posix(p)) p = join_posix(cwd, p);
  941. return normpath_posix(p);
  942. }
  943. std::string abspath(const std::string & path, const std::string & cwd)
  944. {
  945. #ifdef WINDOWS
  946. return abspath_nt(path, cwd);
  947. #else
  948. return abspath_posix(path, cwd);
  949. #endif
  950. }
  951. //////////////////////////////////////////////////////////////////////////////////////////////
  952. ///
  953. ///
  954. std::string join_nt(const std::vector< std::string > & paths)
  955. {
  956. if(paths.empty()) return "";
  957. if(paths.size() == 1) return paths[0];
  958. std::string path = paths[0];
  959. for(unsigned int i=1; i<paths.size(); ++i)
  960. {
  961. std::string b = paths[i];
  962. bool b_nts = false;
  963. if(path.empty())
  964. {
  965. b_nts = true;
  966. }
  967. else if(isabs_nt(b))
  968. {
  969. // This probably wipes out path so far. However, it's more
  970. // complicated if path begins with a drive letter:
  971. // 1. join('c:', '/a') == 'c:/a'
  972. // 2. join('c:/', '/a') == 'c:/a'
  973. // But
  974. // 3. join('c:/a', '/b') == '/b'
  975. // 4. join('c:', 'd:/') = 'd:/'
  976. // 5. join('c:/', 'd:/') = 'd:/'
  977. if( (pystring::slice(path, 1, 2) != ":") ||
  978. (pystring::slice(b, 1, 2) == ":") )
  979. {
  980. // Path doesnt start with a drive letter
  981. b_nts = true;
  982. }
  983. // Else path has a drive letter, and b doesn't but is absolute.
  984. else if((path.size()>3) ||
  985. ((path.size()==3) && !pystring::endswith(path, "/") && !pystring::endswith(path, "\\")))
  986. {
  987. b_nts = true;
  988. }
  989. }
  990. if(b_nts)
  991. {
  992. path = b;
  993. }
  994. else
  995. {
  996. // Join, and ensure there's a separator.
  997. // assert len(path) > 0
  998. if( pystring::endswith(path, "/") || pystring::endswith(path, "\\"))
  999. {
  1000. if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
  1001. {
  1002. path += pystring::slice(b, 1);
  1003. }
  1004. else
  1005. {
  1006. path += b;
  1007. }
  1008. }
  1009. else if(pystring::endswith(path, ":"))
  1010. {
  1011. path += b;
  1012. }
  1013. else if(!b.empty())
  1014. {
  1015. if(pystring::startswith(b,"/") || pystring::startswith(b,"\\"))
  1016. {
  1017. path += b;
  1018. }
  1019. else
  1020. {
  1021. path += "\\" + b;
  1022. }
  1023. }
  1024. else
  1025. {
  1026. // path is not empty and does not end with a backslash,
  1027. // but b is empty; since, e.g., split('a/') produces
  1028. // ('a', ''), it's best if join() adds a backslash in
  1029. // this case.
  1030. path += "\\";
  1031. }
  1032. }
  1033. }
  1034. return path;
  1035. }
  1036. // Join two or more pathname components, inserting "\\" as needed.
  1037. std::string join_nt(const std::string & a, const std::string & b)
  1038. {
  1039. std::vector< std::string > paths(2);
  1040. paths[0] = a;
  1041. paths[1] = b;
  1042. return join_nt(paths);
  1043. }
  1044. // Join pathnames.
  1045. // If any component is an absolute path, all previous path components
  1046. // will be discarded.
  1047. // Ignore the previous parts if a part is absolute.
  1048. // Insert a '/' unless the first part is empty or already ends in '/'.
  1049. std::string join_posix(const std::vector< std::string > & paths)
  1050. {
  1051. if(paths.empty()) return "";
  1052. if(paths.size() == 1) return paths[0];
  1053. std::string path = paths[0];
  1054. for(unsigned int i=1; i<paths.size(); ++i)
  1055. {
  1056. std::string b = paths[i];
  1057. if(pystring::startswith(b, "/"))
  1058. {
  1059. path = b;
  1060. }
  1061. else if(path.empty() || pystring::endswith(path, "/"))
  1062. {
  1063. path += b;
  1064. }
  1065. else
  1066. {
  1067. path += "/" + b;
  1068. }
  1069. }
  1070. return path;
  1071. }
  1072. std::string join_posix(const std::string & a, const std::string & b)
  1073. {
  1074. std::vector< std::string > paths(2);
  1075. paths[0] = a;
  1076. paths[1] = b;
  1077. return join_posix(paths);
  1078. }
  1079. std::string join(const std::string & path1, const std::string & path2)
  1080. {
  1081. #ifdef WINDOWS
  1082. return join_nt(path1, path2);
  1083. #else
  1084. return join_posix(path1, path2);
  1085. #endif
  1086. }
  1087. std::string join(const std::vector< std::string > & paths)
  1088. {
  1089. #ifdef WINDOWS
  1090. return join_nt(paths);
  1091. #else
  1092. return join_posix(paths);
  1093. #endif
  1094. }
  1095. //////////////////////////////////////////////////////////////////////////////////////////////
  1096. ///
  1097. ///
  1098. // Split a pathname.
  1099. // Return (head, tail) where tail is everything after the final slash.
  1100. // Either part may be empty
  1101. void split_nt(std::string & head, std::string & tail, const std::string & path)
  1102. {
  1103. std::string d, p;
  1104. splitdrive_nt(d, p, path);
  1105. // set i to index beyond p's last slash
  1106. int i = (int)p.size();
  1107. while(i>0 && (p[i-1] != '\\') && (p[i-1] != '/'))
  1108. {
  1109. i = i - 1;
  1110. }
  1111. head = pystring::slice(p,0,i);
  1112. tail = pystring::slice(p,i); // now tail has no slashes
  1113. // remove trailing slashes from head, unless it's all slashes
  1114. std::string head2 = head;
  1115. while(!head2.empty() && ((pystring::slice(head2,-1) == "/") ||
  1116. (pystring::slice(head2,-1) == "\\")))
  1117. {
  1118. head2 = pystring::slice(head,0,-1);
  1119. }
  1120. if(!head2.empty()) head = head2;
  1121. head = d + head;
  1122. }
  1123. // Split a path in head (everything up to the last '/') and tail (the
  1124. // rest). If the path ends in '/', tail will be empty. If there is no
  1125. // '/' in the path, head will be empty.
  1126. // Trailing '/'es are stripped from head unless it is the root.
  1127. void split_posix(std::string & head, std::string & tail, const std::string & p)
  1128. {
  1129. int i = pystring::rfind(p, "/") + 1;
  1130. head = pystring::slice(p,0,i);
  1131. tail = pystring::slice(p,i);
  1132. if(!head.empty() && (head != pystring::mul("/", (int) head.size())))
  1133. {
  1134. head = pystring::rstrip(head, "/");
  1135. }
  1136. }
  1137. void split(std::string & head, std::string & tail, const std::string & path)
  1138. {
  1139. #ifdef WINDOWS
  1140. return split_nt(head, tail, path);
  1141. #else
  1142. return split_posix(head, tail, path);
  1143. #endif
  1144. }
  1145. //////////////////////////////////////////////////////////////////////////////////////////////
  1146. ///
  1147. ///
  1148. std::string basename_nt(const std::string & path)
  1149. {
  1150. std::string head, tail;
  1151. split_nt(head, tail, path);
  1152. return tail;
  1153. }
  1154. std::string basename_posix(const std::string & path)
  1155. {
  1156. std::string head, tail;
  1157. split_posix(head, tail, path);
  1158. return tail;
  1159. }
  1160. std::string basename(const std::string & path)
  1161. {
  1162. #ifdef WINDOWS
  1163. return basename_nt(path);
  1164. #else
  1165. return basename_posix(path);
  1166. #endif
  1167. }
  1168. std::string dirname_nt(const std::string & path)
  1169. {
  1170. std::string head, tail;
  1171. split_nt(head, tail, path);
  1172. return head;
  1173. }
  1174. std::string dirname_posix(const std::string & path)
  1175. {
  1176. std::string head, tail;
  1177. split_posix(head, tail, path);
  1178. return head;
  1179. }
  1180. std::string dirname(const std::string & path)
  1181. {
  1182. #ifdef WINDOWS
  1183. return dirname_nt(path);
  1184. #else
  1185. return dirname_posix(path);
  1186. #endif
  1187. }
  1188. //////////////////////////////////////////////////////////////////////////////////////////////
  1189. ///
  1190. ///
  1191. // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
  1192. std::string normpath_nt(const std::string & p)
  1193. {
  1194. std::string path = p;
  1195. path = pystring::replace(path, "/","\\");
  1196. std::string prefix;
  1197. splitdrive_nt(prefix, path, path);
  1198. // We need to be careful here. If the prefix is empty, and the path starts
  1199. // with a backslash, it could either be an absolute path on the current
  1200. // drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It
  1201. // is therefore imperative NOT to collapse multiple backslashes blindly in
  1202. // that case.
  1203. // The code below preserves multiple backslashes when there is no drive
  1204. // letter. This means that the invalid filename \\\a\b is preserved
  1205. // unchanged, where a\\\b is normalised to a\b. It's not clear that there
  1206. // is any better behaviour for such edge cases.
  1207. if(prefix.empty())
  1208. {
  1209. // No drive letter - preserve initial backslashes
  1210. while(pystring::slice(path,0,1) == "\\")
  1211. {
  1212. prefix = prefix + "\\";
  1213. path = pystring::slice(path,1);
  1214. }
  1215. }
  1216. else
  1217. {
  1218. // We have a drive letter - collapse initial backslashes
  1219. if(pystring::startswith(path, "\\"))
  1220. {
  1221. prefix = prefix + "\\";
  1222. path = pystring::lstrip(path, "\\");
  1223. }
  1224. }
  1225. std::vector<std::string> comps;
  1226. pystring::split(path, comps, "\\");
  1227. int i = 0;
  1228. while(i<(int)comps.size())
  1229. {
  1230. if(comps[i].empty() || comps[i] == ".")
  1231. {
  1232. comps.erase(comps.begin()+i);
  1233. }
  1234. else if(comps[i] == "..")
  1235. {
  1236. if(i>0 && comps[i-1] != "..")
  1237. {
  1238. comps.erase(comps.begin()+i-1, comps.begin()+i+1);
  1239. i -= 1;
  1240. }
  1241. else if(i == 0 && pystring::endswith(prefix, "\\"))
  1242. {
  1243. comps.erase(comps.begin()+i);
  1244. }
  1245. else
  1246. {
  1247. i += 1;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. i += 1;
  1253. }
  1254. }
  1255. // If the path is now empty, substitute '.'
  1256. if(prefix.empty() && comps.empty())
  1257. {
  1258. comps.push_back(".");
  1259. }
  1260. return prefix + pystring::join("\\", comps);
  1261. }
  1262. // Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
  1263. // It should be understood that this may change the meaning of the path
  1264. // if it contains symbolic links!
  1265. // Normalize path, eliminating double slashes, etc.
  1266. std::string normpath_posix(const std::string & p)
  1267. {
  1268. if(p.empty()) return ".";
  1269. std::string path = p;
  1270. int initial_slashes = pystring::startswith(path,"/") ? 1 : 0;
  1271. // POSIX allows one or two initial slashes, but treats three or more
  1272. // as single slash.
  1273. if (initial_slashes && pystring::startswith(path,"//")
  1274. && !pystring::startswith(path,"///"))
  1275. initial_slashes = 2;
  1276. std::vector<std::string> comps, new_comps;
  1277. pystring::split(path, comps, "/");
  1278. for(unsigned int i=0; i<comps.size(); ++i)
  1279. {
  1280. std::string comp = comps[i];
  1281. if(comp.empty() || comp == ".")
  1282. continue;
  1283. if( (comp != "..") || ((initial_slashes == 0) && new_comps.empty()) ||
  1284. (!new_comps.empty() && new_comps[new_comps.size()-1] == ".."))
  1285. {
  1286. new_comps.push_back(comp);
  1287. }
  1288. else if (!new_comps.empty())
  1289. {
  1290. new_comps.pop_back();
  1291. }
  1292. }
  1293. path = pystring::join("/", new_comps);
  1294. if (initial_slashes > 0)
  1295. path = pystring::mul("/",initial_slashes) + path;
  1296. if(path.empty()) return ".";
  1297. return path;
  1298. }
  1299. std::string normpath(const std::string & path)
  1300. {
  1301. #ifdef WINDOWS
  1302. return normpath_nt(path);
  1303. #else
  1304. return normpath_posix(path);
  1305. #endif
  1306. }
  1307. //////////////////////////////////////////////////////////////////////////////////////////////
  1308. ///
  1309. ///
  1310. // Split the extension from a pathname.
  1311. // Extension is everything from the last dot to the end, ignoring
  1312. // leading dots. Returns "(root, ext)"; ext may be empty.
  1313. // It is always true that root + ext == p
  1314. void splitext_generic(std::string & root, std::string & ext,
  1315. const std::string & p,
  1316. const std::string & sep,
  1317. const std::string & altsep,
  1318. const std::string & extsep)
  1319. {
  1320. int sepIndex = pystring::rfind(p, sep);
  1321. if(!altsep.empty())
  1322. {
  1323. int altsepIndex = pystring::rfind(p, altsep);
  1324. sepIndex = std::max(sepIndex, altsepIndex);
  1325. }
  1326. int dotIndex = pystring::rfind(p, extsep);
  1327. if(dotIndex > sepIndex)
  1328. {
  1329. // Skip all leading dots
  1330. int filenameIndex = sepIndex + 1;
  1331. while(filenameIndex < dotIndex)
  1332. {
  1333. if(pystring::slice(p,filenameIndex) != extsep)
  1334. {
  1335. root = pystring::slice(p, 0, dotIndex);
  1336. ext = pystring::slice(p, dotIndex);
  1337. return;
  1338. }
  1339. filenameIndex += 1;
  1340. }
  1341. }
  1342. root = p;
  1343. ext = "";
  1344. }
  1345. void splitext_nt(std::string & root, std::string & ext, const std::string & path)
  1346. {
  1347. return splitext_generic(root, ext, path,
  1348. "\\", "/", ".");
  1349. }
  1350. void splitext_posix(std::string & root, std::string & ext, const std::string & path)
  1351. {
  1352. return splitext_generic(root, ext, path,
  1353. "/", "", ".");
  1354. }
  1355. void splitext(std::string & root, std::string & ext, const std::string & path)
  1356. {
  1357. #ifdef WINDOWS
  1358. return splitext_nt(root, ext, path);
  1359. #else
  1360. return splitext_posix(root, ext, path);
  1361. #endif
  1362. }
  1363. } // namespace path
  1364. } // namespace os
  1365. }//namespace pystring
  1366. }
  1367. OCIO_NAMESPACE_EXIT