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