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