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