config.ipp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. //
  2. // impl/config.ipp
  3. // ~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_IMPL_CONFIG_IPP
  11. #define BOOST_ASIO_IMPL_CONFIG_IPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/config.hpp>
  16. #include <boost/asio/detail/concurrency_hint.hpp>
  17. #include <cctype>
  18. #include <cstdio>
  19. #include <cstring>
  20. #include <cstdlib>
  21. #include <vector>
  22. #include <utility>
  23. #include <boost/asio/detail/push_options.hpp>
  24. namespace boost {
  25. namespace asio {
  26. config_service::config_service(execution_context& ctx)
  27. : detail::execution_context_service_base<config_service>(ctx)
  28. {
  29. }
  30. void config_service::shutdown()
  31. {
  32. }
  33. const char* config_service::get_value(const char* /*section*/,
  34. const char* /*key_name*/, char* /*value*/, std::size_t /*value_len*/) const
  35. {
  36. return nullptr;
  37. }
  38. namespace detail {
  39. class config_from_concurrency_hint_service : public config_service
  40. {
  41. public:
  42. explicit config_from_concurrency_hint_service(
  43. execution_context& ctx, int concurrency_hint)
  44. : config_service(ctx),
  45. concurrency_hint_(concurrency_hint)
  46. {
  47. }
  48. const char* get_value(const char* section, const char* key_name,
  49. char* value, std::size_t value_len) const override
  50. {
  51. if (std::strcmp(section, "scheduler") == 0)
  52. {
  53. if (std::strcmp(key_name, "concurrency_hint") == 0)
  54. {
  55. if (BOOST_ASIO_CONCURRENCY_HINT_IS_SPECIAL(concurrency_hint_))
  56. {
  57. return
  58. !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
  59. SCHEDULER, concurrency_hint_) ||
  60. !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
  61. REACTOR_IO, concurrency_hint_) ? "1" : "-1";
  62. }
  63. else
  64. {
  65. std::snprintf(value, value_len, "%d", concurrency_hint_);
  66. return value;
  67. }
  68. }
  69. else if (std::strcmp(key_name, "locking") == 0)
  70. {
  71. return BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
  72. SCHEDULER, concurrency_hint_) ? "1" : "0";
  73. }
  74. }
  75. else if (std::strcmp(section, "reactor") == 0)
  76. {
  77. if (std::strcmp(key_name, "io_locking") == 0)
  78. {
  79. return BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
  80. REACTOR_IO, concurrency_hint_) ? "1" : "0";
  81. }
  82. else if (std::strcmp(key_name, "registration_locking") == 0)
  83. {
  84. return BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(
  85. REACTOR_REGISTRATION, concurrency_hint_) ? "1" : "0";
  86. }
  87. }
  88. return nullptr;
  89. }
  90. private:
  91. int concurrency_hint_;
  92. };
  93. } // namespace detail
  94. config_from_concurrency_hint::config_from_concurrency_hint()
  95. : concurrency_hint_(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT)
  96. {
  97. }
  98. void config_from_concurrency_hint::make(execution_context& ctx) const
  99. {
  100. (void)make_service<detail::config_from_concurrency_hint_service>(ctx,
  101. concurrency_hint_ == 1
  102. ? BOOST_ASIO_CONCURRENCY_HINT_1 : concurrency_hint_);
  103. }
  104. namespace detail {
  105. class config_from_string_service : public config_service
  106. {
  107. public:
  108. config_from_string_service(execution_context& ctx,
  109. std::string s, std::string prefix)
  110. : config_service(ctx),
  111. string_(static_cast<std::string&&>(s)),
  112. prefix_(static_cast<std::string&&>(prefix))
  113. {
  114. enum
  115. {
  116. expecting_key_name,
  117. key_name,
  118. expecting_equals,
  119. expecting_value,
  120. value,
  121. expecting_eol
  122. } state = expecting_key_name;
  123. std::pair<const char*, const char*> entry{};
  124. for (char& c : string_)
  125. {
  126. switch (state)
  127. {
  128. case expecting_key_name:
  129. switch (c)
  130. {
  131. case ' ': case '\t': case '\n':
  132. break;
  133. case '#':
  134. state = expecting_eol;
  135. break;
  136. default:
  137. entry.first = &c;
  138. state = key_name;
  139. break;
  140. }
  141. break;
  142. case key_name:
  143. switch (c)
  144. {
  145. case ' ': case '\t':
  146. c = 0;
  147. state = expecting_equals;
  148. break;
  149. case '=':
  150. c = 0;
  151. state = expecting_value;
  152. break;
  153. case '\n':
  154. entry.first = nullptr;
  155. state = expecting_key_name;
  156. break;
  157. case '#':
  158. entry.first = nullptr;
  159. state = expecting_eol;
  160. break;
  161. default:
  162. break;
  163. }
  164. break;
  165. case expecting_equals:
  166. switch (c)
  167. {
  168. case ' ': case '\t':
  169. break;
  170. case '=':
  171. state = expecting_value;
  172. break;
  173. case '\n':
  174. entry.first = nullptr;
  175. state = expecting_key_name;
  176. break;
  177. default:
  178. entry.first = nullptr;
  179. state = expecting_eol;
  180. break;
  181. }
  182. break;
  183. case expecting_value:
  184. switch (c)
  185. {
  186. case ' ': case '\t':
  187. break;
  188. case '\n':
  189. entry.first = nullptr;
  190. state = expecting_key_name;
  191. break;
  192. case '#':
  193. entry.first = nullptr;
  194. state = expecting_eol;
  195. break;
  196. default:
  197. entry.second = &c;
  198. state = value;
  199. break;
  200. }
  201. break;
  202. case value:
  203. switch (c)
  204. {
  205. case '\n':
  206. c = 0;
  207. entries_.push_back(entry);
  208. entry.first = entry.second = nullptr;
  209. state = expecting_key_name;
  210. break;
  211. case '#':
  212. c = 0;
  213. entries_.push_back(entry);
  214. entry.first = entry.second = nullptr;
  215. state = expecting_eol;
  216. break;
  217. default:
  218. break;
  219. }
  220. break;
  221. case expecting_eol:
  222. switch (c)
  223. {
  224. case '\n':
  225. state = expecting_key_name;
  226. break;
  227. default:
  228. break;
  229. }
  230. break;
  231. }
  232. }
  233. if (entry.first && entry.second)
  234. entries_.push_back(entry);
  235. }
  236. const char* get_value(const char* section, const char* key_name,
  237. char* /*value*/, std::size_t /*value_len*/) const override
  238. {
  239. std::string entry_key;
  240. entry_key.reserve(prefix_.length() + 1
  241. + std::strlen(section) + 1
  242. + std::strlen(key_name) + 1);
  243. entry_key.append(prefix_);
  244. if (!entry_key.empty())
  245. entry_key.append(".");
  246. entry_key.append(section);
  247. entry_key.append(".");
  248. entry_key.append(key_name);
  249. for (const std::pair<const char*, const char*>& entry : entries_)
  250. if (entry_key == entry.first)
  251. return entry.second;
  252. return nullptr;
  253. }
  254. private:
  255. std::string string_;
  256. std::string prefix_;
  257. std::vector<std::pair<const char*, const char*>> entries_;
  258. };
  259. } // namespace detail
  260. void config_from_string::make(execution_context& ctx) const
  261. {
  262. (void)make_service<detail::config_from_string_service>(ctx, string_, prefix_);
  263. }
  264. namespace detail {
  265. #if defined(BOOST_ASIO_MSVC)
  266. # pragma warning (push)
  267. # pragma warning (disable:4996) // suppress unsafe warning for std::getenv
  268. #endif // defined(BOOST_ASIO_MSVC)
  269. class config_from_env_service : public config_service
  270. {
  271. public:
  272. explicit config_from_env_service(
  273. execution_context& ctx, std::string prefix)
  274. : config_service(ctx),
  275. prefix_(static_cast<std::string&&>(prefix))
  276. {
  277. }
  278. const char* get_value(const char* section, const char* key_name,
  279. char* /*value*/, std::size_t /*value_len*/) const override
  280. {
  281. std::string env_var;
  282. env_var.reserve(prefix_.length() + 1
  283. + std::strlen(section) + 1
  284. + std::strlen(key_name) + 1);
  285. env_var.append(prefix_);
  286. if (!env_var.empty())
  287. env_var.append("_");
  288. env_var.append(section);
  289. env_var.append("_");
  290. env_var.append(key_name);
  291. for (char& c : env_var)
  292. c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
  293. return std::getenv(env_var.c_str());
  294. }
  295. private:
  296. std::string prefix_;
  297. };
  298. #if defined(BOOST_ASIO_MSVC)
  299. # pragma warning (pop)
  300. #endif // defined(BOOST_ASIO_MSVC)
  301. } // namespace detail
  302. config_from_env::config_from_env()
  303. : prefix_("asio")
  304. {
  305. }
  306. void config_from_env::make(execution_context& ctx) const
  307. {
  308. (void)make_service<detail::config_from_env_service>(ctx, prefix_);
  309. }
  310. } // namespace asio
  311. } // namespace boost
  312. #include <boost/asio/detail/pop_options.hpp>
  313. #endif // BOOST_ASIO_IMPL_CONFIG_IPP