Flow 1.0.1
Flow project: Full implementation reference.
option_set.cpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
20#include <boost/algorithm/string.hpp>
21#include <boost/algorithm/string/trim_all.hpp>
22
23namespace flow::cfg
24{
25// Static/etc. initializers.
26
27/// @cond
28// -^- Doxygen, please ignore the following. It gets confused thinking this is a macro (@todo fix whenever).
29
30// Just see the guy that uses it. I wish it could be a local `constexpr`. @todo Maybe it can?
31const boost::regex VALUE_SET_MEMBER_ID_TO_OPT_NAME_KEYED_REGEX("(.+)\\[[^]]+\\](.+)");
32
33// -v- Doxygen, please stop ignoring.
34/// @endcond
35
36// Implementations.
37
39{
41 using std::string;
42 using boost::algorithm::replace_all;
43 using boost::algorithm::starts_with;
44 using boost::algorithm::is_any_of;
45 using boost::algorithm::trim_fill_if;
46 using std::replace;
47
48 /* E.g. m_cool_object.m_cool_sub_object->m_badass_sub_guy.m_cool_option_name
49 * => cool-object.cool-sub-object.badass-sub-guy.cool-option-name.
50 * Note, by the way, that in config files as parsed by boost.program_options, one can declare a section like:
51 * [cool-object]
52 * cool-option-1
53 * badass-option-2
54 * which will parse the 2 as cool-object.cool-option-1 and cool-object.badass-option-2. Synergy!
55 *
56 * Also #blah does not remove (at least some) white-space that's part of the original source code `blah`, so we have
57 * to eliminate all those first. For reference here's what gcc docs say about the "stringizing" algorithm. (I have
58 * not verified how this relates to C/C++ standards.)
59 * "All leading and trailing whitespace in text being stringized is ignored."
60 * - Nevertheless we'd still nuke it.
61 * "Any sequence of whitespace in the middle of the text is converted to a single space in the stringized result."
62 * - Cool, but in any case we nuke all space-y chars.
63 * "Comments are replaced by whitespace long before stringizing happens, so they never appear in stringized text."
64 * - That's good.
65 *
66 * Other activity involves auto-escaping string/char literals inside `blah`, but that doesn't apply to us. */
67
68 constexpr String_view M_PFX("m_");
69 constexpr String_view CONCAT_OK("."); // Dots remain (but if followed by m_, get rid of m_).
70 constexpr String_view CONCAT_REPLACED("->"); // -> become dots (and again if m_ follows, get rid of it).
71 constexpr char SEP_REPLACED = '_'; // From this...
72 constexpr char SEP_REPLACEMENT = '-'; // ...to this.
73
74 string opt_name(member_id);
75
76 /* Nuke space-y chars.
77 * Am paranoid about locales; and also didn't feel like using <locale> std::isspace(..., std::locale("C")). */
78 trim_fill_if(opt_name, "", is_any_of(" \f\n\r\t\v"));
79
80 // Should now be a contiguous identifier-composed compound.
81
82 // Eliminate leading M_PFX.
83 if (starts_with(opt_name, M_PFX))
84 {
85 opt_name.erase(0, M_PFX.size());
86 }
87
88 // Normalize object separators.
89 replace_all(opt_name, CONCAT_REPLACED, CONCAT_OK);
90
91 // Now any leading M_PFX gone; and object separators normalized to CONCAT_OK. Can eliminate remaining M_PFX:
92 replace_all(opt_name, string(CONCAT_OK) + string(M_PFX), CONCAT_OK);
93
94 // Lastly transform the word-separators.
95 replace(opt_name.begin(), opt_name.end(), SEP_REPLACED, SEP_REPLACEMENT);
96
97 return opt_name;
98} // value_set_member_id_to_opt_name()
99
100} // namespace flow::cfg
101
102namespace boost::filesystem
103{
104// Implementations.
105
106void validate(boost::any& target, const std::vector<std::string>& user_strings, path*, int)
107{
108 // Read our doc header for all background. Hence only light comments below.
109
112 namespace opts = flow::cfg::opts;
113 using boost::any;
114 using boost::lexical_cast;
115 using boost::bad_lexical_cast;
116 using std::string;
117
118 // Note this is auto-trimmed of spaces on left and right.
119 const string& user_string = opts::validators::get_single_string(user_strings);
120 /* That threw if there's more than 1 string. (I believe impossible in config file; but on command line they
121 * could try, e.g., "--log-path some-file.txt some-other-file.txt" -- that would throw.) */
122
123 path result_path; // Empty.
124 if (!user_string.empty())
125 {
126 /* If not empty then just do what the default validate() would've done: lexical_cast<> (i.e., istream>>) it.
127 * Not actually sure what could still trip the exception other than ""; but re-throw it with a nice error, because
128 * we can. */
129 try
130 {
131 result_path = lexical_cast<decltype(result_path)>(user_string);
132 }
133 catch (const bad_lexical_cast& exc)
134 {
135 throw Runtime_error(ostream_op_string
136 ("Error converting [", user_string,
137 "] to boost::filesystem path. Is there something strange in that string?"));
138 }
139 }
140 // else { Leave result_path at empty. lexical_cast<path>("") would have yielded bad_lexical_cast, but we allow it. }
141
142 target = result_path; // Load variable-type `target` with a `path`.
143} // validate(fs_path)
144
145} // namespace boost::filesystem
An std::runtime_error (which is an std::exception) that stores an Error_code.
Definition: error.hpp:49
We may add some ADL-based overloads into this namespace outside flow.
Definition: cfg_fwd.hpp:267
void validate(boost::any &target, const std::vector< std::string > &user_values, path *, int)
ADL-based overload of boost.program_options validate() to allow for empty boost::filesystem::path val...
Definition: option_set.cpp:106
Short-hand for namespace boost::program_options.
Flow module that facilitates configuring modules, such as applications and APIs, via statically and/o...
Definition: cfg_fwd.hpp:112
std::string value_set_member_id_to_opt_name(util::String_view member_id)
Utility, used by FLOW_CFG_OPTION_SET_DECLARE_OPTION() internally but made available as a public API i...
Definition: option_set.cpp:38
const boost::regex VALUE_SET_MEMBER_ID_TO_OPT_NAME_KEYED_REGEX
An internal constant for value_set_member_id_to_opt_name_keyed().
std::string ostream_op_string(T const &... ostream_args)
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the call...
Definition: util.hpp:356
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.