1 // Copyright (c) 2016 Klemens D. Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 
7 #ifndef BOOST_PROCESS_ENVIRONMENT_HPP_
8 #define BOOST_PROCESS_ENVIRONMENT_HPP_
9 
10 #include <boost/process/detail/config.hpp>
11 #include <boost/algorithm/string/split.hpp>
12 #include <boost/algorithm/string/case_conv.hpp>
13 #include <boost/iterator/transform_iterator.hpp>
14 #include <boost/filesystem/path.hpp>
15 
16 #if defined(BOOST_POSIX_API)
17 #include <boost/process/detail/posix/environment.hpp>
18 #elif defined(BOOST_WINDOWS_API)
19 #include <boost/process/detail/windows/environment.hpp>
20 #endif
21 
22 namespace boost { namespace process {
23 
24 namespace detail {
25 
26 template<typename Char, typename Environment>
27 struct const_entry
28 {
29     using value_type    = Char ;
30     using pointer       = const value_type * ;
31     using string_type   = std::basic_string<value_type> ;
32     using range         = boost::iterator_range<pointer> ;
33     using environment_t = Environment ;
34 
to_vectorboost::process::detail::const_entry35     std::vector<string_type> to_vector() const
36     {
37         if (_data == nullptr)
38             return std::vector<string_type>();
39         std::vector<string_type> data;
40         auto str = string_type(_data);
41         struct splitter
42         {
43             bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();}
44             bool operator()(char c)    const {return c == api::env_seperator<char>   ();}
45         } s;
46         boost::split(data, _data, s);
47         return data;
48     }
to_stringboost::process::detail::const_entry49     string_type to_string()              const
50     {
51         if (_data != nullptr)
52             return string_type(_data);
53         else
54             return string_type();
55     }
get_nameboost::process::detail::const_entry56     string_type get_name() const {return string_type(_name.begin(), _name.end());}
const_entryboost::process::detail::const_entry57     explicit const_entry(string_type&& name, pointer data, environment_t & env_) :
58         _name(std::move(name)), _data(data), _env(&env_) {}
59 
const_entryboost::process::detail::const_entry60     explicit const_entry(string_type &&name, environment_t & env) :
61         _name(std::move(name)), _data(nullptr), _env(&env) {}
62     const_entry(const const_entry&) = default;
63     const_entry& operator=(const const_entry&) = default;
64 
reloadboost::process::detail::const_entry65     void reload()
66     {
67         auto p = _env->find(_name);
68         if (p == _env->end())
69             _data = nullptr;
70         else
71             _data = p->_data;
72         this->_env->reload();
73 
74     }
emptyboost::process::detail::const_entry75     bool empty() const
76     {
77         return _data == nullptr;
78     }
79 protected:
80     string_type _name;
81     pointer _data;
82     environment_t * _env;
83 };
84 
85 template<typename Char, typename Environment>
86 struct entry : const_entry<Char, Environment>
87 {
88     using father = const_entry<Char, Environment>;
89     using value_type    = typename father::value_type;
90     using string_type   = typename father::string_type;
91     using pointer       = typename father::pointer;
92     using environment_t = typename father::environment_t;
93 
entryboost::process::detail::entry94     explicit entry(string_type&& name, pointer data, environment_t & env) :
95         father(std::move(name), data, env) {}
96 
entryboost::process::detail::entry97     explicit entry(string_type &&name, environment_t & env_) :
98         father(std::move(name), env_) {}
99 
100     entry(const entry&) = default;
101     entry& operator=(const entry&) = default;
102 
assignboost::process::detail::entry103     void assign(const string_type &value)
104     {
105         this->_env->set(this->_name, value);
106         this->reload();
107     }
assignboost::process::detail::entry108     void assign(const std::vector<string_type> &value)
109     {
110         string_type data;
111         for (auto &v : value)
112         {
113             if (&v != &value.front())
114                 data += api::env_seperator<value_type>();
115             data += v;
116         }
117         this->_env->set(this->_name, data);
118         this->reload();
119 
120     }
assignboost::process::detail::entry121     void assign(const std::initializer_list<string_type> &value)
122     {
123         string_type data;
124         for (auto &v : value)
125         {
126             if (&v != &*value.begin())
127                 data += api::env_seperator<value_type>();
128             data += v;
129         }
130         this->_env->set(this->_name, data);
131         this->reload();
132 
133     }
appendboost::process::detail::entry134     void append(const string_type &value)
135     {
136         if (this->_data == nullptr)
137             this->_env->set(this->_name, value);
138         else
139         {
140             string_type st = this->_data;
141             this->_env->set(this->_name, st + api::env_seperator<value_type>() + value);
142         }
143 
144 
145         this->reload();
146 
147     }
clearboost::process::detail::entry148     void clear()
149     {
150         this->_env->reset(this->_name);
151         this->_env->reload();
152         this->_data = nullptr;
153     }
operator =boost::process::detail::entry154     entry &operator=(const string_type & value)
155     {
156         assign(value);
157         return *this;
158     }
operator =boost::process::detail::entry159     entry &operator=(const std::vector<string_type> & value)
160     {
161         assign(value);
162         return *this;
163     }
operator =boost::process::detail::entry164     entry &operator=(const std::initializer_list<string_type> & value)
165     {
166         assign(value);
167         return *this;
168     }
operator +=boost::process::detail::entry169     entry &operator+=(const string_type & value)
170     {
171         append(value);
172         return *this;
173     }
174 
175 };
176 
177 
178 
179 template<typename Char, typename Environment>
180 struct make_entry
181 {
182 
183     make_entry(const make_entry&) = default;
184     make_entry& operator=(const make_entry&) = default;
185 
186     Environment *env;
make_entryboost::process::detail::make_entry187     make_entry(Environment & env) : env(&env) {};
operator ()boost::process::detail::make_entry188     entry<Char, Environment> operator()(const Char* data) const
189     {
190         auto p = data;
191         while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
192                 p++;
193         auto name = std::basic_string<Char>(data, p);
194         p++; //go behind equal sign
195 
196         return entry<Char, Environment>(std::move(name), p, *env);
197     }
198 };
199 
200 template<typename Char, typename Environment>
201 struct make_const_entry
202 {
203 
204     make_const_entry(const make_const_entry&) = default;
205     make_const_entry& operator=(const make_const_entry&) = default;
206 
207     Environment *env;
make_const_entryboost::process::detail::make_const_entry208     make_const_entry(Environment & env) : env(&env) {};
operator ()boost::process::detail::make_const_entry209     const_entry<Char, Environment> operator()(const Char* data) const
210     {
211         auto p = data;
212         while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
213                 p++;
214         auto name = std::basic_string<Char>(data, p);
215         p++; //go behind equal sign
216 
217         return const_entry<Char, Environment>(std::move(name), p, *env);
218     }
219 };
220 
221 }
222 
223 #if !defined (BOOST_PROCESS_DOXYGEN)
224 
225 template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl>
226 class basic_environment_impl : public Implementation<Char>
227 {
_get_end() const228     Char** _get_end() const
229     {
230         auto p = this->_env_impl;
231         while (*p != nullptr)
232             p++;
233 
234         return p;
235     }
236 public:
237     using string_type = std::basic_string<Char>;
238     using implementation_type = Implementation<Char>;
239     using base_type = basic_environment_impl<Char, Implementation>;
240     using       entry_maker = detail::make_entry<Char, base_type>;
241     using entry_type        = detail::entry     <Char, base_type>;
242     using const_entry_type  = detail::const_entry     <Char, const base_type>;
243     using const_entry_maker = detail::make_const_entry<Char, const base_type>;
244 
245     friend       entry_type;
246     friend const_entry_type;
247 
248     using iterator        = boost::transform_iterator<      entry_maker, Char**,       entry_type,       entry_type>;
249     using const_iterator  = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>;
250     using size_type       = std::size_t;
251 
begin()252     iterator        begin()       {return       iterator(this->_env_impl,       entry_maker(*this));}
begin() const253     const_iterator  begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
cbegin() const254     const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
255 
end()256     iterator        end()       {return       iterator(_get_end(),       entry_maker(*this));}
end() const257     const_iterator  end() const {return const_iterator(_get_end(), const_entry_maker(*this));}
cend() const258     const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));}
259 
find(const string_type & key)260     iterator        find( const string_type& key )
261     {
262         auto p = this->_env_impl;
263         auto st1 = key + ::boost::process::detail::equal_sign<Char>();
264         while (*p != nullptr)
265         {
266             if (std::equal(st1.begin(), st1.end(), *p))
267                 break;
268             p++;
269         }
270         return iterator(p, entry_maker(*this));
271     }
find(const string_type & key) const272     const_iterator  find( const string_type& key ) const
273     {
274         auto p = this->_env_impl;
275         auto st1 = key + ::boost::process::detail::equal_sign<Char>();
276         while (*p != nullptr)
277         {
278             if (std::equal(st1.begin(), st1.end(), *p))
279                 break;
280             p++;
281         }
282         return const_iterator(p, const_entry_maker(*this));
283     }
284 
count(const string_type & st) const285     std::size_t count(const string_type & st) const
286     {
287         auto p = this->_env_impl;
288         auto st1 = st + ::boost::process::detail::equal_sign<Char>();
289         while (*p != nullptr)
290         {
291             if (std::equal(st1.begin(), st1.end(), *p))
292                 return 1u;
293             p++;
294         }
295         return 0u;
296     }
erase(const string_type & id)297     void erase(const string_type & id)
298     {
299         implementation_type::reset(id);
300         this->reload();
301     }
emplace(const string_type & id,const string_type & value)302     std::pair<iterator,bool> emplace(const string_type & id, const string_type & value)
303     {
304         auto f = find(id);
305         if (f == end())
306         {
307             implementation_type::set(id, value);
308             this->reload();
309             return std::pair<iterator, bool>(find(id), true);
310         }
311         else
312             return std::pair<iterator, bool>(f, false);
313     }
314     using implementation_type::implementation_type;
315     using implementation_type::operator=;
316     using native_handle_type = typename implementation_type::native_handle_type;
317     using implementation_type::native_handle;
318     //copy ctor if impl is copy-constructible
empty()319     bool empty()
320     {
321         return *this->_env_impl == nullptr;
322     }
size() const323     std::size_t size() const
324     {
325         return (_get_end() - this->_env_impl);
326     }
clear()327     void clear()
328     {
329         std::vector<string_type> names;
330         names.resize(size());
331         std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();});
332 
333         for (auto & nm : names)
334             implementation_type::reset(nm);
335 
336         this->reload();
337     }
338 
at(const string_type & key)339     entry_type  at( const string_type& key )
340     {
341         auto f = find(key);
342         if (f== end())
343             throw std::out_of_range(key + " not found");
344         return *f;
345     }
at(const string_type & key) const346     const_entry_type at( const string_type& key ) const
347     {
348         auto f = find(key);
349         if (f== end())
350             throw std::out_of_range(key + " not found");
351         return *f;
352     }
operator [](const string_type & key)353     entry_type operator[](const string_type & key)
354     {
355         auto p = find(key);
356         if (p != end())
357             return *p;
358 
359         return entry_type(string_type(key), *this);
360     }
361 };
362 #endif
363 
364 #if defined(BOOST_PROCESS_DOXYGEN)
365 /**Template representation of environments. It takes a character type (`char` or `wchar_t`)
366  * as template parameter to implement the environment
367  */
368 template<typename Char>
369 class basic_environment
370 {
371 
372 public:
373     typedef std::basic_string<Char> string_type;
374     typedef boost::transform_iterator<      entry_maker, Char**> iterator       ;
375     typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
376     typedef std::size_t                                             size_type      ;
377 
378     iterator       begin()        ; ///<Returns an iterator to the beginning
379     const_iterator begin()  const ; ///<Returns an iterator to the beginning
380     const_iterator cbegin() const ; ///<Returns an iterator to the beginning
381 
382     iterator       end()       ; ///<Returns an iterator to the end
383     const_iterator end()  const; ///<Returns an iterator to the end
384     const_iterator cend() const; ///<Returns an iterator to the end
385 
386     iterator        find( const string_type& key );            ///<Find a variable by its name
387     const_iterator  find( const string_type& key ) const;   ///<Find a variable by its name
388 
389     std::size_t count(const string_type & st) const; ///<Number of variables
390     void erase(const string_type & id); ///<Erase variable by id.
391     ///Emplace an environment variable.
392     std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
393 
394     ///Default constructor
395     basic_environment();
396     ///Copy constructor.
397     basic_environment(const basic_environment & );
398     ///Move constructor.
399     basic_environment(basic_environment && );
400 
401     ///Copy assignment.
402     basic_environment& operator=(const basic_environment & );
403     ///Move assignment.
404     basic_environment& operator=(basic_environment && );
405 
406     typedef typename detail::implementation_type::native_handle_type native_handle;
407 
408     ///Check if environment has entries.
409     bool empty();
410     ///Get the number of variables.
411     std::size_t size() const;
412     ///Clear the environment. @attention Use with care, passed environment cannot be empty.
413     void clear();
414     ///Get the entry with the key. Throws if it does not exist.
415     entry_type  at( const string_type& key );
416     ///Get the entry with the key. Throws if it does not exist.
417     const_entry_type at( const string_type& key ) const;
418     ///Get the entry with the given key. It creates the entry if it doesn't exist.
419     entry_type operator[](const string_type & key);
420 
421     /**Proxy class used for read access to members by [] or .at()
422      * @attention Holds a reference to the environment it was created from.
423      */
424     template<typename Char, typename Environment>
425     struct const_entry_type
426     {
427         typedef Char value_type;
428         typedef const value_type * pointer;
429         typedef std::basic_string<value_type> string_type;
430         typedef boost::iterator_range<pointer> range;
431         typedef Environment environment_t;
432 
433         ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_environment::const_entry_type434         std::vector<string_type> to_vector() const
435         ///Get the value as string.
436         string_type to_string()              const
437         ///Get the name of this entry.
438         string_type get_name() const {return string_type(_name.begin(), _name.end());}
439         ///Copy Constructor
440         const_entry(const const_entry&) = default;
441         ///Move Constructor
442         const_entry& operator=(const const_entry&) = default;
443         ///Check if the entry is empty.
444         bool empty() const;
445     };
446 
447     /**Proxy class used for read and write access to members by [] or .at()
448      * @attention Holds a reference to the environment it was created from.
449      */
450     template<typename Char, typename Environment>
451     struct entry_type
452     {
453 
454         typedef Char value_type;
455         typedef const value_type * pointer;
456         typedef std::basic_string<value_type> string_type;
457         typedef boost::iterator_range<pointer> range;
458         typedef Environment environment_t;
459 
460         ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_environment::entry_type461         std::vector<string_type> to_vector() const
462         ///Get the value as string.
463         string_type to_string()              const
464         ///Get the name of this entry.
465         string_type get_name() const {return string_type(_name.begin(), _name.end());}
466         ///Copy Constructor
467         entry(const entry&) = default;
468         ///Move Constructor
469         entry& operator=(const entry&) = default;
470         ///Check if the entry is empty.
471         bool empty() const;
472 
473         ///Assign a string to the value
474         void assign(const string_type &value);
475         ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
476         void assign(const std::vector<string_type> &value);
477         ///Append a string to the end of the entry, it will separated by ';' or ':'.
478         void append(const string_type &value);
479         ///Reset the value
480         void clear();
481         ///Assign a string to the entry.
482         entry &operator=(const string_type & value);
483         ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
484         entry &operator=(const std::vector<string_type> & value);
485         ///Append a string to the end of the entry, it will separated by ';' or ':'.
486         entry &operator+=(const string_type & value);
487     };
488 
489 };
490 
491 /**Template representation of the environment of this process. It takes a template
492  * as template parameter to implement the environment. All instances of this class
493  * refer to the same environment, but might not get updated if another one makes changes.
494  */
495 template<typename Char>
496 class basic_native_environment
497 {
498 
499 public:
500     typedef std::basic_string<Char> string_type;
501     typedef boost::transform_iterator<      entry_maker, Char**> iterator       ;
502     typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
503     typedef std::size_t                                             size_type      ;
504 
505     iterator       begin()        ; ///<Returns an iterator to the beginning
506     const_iterator begin()  const ; ///<Returns an iterator to the beginning
507     const_iterator cbegin() const ; ///<Returns an iterator to the beginning
508 
509     iterator       end()       ; ///<Returns an iterator to the end
510     const_iterator end()  const; ///<Returns an iterator to the end
511     const_iterator cend() const; ///<Returns an iterator to the end
512 
513     iterator        find( const string_type& key );            ///<Find a variable by its name
514     const_iterator  find( const string_type& key ) const;   ///<Find a variable by its name
515 
516     std::size_t count(const string_type & st) const; ///<Number of variables
517     void erase(const string_type & id); ///<Erase variable by id.
518     ///Emplace an environment variable.
519     std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
520 
521     ///Default constructor
522     basic_native_environment();
523     ///Move constructor.
524     basic_native_environment(basic_native_environment && );
525     ///Move assignment.
526     basic_native_environment& operator=(basic_native_environment && );
527 
528     typedef typename detail::implementation_type::native_handle_type native_handle;
529 
530     ///Check if environment has entries.
531     bool empty();
532     ///Get the number of variables.
533     std::size_t size() const;
534     ///Get the entry with the key. Throws if it does not exist.
535     entry_type  at( const string_type& key );
536     ///Get the entry with the key. Throws if it does not exist.
537     const_entry_type at( const string_type& key ) const;
538     ///Get the entry with the given key. It creates the entry if it doesn't exist.
539     entry_type operator[](const string_type & key);
540 
541     /**Proxy class used for read access to members by [] or .at()
542      * @attention Holds a reference to the environment it was created from.
543      */
544     template<typename Char, typename Environment>
545     struct const_entry_type
546     {
547         typedef Char value_type;
548         typedef const value_type * pointer;
549         typedef std::basic_string<value_type> string_type;
550         typedef boost::iterator_range<pointer> range;
551         typedef Environment environment_t;
552 
553         ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_native_environment::const_entry_type554         std::vector<string_type> to_vector() const
555         ///Get the value as string.
556         string_type to_string()              const
557         ///Get the name of this entry.
558         string_type get_name() const {return string_type(_name.begin(), _name.end());}
559         ///Copy Constructor
560         const_entry(const const_entry&) = default;
561         ///Move Constructor
562         const_entry& operator=(const const_entry&) = default;
563         ///Check if the entry is empty.
564         bool empty() const;
565     };
566 
567     /**Proxy class used for read and write access to members by [] or .at()
568      * @attention Holds a reference to the environment it was created from.
569      */
570     template<typename Char, typename Environment>
571     struct entry_type
572     {
573 
574         typedef Char value_type;
575         typedef const value_type * pointer;
576         typedef std::basic_string<value_type> string_type;
577         typedef boost::iterator_range<pointer> range;
578         typedef Environment environment_t;
579 
580         ///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
to_vectorboost::process::basic_native_environment::entry_type581         std::vector<string_type> to_vector() const
582         ///Get the value as string.
583         string_type to_string()              const
584         ///Get the name of this entry.
585         string_type get_name() const {return string_type(_name.begin(), _name.end());}
586         ///Copy Constructor
587         entry(const entry&) = default;
588         ///Move Constructor
589         entry& operator=(const entry&) = default;
590         ///Check if the entry is empty.
591         bool empty() const;
592 
593         ///Assign a string to the value
594         void assign(const string_type &value);
595         ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
596         void assign(const std::vector<string_type> &value);
597         ///Append a string to the end of the entry, it will separated by ';'  or ':'.
598         void append(const string_type &value);
599         ///Reset the value
600         void clear();
601         ///Assign a string to the entry.
602         entry &operator=(const string_type & value);
603         ///Assign a set of strings to the entry; they will be separated by ';' or ':'.
604         entry &operator=(const std::vector<string_type> & value);
605         ///Append a string to the end of the entry, it will separated by ';' or ':'.
606         entry &operator+=(const string_type & value);
607     };
608 
609 };
610 
611 #endif
612 
613 ///Definition of the environment for the current process.
614 template<typename Char>
615 class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl>
616 {
617 public:
618     using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>;
619     using base_type::base_type;
620     using base_type::operator=;
621 };
622 
623 ///Type definition to hold a seperate environment.
624 template<typename Char>
625 class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl>
626 {
627 public:
628     using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>;
629     using base_type::base_type;
630     using base_type::operator=;
631 };
632 
633 
634 #if !defined(BOOST_NO_ANSI_APIS)
635 ///Definition of the environment for the current process.
636 typedef basic_native_environment<char>     native_environment;
637 #endif
638 ///Definition of the environment for the current process.
639 typedef basic_native_environment<wchar_t> wnative_environment;
640 
641 #if !defined(BOOST_NO_ANSI_APIS)
642 ///Type definition to hold a seperate environment.
643 typedef basic_environment<char>     environment;
644 #endif
645 ///Type definition to hold a seperate environment.
646 typedef basic_environment<wchar_t> wenvironment;
647 
648 }
649 
650 ///Namespace containing information of the calling process.
651 namespace this_process
652 {
653 
654 ///Definition of the native handle type.
655 typedef ::boost::process::detail::api::native_handle_t native_handle_type;
656 
657 #if !defined(BOOST_NO_ANSI_APIS)
658 ///Definition of the environment for this process.
659 using ::boost::process::native_environment;
660 #endif
661 ///Definition of the environment for this process.
662 using ::boost::process::wnative_environment;
663 
664 ///Get the process id of the current process.
get_id()665 inline int get_id()                     { return ::boost::process::detail::api::get_id();}
666 ///Get the native handle of the current process.
native_handle()667 inline native_handle_type native_handle()  { return ::boost::process::detail::api::native_handle();}
668 #if !defined(BOOST_NO_ANSI_APIS)
669 ///Get the enviroment of the current process.
environment()670 inline native_environment   environment() { return ::boost::process:: native_environment(); }
671 #endif
672 ///Get the enviroment of the current process.
wenvironment()673 inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
674 ///Get the path environment variable of the current process runs.
path()675 inline std::vector<boost::filesystem::path> path()
676 {
677 #if defined(BOOST_WINDOWS_API)
678     const ::boost::process::wnative_environment ne{};
679     typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
680     static constexpr auto id = L"PATH";
681 #else
682     const ::boost::process::native_environment ne{};
683     typedef typename ::boost::process::native_environment::const_entry_type value_type;
684     static constexpr auto id = "PATH";
685 #endif
686 
687     auto itr = std::find_if(ne.cbegin(), ne.cend(),
688             [&](const value_type & e)
689              {return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
690 
691     if (itr == ne.cend())
692         return {};
693 
694     auto vec = itr->to_vector();
695 
696     std::vector<boost::filesystem::path> val;
697     val.resize(vec.size());
698 
699     std::copy(vec.begin(), vec.end(), val.begin());
700 
701     return val;
702 }
703 }
704 }
705 #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */
706