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