]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com> | |
7 | * | |
8 | * Author: Loic Dachary <loic@dachary.org> | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | */ | |
16 | ||
17 | #ifndef CEPH_STRMAP_H | |
18 | #define CEPH_STRMAP_H | |
19 | ||
20 | #define CONST_DELIMS ",;\t\n " | |
21 | ||
22 | #include <map> | |
23 | #include <string> | |
24 | #include <sstream> | |
25 | ||
20effc67 TL |
26 | template <typename Func> |
27 | void for_each_pair(std::string_view s, const char* delims, Func&& f) | |
28 | { | |
29 | auto pos = s.find_first_not_of(delims); | |
30 | while (pos != s.npos) { | |
31 | s.remove_prefix(pos); // trim delims from the front | |
32 | auto end = s.find_first_of(delims); | |
33 | auto kv = s.substr(0, end); | |
34 | if (auto equal = kv.find('='); equal != kv.npos) { | |
35 | f(kv.substr(0, equal), kv.substr(equal + 1)); | |
36 | } else { | |
37 | f(kv.substr(0, equal), std::string_view()); | |
38 | } | |
39 | pos = s.find_first_not_of(delims, end); | |
40 | } | |
41 | } | |
42 | ||
43 | using str_map_t = std::map<std::string,std::string>; | |
44 | ||
7c673cae FG |
45 | /** |
46 | * Parse **str** and set **str_map** with the key/value pairs read | |
47 | * from it. The format of **str** is either a well formed JSON object | |
48 | * or a custom key[=value] plain text format. | |
49 | * | |
50 | * JSON is tried first. If successfully parsed into a JSON object, it | |
51 | * is copied into **str_map** verbatim. If it is not a JSON object ( a | |
52 | * string, integer etc. ), -EINVAL is returned and **ss** is set to | |
53 | * a human readable error message. | |
54 | * | |
55 | * If **str** is no valid JSON and if **fallback_to_plain** is set to true | |
56 | * (default: true) it is assumed to be a string containing white space | |
57 | * separated key=value pairs. A white space is either space, tab or newline. | |
58 | * Function **get_str_map** will be leveraged to parse the plain-text | |
59 | * key/value pairs. | |
60 | * | |
61 | * @param [in] str JSON or plain text key/value pairs | |
62 | * @param [out] ss human readable message on error | |
63 | * @param [out] str_map key/value pairs read from str | |
64 | * @param [in] fallback_to_plain attempt parsing as plain-text if json fails | |
65 | * @return **0** on success or a -EINVAL on error. | |
66 | */ | |
20effc67 | 67 | int get_json_str_map( |
7c673cae FG |
68 | const std::string &str, |
69 | std::ostream &ss, | |
20effc67 | 70 | str_map_t* str_map, |
7c673cae FG |
71 | bool fallback_to_plain = true); |
72 | ||
73 | /** | |
74 | * Parse **str** and set **str_map** with the key/value pairs read from | |
75 | * it. The format of **str** is a number of custom key[=value] pairs in | |
76 | * plain text format. | |
77 | * | |
78 | * The string will be parsed taking **delims** as field delimiters for | |
79 | * key/values. The value is optional resulting in an empty string when | |
80 | * not provided. For example, using white space as delimiters: | |
81 | * | |
82 | * insert your own=political/ideological statement=here | |
83 | * | |
84 | * will be parsed into: | |
85 | * | |
86 | * { "insert": "", | |
87 | * "your": "", | |
88 | * "own": "political/ideological", | |
89 | * "statement": "here" } | |
90 | * | |
91 | * Alternative delimiters may be provided. For instance, specifying | |
92 | * "white space and slash", for the above statement, would be parsed | |
93 | * into: | |
94 | * | |
95 | * { "insert": "", | |
96 | * "your": "", | |
97 | * "own": "political", | |
98 | * "ideological": "", | |
99 | * "statement": "here" } | |
100 | * | |
101 | * See how adding '/' to the delimiters field will spawn a new key without | |
102 | * a set value. | |
103 | * | |
104 | * Always returns 0, as there is no condition for failure. | |
105 | * | |
106 | * @param [in] str plain text key/value pairs | |
107 | * @param [in] delims field delimiters to be used for parsing str | |
108 | * @param [out] str_map key/value pairs parsed from str | |
109 | * @return **0** | |
110 | */ | |
20effc67 | 111 | int get_str_map( |
7c673cae | 112 | const std::string &str, |
20effc67 | 113 | str_map_t* str_map, |
7c673cae FG |
114 | const char *delims = CONST_DELIMS); |
115 | ||
20effc67 TL |
116 | // an alternate form (as we never fail): |
117 | str_map_t get_str_map( | |
118 | const std::string& str, | |
119 | const char* delim = CONST_DELIMS); | |
120 | ||
7c673cae FG |
121 | /** |
122 | * Returns the value of **key** in **str_map** if available. | |
123 | * | |
124 | * If **key** is not available in **str_map**, and if **def_val** is | |
125 | * not-NULL then returns **def_val**. Otherwise checks if the value of | |
126 | * **key** is an empty string and if so will return **key**. | |
127 | * If the map contains **key**, the function returns the value of **key**. | |
128 | * | |
129 | * @param[in] str_map Map to obtain **key** from | |
130 | * @param[in] key The key to search for in the map | |
131 | * @param[in] def_val The value to return in case **key** is not present | |
132 | */ | |
20effc67 TL |
133 | std::string get_str_map_value( |
134 | const str_map_t& str_map, | |
7c673cae | 135 | const std::string &key, |
20effc67 | 136 | const std::string *def_val = nullptr); |
7c673cae FG |
137 | |
138 | /** | |
139 | * Returns the value of **key** in **str_map** if available. | |
140 | * | |
141 | * If **key** is available in **str_map** returns the value of **key**. | |
142 | * | |
143 | * If **key** is not available in **str_map**, and if **def_key** | |
144 | * is not-NULL and available in **str_map**, then returns the value | |
145 | * of **def_key**. | |
146 | * | |
147 | * Otherwise returns an empty string. | |
148 | * | |
149 | * @param[in] str_map Map to obtain **key** or **def_key** from | |
150 | * @param[in] key Key to obtain the value of from **str_map** | |
151 | * @param[in] def_key Key to fallback to if **key** is not present | |
152 | * in **str_map** | |
153 | */ | |
20effc67 TL |
154 | std::string get_str_map_key( |
155 | const str_map_t& str_map, | |
7c673cae | 156 | const std::string &key, |
20effc67 | 157 | const std::string *fallback_key = nullptr); |
7c673cae FG |
158 | |
159 | // This function's only purpose is to check whether a given map has only | |
160 | // ONE key with an empty value (which would mean that 'get_str_map()' read | |
161 | // a map in the form of 'VALUE', without any KEY/VALUE pairs) and, in such | |
162 | // event, to assign said 'VALUE' to a given 'def_key', such that we end up | |
163 | // with a map of the form "m = { 'def_key' : 'VALUE' }" instead of the | |
164 | // original "m = { 'VALUE' : '' }". | |
165 | int get_conf_str_map_helper( | |
166 | const std::string &str, | |
167 | std::ostringstream &oss, | |
20effc67 TL |
168 | str_map_t* str_map, |
169 | const std::string &default_key); | |
170 | ||
171 | std::string get_value_via_strmap( | |
172 | const std::string& conf_string, | |
173 | std::string_view default_key); | |
174 | ||
175 | std::string get_value_via_strmap( | |
176 | const std::string& conf_string, | |
177 | const std::string& key, | |
178 | std::string_view default_key); | |
7c673cae FG |
179 | |
180 | #endif |