]>
Commit | Line | Data |
---|---|---|
934b03fc | 1 | /* |
bf95c10a | 2 | * Copyright (C) 1996-2022 The Squid Software Foundation and contributors |
e25c139f | 3 | * |
bbc27441 AJ |
4 | * Squid software is distributed under GPLv2+ license and includes |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
934b03fc | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: none Generate squid.conf.default and cf_parser.cci */ |
10 | ||
934b03fc | 11 | /***************************************************************************** |
f53969cc SM |
12 | * Abstract: This program parses the input file and generates code and |
13 | * files used to configure the variables in squid. | |
14 | * (ie it creates the squid.conf.default file from the cf.data file) | |
934b03fc | 15 | * |
f53969cc SM |
16 | * The output files are as follows: |
17 | * cf_parser.cci - this file contains, default_all() which | |
18 | * initializes variables with the default | |
19 | * values, parse_line() that parses line from | |
20 | * squid.conf.default, dump_config that dumps the | |
21 | * current the values of the variables. | |
22 | * squid.conf.default - default configuration file given to the server | |
23 | * administrator. | |
934b03fc | 24 | *****************************************************************************/ |
25 | ||
2623faf8 FC |
26 | /* |
27 | * hack around a bug in intel's c++ compiler's libraries which do not | |
28 | * correctly support 64-bit iostreams | |
29 | */ | |
30 | #if defined(__INTEL_COMPILER) && defined(_FILE_OFFSET_BITS) && \ | |
fdcb14bd | 31 | _FILE_OFFSET_BITS==64 |
2623faf8 FC |
32 | #undef _FILE_OFFSET_BITS |
33 | #endif | |
34 | ||
c1f8bbd0 AJ |
35 | #include <cassert> |
36 | #include <cctype> | |
37 | #include <cerrno> | |
c5b7499b | 38 | #include <cstdlib> |
c1f8bbd0 | 39 | #include <cstring> |
7ff7a211 | 40 | #include <fstream> |
c1f8bbd0 | 41 | #include <iostream> |
576b1e98 | 42 | #include <list> |
cf1c09f6 | 43 | #include <stack> |
6507d007 | 44 | |
cca8ba0d HN |
45 | #include "cf_gen_defines.cci" |
46 | ||
f53969cc SM |
47 | #define MAX_LINE 1024 /* longest configuration line */ |
48 | #define _PATH_PARSER "cf_parser.cci" | |
49 | #define _PATH_SQUID_CONF "squid.conf.documented" | |
50 | #define _PATH_SQUID_CONF_SHORT "squid.conf.default" | |
51 | #define _PATH_CF_DEPEND "cf.data.depend" | |
934b03fc | 52 | |
53 | enum State { | |
54 | sSTART, | |
55 | s1, | |
56 | sDOC, | |
47f0eaea | 57 | sCFGLINES, |
934b03fc | 58 | sEXIT |
59 | }; | |
60 | ||
576b1e98 AJ |
61 | typedef std::list<std::string> LineList; |
62 | typedef std::list<std::string> TypeDepList; | |
63 | typedef std::list<std::string> EntryAliasList; | |
62e76326 | 64 | |
576b1e98 | 65 | class DefaultValues |
c1f8bbd0 AJ |
66 | { |
67 | public: | |
576b1e98 AJ |
68 | /// Default config lines to be defined before parsing the config files. |
69 | LineList preset; | |
934b03fc | 70 | |
576b1e98 AJ |
71 | /// Default config lines to parse if the directive has no prior settings. |
72 | /// This is mutually exclusive with preset values. | |
73 | /// An error will be printed during build if they clash. | |
74 | LineList if_none; | |
7af1c5ab | 75 | |
10d914f6 CT |
76 | /// Default config lines to parse and add to any prior settings. |
77 | LineList postscriptum; | |
78 | ||
576b1e98 AJ |
79 | /// Text description to use in documentation for the default. |
80 | /// If unset the preset or if-none values will be displayed. | |
81 | LineList docs; | |
c1f8bbd0 AJ |
82 | }; |
83 | ||
84 | class Entry | |
85 | { | |
86 | public: | |
47f0eaea | 87 | explicit Entry(const char *str) : name(str) {} |
c1f8bbd0 AJ |
88 | |
89 | std::string name; | |
576b1e98 | 90 | EntryAliasList alias; |
c1f8bbd0 AJ |
91 | std::string type; |
92 | std::string loc; | |
576b1e98 | 93 | DefaultValues defaults; |
c1f8bbd0 AJ |
94 | std::string comment; |
95 | std::string ifdef; | |
576b1e98 | 96 | LineList doc; |
47f0eaea AJ |
97 | LineList cfgLines; ///< between CONFIG_START and CONFIG_END |
98 | int array_flag = 0; ///< TYPE is a raw array[] declaration | |
62e76326 | 99 | |
576b1e98 | 100 | void genParse(std::ostream &fout) const; |
934b03fc | 101 | |
576b1e98 AJ |
102 | private: |
103 | void genParseAlias(const std::string &, std::ostream &) const; | |
c1f8bbd0 | 104 | }; |
41bd17a4 | 105 | |
576b1e98 AJ |
106 | typedef std::list<class Entry> EntryList; |
107 | ||
c1f8bbd0 AJ |
108 | class Type |
109 | { | |
110 | public: | |
576b1e98 | 111 | Type(const char *str) : name(str) {} |
934b03fc | 112 | |
c1f8bbd0 | 113 | std::string name; |
576b1e98 | 114 | TypeDepList depend; |
c1f8bbd0 | 115 | }; |
41bd17a4 | 116 | |
576b1e98 | 117 | typedef std::list<class Type> TypeList; |
c1f8bbd0 | 118 | |
576b1e98 AJ |
119 | static const char WS[] = " \t\n"; |
120 | static int gen_default(const EntryList &, std::ostream &); | |
121 | static void gen_parse(const EntryList &, std::ostream &); | |
122 | static void gen_dump(const EntryList &, std::ostream&); | |
123 | static void gen_free(const EntryList &, std::ostream&); | |
124 | static void gen_conf(const EntryList &, std::ostream&, bool verbose_output); | |
125 | static void gen_default_if_none(const EntryList &, std::ostream&); | |
10d914f6 | 126 | static void gen_default_postscriptum(const EntryList &, std::ostream&); |
cf1c09f6 | 127 | static bool isDefined(const std::string &name); |
b6ead21b | 128 | static const char *available_if(const std::string &name); |
b11724bb | 129 | static const char *gen_quote_escape(const std::string &var); |
6b53c392 | 130 | |
41bd17a4 | 131 | static void |
576b1e98 | 132 | checkDepend(const std::string &directive, const char *name, const TypeList &types, const EntryList &entries) |
41bd17a4 | 133 | { |
47f0eaea AJ |
134 | for (const auto &t : types) { |
135 | if (t.name.compare(name) != 0) | |
26ac0430 | 136 | continue; |
47f0eaea | 137 | for (const auto &dep : t.depend) { |
576b1e98 AJ |
138 | EntryList::const_iterator entry = entries.begin(); |
139 | for (; entry != entries.end(); ++entry) { | |
47f0eaea | 140 | if (entry->name.compare(dep) == 0) |
26ac0430 AJ |
141 | break; |
142 | } | |
576b1e98 | 143 | if (entry == entries.end()) { |
47f0eaea | 144 | std::cerr << "ERROR: '" << directive << "' (" << name << ") depends on '" << dep << "'\n"; |
24885773 | 145 | exit(EXIT_FAILURE); |
26ac0430 AJ |
146 | } |
147 | } | |
148 | return; | |
41bd17a4 | 149 | } |
7ff7a211 | 150 | std::cerr << "ERROR: Dependencies for cf.data type '" << name << "' used in ' " << directive << "' not defined\n" ; |
24885773 | 151 | exit(EXIT_FAILURE); |
41bd17a4 | 152 | } |
153 | ||
509fba1a HN |
154 | static void |
155 | usage(const char *program_name) | |
156 | { | |
7ff7a211 | 157 | std::cerr << "Usage: " << program_name << " cf.data cf.data.depend\n"; |
24885773 | 158 | exit(EXIT_FAILURE); |
509fba1a HN |
159 | } |
160 | ||
638402dd | 161 | static void |
2ad53ef1 | 162 | errorMsg(const char *filename, int line, const char *detail) |
638402dd | 163 | { |
2ad53ef1 | 164 | std::cerr << "Error in '" << filename << "' on line " << line << |
638402dd AJ |
165 | "--> " << detail << std::endl; |
166 | } | |
167 | ||
934b03fc | 168 | int |
169 | main(int argc, char *argv[]) | |
170 | { | |
509fba1a | 171 | char *input_filename; |
c193c972 | 172 | const char *output_filename = _PATH_PARSER; |
173 | const char *conf_filename = _PATH_SQUID_CONF; | |
509fba1a HN |
174 | const char *conf_filename_short = _PATH_SQUID_CONF_SHORT; |
175 | const char *type_depend; | |
934b03fc | 176 | int linenum = 0; |
576b1e98 AJ |
177 | EntryList entries; |
178 | TypeList types; | |
934b03fc | 179 | enum State state; |
f1dc9b30 | 180 | int rc = 0; |
9906e724 | 181 | char *ptr = NULL; |
41bd17a4 | 182 | char buff[MAX_LINE]; |
7ff7a211 | 183 | std::ifstream fp; |
cf1c09f6 | 184 | std::stack<std::string> IFDEFS; |
41bd17a4 | 185 | |
509fba1a | 186 | if (argc != 3) |
c98dcee3 | 187 | usage(argv[0]); |
509fba1a HN |
188 | |
189 | input_filename = argv[1]; | |
190 | type_depend = argv[2]; | |
41bd17a4 | 191 | |
192 | /*-------------------------------------------------------------------* | |
193 | * Parse type dependencies | |
194 | *-------------------------------------------------------------------*/ | |
7ff7a211 FC |
195 | fp.open(type_depend, std::ifstream::in); |
196 | if (fp.fail()) { | |
638402dd | 197 | std::cerr << "Error while opening type dependencies file '" << |
87f07161 | 198 | type_depend << "': " << strerror(errno) << std::endl; |
24885773 | 199 | exit(EXIT_FAILURE); |
41bd17a4 | 200 | } |
201 | ||
7ff7a211 FC |
202 | while (fp.good()) { |
203 | fp.getline(buff,MAX_LINE); | |
26ac0430 AJ |
204 | const char *type = strtok(buff, WS); |
205 | const char *dep; | |
206 | if (!type || type[0] == '#') | |
207 | continue; | |
576b1e98 | 208 | Type t(type); |
26ac0430 | 209 | while ((dep = strtok(NULL, WS)) != NULL) { |
576b1e98 | 210 | t.depend.push_front(dep); |
26ac0430 | 211 | } |
576b1e98 | 212 | types.push_front(t); |
41bd17a4 | 213 | } |
7ff7a211 | 214 | fp.close(); |
2f0e590e | 215 | fp.clear(); // BSD does not reset flags in close(). |
934b03fc | 216 | |
217 | /*-------------------------------------------------------------------* | |
218 | * Parse input file | |
219 | *-------------------------------------------------------------------*/ | |
220 | ||
221 | /* Open input file */ | |
7ff7a211 FC |
222 | fp.open(input_filename, std::ifstream::in); |
223 | if (fp.fail()) { | |
638402dd | 224 | std::cerr << "Error while opening input file '" << |
2bfdc0a9 | 225 | input_filename << "': " << strerror(errno) << std::endl; |
24885773 | 226 | exit(EXIT_FAILURE); |
934b03fc | 227 | } |
62e76326 | 228 | |
934b03fc | 229 | state = sSTART; |
62e76326 | 230 | |
7ff7a211 | 231 | while (fp.getline(buff,MAX_LINE), fp.good() && state != sEXIT) { |
62e76326 | 232 | char *t; |
233 | ||
5086523e | 234 | ++linenum; |
62e76326 | 235 | |
236 | if ((t = strchr(buff, '\n'))) | |
237 | *t = '\0'; | |
238 | ||
87f237a9 | 239 | if (strncmp(buff, "IF ", 3) == 0) { |
38450a50 | 240 | if ((ptr = strtok(buff + 3, WS)) == NULL) { |
638402dd | 241 | errorMsg(input_filename, linenum, "Missing IF parameter"); |
24885773 | 242 | exit(EXIT_FAILURE); |
62e76326 | 243 | } |
cf1c09f6 | 244 | IFDEFS.push(ptr); |
cf1c09f6 CT |
245 | continue; |
246 | } else if (strcmp(buff, "ENDIF") == 0) { | |
247 | if (IFDEFS.size() == 0) { | |
638402dd | 248 | errorMsg(input_filename, linenum, "ENDIF without IF first"); |
24885773 | 249 | exit(EXIT_FAILURE); |
cf1c09f6 CT |
250 | } |
251 | IFDEFS.pop(); | |
87f237a9 A |
252 | } else if (!IFDEFS.size() || isDefined(IFDEFS.top())) |
253 | switch (state) { | |
254 | ||
255 | case sSTART: | |
256 | ||
257 | if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) { | |
258 | /* ignore empty and comment lines */ | |
259 | (void) 0; | |
260 | } else if (!strncmp(buff, "NAME:", 5)) { | |
261 | char *name, *aliasname; | |
262 | ||
263 | if ((name = strtok(buff + 5, WS)) == NULL) { | |
638402dd | 264 | errorMsg(input_filename, linenum, buff); |
24885773 | 265 | exit(EXIT_FAILURE); |
87f237a9 A |
266 | } |
267 | ||
47f0eaea | 268 | entries.emplace_back(name); |
87f237a9 A |
269 | |
270 | while ((aliasname = strtok(NULL, WS)) != NULL) | |
271 | entries.back().alias.push_front(aliasname); | |
272 | ||
273 | state = s1; | |
274 | } else if (!strcmp(buff, "EOF")) { | |
275 | state = sEXIT; | |
276 | } else if (!strcmp(buff, "COMMENT_START")) { | |
47f0eaea | 277 | entries.emplace_back("comment"); |
87f237a9 A |
278 | entries.back().loc = "none"; |
279 | state = sDOC; | |
280 | } else { | |
638402dd | 281 | errorMsg(input_filename, linenum, buff); |
24885773 | 282 | exit(EXIT_FAILURE); |
62e76326 | 283 | } |
284 | ||
87f237a9 A |
285 | break; |
286 | ||
287 | case s1: { | |
288 | Entry &curr = entries.back(); | |
289 | ||
290 | if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) { | |
291 | /* ignore empty and comment lines */ | |
292 | (void) 0; | |
293 | } else if (!strncmp(buff, "COMMENT:", 8)) { | |
294 | ptr = buff + 8; | |
295 | ||
296 | while (isspace((unsigned char)*ptr)) | |
133c3ad6 | 297 | ++ptr; |
87f237a9 A |
298 | |
299 | curr.comment = ptr; | |
300 | } else if (!strncmp(buff, "DEFAULT:", 8)) { | |
301 | ptr = buff + 8; | |
302 | ||
303 | while (isspace((unsigned char)*ptr)) | |
133c3ad6 | 304 | ++ptr; |
87f237a9 A |
305 | |
306 | curr.defaults.preset.push_back(ptr); | |
307 | } else if (!strncmp(buff, "DEFAULT_IF_NONE:", 16)) { | |
308 | ptr = buff + 16; | |
309 | ||
310 | while (isspace((unsigned char)*ptr)) | |
133c3ad6 | 311 | ++ptr; |
87f237a9 A |
312 | |
313 | curr.defaults.if_none.push_back(ptr); | |
314 | } else if (!strncmp(buff, "POSTSCRIPTUM:", 13)) { | |
315 | ptr = buff + 13; | |
316 | ||
317 | while (isspace((unsigned char)*ptr)) | |
133c3ad6 | 318 | ++ptr; |
87f237a9 A |
319 | |
320 | curr.defaults.postscriptum.push_back(ptr); | |
321 | } else if (!strncmp(buff, "DEFAULT_DOC:", 12)) { | |
322 | ptr = buff + 12; | |
323 | ||
324 | while (isspace((unsigned char)*ptr)) | |
133c3ad6 | 325 | ++ptr; |
87f237a9 A |
326 | |
327 | curr.defaults.docs.push_back(ptr); | |
328 | } else if (!strncmp(buff, "LOC:", 4)) { | |
329 | if ((ptr = strtok(buff + 4, WS)) == NULL) { | |
638402dd | 330 | errorMsg(input_filename, linenum, buff); |
24885773 | 331 | exit(EXIT_FAILURE); |
87f237a9 A |
332 | } |
333 | ||
334 | curr.loc = ptr; | |
335 | } else if (!strncmp(buff, "TYPE:", 5)) { | |
336 | if ((ptr = strtok(buff + 5, WS)) == NULL) { | |
638402dd | 337 | errorMsg(input_filename, linenum, buff); |
24885773 | 338 | exit(EXIT_FAILURE); |
87f237a9 A |
339 | } |
340 | ||
341 | /* hack to support arrays, rather than pointers */ | |
47f0eaea | 342 | if (strcmp(ptr + strlen(ptr) - 2, "[]") == 0) { |
87f237a9 A |
343 | curr.array_flag = 1; |
344 | *(ptr + strlen(ptr) - 2) = '\0'; | |
345 | } | |
346 | ||
347 | checkDepend(curr.name, ptr, types, entries); | |
348 | curr.type = ptr; | |
349 | } else if (!strncmp(buff, "IFDEF:", 6)) { | |
350 | if ((ptr = strtok(buff + 6, WS)) == NULL) { | |
638402dd | 351 | errorMsg(input_filename, linenum, buff); |
24885773 | 352 | exit(EXIT_FAILURE); |
87f237a9 A |
353 | } |
354 | ||
355 | curr.ifdef = ptr; | |
356 | } else if (!strcmp(buff, "DOC_START")) { | |
357 | state = sDOC; | |
358 | } else if (!strcmp(buff, "DOC_NONE")) { | |
359 | state = sSTART; | |
360 | } else { | |
638402dd | 361 | errorMsg(input_filename, linenum, buff); |
24885773 | 362 | exit(EXIT_FAILURE); |
62e76326 | 363 | } |
87f237a9 A |
364 | } |
365 | break; | |
62e76326 | 366 | |
87f237a9 A |
367 | case sDOC: |
368 | if (!strcmp(buff, "DOC_END") || !strcmp(buff, "COMMENT_END")) { | |
369 | state = sSTART; | |
47f0eaea AJ |
370 | } else if (strcmp(buff, "CONFIG_START") == 0) { |
371 | state = sCFGLINES; | |
8b082ed9 | 372 | } else { |
87f237a9 | 373 | entries.back().doc.push_back(buff); |
62e76326 | 374 | } |
87f237a9 A |
375 | break; |
376 | ||
47f0eaea AJ |
377 | case sCFGLINES: |
378 | if (strcmp(buff, "CONFIG_END") == 0) { | |
87f237a9 | 379 | state = sDOC; |
8b082ed9 | 380 | } else { |
47f0eaea | 381 | entries.back().cfgLines.push_back(buff); |
62e76326 | 382 | } |
87f237a9 | 383 | break; |
87f237a9 | 384 | case sEXIT: |
f53969cc | 385 | assert(0); /* should never get here */ |
87f237a9 | 386 | break; |
62e76326 | 387 | } |
7ff7a211 | 388 | |
934b03fc | 389 | } |
62e76326 | 390 | |
934b03fc | 391 | if (state != sEXIT) { |
638402dd | 392 | errorMsg(input_filename, linenum, "Error: unexpected EOF"); |
24885773 | 393 | exit(EXIT_FAILURE); |
934b03fc | 394 | } |
62e76326 | 395 | |
7ff7a211 | 396 | fp.close(); |
934b03fc | 397 | |
398 | /*-------------------------------------------------------------------* | |
399 | * Generate default_all() | |
400 | * Generate parse_line() | |
f53b06f9 | 401 | * Generate dump_config() |
0153d498 | 402 | * Generate free_all() |
e321c7d4 | 403 | * Generate example squid.conf.default file |
934b03fc | 404 | *-------------------------------------------------------------------*/ |
405 | ||
406 | /* Open output x.c file */ | |
62e76326 | 407 | |
7ff7a211 FC |
408 | std::ofstream fout(output_filename,std::ostream::out); |
409 | if (!fout.good()) { | |
638402dd | 410 | std::cerr << "Error while opening output .c file '" << |
2bfdc0a9 | 411 | output_filename << "': " << strerror(errno) << std::endl; |
24885773 | 412 | exit(EXIT_FAILURE); |
934b03fc | 413 | } |
62e76326 | 414 | |
7ff7a211 | 415 | fout << "/*\n" << |
f53969cc SM |
416 | " * Generated automatically from " << input_filename << " by " << |
417 | argv[0] << "\n" | |
418 | " *\n" | |
419 | " * Abstract: This file contains routines used to configure the\n" | |
420 | " * variables in the squid server.\n" | |
421 | " */\n" | |
422 | "\n"; | |
62e76326 | 423 | |
7ff7a211 | 424 | rc = gen_default(entries, fout); |
62e76326 | 425 | |
7ff7a211 | 426 | gen_default_if_none(entries, fout); |
62e76326 | 427 | |
10d914f6 CT |
428 | gen_default_postscriptum(entries, fout); |
429 | ||
7ff7a211 | 430 | gen_parse(entries, fout); |
62e76326 | 431 | |
7ff7a211 | 432 | gen_dump(entries, fout); |
62e76326 | 433 | |
7ff7a211 | 434 | gen_free(entries, fout); |
62e76326 | 435 | |
7ff7a211 | 436 | fout.close(); |
934b03fc | 437 | |
438 | /* Open output x.conf file */ | |
7ff7a211 FC |
439 | fout.open(conf_filename,std::ostream::out); |
440 | if (!fout.good()) { | |
638402dd | 441 | std::cerr << "Error while opening output conf file '" << |
2bfdc0a9 | 442 | output_filename << "': " << strerror(errno) << std::endl; |
24885773 | 443 | exit(EXIT_FAILURE); |
934b03fc | 444 | } |
62e76326 | 445 | |
7ff7a211 | 446 | gen_conf(entries, fout, 1); |
62e76326 | 447 | |
7ff7a211 | 448 | fout.close(); |
934b03fc | 449 | |
7ff7a211 FC |
450 | fout.open(conf_filename_short,std::ostream::out); |
451 | if (!fout.good()) { | |
638402dd | 452 | std::cerr << "Error while opening output short conf file '" << |
2bfdc0a9 | 453 | output_filename << "': " << strerror(errno) << std::endl; |
24885773 | 454 | exit(EXIT_FAILURE); |
509fba1a | 455 | } |
7ff7a211 FC |
456 | gen_conf(entries, fout, 0); |
457 | fout.close(); | |
509fba1a | 458 | |
f1dc9b30 | 459 | return (rc); |
934b03fc | 460 | } |
461 | ||
f1dc9b30 | 462 | static int |
576b1e98 | 463 | gen_default(const EntryList &head, std::ostream &fout) |
934b03fc | 464 | { |
f1dc9b30 | 465 | int rc = 0; |
576b1e98 | 466 | fout << "static void" << std::endl << |
f53969cc SM |
467 | "default_line(const char *s)" << std::endl << |
468 | "{" << std::endl << | |
c2a37876 AR |
469 | " char *tmp_line = xstrdup(s);" << std::endl << |
470 | " int len = strlen(tmp_line);" << std::endl << | |
b6e07b48 | 471 | " ProcessMacros(tmp_line, len);" << std::endl << |
c2a37876 | 472 | " xstrncpy(config_input_line, tmp_line, sizeof(config_input_line));" << std::endl << |
f53969cc SM |
473 | " config_lineno++;" << std::endl << |
474 | " parse_line(tmp_line);" << std::endl << | |
b6e07b48 | 475 | " xfree(tmp_line);" << std::endl << |
f53969cc | 476 | "}" << std::endl << std::endl; |
576b1e98 | 477 | fout << "static void" << std::endl << |
f53969cc SM |
478 | "default_all(void)" << std::endl << |
479 | "{" << std::endl << | |
480 | " cfg_filename = \"Default Configuration\";" << std::endl << | |
481 | " config_lineno = 0;" << std::endl; | |
576b1e98 | 482 | |
47f0eaea AJ |
483 | for (const auto &entry : head) { |
484 | assert(entry.name.size()); | |
62e76326 | 485 | |
47f0eaea | 486 | if (!entry.name.compare("comment")) |
62e76326 | 487 | continue; |
488 | ||
47f0eaea | 489 | if (!entry.type.compare("obsolete")) |
76f44481 AJ |
490 | continue; |
491 | ||
47f0eaea AJ |
492 | if (!entry.loc.size()) { |
493 | std::cerr << "NO LOCATION FOR " << entry.name << std::endl; | |
62e76326 | 494 | rc |= 1; |
495 | continue; | |
496 | } | |
497 | ||
47f0eaea AJ |
498 | if (!entry.defaults.preset.size() && entry.defaults.if_none.empty()) { |
499 | std::cerr << "NO DEFAULT FOR " << entry.name << std::endl; | |
62e76326 | 500 | rc |= 1; |
501 | continue; | |
502 | } | |
503 | ||
47f0eaea AJ |
504 | if (!entry.defaults.preset.size() || entry.defaults.preset.front().compare("none") == 0) { |
505 | fout << " // No default for " << entry.name << std::endl; | |
62e76326 | 506 | } else { |
47f0eaea AJ |
507 | if (entry.ifdef.size()) |
508 | fout << "#if " << entry.ifdef << std::endl; | |
c58a4b53 | 509 | |
47f0eaea AJ |
510 | for (const auto &l : entry.defaults.preset) |
511 | fout << " default_line(\"" << entry.name << " " << gen_quote_escape(l) << "\");" << std::endl; | |
62e76326 | 512 | |
47f0eaea | 513 | if (entry.ifdef.size()) |
576b1e98 | 514 | fout << "#endif" << std::endl; |
2bfdc0a9 | 515 | } |
934b03fc | 516 | } |
62e76326 | 517 | |
576b1e98 | 518 | fout << " cfg_filename = NULL;" << std::endl << |
f53969cc | 519 | "}" << std::endl << std::endl; |
f1dc9b30 | 520 | return rc; |
934b03fc | 521 | } |
522 | ||
f53b06f9 | 523 | static void |
576b1e98 | 524 | gen_default_if_none(const EntryList &head, std::ostream &fout) |
f53b06f9 | 525 | { |
576b1e98 | 526 | fout << "static void" << std::endl << |
f53969cc SM |
527 | "defaults_if_none(void)" << std::endl << |
528 | "{" << std::endl << | |
529 | " cfg_filename = \"Default Configuration (if absent)\";" << std::endl << | |
530 | " config_lineno = 0;" << std::endl; | |
62e76326 | 531 | |
47f0eaea AJ |
532 | for (const auto &entry : head) { |
533 | assert(entry.name.size()); | |
76f44481 | 534 | |
47f0eaea | 535 | if (!entry.loc.size()) |
76f44481 | 536 | continue; |
62e76326 | 537 | |
47f0eaea | 538 | if (entry.defaults.if_none.empty()) |
62e76326 | 539 | continue; |
540 | ||
47f0eaea AJ |
541 | if (!entry.defaults.preset.empty()) { |
542 | std::cerr << "ERROR: " << entry.name << " has preset defaults. DEFAULT_IF_NONE cannot be true." << std::endl; | |
24885773 | 543 | exit(EXIT_FAILURE); |
576b1e98 AJ |
544 | } |
545 | ||
47f0eaea AJ |
546 | if (entry.ifdef.size()) |
547 | fout << "#if " << entry.ifdef << std::endl; | |
62e76326 | 548 | |
47f0eaea AJ |
549 | fout << " if (check_null_" << entry.type << "(" << entry.loc << ")) {" << std::endl; |
550 | for (const auto &l : entry.defaults.if_none) | |
551 | fout << " default_line(\"" << entry.name << " " << gen_quote_escape(l) <<"\");" << std::endl; | |
576b1e98 | 552 | fout << " }" << std::endl; |
62e76326 | 553 | |
47f0eaea | 554 | if (entry.ifdef.size()) |
576b1e98 | 555 | fout << "#endif" << std::endl; |
f53b06f9 | 556 | } |
62e76326 | 557 | |
b6ead21b | 558 | fout << " cfg_filename = NULL;" << std::endl << |
f53969cc | 559 | "}" << std::endl << std::endl; |
f53b06f9 | 560 | } |
561 | ||
10d914f6 CT |
562 | /// append configuration options specified by POSTSCRIPTUM lines |
563 | static void | |
564 | gen_default_postscriptum(const EntryList &head, std::ostream &fout) | |
565 | { | |
566 | fout << "static void" << std::endl << | |
f53969cc SM |
567 | "defaults_postscriptum(void)" << std::endl << |
568 | "{" << std::endl << | |
569 | " cfg_filename = \"Default Configuration (postscriptum)\";" << std::endl << | |
570 | " config_lineno = 0;" << std::endl; | |
10d914f6 | 571 | |
47f0eaea AJ |
572 | for (const auto &entry : head) { |
573 | assert(entry.name.size()); | |
10d914f6 | 574 | |
47f0eaea | 575 | if (!entry.loc.size()) |
10d914f6 CT |
576 | continue; |
577 | ||
47f0eaea | 578 | if (entry.defaults.postscriptum.empty()) |
10d914f6 CT |
579 | continue; |
580 | ||
47f0eaea AJ |
581 | if (entry.ifdef.size()) |
582 | fout << "#if " << entry.ifdef << std::endl; | |
10d914f6 | 583 | |
47f0eaea AJ |
584 | for (const auto &l : entry.defaults.postscriptum) |
585 | fout << " default_line(\"" << entry.name << " " << l <<"\");" << std::endl; | |
10d914f6 | 586 | |
47f0eaea | 587 | if (entry.ifdef.size()) |
10d914f6 CT |
588 | fout << "#endif" << std::endl; |
589 | } | |
590 | ||
b6ead21b | 591 | fout << " cfg_filename = NULL;" << std::endl << |
f53969cc | 592 | "}" << std::endl << std::endl; |
10d914f6 CT |
593 | } |
594 | ||
147a3e90 | 595 | void |
576b1e98 | 596 | Entry::genParseAlias(const std::string &aName, std::ostream &fout) const |
934b03fc | 597 | { |
576b1e98 | 598 | fout << " if (!strcmp(token, \"" << aName << "\")) {" << std::endl; |
b6ead21b AJ |
599 | if (ifdef.size()) |
600 | fout << "#if " << ifdef << std::endl; | |
6f58d7d7 | 601 | fout << " cfg_directive = \"" << aName << "\";" << std::endl; |
576b1e98 AJ |
602 | fout << " "; |
603 | if (type.compare("obsolete") == 0) { | |
604 | fout << "debugs(0, DBG_CRITICAL, \"ERROR: Directive '" << aName << "' is obsolete.\");\n"; | |
47f0eaea | 605 | for (const auto &l : doc) { |
76f44481 | 606 | // offset line to strip initial whitespace tab byte |
47f0eaea | 607 | fout << " debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), \"" << aName << " : " << &l[1] << "\");" << std::endl; |
76f44481 | 608 | } |
576b1e98 AJ |
609 | fout << " parse_obsolete(token);"; |
610 | } else if (!loc.size() || loc.compare("none") == 0) { | |
611 | fout << "parse_" << type << "();"; | |
2e6535ab AR |
612 | } else if (type.find("::") != std::string::npos) { |
613 | fout << "ParseDirective<" << type << ">(" << loc << ", LegacyParser);"; | |
62e76326 | 614 | } else { |
576b1e98 | 615 | fout << "parse_" << type << "(&" << loc << (array_flag ? "[0]" : "") << ");"; |
62e76326 | 616 | } |
576b1e98 | 617 | fout << std::endl; |
6f58d7d7 | 618 | fout << " cfg_directive = NULL;" << std::endl; |
b6ead21b AJ |
619 | if (ifdef.size()) { |
620 | fout << | |
f53969cc SM |
621 | "#else" << std::endl << |
622 | " debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), \"ERROR: '" << name << "' requires " << available_if(ifdef) << "\");" << std::endl << | |
623 | "#endif" << std::endl; | |
b6ead21b | 624 | } |
576b1e98 AJ |
625 | fout << " return 1;" << std::endl; |
626 | fout << " };" << std::endl; | |
147a3e90 | 627 | } |
628 | ||
629 | void | |
576b1e98 | 630 | Entry::genParse(std::ostream &fout) const |
147a3e90 | 631 | { |
576b1e98 | 632 | if (name.compare("comment") == 0) |
62e76326 | 633 | return; |
634 | ||
576b1e98 AJ |
635 | // Once for the current directive name |
636 | genParseAlias(name, fout); | |
62e76326 | 637 | |
576b1e98 | 638 | // All accepted aliases |
47f0eaea AJ |
639 | for (const auto &a : alias) { |
640 | genParseAlias(a, fout); | |
576b1e98 | 641 | } |
147a3e90 | 642 | } |
643 | ||
644 | static void | |
576b1e98 | 645 | gen_parse(const EntryList &head, std::ostream &fout) |
147a3e90 | 646 | { |
7ff7a211 | 647 | fout << |
f53969cc SM |
648 | "static int\n" |
649 | "parse_line(char *buff)\n" | |
650 | "{\n" | |
651 | "\tchar\t*token;\n" | |
652 | "\tif ((token = strtok(buff, w_space)) == NULL) \n" | |
653 | "\t\treturn 1;\t/* ignore empty lines */\n" | |
654 | "\tConfigParser::SetCfgLine(strtok(NULL, \"\"));\n"; | |
147a3e90 | 655 | |
47f0eaea AJ |
656 | for (const auto &e : head) |
657 | e.genParse(fout); | |
7ff7a211 FC |
658 | |
659 | fout << "\treturn 0; /* failure */\n" | |
f53969cc | 660 | "}\n\n"; |
934b03fc | 661 | |
934b03fc | 662 | } |
663 | ||
664 | static void | |
576b1e98 | 665 | gen_dump(const EntryList &head, std::ostream &fout) |
934b03fc | 666 | { |
7ff7a211 | 667 | fout << |
f53969cc SM |
668 | "static void" << std::endl << |
669 | "dump_config(StoreEntry *entry)" << std::endl << | |
670 | "{" << std::endl << | |
bf95c10a | 671 | " debugs(5, 4, MYNAME);" << std::endl; |
62e76326 | 672 | |
47f0eaea | 673 | for (const auto &e : head) { |
62e76326 | 674 | |
47f0eaea | 675 | if (!e.loc.size() || e.loc.compare("none") == 0) |
62e76326 | 676 | continue; |
677 | ||
47f0eaea | 678 | if (e.name.compare("comment") == 0) |
62e76326 | 679 | continue; |
680 | ||
47f0eaea AJ |
681 | if (e.ifdef.size()) |
682 | fout << "#if " << e.ifdef << std::endl; | |
62e76326 | 683 | |
2e6535ab AR |
684 | if (e.type.find("::") != std::string::npos) |
685 | fout << " DumpDirective<" << e.type << ">(" << e.loc << ", entry, \"" << e.name << "\");\n"; | |
686 | else | |
687 | fout << " dump_" << e.type << "(entry, \"" << e.name << "\", " << e.loc << ");" << std::endl; | |
62e76326 | 688 | |
47f0eaea | 689 | if (e.ifdef.size()) |
576b1e98 | 690 | fout << "#endif" << std::endl; |
934b03fc | 691 | } |
62e76326 | 692 | |
576b1e98 | 693 | fout << "}" << std::endl << std::endl; |
934b03fc | 694 | } |
695 | ||
0153d498 | 696 | static void |
576b1e98 | 697 | gen_free(const EntryList &head, std::ostream &fout) |
0153d498 | 698 | { |
7ff7a211 | 699 | fout << |
f53969cc SM |
700 | "static void" << std::endl << |
701 | "free_all(void)" << std::endl << | |
702 | "{" << std::endl << | |
bf95c10a | 703 | " debugs(5, 4, MYNAME);" << std::endl; |
62e76326 | 704 | |
47f0eaea AJ |
705 | for (const auto &e : head) { |
706 | if (!e.loc.size() || e.loc.compare("none") == 0) | |
62e76326 | 707 | continue; |
708 | ||
47f0eaea | 709 | if (e.name.compare("comment") == 0) |
62e76326 | 710 | continue; |
711 | ||
47f0eaea AJ |
712 | if (e.ifdef.size()) |
713 | fout << "#if " << e.ifdef << std::endl; | |
62e76326 | 714 | |
2e6535ab AR |
715 | if (e.type.find("::") != std::string::npos) |
716 | fout << " FreeDirective<" << e.type << ">(" << e.loc << ");\n"; | |
717 | else | |
718 | fout << " free_" << e.type << "(&" << e.loc << (e.array_flag ? "[0]" : "") << ");" << std::endl; | |
62e76326 | 719 | |
47f0eaea | 720 | if (e.ifdef.size()) |
576b1e98 | 721 | fout << "#endif" << std::endl; |
0153d498 | 722 | } |
62e76326 | 723 | |
576b1e98 | 724 | fout << "}" << std::endl << std::endl; |
0153d498 | 725 | } |
726 | ||
c1f8bbd0 | 727 | static bool |
576b1e98 | 728 | isDefined(const std::string &name) |
6b53c392 | 729 | { |
c1f8bbd0 AJ |
730 | if (!name.size()) |
731 | return true; | |
62e76326 | 732 | |
5086523e | 733 | for (int i = 0; defines[i].name; ++i) { |
c1f8bbd0 AJ |
734 | if (name.compare(defines[i].name) == 0) |
735 | return defines[i].defined; | |
a4b8110e | 736 | } |
62e76326 | 737 | |
c1f8bbd0 | 738 | return false; |
6b53c392 | 739 | } |
740 | ||
a4b8110e | 741 | static const char * |
c1f8bbd0 | 742 | available_if(const std::string &name) |
6b53c392 | 743 | { |
c1f8bbd0 | 744 | assert(name.size()); |
62e76326 | 745 | |
5086523e | 746 | for (int i = 0; defines[i].name; ++i) { |
576b1e98 | 747 | if (name.compare(defines[i].name) == 0) |
c1f8bbd0 | 748 | return defines[i].enable; |
a4b8110e | 749 | } |
62e76326 | 750 | |
c1f8bbd0 | 751 | return name.c_str(); |
6b53c392 | 752 | } |
753 | ||
934b03fc | 754 | static void |
576b1e98 | 755 | gen_conf(const EntryList &head, std::ostream &fout, bool verbose_output) |
934b03fc | 756 | { |
47f0eaea | 757 | for (const auto &entry : head) { |
576b1e98 AJ |
758 | char buf[8192]; |
759 | LineList def; | |
26ac0430 | 760 | int enabled = 1; |
62e76326 | 761 | |
576b1e98 | 762 | // Display TAG: line |
47f0eaea | 763 | if (!entry.name.compare("comment")) |
62e76326 | 764 | (void) 0; |
47f0eaea | 765 | else if (!entry.name.compare("obsolete")) |
76f44481 | 766 | (void) 0; |
c98dcee3 | 767 | else if (verbose_output) { |
47f0eaea | 768 | fout << "# TAG: " << entry.name; |
62e76326 | 769 | |
47f0eaea AJ |
770 | if (entry.comment.size()) |
771 | fout << "\t" << entry.comment; | |
62e76326 | 772 | |
7ff7a211 | 773 | fout << std::endl; |
c98dcee3 | 774 | } |
62e76326 | 775 | |
576b1e98 | 776 | // Display --enable/--disable disclaimer |
47f0eaea | 777 | if (!isDefined(entry.ifdef)) { |
c98dcee3 | 778 | if (verbose_output) { |
576b1e98 | 779 | fout << "# Note: This option is only available if Squid is rebuilt with the" << std::endl << |
47f0eaea | 780 | "# " << available_if(entry.ifdef) << std::endl << |
f53969cc | 781 | "#" << std::endl; |
c98dcee3 A |
782 | } |
783 | enabled = 0; | |
62e76326 | 784 | } |
785 | ||
576b1e98 | 786 | // Display DOC_START section |
47f0eaea AJ |
787 | if (verbose_output && entry.doc.size()) { |
788 | for (const auto &line : entry.doc) { | |
789 | fout << "#" << line << std::endl; | |
c98dcee3 A |
790 | } |
791 | } | |
62e76326 | 792 | |
47f0eaea | 793 | if (entry.defaults.docs.size()) { |
576b1e98 | 794 | // Display the DEFAULT_DOC line(s) |
47f0eaea | 795 | def = entry.defaults.docs; |
576b1e98 | 796 | } else { |
47f0eaea | 797 | if (entry.defaults.preset.size() && entry.defaults.preset.front().compare("none") != 0) { |
576b1e98 | 798 | // Display DEFAULT: line(s) |
47f0eaea AJ |
799 | for (const auto &l : entry.defaults.preset) { |
800 | snprintf(buf, sizeof(buf), "%s %s", entry.name.c_str(), l.c_str()); | |
576b1e98 AJ |
801 | def.push_back(buf); |
802 | } | |
47f0eaea | 803 | } else if (entry.defaults.if_none.size()) { |
576b1e98 | 804 | // Display DEFAULT_IF_NONE: line(s) |
47f0eaea AJ |
805 | for (const auto &l : entry.defaults.if_none) { |
806 | snprintf(buf, sizeof(buf), "%s %s", entry.name.c_str(), l.c_str()); | |
576b1e98 AJ |
807 | def.push_back(buf); |
808 | } | |
62e76326 | 809 | } |
810 | } | |
811 | ||
576b1e98 | 812 | // Display "none" if no default is set or comments to display |
47f0eaea | 813 | if (def.empty() && entry.cfgLines.empty() && entry.name.compare("comment") != 0) |
576b1e98 | 814 | def.push_back("none"); |
62e76326 | 815 | |
576b1e98 | 816 | if (verbose_output && def.size()) { |
7ff7a211 | 817 | fout << "#Default:\n"; |
576b1e98 AJ |
818 | while (def.size()) { |
819 | fout << "# " << def.front() << std::endl; | |
820 | def.pop_front(); | |
62e76326 | 821 | } |
47f0eaea | 822 | if (entry.doc.empty() && entry.cfgLines.empty()) |
576b1e98 | 823 | fout << std::endl; |
62e76326 | 824 | } |
825 | ||
47f0eaea | 826 | if (verbose_output && entry.cfgLines.size()) |
7ff7a211 | 827 | fout << "#" << std::endl; |
62e76326 | 828 | |
c98dcee3 | 829 | if (enabled || verbose_output) { |
47f0eaea AJ |
830 | for (const auto &line : entry.cfgLines) { |
831 | if (!enabled && line.at(0) != '#') | |
576b1e98 | 832 | fout << "#"; |
47f0eaea | 833 | fout << line << std::endl; |
c98dcee3 A |
834 | } |
835 | } | |
62e76326 | 836 | |
47f0eaea | 837 | if (verbose_output && entry.doc.size()) { |
7ff7a211 | 838 | fout << std::endl; |
62e76326 | 839 | } |
934b03fc | 840 | } |
841 | } | |
b11724bb CT |
842 | |
843 | static const char * | |
844 | gen_quote_escape(const std::string &var) | |
845 | { | |
846 | static std::string esc; | |
847 | esc.clear(); | |
848 | ||
8b082ed9 FC |
849 | for (const auto c : var) { |
850 | switch (c) { | |
e2849af8 A |
851 | case '"': |
852 | case '\\': | |
853 | esc += '\\'; | |
8b082ed9 | 854 | /* [[fallthrough]] */ |
e2849af8 | 855 | default: |
8b082ed9 | 856 | esc += c; |
b11724bb CT |
857 | } |
858 | } | |
859 | ||
860 | return esc.c_str(); | |
861 | } | |
f53969cc | 862 |