You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

917 lines
29 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: platformstl/system/environment_map.hpp
  3. *
  4. * Purpose: Definition of the environment_map class.
  5. *
  6. * Created: 14th November 2005
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2005-2009, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file platformstl/system/environment_map.hpp
  40. *
  41. * \brief [C++ only] Definition of the platformstl::environment_map class
  42. * (\ref group__library__system "System" Library).
  43. */
  44. #ifndef PLATFORMSTL_INCL_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_MAP
  45. #define PLATFORMSTL_INCL_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_MAP
  46. /* File version */
  47. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  48. # define PLATFORMSTL_VER_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_MAP_MAJOR 2
  49. # define PLATFORMSTL_VER_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_MAP_MINOR 3
  50. # define PLATFORMSTL_VER_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_MAP_REVISION 1
  51. # define PLATFORMSTL_VER_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_MAP_EDIT 56
  52. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  53. /* /////////////////////////////////////////////////////////////////////////
  54. * Auto-generation and compatibility
  55. */
  56. /*
  57. [Incompatibilies-start]
  58. STLSOFT_COMPILER_IS_WATCOM:
  59. [Incompatibilies-end]
  60. */
  61. /* /////////////////////////////////////////////////////////////////////////
  62. * Includes
  63. */
  64. #ifndef PLATFORMSTL_INCL_PLATFORMSTL_HPP_PLATFORMSTL
  65. # include <platformstl/platformstl.hpp>
  66. #endif /* !PLATFORMSTL_INCL_PLATFORMSTL_HPP_PLATFORMSTL */
  67. #ifndef PLATFORMSTL_INCL_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_VARIABLE_TRAITS
  68. # include <platformstl/system/environment_variable_traits.hpp>
  69. #endif /* !PLATFORMSTL_INCL_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_VARIABLE_TRAITS */
  70. #if defined(PLATFORMSTL_OS_IS_UNIX)
  71. #elif defined(PLATFORMSTL_OS_IS_WINDOWS)
  72. #else /* ? operating system */
  73. # error Operating system not discriminated
  74. #endif /* operating system */
  75. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_LIBRARY_DISCRIMINATOR
  76. # include <stlsoft/util/std/library_discriminator.hpp>
  77. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_LIBRARY_DISCRIMINATOR */
  78. #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE
  79. # include <stlsoft/smartptr/scoped_handle.hpp>
  80. #endif /* !STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE */
  81. #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SHARED_PTR
  82. # include <stlsoft/smartptr/shared_ptr.hpp>
  83. #endif /* !STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SHARED_PTR */
  84. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  85. # include <stlsoft/shims/access/string.hpp>
  86. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  87. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SPLIT_FUNCTIONS
  88. # include <stlsoft/string/split_functions.hpp>
  89. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SPLIT_FUNCTIONS */
  90. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  91. # include <stlsoft/util/std/iterator_helper.hpp>
  92. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  93. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  94. # include <stlsoft/collections/util/collections.hpp>
  95. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  96. #ifndef STLSOFT_INCL_MAP
  97. # define STLSOFT_INCL_MAP
  98. # include <map>
  99. #endif /* !STLSOFT_INCL_MAP */
  100. #ifndef STLSOFT_INCL_UTILITY
  101. # define STLSOFT_INCL_UTILITY
  102. # include <utility>
  103. #endif /* !STLSOFT_INCL_UTILITY */
  104. /* /////////////////////////////////////////////////////////////////////////
  105. * Namespace
  106. */
  107. #if defined(_STLSOFT_NO_NAMESPACE) || \
  108. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  109. /* There is no stlsoft namespace, so must define ::platformstl */
  110. namespace platformstl
  111. {
  112. #else
  113. /* Define stlsoft::platformstl_project */
  114. namespace stlsoft
  115. {
  116. namespace platformstl_project
  117. {
  118. #endif /* _STLSOFT_NO_NAMESPACE */
  119. /* /////////////////////////////////////////////////////////////////////////
  120. * Classes
  121. */
  122. /** \brief Provides an associative STL-collection interface to the current
  123. * process's system environment.
  124. *
  125. * \note The design and implementation of this class is documented in Part 2
  126. * of the forthcoming book
  127. * <a href = "http://extendedstl.com">Extended STL</a>.
  128. */
  129. class environment_map
  130. : public stlsoft_ns_qual(stl_collection_tag)
  131. {
  132. /// \name Member Types
  133. /// @{
  134. private:
  135. typedef environment_variable_traits traits_type;
  136. typedef stlsoft_ns_qual_std(string) string_type;
  137. public:
  138. /// \brief The string type used for variable name, and lookup
  139. ///
  140. /// \note This is the association "key" type
  141. typedef string_type first_type;
  142. /// \brief The string type used for variable value, and retrieval
  143. ///
  144. /// \note This is the association "value" type
  145. typedef string_type second_type;
  146. /// \brief Value type of the class: a pair of first_type and second_type
  147. typedef std::pair< const first_type
  148. , second_type
  149. > value_type;
  150. /// \brief The size type
  151. typedef ss_size_t size_type;
  152. /// \brief The difference type
  153. typedef ss_ptrdiff_t difference_type;
  154. /// \brief The non-mutating (const) reference type
  155. typedef const value_type const_reference; // BVT
  156. /// \brief The non-mutating (const) iterator type
  157. class const_iterator;
  158. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT) && \
  159. !defined(STLSOFT_COMPILER_IS_BORLAND)
  160. typedef const_reverse_bidirectional_iterator_base< const_iterator
  161. , value_type
  162. , const_reference
  163. , void // By-Value Temporary reference category
  164. , difference_type
  165. > const_reverse_iterator;
  166. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  167. /// \brief The type of the class
  168. typedef environment_map class_type;
  169. private:
  170. friend class const_iterator;
  171. class snapshot
  172. {
  173. public: // Member Types
  174. typedef stlsoft_ns_qual(shared_ptr)<snapshot> ref_type;
  175. #if defined(STLSOFT_CF_STD_LIBRARY_IS_DINKUMWARE_VC) && \
  176. STLSOFT_CF_STD_LIBRARY_DINKUMWARE_VC_VERSION == STLSOFT_CF_DINKUMWARE_VC_VERSION_7_0
  177. // VC7 libs get confused with const key type here
  178. typedef stlsoft_ns_qual_std(map)< first_type
  179. #else /* ? library */
  180. typedef stlsoft_ns_qual_std(map)< const first_type
  181. #endif /* library */
  182. , second_type
  183. > variables_type_;
  184. typedef variables_type_::iterator iterator;
  185. public: // Construction
  186. snapshot();
  187. public: // Operations
  188. ss_bool_t erase( first_type const& name) throw();
  189. void erase( iterator it) throw();
  190. void insert( first_type const &name
  191. , second_type const& value);
  192. void set( first_type const& name
  193. , second_type const& value);
  194. ss_bool_t lookup( first_type const& name
  195. , second_type*& pvalue) throw();
  196. public: // Iteration
  197. iterator begin();
  198. iterator end();
  199. private: // Members
  200. variables_type_ m_variables;
  201. };
  202. /// @}
  203. /// \name Construction
  204. /// @{
  205. public:
  206. /// \brief Constructs an instance of the type
  207. ///
  208. /// \note This instance does <b>not</b> store a snapshot of the
  209. /// environment at the time of its construction. All lookup and
  210. /// iteration is carried out 'live' at the time of invocation.
  211. environment_map();
  212. /// @}
  213. /// \name Element Access
  214. /// @{
  215. public:
  216. /// \brief Returns the value of the given environment variable, or throws
  217. /// std::out_of_range if it does not exist.
  218. ///
  219. /// \param name The name of the environment variable whose value is to be
  220. /// retrieved
  221. ///
  222. /// \exception std::out_of_range If no variable exists with the given name
  223. second_type operator [](char const* name) const;
  224. /// \brief Returns the value of the given environment variable, or throws
  225. /// std::out_of_range if it does not exist.
  226. ///
  227. /// \param name The name of the environment variable whose value is to be
  228. /// retrieved
  229. ///
  230. /// \exception std::out_of_range If no variable exists with the given name
  231. second_type operator [](first_type const& name) const;
  232. /// \brief Looks for the variable of the given name in the current
  233. /// process environment.
  234. ///
  235. /// \return A Boolean value indicating whether the variable was found
  236. ss_bool_t lookup(char const* name, second_type& value) const;
  237. /// \brief Looks for the variable of the given name in the current
  238. /// process environment.
  239. ///
  240. /// \return A Boolean value indicating whether the variable was found
  241. ss_bool_t lookup(first_type const& name, second_type& value) const;
  242. /// @}
  243. /// \name Operations
  244. /// @{
  245. public:
  246. /// \brief Discard any current enumeration snapshots.
  247. ///
  248. /// Used to force the collection instance to discard any currently snapshotd
  249. /// snapshot it may be holding on behalf of extant iterator instances, so
  250. /// that new iterator instances will receive a refreshed view of the
  251. /// underlying environment.
  252. void refresh();
  253. /// @}
  254. /// \name Modifiers
  255. /// @{
  256. public:
  257. #ifdef PLATFORMSTL_ENVVAR_SET_SUPPORTED
  258. /// \brief Inserts or updates and environment variable
  259. ///
  260. /// \note This method is strongly exception-safe. The insertion into the
  261. /// snapshot is done first. If that does not throw an exception, but the
  262. /// insertion into the process' environment fails, it is removed from
  263. /// the snapshot. The only way that could fail would be if the element
  264. /// already exists, in which case
  265. void insert(first_type const& name, second_type const& value);
  266. /// \brief The semantics of this function are identical to the string object overload
  267. ///
  268. /// \param name The name of the variable to insert/update
  269. /// \param value The new value of the variable
  270. void insert(char const* name, char const* value);
  271. #endif /* PLATFORMSTL_ENVVAR_SET_SUPPORTED */
  272. #ifdef PLATFORMSTL_ENVVAR_ERASE_SUPPORTED
  273. /// \brief Removes the entry of the given name
  274. ///
  275. /// \note If the given entry does not exist
  276. size_type erase(first_type const& name);
  277. /// \brief Removes the entry of the given name
  278. ///
  279. /// \note If the given entry does not exist
  280. size_type erase(char const* name);
  281. /// \brief Removes the entry corresponding to the given iterator
  282. void erase(const_iterator it);
  283. #endif /* PLATFORMSTL_ENVVAR_ERASE_SUPPORTED */
  284. /// @}
  285. /// \name Iteration
  286. /// @{
  287. public:
  288. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  289. /// \brief Begins the iteration
  290. ///
  291. /// \return A non-mutating (const) iterator representing the start of the sequence
  292. const_iterator begin() const;
  293. /// \brief Ends the iteration
  294. ///
  295. /// \return A non-mutating (const) iterator representing (one past) the end of the sequence
  296. const_iterator end() const;
  297. # if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT) && \
  298. !defined(STLSOFT_COMPILER_IS_BORLAND)
  299. /// \brief Begins the reverse iteration
  300. ///
  301. /// \return A non-mutating (const) iterator representing the start of the reverse sequence
  302. const_reverse_iterator rbegin() const;
  303. /// \brief Ends the reverse iteration
  304. ///
  305. /// \return A non-mutating (const) iterator representing (one past) the end of the reverse sequence
  306. const_reverse_iterator rend() const;
  307. # endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  308. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  309. /// @}
  310. /// \name Iteration
  311. /// @{
  312. public:
  313. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  314. /// \brief const_iterator class
  315. ///
  316. /// \note Even though the const_iterator class, in and of itself, supports Invalidatable
  317. /// References, the collection as a whole supports only By-Value Temporary (BVT) References
  318. /// because that is the highest model that the subscript operations can support. (See XSTL
  319. /// for details.)
  320. class const_iterator
  321. : public stlsoft_ns_qual(iterator_base)<stlsoft_ns_qual_std(bidirectional_iterator_tag)
  322. , value_type
  323. , ss_ptrdiff_t
  324. , void // By-Value Temporary reference
  325. , const value_type // By-Value Temporary reference
  326. >
  327. {
  328. /// \name Member Types
  329. /// @{
  330. public:
  331. typedef const_iterator class_type;
  332. /// @}
  333. /// \name Construction
  334. /// @{
  335. private:
  336. friend class environment_map;
  337. const_iterator(snapshot::iterator it, snapshot::ref_type snapshot);
  338. public:
  339. const_iterator();
  340. const_iterator(class_type const& rhs);
  341. /// @}
  342. /// \name Forward Iterator Operations
  343. /// @{
  344. public:
  345. class_type& operator ++();
  346. class_type operator ++(int);
  347. const_reference operator *() const;
  348. /// @}
  349. /// \name BiDirectional Iterator Operations
  350. /// @{
  351. public:
  352. class_type& operator --();
  353. class_type operator --(int);
  354. /// @}
  355. /// \name Comparison
  356. /// @{
  357. public:
  358. ss_bool_t equal(class_type const& rhs) const;
  359. /// @}
  360. /// \name Members
  361. /// @{
  362. private:
  363. snapshot::iterator m_it;
  364. snapshot::ref_type m_snapshot;
  365. /// @}
  366. };
  367. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  368. /// @}
  369. /// \name Implementation
  370. /// @{
  371. private:
  372. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  373. void check_refresh_snapshot_() const;
  374. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  375. /// @}
  376. /// \name Members
  377. /// @{
  378. private:
  379. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  380. mutable snapshot::ref_type m_snapshot;
  381. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  382. /// @}
  383. /// \name Not to be defined
  384. /// @{
  385. private:
  386. environment_map(environment_map const& rhs);
  387. environment_map& operator =(environment_map const& rhs);
  388. /// @}
  389. };
  390. /* /////////////////////////////////////////////////////////////////////////
  391. * Operators
  392. */
  393. // NOTE: Neither Borland (5.6+) nor DMC++ correctly handle ADL for (comparison)
  394. // operators of types within a namespace, so we temporarily skip out into
  395. // the global namespace.
  396. #if ( defined(STLSOFT_COMPILER_IS_BORLAND) && \
  397. __BORLANDC__ >= 0x0560) || \
  398. defined(STLSOFT_COMPILER_IS_DMC)
  399. # if defined(_STLSOFT_NO_NAMESPACE) || \
  400. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  401. } // namespace platformstl
  402. # else
  403. } // namespace platformstl_project
  404. } // namespace stlsoft
  405. # endif /* _STLSOFT_NO_NAMESPACE */
  406. #endif /* compiler */
  407. inline stlsoft_ns_qual(ss_bool_t) operator ==( platformstl_ns_qual(environment_map)::const_iterator const& lhs
  408. , platformstl_ns_qual(environment_map)::const_iterator const& rhs)
  409. {
  410. return lhs.equal(rhs);
  411. }
  412. inline stlsoft_ns_qual(ss_bool_t) operator !=( platformstl_ns_qual(environment_map)::const_iterator const& lhs
  413. , platformstl_ns_qual(environment_map)::const_iterator const& rhs)
  414. {
  415. return !lhs.equal(rhs);
  416. }
  417. // TODO: Make this a discriminated feature declared in the cccap files
  418. #if ( defined(STLSOFT_COMPILER_IS_BORLAND) && \
  419. __BORLANDC__ >= 0x0560) || \
  420. defined(STLSOFT_COMPILER_IS_DMC)
  421. # if defined(_STLSOFT_NO_NAMESPACE) || \
  422. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  423. /* There is no stlsoft namespace, so must define ::platformstl */
  424. namespace platformstl
  425. {
  426. # else
  427. /* Define stlsoft::platformstl_project */
  428. namespace stlsoft
  429. {
  430. namespace platformstl_project
  431. {
  432. # endif /* _STLSOFT_NO_NAMESPACE */
  433. #endif /* compiler */
  434. ////////////////////////////////////////////////////////////////////////////
  435. // Unit-testing
  436. #ifdef STLSOFT_UNITTEST
  437. # include "./unittest/environment_map_unittest_.h"
  438. #endif /* STLSOFT_UNITTEST */
  439. /* /////////////////////////////////////////////////////////////////////////
  440. * Implementation
  441. */
  442. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  443. // environment_map::const_iterator
  444. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  445. inline environment_map::const_iterator::const_iterator()
  446. : m_it()
  447. {}
  448. inline environment_map::const_iterator::const_iterator(environment_map::snapshot::iterator it, environment_map::snapshot::ref_type snapshot)
  449. : m_it(it)
  450. , m_snapshot(snapshot)
  451. {}
  452. inline environment_map::const_iterator::const_iterator(environment_map::const_iterator::class_type const& rhs)
  453. : m_it(rhs.m_it)
  454. , m_snapshot(rhs.m_snapshot)
  455. {}
  456. inline environment_map::const_iterator::class_type& environment_map::const_iterator::operator ++()
  457. {
  458. ++m_it;
  459. return *this;
  460. }
  461. inline environment_map::const_iterator::class_type environment_map::const_iterator::operator ++(int)
  462. {
  463. class_type r(*this);
  464. operator ++();
  465. return r;
  466. }
  467. inline environment_map::const_reference environment_map::const_iterator::operator *() const
  468. {
  469. return *m_it;
  470. }
  471. inline environment_map::const_iterator::class_type& environment_map::const_iterator::operator --()
  472. {
  473. --m_it;
  474. return *this;
  475. }
  476. inline environment_map::const_iterator::class_type environment_map::const_iterator::operator --(int)
  477. {
  478. class_type r(*this);
  479. operator --();
  480. return r;
  481. }
  482. inline ss_bool_t environment_map::const_iterator::equal(environment_map::const_iterator::class_type const& rhs) const
  483. {
  484. return m_it == rhs.m_it;
  485. }
  486. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  487. // environment_map
  488. inline environment_map::environment_map()
  489. {}
  490. inline environment_map::second_type environment_map::operator [](char const* name) const
  491. {
  492. char const *value = traits_type::get_variable(name);
  493. if(NULL == value)
  494. {
  495. STLSOFT_THROW_X(stlsoft_ns_qual_std(out_of_range)("variable does not exist"));
  496. }
  497. return value;
  498. }
  499. inline environment_map::second_type environment_map::operator [](environment_map::first_type const& name) const
  500. {
  501. return operator [](name.c_str());
  502. }
  503. inline ss_bool_t environment_map::lookup(char const* name, environment_map::second_type& value) const
  504. {
  505. char const *value_ = traits_type::get_variable(name);
  506. return (NULL == value_) ? false : (value = value_, true);
  507. }
  508. inline ss_bool_t environment_map::lookup(environment_map::first_type const& name, environment_map::second_type& value) const
  509. {
  510. return lookup(name.c_str(), value);
  511. }
  512. inline void environment_map::refresh()
  513. {
  514. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  515. m_snapshot.close();
  516. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  517. }
  518. #ifdef PLATFORMSTL_ENVVAR_SET_SUPPORTED
  519. inline void environment_map::insert(environment_map::first_type const& name, environment_map::second_type const& value)
  520. {
  521. // Preconditions
  522. STLSOFT_MESSAGE_ASSERT("Name may not be empty", !name.empty());
  523. STLSOFT_MESSAGE_ASSERT("Name may not contain '='", name.end() == std::find(name.begin(), name.end(), '='));
  524. STLSOFT_MESSAGE_ASSERT("Empty value not allowed in insertion", !value.empty());
  525. second_type *pstr = NULL;
  526. if( 1 < m_snapshot.use_count() &&
  527. m_snapshot->lookup(name, pstr))
  528. {
  529. // If it exists, then:
  530. // 1. Reserve the appropriate amount of storage (which may throw,
  531. // but doesn't need to be rolled back). If this succeeds, then
  532. // it means that the insert() call cannot throw an exception.
  533. pstr->reserve(value.size());
  534. // 2. Insert into the host environment
  535. if(0 != traits_type::set_variable(name.c_str(), value.c_str()))
  536. {
  537. STLSOFT_THROW_X(stlsoft_ns_qual_std(runtime_error)("Cannot set environment variable"));
  538. }
  539. // 3. Update the snapshot
  540. m_snapshot->set(name, value);
  541. }
  542. else
  543. {
  544. // If it does not exist, then we add it first, and remove
  545. // again if the set_variable() call fails to also put it
  546. // in the host environment
  547. if(1 < m_snapshot.use_count())
  548. {
  549. m_snapshot->insert(name, value);
  550. }
  551. if(0 != traits_type::set_variable(name.c_str(), value.c_str()))
  552. {
  553. if(1 < m_snapshot.use_count())
  554. {
  555. m_snapshot->erase(name);
  556. }
  557. STLSOFT_THROW_X(stlsoft_ns_qual_std(runtime_error)("Cannot set environment variable"));
  558. }
  559. }
  560. }
  561. inline void environment_map::insert(char const* name, char const* value)
  562. {
  563. // Preconditions
  564. STLSOFT_ASSERT(NULL != name);
  565. STLSOFT_MESSAGE_ASSERT("Name may not be empty", 0 != ::strlen(name));
  566. STLSOFT_MESSAGE_ASSERT("Name may not contain '='", NULL == ::strchr(name, '='));
  567. STLSOFT_MESSAGE_ASSERT("Null value not allowed in insertion", NULL != value);
  568. STLSOFT_MESSAGE_ASSERT("Empty value not allowed in insertion", 0 != ::strlen(value));
  569. insert(first_type(name), second_type(value));
  570. }
  571. #endif /* PLATFORMSTL_ENVVAR_SET_SUPPORTED */
  572. #ifdef PLATFORMSTL_ENVVAR_ERASE_SUPPORTED
  573. inline environment_map::size_type environment_map::erase(environment_map::first_type const& name)
  574. {
  575. // Preconditions
  576. STLSOFT_MESSAGE_ASSERT("Name may not be empty", !name.empty());
  577. STLSOFT_MESSAGE_ASSERT("Name may not contain '='", name.end() == std::find(name.begin(), name.end(), '='));
  578. size_type b = 0;
  579. if(0 != traits_type::erase_variable(name.c_str()))
  580. {
  581. #if 0
  582. // Failure to erase might be if some external part of the
  583. // process has already erased it.
  584. //
  585. // Hence, the somewhat crude measure to checking whether it
  586. // still exists (rather than knowing what value(s) to check
  587. // the return value of erase_variable() for).
  588. if(NULL != traits_type::get_variable(name.c_str()))
  589. #endif /* 0 */
  590. {
  591. STLSOFT_THROW_X(stlsoft_ns_qual_std(runtime_error)("Cannot erase environment variable"));
  592. }
  593. }
  594. else
  595. {
  596. b = 1;
  597. }
  598. if(1 < m_snapshot.use_count())
  599. {
  600. if(m_snapshot->erase(name))
  601. {
  602. b = 1;
  603. }
  604. }
  605. return b;
  606. }
  607. inline environment_map::size_type environment_map::erase(char const* name)
  608. {
  609. // Preconditions
  610. STLSOFT_ASSERT(NULL != name);
  611. STLSOFT_MESSAGE_ASSERT("Name may not be empty", 0 != ::strlen(name));
  612. STLSOFT_MESSAGE_ASSERT("Name may not contain '='", NULL == ::strchr(name, '='));
  613. return erase(first_type(name));
  614. }
  615. inline void environment_map::erase(environment_map::const_iterator it)
  616. {
  617. STLSOFT_MESSAGE_ASSERT("No snapshot assigned, so erase() is inappropriate; maybe premature call to clear()", 1 < m_snapshot.use_count());
  618. #if 0
  619. first_type const &name = (*it).first;
  620. #else /* ? 0 */
  621. first_type const &name = (*it.m_it).first; // Avoid CUR
  622. #endif /* 0 */
  623. if(0 != traits_type::erase_variable(name.c_str()))
  624. {
  625. #if 0
  626. // Failure to erase might be if some external part of the
  627. // process has already erased it.
  628. //
  629. // Hence, the somewhat crude measure to checking whether it
  630. // still exists (rather than knowing what value(s) to check
  631. // the return value of erase_variable() for).
  632. if(NULL != traits_type::get_variable(name.c_str()))
  633. #endif /* 0 */
  634. {
  635. STLSOFT_THROW_X(stlsoft_ns_qual_std(runtime_error)("Cannot erase environment variable"));
  636. }
  637. }
  638. m_snapshot->erase(it.m_it);
  639. }
  640. #endif /* PLATFORMSTL_ENVVAR_ERASE_SUPPORTED */
  641. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  642. inline environment_map::const_iterator environment_map::begin() const
  643. {
  644. check_refresh_snapshot_();
  645. #if 0
  646. snapshot::ref_type snapshot = m_snapshot; // Avoid a const_cast
  647. return const_iterator(snapshot->begin(), m_snapshot);
  648. #else /* ? 0 */
  649. return const_iterator(m_snapshot->begin(), m_snapshot);
  650. #endif /* 0 */
  651. }
  652. inline environment_map::const_iterator environment_map::end() const
  653. {
  654. check_refresh_snapshot_();
  655. #if 0
  656. snapshot::ref_type snapshot = m_snapshot; // Avoid a const_cast
  657. return const_iterator(snapshot->end(), m_snapshot);
  658. #else /* ? 0 */
  659. return const_iterator(m_snapshot->end(), m_snapshot);
  660. #endif /* 0 */
  661. }
  662. # if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT) && \
  663. !defined(STLSOFT_COMPILER_IS_BORLAND)
  664. inline environment_map::const_reverse_iterator environment_map::rbegin() const
  665. {
  666. return const_reverse_iterator(end());
  667. }
  668. inline environment_map::const_reverse_iterator environment_map::rend() const
  669. {
  670. return const_reverse_iterator(begin());
  671. }
  672. # endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  673. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  674. #ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  675. inline void environment_map::check_refresh_snapshot_() const
  676. {
  677. if(m_snapshot.use_count() < 2)
  678. {
  679. m_snapshot = snapshot::ref_type(new snapshot());
  680. }
  681. }
  682. #endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  683. // environment_map::snapshot
  684. # ifdef PLATFORMSTL_ENVVAR_HAS_ENVIRON
  685. inline environment_map::snapshot::snapshot()
  686. {
  687. first_type name;
  688. second_type value;
  689. stlsoft::scoped_handle<char const**> env( traits_type::get_environ()
  690. , &traits_type::release_environ);
  691. { for(char const** p = env.get(); NULL != *p; ++p)
  692. {
  693. stlsoft::split(*p, '=', name, value);
  694. m_variables[name] = value;
  695. }}
  696. }
  697. inline environment_map::snapshot::iterator environment_map::snapshot::begin()
  698. {
  699. return m_variables.begin();
  700. }
  701. inline environment_map::snapshot::iterator environment_map::snapshot::end()
  702. {
  703. return m_variables.end();
  704. }
  705. inline ss_bool_t environment_map::snapshot::erase(first_type const& name) throw()
  706. {
  707. variables_type_::iterator it = m_variables.find(name);
  708. if(m_variables.end() != it)
  709. {
  710. m_variables.erase(it);
  711. return true;
  712. }
  713. return false;
  714. }
  715. inline void environment_map::snapshot::erase(environment_map::snapshot::iterator it) throw()
  716. {
  717. m_variables.erase(it);
  718. }
  719. inline void environment_map::snapshot::insert(first_type const& name, second_type const& value)
  720. {
  721. # if 0
  722. /// This is not strongly exception safe, ...
  723. m_variables[name] = value;
  724. # else /* ? 0 */
  725. /// ... but this is.
  726. m_variables.insert(value_type(name, value));
  727. # endif /* 0 */
  728. }
  729. inline void environment_map::snapshot::set(first_type const& name, second_type const& value)
  730. {
  731. variables_type_::iterator it = m_variables.find(name);
  732. STLSOFT_ASSERT(m_variables.end() != it);
  733. STLSOFT_ASSERT((*it).second.capacity() >= value.size());
  734. # ifdef _DEBUG
  735. try
  736. # endif /* _DEBUG */
  737. {
  738. (*it).second.assign(value);
  739. }
  740. # ifdef _DEBUG
  741. catch(...)
  742. {
  743. STLSOFT_MESSAGE_ASSERT("Should never happen", 0);
  744. throw; // Might as well pass on to precipitate unexpected()
  745. }
  746. # endif /* _DEBUG */
  747. }
  748. inline ss_bool_t environment_map::snapshot::lookup(first_type const& name, second_type *&pvalue) throw()
  749. {
  750. variables_type_::iterator it = m_variables.find(name);
  751. if(m_variables.end() == it)
  752. {
  753. return false;
  754. }
  755. else
  756. {
  757. pvalue = &(*it).second;
  758. return true;
  759. }
  760. }
  761. # endif /* PLATFORMSTL_ENVVAR_HAS_ENVIRON */
  762. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  763. /* ////////////////////////////////////////////////////////////////////// */
  764. #if defined(_STLSOFT_NO_NAMESPACE) || \
  765. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  766. } // namespace platformstl
  767. #else
  768. } // namespace platformstl_project
  769. } // namespace stlsoft
  770. #endif /* _STLSOFT_NO_NAMESPACE */
  771. /* ////////////////////////////////////////////////////////////////////// */
  772. #endif /* !PLATFORMSTL_INCL_PLATFORMSTL_SYSTEM_HPP_ENVIRONMENT_MAP */
  773. /* ///////////////////////////// end of file //////////////////////////// */