env.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. #ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
  6. #define BOOST_PROCESS_DETAIL_ENV_HPP_
  7. #include <boost/process/detail/traits/wchar_t.hpp>
  8. #include <boost/process/environment.hpp>
  9. #include <boost/none.hpp>
  10. #if defined(BOOST_POSIX_API)
  11. #include <boost/process/detail/posix/env_init.hpp>
  12. #elif defined(BOOST_WINDOWS_API)
  13. #include <boost/process/detail/windows/env_init.hpp>
  14. #endif
  15. /** \file boost/process/env.hpp
  16. *
  17. * This header which provides the `env` property. It allows the modification of the
  18. * environment the child process will run in, in a functional style.
  19. *
  20. * \xmlonly
  21. <programlisting>
  22. namespace boost {
  23. namespace process {
  24. <emphasis>unspecified</emphasis> <globalname alt="boost::process::env">env</globalname>;
  25. }
  26. }
  27. </programlisting>
  28. * \endxmlonly
  29. *
  30. * For additional information see the platform documentations:
  31. *
  32. * - [windows](https://msdn.microsoft.com/en-US/library/windows/desktop/ms682653.aspx)
  33. * - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
  34. *
  35. */
  36. namespace boost {
  37. namespace process { namespace detail {
  38. template<typename Char>
  39. std::size_t make_env_string_size(const std::basic_string<Char> & ch)
  40. {
  41. return ch.size() + 1;
  42. }
  43. template<typename Char>
  44. std::size_t make_env_string_size(const Char * ch)
  45. {
  46. std::size_t sz = 0;
  47. while (ch[sz] != null_char<Char>())
  48. sz++;
  49. sz++;
  50. return sz;
  51. }
  52. template<typename Char, typename Container>
  53. inline std::basic_string<Char> make_env_string(const Container & value)
  54. {
  55. std::size_t sz = 0;
  56. for (auto & v : value)
  57. sz += make_env_string_size(v);
  58. std::basic_string<Char> s;
  59. s.reserve(sz); //+1 for ;, end doesn't have one.
  60. for (auto & val : value)
  61. (s += val) += api::env_seperator<Char>();
  62. s.resize(s.size() -1); //remove last ';'
  63. return s;
  64. }
  65. template<typename Char>
  66. struct env_set
  67. {
  68. using string_type = std::basic_string<Char>;
  69. string_type key;
  70. string_type value;
  71. };
  72. template<typename Char>
  73. struct env_append
  74. {
  75. using string_type = std::basic_string<Char>;
  76. string_type key;
  77. string_type value;
  78. };
  79. template<typename Char>
  80. struct env_reset
  81. {
  82. using string_type = std::basic_string<Char>;
  83. string_type key;
  84. };
  85. template<> struct is_wchar_t<env_set<wchar_t>> : std::true_type {};
  86. template<> struct is_wchar_t<env_append<wchar_t>> : std::true_type {};
  87. template<> struct is_wchar_t<env_reset<wchar_t>> : std::true_type {};
  88. template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {};
  89. template<>
  90. struct char_converter<char, env_set<wchar_t>>
  91. {
  92. static env_set<char> conv(const env_set<wchar_t> & in)
  93. {
  94. return {::boost::process::detail::convert(in.key),
  95. ::boost::process::detail::convert(in.value)};
  96. }
  97. };
  98. template<>
  99. struct char_converter<wchar_t, env_set<char>>
  100. {
  101. static env_set<wchar_t> conv(const env_set<char> & in)
  102. {
  103. return {::boost::process::detail::convert(in.key),
  104. ::boost::process::detail::convert(in.value)};
  105. }
  106. };
  107. template<>
  108. struct char_converter<char, env_append<wchar_t>>
  109. {
  110. static env_append<char> conv(const env_append<wchar_t> & in)
  111. {
  112. return {::boost::process::detail::convert(in.key),
  113. ::boost::process::detail::convert(in.value)};
  114. }
  115. };
  116. template<>
  117. struct char_converter<wchar_t, env_append<char>>
  118. {
  119. static env_append<wchar_t> conv(const env_append<char> & in)
  120. {
  121. return {::boost::process::detail::convert(in.key),
  122. ::boost::process::detail::convert(in.value)};
  123. }
  124. };
  125. template<>
  126. struct char_converter<char, env_reset<wchar_t>>
  127. {
  128. static env_reset<char> conv(const env_reset<wchar_t> & in)
  129. {
  130. return {::boost::process::detail::convert(in.key)};
  131. }
  132. };
  133. template<>
  134. struct char_converter<wchar_t, env_reset<char>>
  135. {
  136. static env_reset<wchar_t> conv(const env_reset<char> & in)
  137. {
  138. return {::boost::process::detail::convert(in.key)};
  139. }
  140. };
  141. template<typename Char>
  142. struct env_init
  143. {
  144. basic_environment<Char> env;
  145. };
  146. template<>
  147. struct char_converter<char, env_init<wchar_t>>
  148. {
  149. static env_init<char> conv(const env_init<wchar_t> & in)
  150. {
  151. return {basic_environment<char>(in.env)};
  152. }
  153. };
  154. template<>
  155. struct char_converter<wchar_t, env_init<char>>
  156. {
  157. static env_init<wchar_t> conv(const env_init<char> & in)
  158. {
  159. return {basic_environment<wchar_t>(in.env)};
  160. }
  161. };
  162. template<>
  163. struct char_converter<char, basic_environment<wchar_t>>
  164. {
  165. static basic_environment<char> conv(const basic_environment<wchar_t> & in)
  166. {
  167. return { basic_environment<char>(in) };
  168. }
  169. };
  170. template<>
  171. struct char_converter<wchar_t, basic_environment<char>>
  172. {
  173. static basic_environment<wchar_t> conv(const basic_environment<char> & in)
  174. {
  175. return { basic_environment<wchar_t>(in) };
  176. }
  177. };
  178. template<typename Char>
  179. struct env_proxy
  180. {
  181. using string_type = std::basic_string<Char>;
  182. string_type key;
  183. env_set<Char> operator=(const string_type & value)
  184. {
  185. return {std::move(key), value};
  186. }
  187. env_set<Char> operator=(const std::vector<string_type> & value)
  188. {
  189. return {std::move(key), make_env_string<Char>(value)};
  190. }
  191. env_set<Char> operator=(const std::initializer_list<const Char*> & value)
  192. {
  193. return {std::move(key), make_env_string<Char>(value)};
  194. }
  195. env_append<Char> operator+=(const string_type & value)
  196. {
  197. return {std::move(key), value};
  198. }
  199. env_append<Char> operator+=(const std::vector<string_type> & value)
  200. {
  201. return {std::move(key), make_env_string<Char>(value)};
  202. }
  203. env_append<Char> operator+=(const std::initializer_list<const Char*> & value)
  204. {
  205. return {std::move(key), make_env_string<Char>(value)};
  206. }
  207. env_reset<Char> operator=(boost::none_t)
  208. {
  209. return {std::move(key)};
  210. }
  211. };
  212. struct env_
  213. {
  214. constexpr env_() {};
  215. template<typename Char>
  216. env_set<Char> operator()(const std::basic_string<Char> & key,
  217. const std::basic_string<Char> & value) const
  218. {
  219. return {key, value};
  220. }
  221. template<typename Char>
  222. env_set<Char> operator()(const std::basic_string<Char> & key,
  223. const std::vector<std::basic_string<Char>> & value) const
  224. {
  225. return {key, make_env_string<Char>(value)};
  226. }
  227. template<typename Char>
  228. env_set<Char> operator()(const std::basic_string<Char> & key,
  229. const std::initializer_list<Char*> & value) const
  230. {
  231. return {key, make_env_string<Char>(value)};
  232. }
  233. template<typename Char>
  234. env_reset<Char> operator()(const std::basic_string<Char> & key, boost::none_t)
  235. {
  236. return {key};
  237. }
  238. template<typename Char>
  239. env_proxy<Char> operator[](const std::basic_string<Char> & key) const
  240. {
  241. return {key};
  242. }
  243. template<typename Char>
  244. env_proxy<Char> operator[](const Char* key) const
  245. {
  246. return {key};
  247. }
  248. template<typename Char>
  249. env_init<Char> operator()(const basic_environment<Char> & env) const
  250. {
  251. return {env};
  252. }
  253. template<typename Char>
  254. env_init<Char> operator= (const basic_environment<Char> & env) const
  255. {
  256. return {env};
  257. }
  258. };
  259. template<typename Char>
  260. struct env_builder
  261. {
  262. basic_environment<Char> env;
  263. env_builder() : env{basic_native_environment<Char>()} {}
  264. void operator()(const basic_environment<Char> & e)
  265. {
  266. env = e;
  267. }
  268. void operator()(env_init<Char> & ei)
  269. {
  270. env = std::move(ei.env);
  271. }
  272. void operator()(env_set<Char> & es)
  273. {
  274. env[es.key] = es.value;
  275. }
  276. void operator()(env_reset<Char> & es)
  277. {
  278. env.erase(es.key);
  279. }
  280. template<typename T>
  281. void operator()(env_append<T> & es)
  282. {
  283. env[es.key] += es.value;
  284. }
  285. typedef api::env_init<Char> result_type;
  286. api::env_init<Char> get_initializer()
  287. {
  288. return api::env_init<Char>(std::move(env));
  289. }
  290. };
  291. template<>
  292. struct initializer_builder<env_tag<char>>
  293. {
  294. typedef env_builder<char> type;
  295. };
  296. template<>
  297. struct initializer_builder<env_tag<wchar_t>>
  298. {
  299. typedef env_builder<wchar_t> type;
  300. };
  301. }
  302. /**
  303. The `env` property provides a functional way to modify the environment used by
  304. the child process. If none is passed the environment is inherited from the father
  305. process. Appending means that the environment will be interpreted as a ';' or ':'
  306. separated list as used in `PATH`.
  307. On both `posix` and `windows` the environment variables can be lists of strings,
  308. separated by ';'. This is typically used for the `PATH` variable.
  309. By default the environment will be inherited from the launching process,
  310. which is also true if environment are modified with this initializer.
  311. \section env_details Details
  312. \subsection env_operations Operations
  313. \subsubsection env_set_var Setting variables
  314. To set a variable `id` the value `value` the following syntax can be used.
  315. \code{.cpp}
  316. env[id] = value;
  317. env(id, value);
  318. \endcode
  319. `std::initializer_list` is among the allowed types, so the following syntax is also possible.
  320. \code{.cpp}
  321. env[id] = {value1, value2};
  322. env(id, {value1, value2});
  323. \endcode
  324. \note Creates the variable if it does not exist.
  325. The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
  326. for both `id` and `value`.
  327. \paragraph id id
  328. - `std::basic_string<char_type>`
  329. - `const char_type *`
  330. \paragraph env_set_var_value value
  331. - `std::basic_string<char_type>`
  332. - `const char_type * `
  333. - `std::initializer_list<const char_type *>`
  334. - `std::vector<std::basic_string<char_type>>`
  335. \note Using `std::vector` or `std::initializer_list`
  336. \subsubsection env_append_var Append variables
  337. Appending means, that a variable will be interpreted as a
  338. To append a variable `id` the value `value` the following syntax can be used:
  339. \code{.cpp}
  340. env[id] += value;
  341. \endcode
  342. `std::initializer_list` is among the allowed types, so the following syntax is also possible.
  343. \code{.cpp}
  344. env[id] += {value1, value2};
  345. \endcode
  346. \note Creates the variable if it does not exist.
  347. The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
  348. for both `id` and `value`.
  349. \paragraph env_append_var_id id
  350. - `std::basic_string<char_type>`
  351. - `const char_type *`
  352. \paragraph env_append_var_value value
  353. - `std::basic_string<char_type>`
  354. - `const char_type *`
  355. - `std::initializer_list<const char_type *>`
  356. - `std::vector<std::basic_string<char_type>>`
  357. \subsubsection env_reset Reset variables
  358. Resetting single variables can be done in the following way:
  359. \code{.cpp}
  360. env[id] = boost::none;
  361. env(id, boost::none);
  362. \endcode
  363. \note This does not set the value empty, but removes it from the list.
  364. The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`:
  365. \paragraph env_reset_var_id id
  366. - `std::basic_string<char_type>`
  367. - `const char_type *`
  368. \subsubsection env_init Initialize the environment
  369. The whole environment can be initialized from an object of type
  370. \xmlonly <classname>boost::process::environment</classname> \endxmlonly
  371. \code{.cpp}
  372. env=env;
  373. env(env);
  374. \endcode
  375. \note The passed `environment` can also be default-constructed to get an empty environment.
  376. \paragraph env_init_var_id id
  377. - `std::basic_string<char_type>`
  378. - `const char_type *`
  379. \paragraph env_init_var_value value
  380. - `boost::process::basic_environment<char_type>`
  381. \subsection env_example Example
  382. \code{.cpp}
  383. spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE");
  384. \endcode
  385. If the overload style should be done by passing an instance of
  386. \xmlonly <classname>boost::process::environment</classname> \endxmlonly
  387. the above example would look like this.
  388. \code{.cpp}
  389. environment e = this_process::environment();
  390. e["PATH"] += "F:/boost";
  391. e.erase("SOME_VAR");
  392. e["NEW_VAR"] = "VALUE";
  393. spawn("b2", e);
  394. \endcode
  395. \warning Passing an empty environment will cause undefined behaviour.
  396. */
  397. constexpr boost::process::detail::env_ env{};
  398. }}
  399. #endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */