env.hpp 12 KB

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