]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cf_gen.cc
Various audit updates
[thirdparty/squid.git] / src / cf_gen.cc
1 /*
2 * DEBUG: none Generate squid.conf.default and cf_parser.cci
3 * AUTHOR: Max Okumoto
4 * AUTHOR: Francesco Chemolli
5 * AUTHOR: Amos Jeffries
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
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.
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.
23 *
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.
28 *
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
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35 /*****************************************************************************
36 * Abstract: This program parses the input file and generates code and
37 * files used to configure the variables in squid.
38 * (ie it creates the squid.conf.default file from the cf.data file)
39 *
40 * The output files are as follows:
41 * cf_parser.cci - this file contains, default_all() which
42 * initializes variables with the default
43 * values, parse_line() that parses line from
44 * squid.conf.default, dump_config that dumps the
45 * current the values of the variables.
46 * squid.conf.default - default configuration file given to the server
47 * administrator.
48 *****************************************************************************/
49
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) && \
55 _FILE_OFFSET_BITS==64
56 #undef _FILE_OFFSET_BITS
57 #endif
58
59 #include <cassert>
60 #include <cctype>
61 #include <cerrno>
62 #include <cstdlib>
63 #include <cstring>
64 #include <fstream>
65 #include <iostream>
66 #include <list>
67 #include <stack>
68
69 #include "cf_gen_defines.cci"
70
71 #define MAX_LINE 1024 /* longest configuration line */
72 #define _PATH_PARSER "cf_parser.cci"
73 #define _PATH_SQUID_CONF "squid.conf.documented"
74 #define _PATH_SQUID_CONF_SHORT "squid.conf.default"
75 #define _PATH_CF_DEPEND "cf.data.depend"
76
77 enum State {
78 sSTART,
79 s1,
80 sDOC,
81 sNOCOMMENT,
82 sEXIT
83 };
84
85 typedef std::list<std::string> LineList;
86 typedef std::list<std::string> TypeDepList;
87 typedef std::list<std::string> EntryAliasList;
88
89 class DefaultValues
90 {
91 public:
92 DefaultValues() : preset(), if_none(), docs() {}
93 ~DefaultValues() {}
94
95 /// Default config lines to be defined before parsing the config files.
96 LineList preset;
97
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;
102
103 /// Default config lines to parse and add to any prior settings.
104 LineList postscriptum;
105
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;
109 };
110
111 class Entry
112 {
113 public:
114 Entry(const char *str) :
115 name(str), alias(),type(), loc(),
116 defaults(), comment(), ifdef(), doc(), nocomment(),
117 array_flag(0) {}
118 ~Entry() {}
119
120 std::string name;
121 EntryAliasList alias;
122 std::string type;
123 std::string loc;
124 DefaultValues defaults;
125 std::string comment;
126 std::string ifdef;
127 LineList doc;
128 LineList nocomment;
129 int array_flag;
130
131 void genParse(std::ostream &fout) const;
132
133 private:
134 void genParseAlias(const std::string &, std::ostream &) const;
135 };
136
137 typedef std::list<class Entry> EntryList;
138
139 class Type
140 {
141 public:
142 Type(const char *str) : name(str) {}
143 ~Type() {}
144
145 std::string name;
146 TypeDepList depend;
147 };
148
149 typedef std::list<class Type> TypeList;
150
151 static const char WS[] = " \t\n";
152 static int gen_default(const EntryList &, std::ostream &);
153 static void gen_parse(const EntryList &, std::ostream &);
154 static void gen_dump(const EntryList &, std::ostream&);
155 static void gen_free(const EntryList &, std::ostream&);
156 static void gen_conf(const EntryList &, std::ostream&, bool verbose_output);
157 static void gen_default_if_none(const EntryList &, std::ostream&);
158 static void gen_default_postscriptum(const EntryList &, std::ostream&);
159 static bool isDefined(const std::string &name);
160 static const char *available_if(const std::string &name);
161 static const char *gen_quote_escape(const std::string &var);
162
163 static void
164 checkDepend(const std::string &directive, const char *name, const TypeList &types, const EntryList &entries)
165 {
166 for (TypeList::const_iterator t = types.begin(); t != types.end(); ++t) {
167 if (t->name.compare(name) != 0)
168 continue;
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)
173 break;
174 }
175 if (entry == entries.end()) {
176 std::cerr << "ERROR: '" << directive << "' (" << name << ") depends on '" << *dep << "'\n";
177 exit(1);
178 }
179 }
180 return;
181 }
182 std::cerr << "ERROR: Dependencies for cf.data type '" << name << "' used in ' " << directive << "' not defined\n" ;
183 exit(1);
184 }
185
186 static void
187 usage(const char *program_name)
188 {
189 std::cerr << "Usage: " << program_name << " cf.data cf.data.depend\n";
190 exit(1);
191 }
192
193 static void
194 errorMsg(const char *filename, int line, const char *detail)
195 {
196 std::cerr << "Error in '" << filename << "' on line " << line <<
197 "--> " << detail << std::endl;
198 }
199
200 int
201 main(int argc, char *argv[])
202 {
203 char *input_filename;
204 const char *output_filename = _PATH_PARSER;
205 const char *conf_filename = _PATH_SQUID_CONF;
206 const char *conf_filename_short = _PATH_SQUID_CONF_SHORT;
207 const char *type_depend;
208 int linenum = 0;
209 EntryList entries;
210 TypeList types;
211 enum State state;
212 int rc = 0;
213 char *ptr = NULL;
214 char buff[MAX_LINE];
215 std::ifstream fp;
216 std::stack<std::string> IFDEFS;
217
218 if (argc != 3)
219 usage(argv[0]);
220
221 input_filename = argv[1];
222 type_depend = argv[2];
223
224 /*-------------------------------------------------------------------*
225 * Parse type dependencies
226 *-------------------------------------------------------------------*/
227 fp.open(type_depend, std::ifstream::in);
228 if (fp.fail()) {
229 std::cerr << "Error while opening type dependencies file '" <<
230 type_depend << "': " << strerror(errno) << std::endl;
231 exit(1);
232 }
233
234 while (fp.good()) {
235 fp.getline(buff,MAX_LINE);
236 const char *type = strtok(buff, WS);
237 const char *dep;
238 if (!type || type[0] == '#')
239 continue;
240 Type t(type);
241 while ((dep = strtok(NULL, WS)) != NULL) {
242 t.depend.push_front(dep);
243 }
244 types.push_front(t);
245 }
246 fp.close();
247 fp.clear(); // BSD does not reset flags in close().
248
249 /*-------------------------------------------------------------------*
250 * Parse input file
251 *-------------------------------------------------------------------*/
252
253 /* Open input file */
254 fp.open(input_filename, std::ifstream::in);
255 if (fp.fail()) {
256 std::cerr << "Error while opening input file '" <<
257 input_filename << "': " << strerror(errno) << std::endl;
258 exit(1);
259 }
260
261 state = sSTART;
262
263 while (fp.getline(buff,MAX_LINE), fp.good() && state != sEXIT) {
264 char *t;
265
266 ++linenum;
267
268 if ((t = strchr(buff, '\n')))
269 *t = '\0';
270
271 if (strncmp(buff, "IF ", 3) == 0) {
272 if ((ptr = strtok(buff + 3, WS)) == NULL) {
273 errorMsg(input_filename, linenum, "Missing IF parameter");
274 exit(1);
275 }
276 IFDEFS.push(ptr);
277 continue;
278 } else if (strcmp(buff, "ENDIF") == 0) {
279 if (IFDEFS.size() == 0) {
280 errorMsg(input_filename, linenum, "ENDIF without IF first");
281 exit(1);
282 }
283 IFDEFS.pop();
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) {
296 errorMsg(input_filename, linenum, buff);
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 {
313 errorMsg(input_filename, linenum, buff);
314 exit(1);
315 }
316
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))
329 ++ptr;
330
331 curr.comment = ptr;
332 } else if (!strncmp(buff, "DEFAULT:", 8)) {
333 ptr = buff + 8;
334
335 while (isspace((unsigned char)*ptr))
336 ++ptr;
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))
343 ++ptr;
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))
350 ++ptr;
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))
357 ++ptr;
358
359 curr.defaults.docs.push_back(ptr);
360 } else if (!strncmp(buff, "LOC:", 4)) {
361 if ((ptr = strtok(buff + 4, WS)) == NULL) {
362 errorMsg(input_filename, linenum, buff);
363 exit(1);
364 }
365
366 curr.loc = ptr;
367 } else if (!strncmp(buff, "TYPE:", 5)) {
368 if ((ptr = strtok(buff + 5, WS)) == NULL) {
369 errorMsg(input_filename, linenum, buff);
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) {
383 errorMsg(input_filename, linenum, buff);
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 {
393 errorMsg(input_filename, linenum, buff);
394 exit(1);
395 }
396 }
397 break;
398
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);
407 }
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);
416 }
417 break;
418
419 case sEXIT:
420 assert(0); /* should never get here */
421 break;
422 }
423
424 }
425
426 if (state != sEXIT) {
427 errorMsg(input_filename, linenum, "Error: unexpected EOF");
428 exit(1);
429 }
430
431 fp.close();
432
433 /*-------------------------------------------------------------------*
434 * Generate default_all()
435 * Generate parse_line()
436 * Generate dump_config()
437 * Generate free_all()
438 * Generate example squid.conf.default file
439 *-------------------------------------------------------------------*/
440
441 /* Open output x.c file */
442
443 std::ofstream fout(output_filename,std::ostream::out);
444 if (!fout.good()) {
445 std::cerr << "Error while opening output .c file '" <<
446 output_filename << "': " << strerror(errno) << std::endl;
447 exit(1);
448 }
449
450 fout << "/*\n" <<
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"
457 "\n";
458
459 rc = gen_default(entries, fout);
460
461 gen_default_if_none(entries, fout);
462
463 gen_default_postscriptum(entries, fout);
464
465 gen_parse(entries, fout);
466
467 gen_dump(entries, fout);
468
469 gen_free(entries, fout);
470
471 fout.close();
472
473 /* Open output x.conf file */
474 fout.open(conf_filename,std::ostream::out);
475 if (!fout.good()) {
476 std::cerr << "Error while opening output conf file '" <<
477 output_filename << "': " << strerror(errno) << std::endl;
478 exit(1);
479 }
480
481 gen_conf(entries, fout, 1);
482
483 fout.close();
484
485 fout.open(conf_filename_short,std::ostream::out);
486 if (!fout.good()) {
487 std::cerr << "Error while opening output short conf file '" <<
488 output_filename << "': " << strerror(errno) << std::endl;
489 exit(1);
490 }
491 gen_conf(entries, fout, 0);
492 fout.close();
493
494 return (rc);
495 }
496
497 static int
498 gen_default(const EntryList &head, std::ostream &fout)
499 {
500 int rc = 0;
501 fout << "static void" << std::endl <<
502 "default_line(const char *s)" << std::endl <<
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) {
517 assert(entry->name.size());
518
519 if (!entry->name.compare("comment"))
520 continue;
521
522 if (!entry->type.compare("obsolete"))
523 continue;
524
525 if (!entry->loc.size()) {
526 std::cerr << "NO LOCATION FOR " << entry->name << std::endl;
527 rc |= 1;
528 continue;
529 }
530
531 if (!entry->defaults.preset.size() && entry->defaults.if_none.empty()) {
532 std::cerr << "NO DEFAULT FOR " << entry->name << std::endl;
533 rc |= 1;
534 continue;
535 }
536
537 if (!entry->defaults.preset.size() || entry->defaults.preset.front().compare("none") == 0) {
538 fout << " // No default for " << entry->name << std::endl;
539 } else {
540 if (entry->ifdef.size())
541 fout << "#if " << entry->ifdef << std::endl;
542
543 for (LineList::const_iterator l = entry->defaults.preset.begin(); l != entry->defaults.preset.end(); ++l) {
544 fout << " default_line(\"" << entry->name << " " << gen_quote_escape(*l) << "\");" << std::endl;
545 }
546
547 if (entry->ifdef.size())
548 fout << "#endif" << std::endl;
549 }
550 }
551
552 fout << " cfg_filename = NULL;" << std::endl <<
553 "}" << std::endl << std::endl;
554 return rc;
555 }
556
557 static void
558 gen_default_if_none(const EntryList &head, std::ostream &fout)
559 {
560 fout << "static void" << std::endl <<
561 "defaults_if_none(void)" << std::endl <<
562 "{" << std::endl <<
563 " cfg_filename = \"Default Configuration (if absent)\";" << std::endl <<
564 " config_lineno = 0;" << std::endl;
565
566 for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) {
567 assert(entry->name.size());
568
569 if (!entry->loc.size())
570 continue;
571
572 if (entry->defaults.if_none.empty())
573 continue;
574
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
580 if (entry->ifdef.size())
581 fout << "#if " << entry->ifdef << std::endl;
582
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)
585 fout << " default_line(\"" << entry->name << " " << gen_quote_escape(*l) <<"\");" << std::endl;
586 fout << " }" << std::endl;
587
588 if (entry->ifdef.size())
589 fout << "#endif" << std::endl;
590 }
591
592 fout << " cfg_filename = NULL;" << std::endl <<
593 "}" << std::endl << std::endl;
594 }
595
596 /// append configuration options specified by POSTSCRIPTUM lines
597 static void
598 gen_default_postscriptum(const EntryList &head, std::ostream &fout)
599 {
600 fout << "static void" << std::endl <<
601 "defaults_postscriptum(void)" << std::endl <<
602 "{" << std::endl <<
603 " cfg_filename = \"Default Configuration (postscriptum)\";" << std::endl <<
604 " config_lineno = 0;" << std::endl;
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
625 fout << " cfg_filename = NULL;" << std::endl <<
626 "}" << std::endl << std::endl;
627 }
628
629 void
630 Entry::genParseAlias(const std::string &aName, std::ostream &fout) const
631 {
632 fout << " if (!strcmp(token, \"" << aName << "\")) {" << std::endl;
633 if (ifdef.size())
634 fout << "#if " << ifdef << std::endl;
635 fout << " cfg_directive = \"" << aName << "\";" << std::endl;
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) {
640 // offset line to strip initial whitespace tab byte
641 fout << " debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), \"" << aName << " : " << &(*l)[1] << "\");" << std::endl;
642 }
643 fout << " parse_obsolete(token);";
644 } else if (!loc.size() || loc.compare("none") == 0) {
645 fout << "parse_" << type << "();";
646 } else {
647 fout << "parse_" << type << "(&" << loc << (array_flag ? "[0]" : "") << ");";
648 }
649 fout << std::endl;
650 fout << " cfg_directive = NULL;" << std::endl;
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 }
657 fout << " return 1;" << std::endl;
658 fout << " };" << std::endl;
659 }
660
661 void
662 Entry::genParse(std::ostream &fout) const
663 {
664 if (name.compare("comment") == 0)
665 return;
666
667 // Once for the current directive name
668 genParseAlias(name, fout);
669
670 // All accepted aliases
671 for (EntryAliasList::const_iterator a = alias.begin(); a != alias.end(); ++a) {
672 genParseAlias(*a, fout);
673 }
674 }
675
676 static void
677 gen_parse(const EntryList &head, std::ostream &fout)
678 {
679 fout <<
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"
685 "\t\treturn 1;\t/* ignore empty lines */\n"
686 "\tConfigParser::SetCfgLine(strtok(NULL, \"\"));\n";
687
688 for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e)
689 e->genParse(fout);
690
691 fout << "\treturn 0; /* failure */\n"
692 "}\n\n";
693
694 }
695
696 static void
697 gen_dump(const EntryList &head, std::ostream &fout)
698 {
699 fout <<
700 "static void" << std::endl <<
701 "dump_config(StoreEntry *entry)" << std::endl <<
702 "{" << std::endl <<
703 " debugs(5, 4, HERE);" << std::endl;
704
705 for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) {
706
707 if (!e->loc.size() || e->loc.compare("none") == 0)
708 continue;
709
710 if (e->name.compare("comment") == 0)
711 continue;
712
713 if (e->ifdef.size())
714 fout << "#if " << e->ifdef << std::endl;
715
716 fout << " dump_" << e->type << "(entry, \"" << e->name << "\", " << e->loc << ");" << std::endl;
717
718 if (e->ifdef.size())
719 fout << "#endif" << std::endl;
720 }
721
722 fout << "}" << std::endl << std::endl;
723 }
724
725 static void
726 gen_free(const EntryList &head, std::ostream &fout)
727 {
728 fout <<
729 "static void" << std::endl <<
730 "free_all(void)" << std::endl <<
731 "{" << std::endl <<
732 " debugs(5, 4, HERE);" << std::endl;
733
734 for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) {
735 if (!e->loc.size() || e->loc.compare("none") == 0)
736 continue;
737
738 if (e->name.compare("comment") == 0)
739 continue;
740
741 if (e->ifdef.size())
742 fout << "#if " << e->ifdef << std::endl;
743
744 fout << " free_" << e->type << "(&" << e->loc << (e->array_flag ? "[0]" : "") << ");" << std::endl;
745
746 if (e->ifdef.size())
747 fout << "#endif" << std::endl;
748 }
749
750 fout << "}" << std::endl << std::endl;
751 }
752
753 static bool
754 isDefined(const std::string &name)
755 {
756 if (!name.size())
757 return true;
758
759 for (int i = 0; defines[i].name; ++i) {
760 if (name.compare(defines[i].name) == 0)
761 return defines[i].defined;
762 }
763
764 return false;
765 }
766
767 static const char *
768 available_if(const std::string &name)
769 {
770 assert(name.size());
771
772 for (int i = 0; defines[i].name; ++i) {
773 if (name.compare(defines[i].name) == 0)
774 return defines[i].enable;
775 }
776
777 return name.c_str();
778 }
779
780 static void
781 gen_conf(const EntryList &head, std::ostream &fout, bool verbose_output)
782 {
783 for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) {
784 char buf[8192];
785 LineList def;
786 int enabled = 1;
787
788 // Display TAG: line
789 if (!entry->name.compare("comment"))
790 (void) 0;
791 else if (!entry->name.compare("obsolete"))
792 (void) 0;
793 else if (verbose_output) {
794 fout << "# TAG: " << entry->name;
795
796 if (entry->comment.size())
797 fout << "\t" << entry->comment;
798
799 fout << std::endl;
800 }
801
802 // Display --enable/--disable disclaimer
803 if (!isDefined(entry->ifdef)) {
804 if (verbose_output) {
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;
808 }
809 enabled = 0;
810 }
811
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;
816 }
817 }
818
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) {
826 snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), l->c_str());
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) {
832 snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), l->c_str());
833 def.push_back(buf);
834 }
835 }
836 }
837
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");
841
842 if (verbose_output && def.size()) {
843 fout << "#Default:\n";
844 while (def.size()) {
845 fout << "# " << def.front() << std::endl;
846 def.pop_front();
847 }
848 if (entry->doc.empty() && entry->nocomment.empty())
849 fout << std::endl;
850 }
851
852 if (verbose_output && entry->nocomment.size())
853 fout << "#" << std::endl;
854
855 if (enabled || verbose_output) {
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;
860 }
861 }
862
863 if (verbose_output && entry->doc.size()) {
864 fout << std::endl;
865 }
866 }
867 }
868
869 static const char *
870 gen_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 }