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 #ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
7 #define BOOST_PROCESS_DETAIL_ENV_HPP_
8
9 #include <boost/process/environment.hpp>
10 #include <boost/none.hpp>
11
12 #if defined(BOOST_POSIX_API)
13 #include <boost/process/detail/posix/env_init.hpp>
14 #elif defined(BOOST_WINDOWS_API)
15 #include <boost/process/detail/windows/env_init.hpp>
16 #endif
17
18 /** \file boost/process/env.hpp
19 *
20 * This header which provides the `env` property. It allows the modification of the
21 * environment the child process will run in, in a functional style.
22 *
23 * \xmlonly
24 <programlisting>
25 namespace boost {
26 namespace process {
27 <emphasis>unspecified</emphasis> <globalname alt="boost::process::env">env</globalname>;
28 }
29 }
30 </programlisting>
31 * \endxmlonly
32 *
33 * For additional information see the platform documentations:
34 *
35 * - [windows](https://msdn.microsoft.com/en-US/library/windows/desktop/ms682653.aspx)
36 * - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
37 *
38 */
39
40
41 namespace boost {
42
43 namespace process { namespace detail {
44
45
46 template<typename Char>
make_env_string_size(const std::basic_string<Char> & ch)47 std::size_t make_env_string_size(const std::basic_string<Char> & ch)
48 {
49 return ch.size() + 1;
50 }
51
52 template<typename Char>
make_env_string_size(const Char * ch)53 std::size_t make_env_string_size(const Char * ch)
54 {
55 std::size_t sz = 0;
56 while (ch[sz] != null_char<Char>())
57 sz++;
58
59 sz++;
60 return sz;
61 }
62
63 template<typename Char, typename Container>
make_env_string(const Container & value)64 inline std::basic_string<Char> make_env_string(const Container & value)
65 {
66 std::size_t sz = 0;
67 for (auto & v : value)
68 sz += make_env_string_size(v);
69
70 std::basic_string<Char> s;
71 s.reserve(sz); //+1 for ;, end doesn't have one.
72
73 for (auto & val : value)
74 (s += val) += api::env_seperator<Char>();
75
76 s.resize(s.size() -1); //remove last ';'
77 return s;
78 }
79
80
81 template<typename Char>
82 struct env_set
83 {
84 using string_type = std::basic_string<Char>;
85 string_type key;
86 string_type value;
87 };
88
89 template<typename Char>
90 struct env_append
91 {
92 using string_type = std::basic_string<Char>;
93 string_type key;
94 string_type value;
95 };
96
97
98
99 template<typename Char>
100 struct env_reset
101 {
102 using string_type = std::basic_string<Char>;
103 string_type key;
104 };
105
106
107 template<> struct is_wchar_t<env_set<wchar_t>> : std::true_type {};
108 template<> struct is_wchar_t<env_append<wchar_t>> : std::true_type {};
109 template<> struct is_wchar_t<env_reset<wchar_t>> : std::true_type {};
110 template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {};
111
112
113 template<>
114 struct char_converter<char, env_set<wchar_t>>
115 {
convboost::process::detail::char_converter116 static env_set<char> conv(const env_set<wchar_t> & in)
117 {
118 return {::boost::process::detail::convert(in.key),
119 ::boost::process::detail::convert(in.value)};
120 }
121 };
122
123 template<>
124 struct char_converter<wchar_t, env_set<char>>
125 {
convboost::process::detail::char_converter126 static env_set<wchar_t> conv(const env_set<char> & in)
127 {
128 return {::boost::process::detail::convert(in.key),
129 ::boost::process::detail::convert(in.value)};
130 }
131 };
132
133 template<>
134 struct char_converter<char, env_append<wchar_t>>
135 {
convboost::process::detail::char_converter136 static env_append<char> conv(const env_append<wchar_t> & in)
137 {
138 return {::boost::process::detail::convert(in.key),
139 ::boost::process::detail::convert(in.value)};
140 }
141 };
142
143 template<>
144 struct char_converter<wchar_t, env_append<char>>
145 {
convboost::process::detail::char_converter146 static env_append<wchar_t> conv(const env_append<char> & in)
147 {
148 return {::boost::process::detail::convert(in.key),
149 ::boost::process::detail::convert(in.value)};
150 }
151 };
152
153 template<>
154 struct char_converter<char, env_reset<wchar_t>>
155 {
convboost::process::detail::char_converter156 static env_reset<char> conv(const env_reset<wchar_t> & in)
157 {
158 return {::boost::process::detail::convert(in.key)};
159 }
160 };
161
162 template<>
163 struct char_converter<wchar_t, env_reset<char>>
164 {
convboost::process::detail::char_converter165 static env_reset<wchar_t> conv(const env_reset<char> & in)
166 {
167 return {::boost::process::detail::convert(in.key)};
168 }
169 };
170
171
172 template<typename Char>
173 struct env_init
174 {
175 basic_environment<Char> env;
176 };
177
178 template<>
179 struct char_converter<char, env_init<wchar_t>>
180 {
convboost::process::detail::char_converter181 static env_init<char> conv(const env_init<wchar_t> & in)
182 {
183 return {basic_environment<char>(in.env)};
184 }
185 };
186
187 template<>
188 struct char_converter<wchar_t, env_init<char>>
189 {
convboost::process::detail::char_converter190 static env_init<wchar_t> conv(const env_init<char> & in)
191 {
192 return {basic_environment<wchar_t>(in.env)};
193 }
194 };
195
196 template<>
197 struct char_converter<char, basic_environment<wchar_t>>
198 {
convboost::process::detail::char_converter199 static basic_environment<char> conv(const basic_environment<wchar_t> & in)
200 {
201 return { basic_environment<char>(in) };
202 }
203 };
204
205 template<>
206 struct char_converter<wchar_t, basic_environment<char>>
207 {
convboost::process::detail::char_converter208 static basic_environment<wchar_t> conv(const basic_environment<char> & in)
209 {
210 return { basic_environment<wchar_t>(in) };
211 }
212 };
213
214 template<typename Char>
215 struct env_proxy
216 {
217 using string_type = std::basic_string<Char>;
218 string_type key;
219
220
operator =boost::process::detail::env_proxy221 env_set<Char> operator=(const string_type & value)
222 {
223 return {std::move(key), value};
224 }
operator =boost::process::detail::env_proxy225 env_set<Char> operator=(const std::vector<string_type> & value)
226 {
227 return {std::move(key), make_env_string<Char>(value)};
228 }
operator =boost::process::detail::env_proxy229 env_set<Char> operator=(const std::initializer_list<const Char*> & value)
230 {
231 return {std::move(key), make_env_string<Char>(value)};
232 }
233
operator +=boost::process::detail::env_proxy234 env_append<Char> operator+=(const string_type & value)
235 {
236 return {std::move(key), value};
237 }
operator +=boost::process::detail::env_proxy238 env_append<Char> operator+=(const std::vector<string_type> & value)
239 {
240 return {std::move(key), make_env_string<Char>(value)};
241 }
operator +=boost::process::detail::env_proxy242 env_append<Char> operator+=(const std::initializer_list<const Char*> & value)
243 {
244 return {std::move(key), make_env_string<Char>(value)};
245 }
operator =boost::process::detail::env_proxy246 env_reset<Char> operator=(boost::none_t)
247 {
248 return {std::move(key)};
249 }
250 };
251
252 struct env_
253 {
env_boost::process::detail::env_254 constexpr env_() {};
255
256 template<typename Char>
operator ()boost::process::detail::env_257 env_set<Char> operator()(const std::basic_string<Char> & key,
258 const std::basic_string<Char> & value) const
259 {
260 return {key, value};
261 }
262 template<typename Char>
operator ()boost::process::detail::env_263 env_set<Char> operator()(const std::basic_string<Char> & key,
264 const std::vector<std::basic_string<Char>> & value) const
265 {
266 return {key, make_env_string<Char>(value)};
267 }
268 template<typename Char>
operator ()boost::process::detail::env_269 env_set<Char> operator()(const std::basic_string<Char> & key,
270 const std::initializer_list<Char*> & value) const
271 {
272 return {key, make_env_string<Char>(value)};
273 }
274 template<typename Char>
operator ()boost::process::detail::env_275 env_reset<Char> operator()(const std::basic_string<Char> & key, boost::none_t)
276 {
277 return {key};
278 }
279 template<typename Char>
operator []boost::process::detail::env_280 env_proxy<Char> operator[](const std::basic_string<Char> & key) const
281 {
282 return {key};
283 }
284 template<typename Char>
operator []boost::process::detail::env_285 env_proxy<Char> operator[](const Char* key) const
286 {
287 return {key};
288 }
289 template<typename Char>
operator ()boost::process::detail::env_290 env_init<Char> operator()(const basic_environment<Char> & env) const
291 {
292 return {env};
293 }
294 template<typename Char>
operator =boost::process::detail::env_295 env_init<Char> operator= (const basic_environment<Char> & env) const
296 {
297 return {env};
298 }
299 };
300
301 template<typename Char>
302 struct env_builder
303 {
304 basic_environment<Char> env;
env_builderboost::process::detail::env_builder305 env_builder() : env{basic_native_environment<Char>()} {}
306
operator ()boost::process::detail::env_builder307 void operator()(const basic_environment<Char> & e)
308 {
309 env = e;
310 }
311
operator ()boost::process::detail::env_builder312 void operator()(env_init<Char> & ei)
313 {
314 env = std::move(ei.env);
315 }
operator ()boost::process::detail::env_builder316 void operator()(env_set<Char> & es)
317 {
318 env[es.key] = es.value;
319 }
operator ()boost::process::detail::env_builder320 void operator()(env_reset<Char> & es)
321 {
322 env.erase(es.key);
323 }
324 template<typename T>
operator ()boost::process::detail::env_builder325 void operator()(env_append<T> & es)
326 {
327 env[es.key] += es.value;
328 }
329
330 typedef api::env_init<Char> result_type;
get_initializerboost::process::detail::env_builder331 api::env_init<Char> get_initializer()
332 {
333 return api::env_init<Char>(std::move(env));
334 }
335 };
336
337 template<>
338 struct initializer_builder<env_tag<char>>
339 {
340 typedef env_builder<char> type;
341 };
342
343 template<>
344 struct initializer_builder<env_tag<wchar_t>>
345 {
346 typedef env_builder<wchar_t> type;
347 };
348
349 }
350
351 /**
352
353 The `env` property provides a functional way to modify the environment used by
354 the child process. If none is passed the environment is inherited from the father
355 process. Appending means that the environment will be interpreted as a ';' or ':'
356 separated list as used in `PATH`.
357
358 On both `posix` and `windows` the environment variables can be lists of strings,
359 separated by ';'. This is typically used for the `PATH` variable.
360
361 By default the environment will be inherited from the launching process,
362 which is also true if environment are modified with this initializer.
363
364 \section env_details Details
365
366 \subsection env_operations Operations
367
368 \subsubsection env_set_var Setting variables
369
370 To set a variable `id` the value `value` the following syntax can be used.
371
372 \code{.cpp}
373 env[id] = value;
374 env(id, value);
375 \endcode
376
377 `std::initializer_list` is among the allowed types, so the following syntax is also possible.
378
379 \code{.cpp}
380 env[id] = {value1, value2};
381 env(id, {value1, value2});
382 \endcode
383
384 \note Creates the variable if it does not exist.
385
386 The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
387 for both `id` and `value`.
388
389 \paragraph id id
390
391 - `std::basic_string<char_type>`
392 - `const char_type *`
393
394 \paragraph env_set_var_value value
395
396 - `std::basic_string<char_type>`
397 - `const char_type * `
398 - `std::initializer_list<const char_type *>`
399 - `std::vector<std::basic_string<char_type>>`
400
401
402 \note Using `std::vector` or `std::initializer_list`
403
404 \subsubsection env_append_var Append variables
405
406 Appending means, that a variable will be interpreted as a
407 To append a variable `id` the value `value` the following syntax can be used:
408
409 \code{.cpp}
410 env[id] += value;
411 \endcode
412
413 `std::initializer_list` is among the allowed types, so the following syntax is also possible.
414
415 \code{.cpp}
416 env[id] += {value1, value2};
417 \endcode
418
419 \note Creates the variable if it does not exist.
420
421 The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
422 for both `id` and `value`.
423
424 \paragraph env_append_var_id id
425
426 - `std::basic_string<char_type>`
427 - `const char_type *`
428
429 \paragraph env_append_var_value value
430
431 - `std::basic_string<char_type>`
432 - `const char_type *`
433 - `std::initializer_list<const char_type *>`
434 - `std::vector<std::basic_string<char_type>>`
435
436
437 \subsubsection env_reset Reset variables
438
439 Reseting signle variables can be done in the following way:
440
441 \code{.cpp}
442 env[id] = boost::none;
443 env(id, boost::none);
444 \endcode
445
446 \note This does not set the value empty, but removes it from the list.
447
448 The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`:
449
450 \paragraph env_reset_var_id id
451
452 - `std::basic_string<char_type>`
453 - `const char_type *`
454
455 \subsubsection env_init Initialize the environment
456
457 The whole environment can be initialized from an object of type
458 \xmlonly <classname>boost::process::environment</classname> \endxmlonly
459
460 \code{.cpp}
461 env=env;
462 env(env);
463 \endcode
464
465 \note The passed `environment` can also be default-constructed to get an empty environment.
466
467 \paragraph env_init_var_id id
468
469 - `std::basic_string<char_type>`
470 - `const char_type *`
471
472 \paragraph env_init_var_value value
473
474 - `boost::process::basic_environment<char_type>`
475
476 \subsection env_example Example
477
478 \code{.cpp}
479 spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE");
480 \endcode
481
482 If the overload style should be done by passing an instance of
483 \xmlonly <classname>boost::process::environment</classname> \endxmlonly
484 the above example would look like this.
485
486 \code{.cpp}
487 environment e = this_process::environment();
488 e["PATH"] += "F:/boost";
489 e.erase("SOME_VAR");
490 e["NEW_VAR"] = "VALUE";
491 spawn("b2", e);
492 \endcode
493
494 \warning Passing an empty environment will cause undefined behaviour.
495
496 */
497 constexpr boost::process::detail::env_ env{};
498
499
500 }}
501
502 #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
503