]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cf_gen.cc
Boilerplate: update copyright blurbs on src/
[thirdparty/squid.git] / src / cf_gen.cc
CommitLineData
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/*****************************************************************************
12 * Abstract: This program parses the input file and generates code and
13 * files used to configure the variables in squid.
e321c7d4 14 * (ie it creates the squid.conf.default file from the cf.data file)
934b03fc 15 *
16 * The output files are as follows:
cca8ba0d 17 * cf_parser.cci - this file contains, default_all() which
f53b06f9 18 * initializes variables with the default
19 * values, parse_line() that parses line from
e321c7d4 20 * squid.conf.default, dump_config that dumps the
934b03fc 21 * current the values of the variables.
e321c7d4 22 * squid.conf.default - default configuration file given to the server
934b03fc 23 * administrator.
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
934b03fc 47#define MAX_LINE 1024 /* longest configuration line */
cca8ba0d 48#define _PATH_PARSER "cf_parser.cci"
1446a5fd 49#define _PATH_SQUID_CONF "squid.conf.documented"
509fba1a 50#define _PATH_SQUID_CONF_SHORT "squid.conf.default"
41bd17a4 51#define _PATH_CF_DEPEND "cf.data.depend"
934b03fc 52
53enum State {
54 sSTART,
55 s1,
56 sDOC,
c68e9c6b 57 sNOCOMMENT,
934b03fc 58 sEXIT
59};
60
576b1e98
AJ
61typedef std::list<std::string> LineList;
62typedef std::list<std::string> TypeDepList;
63typedef std::list<std::string> EntryAliasList;
62e76326 64
576b1e98 65class DefaultValues
c1f8bbd0
AJ
66{
67public:
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
87class Entry
88{
89public:
90 Entry(const char *str) :
576b1e98
AJ
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
109private:
110 void genParseAlias(const std::string &, std::ostream &) const;
c1f8bbd0 111};
41bd17a4 112
576b1e98
AJ
113typedef std::list<class Entry> EntryList;
114
c1f8bbd0
AJ
115class Type
116{
117public:
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 125typedef std::list<class Type> TypeList;
c1f8bbd0 126
576b1e98
AJ
127static const char WS[] = " \t\n";
128static int gen_default(const EntryList &, std::ostream &);
129static void gen_parse(const EntryList &, std::ostream &);
130static void gen_dump(const EntryList &, std::ostream&);
131static void gen_free(const EntryList &, std::ostream&);
132static void gen_conf(const EntryList &, std::ostream&, bool verbose_output);
133static void gen_default_if_none(const EntryList &, std::ostream&);
10d914f6 134static void gen_default_postscriptum(const EntryList &, std::ostream&);
cf1c09f6 135static bool isDefined(const std::string &name);
b6ead21b 136static const char *available_if(const std::string &name);
b11724bb 137static const char *gen_quote_escape(const std::string &var);
6b53c392 138
41bd17a4 139static void
576b1e98 140checkDepend(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
162static void
163usage(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 169static void
2ad53ef1 170errorMsg(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 176int
177main(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
A
395 case sEXIT:
396 assert(0); /* should never get here */
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" <<
2bfdc0a9
A
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"
2bfdc0a9 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 473static int
576b1e98 474gen_default(const EntryList &head, std::ostream &fout)
934b03fc 475{
f1dc9b30 476 int rc = 0;
576b1e98 477 fout << "static void" << std::endl <<
116a7366 478 "default_line(const char *s)" << std::endl <<
576b1e98
AJ
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;
486 fout << "static void" << std::endl <<
487 "default_all(void)" << std::endl <<
488 "{" << std::endl <<
489 " cfg_filename = \"Default Configuration\";" << std::endl <<
490 " config_lineno = 0;" << std::endl;
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
AJ
528 fout << " cfg_filename = NULL;" << std::endl <<
529 "}" << std::endl << std::endl;
f1dc9b30 530 return rc;
934b03fc 531}
532
f53b06f9 533static void
576b1e98 534gen_default_if_none(const EntryList &head, std::ostream &fout)
f53b06f9 535{
576b1e98
AJ
536 fout << "static void" << std::endl <<
537 "defaults_if_none(void)" << std::endl <<
b6ead21b
AJ
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
AJ
568 fout << " cfg_filename = NULL;" << std::endl <<
569 "}" << std::endl << std::endl;
f53b06f9 570}
571
10d914f6
CT
572/// append configuration options specified by POSTSCRIPTUM lines
573static void
574gen_default_postscriptum(const EntryList &head, std::ostream &fout)
575{
576 fout << "static void" << std::endl <<
577 "defaults_postscriptum(void)" << std::endl <<
b6ead21b
AJ
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
AJ
601 fout << " cfg_filename = NULL;" << std::endl <<
602 "}" << std::endl << std::endl;
10d914f6
CT
603}
604
147a3e90 605void
576b1e98 606Entry::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 <<
629 "#else" << std::endl <<
630 " debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), \"ERROR: '" << name << "' requires " << available_if(ifdef) << "\");" << std::endl <<
631 "#endif" << std::endl;
632 }
576b1e98
AJ
633 fout << " return 1;" << std::endl;
634 fout << " };" << std::endl;
147a3e90 635}
636
637void
576b1e98 638Entry::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
652static void
576b1e98 653gen_parse(const EntryList &head, std::ostream &fout)
147a3e90 654{
7ff7a211 655 fout <<
2bfdc0a9
A
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"
2eceb328
CT
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"
2bfdc0a9 668 "}\n\n";
934b03fc 669
934b03fc 670}
671
672static void
576b1e98 673gen_dump(const EntryList &head, std::ostream &fout)
934b03fc 674{
7ff7a211 675 fout <<
576b1e98
AJ
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 701static void
576b1e98 702gen_free(const EntryList &head, std::ostream &fout)
0153d498 703{
7ff7a211 704 fout <<
576b1e98
AJ
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 729static bool
576b1e98 730isDefined(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 743static const char *
c1f8bbd0 744available_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 756static void
576b1e98 757gen_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
AJ
781 fout << "# Note: This option is only available if Squid is rebuilt with the" << std::endl <<
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
845static const char *
846gen_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}