bes Updated for version 3.20.13
kvp_utils.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of the BES
4
5// Copyright (c) 2020 OPeNDAP, Inc.
6// Author: Nathan Potter<ndp@opendap.org>
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Lesser General Public
10// License as published by the Free Software Foundation; either
11// version 2.1 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Lesser General Public License for more details.
17//
18// You should have received a copy of the GNU Lesser General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21//
22// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
23// Created by ndp on 12/11/19.
24//
25
26#include "config.h"
27
28#include <cerrno>
29#include <cstring>
30
31#include <string>
32#include <sstream>
33#include <set>
34
35#if HAVE_UNISTD_H
36#include <unistd.h>
37#endif
38
39#include "BESUtil.h"
40#include "BESFSDir.h"
41#include "BESFSFile.h"
42#include "BESInternalFatalError.h"
43
44#include "kvp_utils.h"
45
46
47#define BES_INCLUDE_KEY "BES.Include"
48
49using namespace std;
50
51namespace kvp {
52
53 // Forward declaration, implementation at end of file..
54 void load_keys(
55 const std::string &keys_file_name,
56 set<string> &loaded_kvp_files,
57 std::map<std::string, std::vector<std::string> > &keystore);
58
59 bool only_blanks(const char *line) {
60 string my_line = line;
61 if (my_line.find_first_not_of(" ") != string::npos)
62 return false;
63 else
64 return true;
65 }
66
67
68// The string contained in the character buffer b should be of the
69// format key=value or key+=value. The pair is broken apart, storing the
70// key in the key parameter and the value of the key in the value
71// parameter. If += is used, then the value should be added to the value
72// of key, not replacing.
73//
74// It used to be that we would validate the key=value line. Instead,
75// anything after the equal sign is considered the value of the key.
76 bool break_pair(const char *b, string &key, string &value, bool &addto) {
77 addto = false;
78 // Ignore comments and lines with only spaces
79 if (b && (b[0] != '#') && (!only_blanks(b))) {
80 size_t l = strlen(b);
81 if (l > 1) {
82 int pos = 0;
83 bool done = false;
84 for (size_t j = 0; j < l && !done; j++) {
85 if (b[j] == '=') {
86 if (!addto)
87 pos = j;
88 else {
89 if (pos != static_cast<int>(j - 1)) {
90 string s = string("BES: Invalid entry ") + b +
91 " in configuration file "// + d_keys_file_name
92 + " '+' character found in variable name" + " or attempting '+=' with space"
93 + " between the characters.\n";
94 throw BESInternalFatalError(s, __FILE__, __LINE__);
95 }
96 }
97 done = true;
98 } else if (b[j] == '+') {
99 addto = true;
100 pos = j;
101 }
102 }
103 if (!done) {
104 string s = string("BES: Invalid entry ") + b + " in configuration file " //+ d_keys_file_name + ": "
105 + " '=' character not found.\n";
106 throw BESInternalFatalError(s, __FILE__, __LINE__);
107 }
108
109 string s = b;
110 key = s.substr(0, pos);
112 if (addto)
113 value = s.substr(pos + 2, s.size());
114 else
115 value = s.substr(pos + 1, s.size());
117 return true;
118 }
119 return false;
120 }
121 return false;
122 }
123
124
131 void load_include_file(
132 const string &file,
133 set<string> &loaded_kvp_files,
134 std::map<std::string, std::vector<std::string> > &keystore
135 ) {
136 // make sure the file exists and is readable
137 // throws exception if unable to read
138 // not loaded if has already be started to be loaded
139 set<string>::iterator it = loaded_kvp_files.find(file);
140
141 if (it == loaded_kvp_files.end()) {
142 // Didn't find it, better load it...
143 loaded_kvp_files.insert(file);
144 load_keys(file, loaded_kvp_files, keystore);
145 }
146 }
147
148
160 void load_include_files(
161 const string &current_keys_file_name,
162 const string &file_expr,
163 set<string> &loaded_kvp_files,
164 std::map<std::string, std::vector<std::string> > &keystore
165 ) {
166 string newdir = "";
167 BESFSFile allfiles(file_expr);
168
169 // If the files specified begin with a /, then use that directory
170 // instead of the current keys file directory.
171 if (!file_expr.empty() && file_expr[0] == '/') {
172 newdir = allfiles.getDirName();
173 } else {
174 // determine the directory of the current keys file. All included
175 // files will be relative to this file.
176 BESFSFile currfile(current_keys_file_name);
177 string currdir = currfile.getDirName();
178
179 string alldir = allfiles.getDirName();
180
181 if ((currdir == "./" || currdir == ".") && (alldir == "./" || alldir == ".")) {
182 newdir = "./";
183 } else {
184 if (alldir == "./" || alldir == ".") {
185 newdir = currdir;
186 } else {
187 newdir = currdir + "/" + alldir;
188 }
189 }
190 }
191
192 // load the files one at a time. If the directory doesn't exist,
193 // then don't load any configuration files
194 BESFSDir fsd(newdir, allfiles.getFileName());
195 BESFSDir::fileIterator i = fsd.beginOfFileList();
196 BESFSDir::fileIterator e = fsd.endOfFileList();
197 for (; i != e; i++) {
198 string include_file = (*i).getFullPath();
199 load_include_file(include_file, loaded_kvp_files, keystore);
200 }
201 }
202
203 void set_key(
204 const string &key,
205 const string &val,
206 bool addto,
207 std::map<std::string, std::vector<std::string> > &keystore) {
208 map<string, vector<string> >::iterator i;
209 i = keystore.find(key);
210 if (i == keystore.end()) {
211 vector<string> vals;
212 keystore[key] = vals;
213 }
214 if (!addto) keystore[key].clear();
215 if (!val.empty()) {
216 keystore[key].push_back(val);
217 }
218 }
219
220 void load_keys(
221 const string &current_keys_file_name,
222 std::ifstream &keys_file,
223 set<string> &loaded_kvp_files,
224 std::map<std::string, std::vector<std::string> > &keystore ) {
225
226 string key, value, line;
227 while (!keys_file.eof()) {
228 bool addto = false;
229 getline(keys_file, line);
230 if (break_pair(line.c_str(), key, value, addto)) {
231 if (key == BES_INCLUDE_KEY) {
232 // We make this call to set_key() and force 'addto' to
233 // be true because we need access to the child configuration
234 // files and their values for the admin interface.
235 set_key(key, value, true, keystore);
236 //load_include_files(kvp_files, value, keystore);
237 load_include_files(current_keys_file_name, value, loaded_kvp_files, keystore );
238 } else {
239 set_key(key, value, addto, keystore);
240 }
241 }
242 }
243 }
244
245 void load_keys(
246 const std::string &keys_file_name,
247 set<string> &loaded_kvp_files,
248 std::map<std::string, std::vector<std::string> > &keystore
249 ) {
250 std::ifstream keys_file(keys_file_name.c_str());
251
252 if (!keys_file) {
253 char path[500];
254 getcwd(path, sizeof(path));
255 string s = string("Cannot open configuration file '") + keys_file_name + "': ";
256 char *err = strerror(errno);
257 if (err)
258 s += err;
259 else
260 s += "Unknown error";
261
262 s += (string) ".\n" + "The current working directory is " + path;
263 throw BESInternalFatalError(s, __FILE__, __LINE__);
264 }
265
266 try {
267 loaded_kvp_files.insert(keys_file_name);
268 load_keys(keys_file_name, keys_file, loaded_kvp_files, keystore);
269 }
270 catch (BESError &e) {
271 // be sure we're throwing a fatal error, since the BES can't run
272 // without the configuration file
273 //clean();
275 }
276 catch (std::exception &e) {
277 //clean();
278 string s = (string) "Caught exception load keys from the BES configuration file '"
279 + keys_file_name + "' message:" + e.what();
280 throw BESInternalFatalError(s, __FILE__, __LINE__);
281 }
282 }
283
284
285 void load_keys(
286 const std::string &keys_file_name,
287 std::map<std::string, std::vector<std::string> > &keystore
288 ) {
289 set<string> loaded_kvp_files;
290 load_keys(keys_file_name, loaded_kvp_files, keystore);
291 }
292
293} // namespace kvp
Base exception class for the BES with basic string message.
Definition: BESError.h:59
unsigned int get_line() const
get the line number where the exception was thrown
Definition: BESError.h:129
std::string get_file() const
get the file name where the exception was thrown
Definition: BESError.h:120
std::string get_message() const
get the error message for this exception
Definition: BESError.h:111
exception thrown if an internal error is found and is fatal to the BES
static void removeLeadingAndTrailingBlanks(std::string &key)
Definition: BESUtil.cc:445