]>
Commit | Line | Data |
---|---|---|
934b03fc | 1 | /* |
bbc27441 | 2 | * Copyright (C) 1996-2014 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; |
62e76326 | 394 | |
87f237a9 | 395 | case sEXIT: |
f53969cc | 396 | assert(0); /* should never get here */ |
87f237a9 | 397 | break; |
62e76326 | 398 | } |
7ff7a211 | 399 | |
934b03fc | 400 | } |
62e76326 | 401 | |
934b03fc | 402 | if (state != sEXIT) { |
638402dd | 403 | errorMsg(input_filename, linenum, "Error: unexpected EOF"); |
62e76326 | 404 | exit(1); |
934b03fc | 405 | } |
62e76326 | 406 | |
7ff7a211 | 407 | fp.close(); |
934b03fc | 408 | |
409 | /*-------------------------------------------------------------------* | |
410 | * Generate default_all() | |
411 | * Generate parse_line() | |
f53b06f9 | 412 | * Generate dump_config() |
0153d498 | 413 | * Generate free_all() |
e321c7d4 | 414 | * Generate example squid.conf.default file |
934b03fc | 415 | *-------------------------------------------------------------------*/ |
416 | ||
417 | /* Open output x.c file */ | |
62e76326 | 418 | |
7ff7a211 FC |
419 | std::ofstream fout(output_filename,std::ostream::out); |
420 | if (!fout.good()) { | |
638402dd | 421 | std::cerr << "Error while opening output .c file '" << |
2bfdc0a9 | 422 | output_filename << "': " << strerror(errno) << std::endl; |
62e76326 | 423 | exit(1); |
934b03fc | 424 | } |
62e76326 | 425 | |
7ff7a211 | 426 | fout << "/*\n" << |
f53969cc SM |
427 | " * Generated automatically from " << input_filename << " by " << |
428 | argv[0] << "\n" | |
429 | " *\n" | |
430 | " * Abstract: This file contains routines used to configure the\n" | |
431 | " * variables in the squid server.\n" | |
432 | " */\n" | |
433 | "\n"; | |
62e76326 | 434 | |
7ff7a211 | 435 | rc = gen_default(entries, fout); |
62e76326 | 436 | |
7ff7a211 | 437 | gen_default_if_none(entries, fout); |
62e76326 | 438 | |
10d914f6 CT |
439 | gen_default_postscriptum(entries, fout); |
440 | ||
7ff7a211 | 441 | gen_parse(entries, fout); |
62e76326 | 442 | |
7ff7a211 | 443 | gen_dump(entries, fout); |
62e76326 | 444 | |
7ff7a211 | 445 | gen_free(entries, fout); |
62e76326 | 446 | |
7ff7a211 | 447 | fout.close(); |
934b03fc | 448 | |
449 | /* Open output x.conf file */ | |
7ff7a211 FC |
450 | fout.open(conf_filename,std::ostream::out); |
451 | if (!fout.good()) { | |
638402dd | 452 | std::cerr << "Error while opening output conf file '" << |
2bfdc0a9 | 453 | output_filename << "': " << strerror(errno) << std::endl; |
62e76326 | 454 | exit(1); |
934b03fc | 455 | } |
62e76326 | 456 | |
7ff7a211 | 457 | gen_conf(entries, fout, 1); |
62e76326 | 458 | |
7ff7a211 | 459 | fout.close(); |
934b03fc | 460 | |
7ff7a211 FC |
461 | fout.open(conf_filename_short,std::ostream::out); |
462 | if (!fout.good()) { | |
638402dd | 463 | std::cerr << "Error while opening output short conf file '" << |
2bfdc0a9 | 464 | output_filename << "': " << strerror(errno) << std::endl; |
509fba1a HN |
465 | exit(1); |
466 | } | |
7ff7a211 FC |
467 | gen_conf(entries, fout, 0); |
468 | fout.close(); | |
509fba1a | 469 | |
f1dc9b30 | 470 | return (rc); |
934b03fc | 471 | } |
472 | ||
f1dc9b30 | 473 | static int |
576b1e98 | 474 | gen_default(const EntryList &head, std::ostream &fout) |
934b03fc | 475 | { |
f1dc9b30 | 476 | int rc = 0; |
576b1e98 | 477 | fout << "static void" << std::endl << |
f53969cc SM |
478 | "default_line(const char *s)" << std::endl << |
479 | "{" << std::endl << | |
480 | " LOCAL_ARRAY(char, tmp_line, BUFSIZ);" << std::endl << | |
481 | " xstrncpy(tmp_line, s, BUFSIZ);" << std::endl << | |
482 | " xstrncpy(config_input_line, s, BUFSIZ);" << std::endl << | |
483 | " config_lineno++;" << std::endl << | |
484 | " parse_line(tmp_line);" << std::endl << | |
485 | "}" << std::endl << std::endl; | |
576b1e98 | 486 | fout << "static void" << std::endl << |
f53969cc SM |
487 | "default_all(void)" << std::endl << |
488 | "{" << std::endl << | |
489 | " cfg_filename = \"Default Configuration\";" << std::endl << | |
490 | " config_lineno = 0;" << std::endl; | |
576b1e98 AJ |
491 | |
492 | for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) { | |
c1f8bbd0 | 493 | assert(entry->name.size()); |
62e76326 | 494 | |
c1f8bbd0 | 495 | if (!entry->name.compare("comment")) |
62e76326 | 496 | continue; |
497 | ||
c1f8bbd0 | 498 | if (!entry->type.compare("obsolete")) |
76f44481 AJ |
499 | continue; |
500 | ||
c1f8bbd0 | 501 | if (!entry->loc.size()) { |
7ff7a211 | 502 | std::cerr << "NO LOCATION FOR " << entry->name << std::endl; |
62e76326 | 503 | rc |= 1; |
504 | continue; | |
505 | } | |
506 | ||
576b1e98 | 507 | if (!entry->defaults.preset.size() && entry->defaults.if_none.empty()) { |
7ff7a211 | 508 | std::cerr << "NO DEFAULT FOR " << entry->name << std::endl; |
62e76326 | 509 | rc |= 1; |
510 | continue; | |
511 | } | |
512 | ||
576b1e98 AJ |
513 | if (!entry->defaults.preset.size() || entry->defaults.preset.front().compare("none") == 0) { |
514 | fout << " // No default for " << entry->name << std::endl; | |
62e76326 | 515 | } else { |
c1f8bbd0 | 516 | if (entry->ifdef.size()) |
7ff7a211 | 517 | fout << "#if " << entry->ifdef << std::endl; |
c58a4b53 | 518 | |
576b1e98 | 519 | for (LineList::const_iterator l = entry->defaults.preset.begin(); l != entry->defaults.preset.end(); ++l) { |
b11724bb | 520 | fout << " default_line(\"" << entry->name << " " << gen_quote_escape(*l) << "\");" << std::endl; |
576b1e98 | 521 | } |
62e76326 | 522 | |
c1f8bbd0 | 523 | if (entry->ifdef.size()) |
576b1e98 | 524 | fout << "#endif" << std::endl; |
2bfdc0a9 | 525 | } |
934b03fc | 526 | } |
62e76326 | 527 | |
576b1e98 | 528 | fout << " cfg_filename = NULL;" << std::endl << |
f53969cc | 529 | "}" << std::endl << std::endl; |
f1dc9b30 | 530 | return rc; |
934b03fc | 531 | } |
532 | ||
f53b06f9 | 533 | static void |
576b1e98 | 534 | gen_default_if_none(const EntryList &head, std::ostream &fout) |
f53b06f9 | 535 | { |
576b1e98 | 536 | fout << "static void" << std::endl << |
f53969cc SM |
537 | "defaults_if_none(void)" << std::endl << |
538 | "{" << std::endl << | |
539 | " cfg_filename = \"Default Configuration (if absent)\";" << std::endl << | |
540 | " config_lineno = 0;" << std::endl; | |
62e76326 | 541 | |
576b1e98 | 542 | for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) { |
c1f8bbd0 | 543 | assert(entry->name.size()); |
76f44481 | 544 | |
c1f8bbd0 | 545 | if (!entry->loc.size()) |
76f44481 | 546 | continue; |
62e76326 | 547 | |
576b1e98 | 548 | if (entry->defaults.if_none.empty()) |
62e76326 | 549 | continue; |
550 | ||
576b1e98 AJ |
551 | if (!entry->defaults.preset.empty()) { |
552 | std::cerr << "ERROR: " << entry->name << " has preset defaults. DEFAULT_IF_NONE cannot be true." << std::endl; | |
553 | exit(1); | |
554 | } | |
555 | ||
c1f8bbd0 | 556 | if (entry->ifdef.size()) |
7ff7a211 | 557 | fout << "#if " << entry->ifdef << std::endl; |
62e76326 | 558 | |
576b1e98 AJ |
559 | fout << " if (check_null_" << entry->type << "(" << entry->loc << ")) {" << std::endl; |
560 | for (LineList::const_iterator l = entry->defaults.if_none.begin(); l != entry->defaults.if_none.end(); ++l) | |
b11724bb | 561 | fout << " default_line(\"" << entry->name << " " << gen_quote_escape(*l) <<"\");" << std::endl; |
576b1e98 | 562 | fout << " }" << std::endl; |
62e76326 | 563 | |
c1f8bbd0 | 564 | if (entry->ifdef.size()) |
576b1e98 | 565 | fout << "#endif" << std::endl; |
f53b06f9 | 566 | } |
62e76326 | 567 | |
b6ead21b | 568 | fout << " cfg_filename = NULL;" << std::endl << |
f53969cc | 569 | "}" << std::endl << std::endl; |
f53b06f9 | 570 | } |
571 | ||
10d914f6 CT |
572 | /// append configuration options specified by POSTSCRIPTUM lines |
573 | static void | |
574 | gen_default_postscriptum(const EntryList &head, std::ostream &fout) | |
575 | { | |
576 | fout << "static void" << std::endl << | |
f53969cc SM |
577 | "defaults_postscriptum(void)" << std::endl << |
578 | "{" << std::endl << | |
579 | " cfg_filename = \"Default Configuration (postscriptum)\";" << std::endl << | |
580 | " config_lineno = 0;" << std::endl; | |
10d914f6 CT |
581 | |
582 | for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) { | |
583 | assert(entry->name.size()); | |
584 | ||
585 | if (!entry->loc.size()) | |
586 | continue; | |
587 | ||
588 | if (entry->defaults.postscriptum.empty()) | |
589 | continue; | |
590 | ||
591 | if (entry->ifdef.size()) | |
592 | fout << "#if " << entry->ifdef << std::endl; | |
593 | ||
594 | for (LineList::const_iterator l = entry->defaults.postscriptum.begin(); l != entry->defaults.postscriptum.end(); ++l) | |
595 | fout << " default_line(\"" << entry->name << " " << *l <<"\");" << std::endl; | |
596 | ||
597 | if (entry->ifdef.size()) | |
598 | fout << "#endif" << std::endl; | |
599 | } | |
600 | ||
b6ead21b | 601 | fout << " cfg_filename = NULL;" << std::endl << |
f53969cc | 602 | "}" << std::endl << std::endl; |
10d914f6 CT |
603 | } |
604 | ||
147a3e90 | 605 | void |
576b1e98 | 606 | Entry::genParseAlias(const std::string &aName, std::ostream &fout) const |
934b03fc | 607 | { |
576b1e98 | 608 | fout << " if (!strcmp(token, \"" << aName << "\")) {" << std::endl; |
b6ead21b AJ |
609 | if (ifdef.size()) |
610 | fout << "#if " << ifdef << std::endl; | |
6f58d7d7 | 611 | fout << " cfg_directive = \"" << aName << "\";" << std::endl; |
576b1e98 AJ |
612 | fout << " "; |
613 | if (type.compare("obsolete") == 0) { | |
614 | fout << "debugs(0, DBG_CRITICAL, \"ERROR: Directive '" << aName << "' is obsolete.\");\n"; | |
615 | for (LineList::const_iterator l = doc.begin(); l != doc.end(); ++l) { | |
76f44481 | 616 | // offset line to strip initial whitespace tab byte |
aa7e2b35 | 617 | fout << " debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), \"" << aName << " : " << &(*l)[1] << "\");" << std::endl; |
76f44481 | 618 | } |
576b1e98 AJ |
619 | fout << " parse_obsolete(token);"; |
620 | } else if (!loc.size() || loc.compare("none") == 0) { | |
621 | fout << "parse_" << type << "();"; | |
62e76326 | 622 | } else { |
576b1e98 | 623 | fout << "parse_" << type << "(&" << loc << (array_flag ? "[0]" : "") << ");"; |
62e76326 | 624 | } |
576b1e98 | 625 | fout << std::endl; |
6f58d7d7 | 626 | fout << " cfg_directive = NULL;" << std::endl; |
b6ead21b AJ |
627 | if (ifdef.size()) { |
628 | fout << | |
f53969cc SM |
629 | "#else" << std::endl << |
630 | " debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), \"ERROR: '" << name << "' requires " << available_if(ifdef) << "\");" << std::endl << | |
631 | "#endif" << std::endl; | |
b6ead21b | 632 | } |
576b1e98 AJ |
633 | fout << " return 1;" << std::endl; |
634 | fout << " };" << std::endl; | |
147a3e90 | 635 | } |
636 | ||
637 | void | |
576b1e98 | 638 | Entry::genParse(std::ostream &fout) const |
147a3e90 | 639 | { |
576b1e98 | 640 | if (name.compare("comment") == 0) |
62e76326 | 641 | return; |
642 | ||
576b1e98 AJ |
643 | // Once for the current directive name |
644 | genParseAlias(name, fout); | |
62e76326 | 645 | |
576b1e98 AJ |
646 | // All accepted aliases |
647 | for (EntryAliasList::const_iterator a = alias.begin(); a != alias.end(); ++a) { | |
648 | genParseAlias(*a, fout); | |
649 | } | |
147a3e90 | 650 | } |
651 | ||
652 | static void | |
576b1e98 | 653 | gen_parse(const EntryList &head, std::ostream &fout) |
147a3e90 | 654 | { |
7ff7a211 | 655 | fout << |
f53969cc SM |
656 | "static int\n" |
657 | "parse_line(char *buff)\n" | |
658 | "{\n" | |
659 | "\tchar\t*token;\n" | |
660 | "\tif ((token = strtok(buff, w_space)) == NULL) \n" | |
661 | "\t\treturn 1;\t/* ignore empty lines */\n" | |
662 | "\tConfigParser::SetCfgLine(strtok(NULL, \"\"));\n"; | |
147a3e90 | 663 | |
576b1e98 AJ |
664 | for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) |
665 | e->genParse(fout); | |
7ff7a211 FC |
666 | |
667 | fout << "\treturn 0; /* failure */\n" | |
f53969cc | 668 | "}\n\n"; |
934b03fc | 669 | |
934b03fc | 670 | } |
671 | ||
672 | static void | |
576b1e98 | 673 | gen_dump(const EntryList &head, std::ostream &fout) |
934b03fc | 674 | { |
7ff7a211 | 675 | fout << |
f53969cc SM |
676 | "static void" << std::endl << |
677 | "dump_config(StoreEntry *entry)" << std::endl << | |
678 | "{" << std::endl << | |
679 | " debugs(5, 4, HERE);" << std::endl; | |
62e76326 | 680 | |
576b1e98 | 681 | for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) { |
62e76326 | 682 | |
576b1e98 | 683 | if (!e->loc.size() || e->loc.compare("none") == 0) |
62e76326 | 684 | continue; |
685 | ||
576b1e98 | 686 | if (e->name.compare("comment") == 0) |
62e76326 | 687 | continue; |
688 | ||
576b1e98 AJ |
689 | if (e->ifdef.size()) |
690 | fout << "#if " << e->ifdef << std::endl; | |
62e76326 | 691 | |
576b1e98 | 692 | fout << " dump_" << e->type << "(entry, \"" << e->name << "\", " << e->loc << ");" << std::endl; |
62e76326 | 693 | |
576b1e98 AJ |
694 | if (e->ifdef.size()) |
695 | fout << "#endif" << std::endl; | |
934b03fc | 696 | } |
62e76326 | 697 | |
576b1e98 | 698 | fout << "}" << std::endl << std::endl; |
934b03fc | 699 | } |
700 | ||
0153d498 | 701 | static void |
576b1e98 | 702 | gen_free(const EntryList &head, std::ostream &fout) |
0153d498 | 703 | { |
7ff7a211 | 704 | fout << |
f53969cc SM |
705 | "static void" << std::endl << |
706 | "free_all(void)" << std::endl << | |
707 | "{" << std::endl << | |
708 | " debugs(5, 4, HERE);" << std::endl; | |
62e76326 | 709 | |
576b1e98 AJ |
710 | for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) { |
711 | if (!e->loc.size() || e->loc.compare("none") == 0) | |
62e76326 | 712 | continue; |
713 | ||
576b1e98 | 714 | if (e->name.compare("comment") == 0) |
62e76326 | 715 | continue; |
716 | ||
576b1e98 AJ |
717 | if (e->ifdef.size()) |
718 | fout << "#if " << e->ifdef << std::endl; | |
62e76326 | 719 | |
576b1e98 | 720 | fout << " free_" << e->type << "(&" << e->loc << (e->array_flag ? "[0]" : "") << ");" << std::endl; |
62e76326 | 721 | |
576b1e98 AJ |
722 | if (e->ifdef.size()) |
723 | fout << "#endif" << std::endl; | |
0153d498 | 724 | } |
62e76326 | 725 | |
576b1e98 | 726 | fout << "}" << std::endl << std::endl; |
0153d498 | 727 | } |
728 | ||
c1f8bbd0 | 729 | static bool |
576b1e98 | 730 | isDefined(const std::string &name) |
6b53c392 | 731 | { |
c1f8bbd0 AJ |
732 | if (!name.size()) |
733 | return true; | |
62e76326 | 734 | |
5086523e | 735 | for (int i = 0; defines[i].name; ++i) { |
c1f8bbd0 AJ |
736 | if (name.compare(defines[i].name) == 0) |
737 | return defines[i].defined; | |
a4b8110e | 738 | } |
62e76326 | 739 | |
c1f8bbd0 | 740 | return false; |
6b53c392 | 741 | } |
742 | ||
a4b8110e | 743 | static const char * |
c1f8bbd0 | 744 | available_if(const std::string &name) |
6b53c392 | 745 | { |
c1f8bbd0 | 746 | assert(name.size()); |
62e76326 | 747 | |
5086523e | 748 | for (int i = 0; defines[i].name; ++i) { |
576b1e98 | 749 | if (name.compare(defines[i].name) == 0) |
c1f8bbd0 | 750 | return defines[i].enable; |
a4b8110e | 751 | } |
62e76326 | 752 | |
c1f8bbd0 | 753 | return name.c_str(); |
6b53c392 | 754 | } |
755 | ||
934b03fc | 756 | static void |
576b1e98 | 757 | gen_conf(const EntryList &head, std::ostream &fout, bool verbose_output) |
934b03fc | 758 | { |
576b1e98 AJ |
759 | for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) { |
760 | char buf[8192]; | |
761 | LineList def; | |
26ac0430 | 762 | int enabled = 1; |
62e76326 | 763 | |
576b1e98 | 764 | // Display TAG: line |
c1f8bbd0 | 765 | if (!entry->name.compare("comment")) |
62e76326 | 766 | (void) 0; |
c1f8bbd0 | 767 | else if (!entry->name.compare("obsolete")) |
76f44481 | 768 | (void) 0; |
c98dcee3 | 769 | else if (verbose_output) { |
7ff7a211 | 770 | fout << "# TAG: " << entry->name; |
62e76326 | 771 | |
c1f8bbd0 | 772 | if (entry->comment.size()) |
7ff7a211 | 773 | fout << "\t" << entry->comment; |
62e76326 | 774 | |
7ff7a211 | 775 | fout << std::endl; |
c98dcee3 | 776 | } |
62e76326 | 777 | |
576b1e98 AJ |
778 | // Display --enable/--disable disclaimer |
779 | if (!isDefined(entry->ifdef)) { | |
c98dcee3 | 780 | if (verbose_output) { |
576b1e98 | 781 | fout << "# Note: This option is only available if Squid is rebuilt with the" << std::endl << |
f53969cc SM |
782 | "# " << available_if(entry->ifdef) << std::endl << |
783 | "#" << std::endl; | |
c98dcee3 A |
784 | } |
785 | enabled = 0; | |
62e76326 | 786 | } |
787 | ||
576b1e98 AJ |
788 | // Display DOC_START section |
789 | if (verbose_output && entry->doc.size()) { | |
790 | for (LineList::const_iterator line = entry->doc.begin(); line != entry->doc.end(); ++line) { | |
791 | fout << "#" << *line << std::endl; | |
c98dcee3 A |
792 | } |
793 | } | |
62e76326 | 794 | |
576b1e98 AJ |
795 | if (entry->defaults.docs.size()) { |
796 | // Display the DEFAULT_DOC line(s) | |
797 | def = entry->defaults.docs; | |
798 | } else { | |
799 | if (entry->defaults.preset.size() && entry->defaults.preset.front().compare("none") != 0) { | |
800 | // Display DEFAULT: line(s) | |
801 | for (LineList::const_iterator l = entry->defaults.preset.begin(); l != entry->defaults.preset.end(); ++l) { | |
fe7966ec | 802 | snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), l->c_str()); |
576b1e98 AJ |
803 | def.push_back(buf); |
804 | } | |
805 | } else if (entry->defaults.if_none.size()) { | |
806 | // Display DEFAULT_IF_NONE: line(s) | |
807 | for (LineList::const_iterator l = entry->defaults.if_none.begin(); l != entry->defaults.if_none.end(); ++l) { | |
fe7966ec | 808 | snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), l->c_str()); |
576b1e98 AJ |
809 | def.push_back(buf); |
810 | } | |
62e76326 | 811 | } |
812 | } | |
813 | ||
576b1e98 AJ |
814 | // Display "none" if no default is set or comments to display |
815 | if (def.empty() && entry->nocomment.empty() && entry->name.compare("comment") != 0) | |
816 | def.push_back("none"); | |
62e76326 | 817 | |
576b1e98 | 818 | if (verbose_output && def.size()) { |
7ff7a211 | 819 | fout << "#Default:\n"; |
576b1e98 AJ |
820 | while (def.size()) { |
821 | fout << "# " << def.front() << std::endl; | |
822 | def.pop_front(); | |
62e76326 | 823 | } |
576b1e98 AJ |
824 | if (entry->doc.empty() && entry->nocomment.empty()) |
825 | fout << std::endl; | |
62e76326 | 826 | } |
827 | ||
576b1e98 | 828 | if (verbose_output && entry->nocomment.size()) |
7ff7a211 | 829 | fout << "#" << std::endl; |
62e76326 | 830 | |
c98dcee3 | 831 | if (enabled || verbose_output) { |
576b1e98 AJ |
832 | for (LineList::const_iterator line = entry->nocomment.begin(); line != entry->nocomment.end(); ++line) { |
833 | if (!enabled && line->at(0) != '#') | |
834 | fout << "#"; | |
835 | fout << *line << std::endl; | |
c98dcee3 A |
836 | } |
837 | } | |
62e76326 | 838 | |
576b1e98 | 839 | if (verbose_output && entry->doc.size()) { |
7ff7a211 | 840 | fout << std::endl; |
62e76326 | 841 | } |
934b03fc | 842 | } |
843 | } | |
b11724bb CT |
844 | |
845 | static const char * | |
846 | gen_quote_escape(const std::string &var) | |
847 | { | |
848 | static std::string esc; | |
849 | esc.clear(); | |
850 | ||
851 | for (int i = 0; i < var.length(); ++i) { | |
852 | switch (var[i]) { | |
e2849af8 A |
853 | case '"': |
854 | case '\\': | |
855 | esc += '\\'; | |
856 | default: | |
857 | esc += var[i]; | |
b11724bb CT |
858 | } |
859 | } | |
860 | ||
861 | return esc.c_str(); | |
862 | } | |
f53969cc | 863 |