]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/str_map.cc
638a307845cb8401b72896525b187f8d377a25f3
[ceph.git] / ceph / src / common / str_map.cc
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 #include "include/str_map.h"
18 #include "include/str_list.h"
19
20 #include <boost/algorithm/string.hpp>
21
22 #include "json_spirit/json_spirit.h"
23
24 using namespace std;
25
26 int get_json_str_map(
27 const string &str,
28 ostream &ss,
29 str_map_t *str_map,
30 bool fallback_to_plain)
31 {
32 json_spirit::mValue json;
33 try {
34 // try json parsing first
35
36 json_spirit::read_or_throw(str, json);
37
38 if (json.type() != json_spirit::obj_type) {
39 ss << str << " must be a JSON object but is of type "
40 << json.type() << " instead";
41 return -EINVAL;
42 }
43
44 json_spirit::mObject o = json.get_obj();
45
46 for (map<string, json_spirit::mValue>::iterator i = o.begin();
47 i != o.end();
48 ++i) {
49 (*str_map)[i->first] = i->second.get_str();
50 }
51 } catch (json_spirit::Error_position &e) {
52 if (fallback_to_plain) {
53 // fallback to key=value format
54 get_str_map(str, str_map, "\t\n ");
55 } else {
56 return -EINVAL;
57 }
58 }
59 return 0;
60 }
61
62 static std::string_view trim(std::string_view str)
63 {
64 static const char* whitespaces = "\t\n ";
65 auto beg = str.find_first_not_of(whitespaces);
66 if (beg == str.npos) {
67 return {};
68 }
69 auto end = str.find_last_not_of(whitespaces);
70 return str.substr(beg, end - beg + 1);
71 }
72
73 int get_str_map(
74 const string &str,
75 str_map_t* str_map,
76 const char *delims)
77 {
78 for_each_pair(str, delims, [str_map](std::string_view key,
79 std::string_view val) {
80 // is the format 'K=V' or just 'K'?
81 if (val.empty()) {
82 str_map->emplace(std::string(key), "");
83 } else {
84 str_map->emplace(std::string(trim(key)), std::string(trim(val)));
85 }
86 });
87 return 0;
88 }
89
90 str_map_t get_str_map(
91 const string& str,
92 const char* delim)
93 {
94 str_map_t str_map;
95 get_str_map(str, &str_map, delim);
96 return str_map;
97 }
98
99 string get_str_map_value(
100 const str_map_t &str_map,
101 const string &key,
102 const string *def_val)
103 {
104 auto p = str_map.find(key);
105
106 // key exists in str_map
107 if (p != str_map.end()) {
108 // but value is empty
109 if (p->second.empty())
110 return p->first;
111 // and value is not empty
112 return p->second;
113 }
114
115 // key DNE in str_map and def_val was specified
116 if (def_val != nullptr)
117 return *def_val;
118
119 // key DNE in str_map, no def_val was specified
120 return string();
121 }
122
123 string get_str_map_key(
124 const str_map_t &str_map,
125 const string &key,
126 const string *fallback_key)
127 {
128 auto p = str_map.find(key);
129 if (p != str_map.end())
130 return p->second;
131
132 if (fallback_key != nullptr) {
133 p = str_map.find(*fallback_key);
134 if (p != str_map.end())
135 return p->second;
136 }
137 return string();
138 }
139
140 // This function's only purpose is to check whether a given map has only
141 // ONE key with an empty value (which would mean that 'get_str_map()' read
142 // a map in the form of 'VALUE', without any KEY/VALUE pairs) and, in such
143 // event, to assign said 'VALUE' to a given 'def_key', such that we end up
144 // with a map of the form "m = { 'def_key' : 'VALUE' }" instead of the
145 // original "m = { 'VALUE' : '' }".
146 int get_conf_str_map_helper(
147 const string &str,
148 ostringstream &oss,
149 str_map_t* str_map,
150 const string &default_key)
151 {
152 get_str_map(str, str_map);
153
154 if (str_map->size() == 1) {
155 auto p = str_map->begin();
156 if (p->second.empty()) {
157 string s = p->first;
158 str_map->erase(s);
159 (*str_map)[default_key] = s;
160 }
161 }
162 return 0;
163 }
164
165 std::string get_value_via_strmap(
166 const string& conf_string,
167 std::string_view default_key)
168 {
169 auto mp = get_str_map(conf_string);
170 if (mp.size() != 1) {
171 return "";
172 }
173
174 // if the one-elem "map" is of the form { 'value' : '' }
175 // replace it with { 'default_key' : 'value' }
176 const auto& [k, v] = *(mp.begin());
177 if (v.empty()) {
178 return k;
179 }
180 return v;
181 }
182
183 std::string get_value_via_strmap(
184 const string& conf_string,
185 const string& key,
186 std::string_view default_key)
187 {
188 auto mp = get_str_map(conf_string);
189 if (mp.size() != 1) {
190 return std::string{};
191 }
192
193 // if the one-elem "map" is of the form { 'value' : '' }
194 // replace it with { 'default_key' : 'value' }
195 const auto& [k, v] = *(mp.begin());
196 if (v.empty()) {
197 return k;
198 }
199 if (k == key) {
200 return k;
201 }
202 if (k == default_key) {
203 return v;
204 }
205
206 return string{};
207 }