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