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