MB-24142: Use correct unit for slowTask recording
[ep-engine.git] / tools / genconfig.cc
1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2011 Couchbase, Inc
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #include <platform/cbassert.h>
18 #include <cstdio>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <cerrno>
23 #include <sys/stat.h>
24 #include <string>
25 #include <sstream>
26 #include <iostream>
27 #include <fstream>
28 #include <map>
29
30 #include <ctype.h>
31
32 #include "cJSON.h"
33
34 using namespace std;
35
36 stringstream prototypes;
37 stringstream initialization;
38 stringstream implementation;
39
40 typedef string (*getValidatorCode)(const std::string &, cJSON*);
41
42 std::map<string, getValidatorCode> validators;
43 map<string, string> getters;
44 map<string, string> datatypes;
45
46 static string getDatatype(const std::string& key, cJSON* o);
47
48 static string getRangeValidatorCode(const std::string &key, cJSON *o) {
49     cJSON* validator = cJSON_GetObjectItem(o, "validator");
50
51     cJSON* n = cJSON_GetArrayItem(validator, 0);
52     if (n == NULL) {
53         return "";
54     }
55
56     // the range validator should contain a "min" or a "max" element
57     cJSON* min = cJSON_GetObjectItem(n, "min");
58     cJSON* max = cJSON_GetObjectItem(n, "max");
59
60     if (min == nullptr && max == nullptr) {
61         cerr << "Incorrect syntax for a range validator specified for"
62              << "\"" << key << "\"." << endl
63              <<"You need at least one of a min or a max clause." << endl;
64         exit(1);
65     }
66
67     if (min && min->type != cJSON_Number) {
68         cerr << "Incorrect datatype for the range validator specified for "
69              << "\"" << key << "\"." << endl
70              << "Only numbers are supported." << endl;
71         exit(1);
72     }
73     if (max && max->type != cJSON_Number) {
74         cerr << "Incorrect datatype for the range validator specified for "
75         << "\"" << key << "\"." << endl
76         << "Only numbers are supported." << endl;
77         exit(1);
78     }
79
80     string validator_type;
81     string mins;
82     string maxs;
83
84     if (getDatatype(key, o) == "float") {
85         validator_type = "FloatRangeValidator";
86         if (min) {
87             mins = to_string(min->valuedouble);
88         } else {
89             mins = "std::numeric_limits<float>::min()";
90         }
91         if (max) {
92             maxs = to_string(max->valuedouble);
93         } else {
94             maxs = "std::numeric_limits<float>::max()";
95         }
96
97     } else if (getDatatype(key, o) == "ssize_t") {
98         validator_type = "SSizeRangeValidator";
99         if (min) {
100             mins = to_string(min->valueint);
101         } else {
102             mins = "std::numeric_limits<ssize_t>::min()";
103         }
104         if (max) {
105             maxs = to_string(max->valueint);
106         } else {
107             maxs = "std::numeric_limits<ssize_t>::max()";
108         }
109     } else {
110         validator_type = "SizeRangeValidator";
111         if (min) {
112             mins = to_string(min->valueint);
113         } else {
114             mins = "std::numeric_limits<size_t>::min()";
115         }
116         if (max) {
117             maxs = to_string(max->valueint);
118         } else {
119             maxs = "std::numeric_limits<size_t>::max()";
120         }
121     }
122
123     string out = "(new " + validator_type + "())->min(" + mins + ")->max(" + maxs + ")";
124     return out;
125 }
126
127 static string getEnumValidatorCode(const std::string &key, cJSON *o) {
128     cJSON *validator = cJSON_GetObjectItem(o, "validator");
129
130     cJSON *n = cJSON_GetArrayItem(validator, 0);
131     if (n == NULL) {
132         return "";
133     }
134
135     if (n->type != cJSON_Array) {
136         cerr << "Incorrect enum value for " << key
137              << ".  Array of values is required." << endl;
138         exit(1);
139     }
140
141     if (cJSON_GetArraySize(n) < 1) {
142         cerr << "At least one validator enum element is required ("
143              << key << ")" << endl;
144         exit(1);
145     }
146
147     stringstream ss;
148     ss << "(new EnumValidator())";
149
150     for (cJSON* p(n->child); p; p = p->next) {
151         if (p->type != cJSON_String) {
152             cerr << "Incorrect validator for " << key
153                  << ", all enum entries must be strings." << endl;
154             exit(1);
155         }
156         char *value = cJSON_Print(p);
157         ss << "\n\t\t->add(" << value << ")";
158         cJSON_Free(value);
159     }
160     return ss.str();
161 }
162
163 static void initialize() {
164     prototypes
165         << "/*" << endl
166         << " *     Copyright 2011 Couchbase, Inc" << endl
167         << " *" << endl
168         << " *   Licensed under the Apache License, Version 2.0 (the \"License\");" << endl
169         << " *   you may not use this file except in compliance with the License." << endl
170         << " *   You may obtain a copy of the License at" << endl
171         << " *" << endl
172         << " *       http://www.apache.org/licenses/LICENSE-2.0" << endl
173         << " *" << endl
174         << " *   Unless required by applicable law or agreed to in writing, software" << endl
175         << " *   distributed under the License is distributed on an \"AS IS\" BASIS," << endl
176         << " *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." << endl
177         << " *   See the License for the specific language governing permissions and" << endl
178         << " *   limitations under the License." << endl
179         << " */" << endl
180         << endl
181         << "// ###########################################" << endl
182         << "// # DO NOT EDIT! THIS IS A GENERATED FILE " << endl
183         << "// ###########################################" << endl
184         << "#ifndef SRC_GENERATED_CONFIGURATION_H_" << endl
185         << "#define SRC_GENERATED_CONFIGURATION_H_ 1" << endl
186         << endl
187         << "#include \"config.h\"" << endl
188         << endl
189         << "#include <string>" << endl;
190
191     implementation
192         << "/*" << endl
193         << " *     Copyright 2011 Couchbase, Inc" << endl
194         << " *" << endl
195         << " *   Licensed under the Apache License, Version 2.0 (the \"License\");" << endl
196         << " *   you may not use this file except in compliance with the License." << endl
197         << " *   You may obtain a copy of the License at" << endl
198         << " *" << endl
199         << " *       http://www.apache.org/licenses/LICENSE-2.0" << endl
200         << " *" << endl
201         << " *   Unless required by applicable law or agreed to in writing, software" << endl
202         << " *   distributed under the License is distributed on an \"AS IS\" BASIS," << endl
203         << " *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." << endl
204         << " *   See the License for the specific language governing permissions and" << endl
205         << " *   limitations under the License." << endl
206         << " */" << endl
207         << endl
208         << "// ###########################################" << endl
209         << "// # DO NOT EDIT! THIS IS A GENERATED FILE " << endl
210         << "// ###########################################" << endl
211         << endl
212         << "#include \"config.h\"" << endl
213         << "#include \"configuration.h\"" << endl;
214     validators["range"] = getRangeValidatorCode;
215     validators["enum"] = getEnumValidatorCode;
216     getters["std::string"] = "getString";
217     getters["bool"] = "getBool";
218     getters["size_t"] = "getInteger";
219     getters["ssize_t"] = "getSignedInteger";
220     getters["float"] = "getFloat";
221     datatypes["bool"] = "bool";
222     datatypes["size_t"] = "size_t";
223     datatypes["ssize_t"] = "ssize_t";
224     datatypes["float"] = "float";
225     datatypes["string"] = "std::string";
226     datatypes["std::string"] = "std::string";
227 }
228
229 static string getString(cJSON *i) {
230     if (i == NULL) {
231         return "";
232     }
233     cb_assert(i->type == cJSON_String);
234     return i->valuestring;
235 }
236
237 static bool isReadOnly(cJSON *o) {
238     cJSON *i = cJSON_GetObjectItem(o, "dynamic");
239     if (i == NULL || i->type == cJSON_False) {
240         return false;
241     }
242
243     cb_assert(i->type == cJSON_True);
244     return true;
245 }
246
247 static string getDatatype(const std::string &key, cJSON *o) {
248     cJSON *i = cJSON_GetObjectItem(o, "type");
249     cb_assert(i != NULL && i->type == cJSON_String);
250     string ret = i->valuestring;
251
252     map<string, string>::iterator iter = datatypes.find(ret);
253     if (iter == datatypes.end()) {
254         cerr << "Invalid datatype specified for \"" << key << "\": "
255              << i->valuestring << endl;
256         exit(1);
257     }
258
259     return iter->second;
260 }
261
262 static string getValidator(const std::string &key, cJSON *o) {
263     if (o == NULL) {
264         return "";
265     }
266
267     cJSON* validator = cJSON_GetObjectItem(o, "validator");
268
269     if (validator == NULL) {
270         return "";
271     }
272
273     cJSON* n = cJSON_GetArrayItem(validator, 0);
274     if (n == NULL) {
275         return "";
276     }
277
278     std::map<string, getValidatorCode>::iterator iter;
279     iter = validators.find(string(n->string));
280     if (iter == validators.end()) {
281         cerr << "Unknown validator specified for \"" << key
282              << "\": \"" << n->string << "\""
283              << endl;
284         exit(1);
285     }
286
287     return (iter->second)(key, o);
288 }
289
290 static string getGetterPrefix(const string &str) {
291     if (str.compare("bool") == 0) {
292         return "is";
293     } else {
294         return "get";
295     }
296 }
297
298 static string getCppName(const string &str) {
299     stringstream ss;
300     bool doUpper = true;
301
302     string::const_iterator iter;
303     for (iter = str.begin(); iter != str.end(); ++iter) {
304         if (*iter == '_') {
305             doUpper = true;
306         } else {
307             if (doUpper) {
308                 ss << (char)toupper(*iter);
309                 doUpper = false;
310             } else {
311                 ss << (char)*iter;
312             }
313         }
314     }
315     return ss.str();
316 }
317
318 static void generate(cJSON *o) {
319     cb_assert(o != NULL);
320
321     string config_name = o->string;
322     string cppname = getCppName(config_name);
323     string type = getDatatype(config_name, o);
324     string defaultVal = getString(cJSON_GetObjectItem(o, "default"));
325
326     if (defaultVal.compare("max") == 0 || defaultVal.compare("min") == 0) {
327         if (type.compare("std::string") != 0) {
328             stringstream ss;
329             ss << "std::numeric_limits<" << type << ">::" << defaultVal << "()";
330             defaultVal = ss.str();
331         }
332     }
333
334     string validator = getValidator(config_name, o);
335
336     // Generate prototypes
337     prototypes << "    " << type
338                << " " << getGetterPrefix(type)
339                << cppname << "() const;" << endl;
340     if  (!isReadOnly(o)) {
341         prototypes << "    void set" << cppname << "(const " << type
342                    << " &nval);" << endl;
343     }
344
345     // Generate initialization code
346     initialization << "    setParameter(\"" << config_name << "\", ";
347     if (type.compare("std::string") == 0) {
348         initialization << "(const char*)\"" << defaultVal << "\");" << endl;
349     } else {
350         initialization << "(" << type << ")" << defaultVal << ");" << endl;
351     }
352     if (!validator.empty()) {
353         initialization << "    setValueValidator(\"" << config_name
354                        << "\", " << validator << ");" << endl;
355     }
356
357
358     // Generate the getter
359     implementation << type << " Configuration::" << getGetterPrefix(type)
360                    << cppname << "() const {" << endl
361                    << "    return " << getters[type] << "(\""
362                    << config_name << "\");" << endl << "}" << endl;
363
364     if  (!isReadOnly(o)) {
365         // generate the setter
366         implementation << "void Configuration::set" << cppname
367                        << "(const " << type << " &nval) {" << endl
368                        << "    setParameter(\"" << config_name
369                        << "\", nval);" << endl
370                        << "}" << endl;
371     }
372 }
373
374 /**
375  * Read "configuration.json" and generate getters and setters
376  * for the parameters in there
377  */
378 int main(int argc, char **argv) {
379     const char *file = "configuration.json";
380     if (argc == 2) {
381         file = argv[1];
382     }
383
384     initialize();
385
386     struct stat st;
387     if (stat(file, &st) == -1) {
388         cerr << "Failed to look up " << file << ": "
389              << strerror(errno) << endl;
390         return 1;
391     }
392
393     char *data = new char[st.st_size + 1];
394     data[st.st_size] = 0;
395     ifstream input(file);
396     input.read(data, st.st_size);
397     input.close();
398
399     cJSON *c = cJSON_Parse(data);
400     if (c == NULL) {
401         cerr << "Failed to parse JSON.. probably syntax error" << endl;
402         return 1;
403     }
404
405     cJSON *params = cJSON_GetObjectItem(c, "params");
406     if (params == NULL) {
407         cerr << "FATAL: could not find \"params\" section" << endl;
408         return 1;
409     }
410
411     int num = cJSON_GetArraySize(params);
412     for (int ii = 0; ii < num; ++ii) {
413         generate(cJSON_GetArrayItem(params, ii));
414     }
415     prototypes << "#endif  // SRC_GENERATED_CONFIGURATION_H_" << endl;
416
417     ofstream headerfile("src/generated_configuration.h");
418     headerfile << prototypes.str();
419     headerfile.close();
420
421     ofstream implfile("src/generated_configuration.cc");
422     implfile << implementation.str() << endl
423              << "void Configuration::initialize() {" << endl
424              << initialization.str()
425              << "}" << endl;
426     implfile.close();
427
428     cJSON_Delete(c);
429     delete []data;
430
431     return 0;
432 }