]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/cf_gen.cc
2 * DEBUG: none Generate squid.conf.default and cf_parser.cci
4 * AUTHOR: Francesco Chemolli
5 * AUTHOR: Amos Jeffries
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
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.
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.
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.
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.
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)
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
48 *****************************************************************************/
51 * hack around a bug in intel's c++ compiler's libraries which do not
52 * correctly support 64-bit iostreams
54 #if defined(__INTEL_COMPILER) && defined(_FILE_OFFSET_BITS) && \
56 #undef _FILE_OFFSET_BITS
69 #include "cf_gen_defines.cci"
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"
85 typedef std::list
<std::string
> LineList
;
86 typedef std::list
<std::string
> TypeDepList
;
87 typedef std::list
<std::string
> EntryAliasList
;
92 DefaultValues() : preset(), if_none(), docs() {}
95 /// Default config lines to be defined before parsing the config files.
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.
103 /// Default config lines to parse and add to any prior settings.
104 LineList postscriptum
;
106 /// Text description to use in documentation for the default.
107 /// If unset the preset or if-none values will be displayed.
114 Entry(const char *str
) :
115 name(str
), alias(),type(), loc(),
116 defaults(), comment(), ifdef(), doc(), nocomment(),
121 EntryAliasList alias
;
124 DefaultValues defaults
;
131 void genParse(std::ostream
&fout
) const;
134 void genParseAlias(const std::string
&, std::ostream
&) const;
137 typedef std::list
<class Entry
> EntryList
;
142 Type(const char *str
) : name(str
) {}
149 typedef std::list
<class Type
> TypeList
;
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
);
163 checkDepend(const std::string
&directive
, const char *name
, const TypeList
&types
, const EntryList
&entries
)
165 for (TypeList::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
) {
166 if (t
->name
.compare(name
) != 0)
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)
174 if (entry
== entries
.end()) {
175 std::cerr
<< "ERROR: '" << directive
<< "' (" << name
<< ") depends on '" << *dep
<< "'\n";
181 std::cerr
<< "ERROR: Dependencies for cf.data type '" << name
<< "' used in ' " << directive
<< "' not defined\n" ;
186 usage(const char *program_name
)
188 std::cerr
<< "Usage: " << program_name
<< " cf.data cf.data.depend\n";
193 main(int argc
, char *argv
[])
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
;
208 std::stack
<std::string
> IFDEFS
;
213 input_filename
= argv
[1];
214 type_depend
= argv
[2];
216 /*-------------------------------------------------------------------*
217 * Parse type dependencies
218 *-------------------------------------------------------------------*/
219 fp
.open(type_depend
, std::ifstream::in
);
221 std::cerr
<< "error while opening type dependencies file '" <<
222 type_depend
<< "': " << strerror(errno
) << std::endl
;
227 fp
.getline(buff
,MAX_LINE
);
228 const char *type
= strtok(buff
, WS
);
230 if (!type
|| type
[0] == '#')
233 while ((dep
= strtok(NULL
, WS
)) != NULL
) {
234 t
.depend
.push_front(dep
);
239 fp
.clear(); // BSD does not reset flags in close().
241 /*-------------------------------------------------------------------*
243 *-------------------------------------------------------------------*/
245 /* Open input file */
246 fp
.open(input_filename
, std::ifstream::in
);
248 std::cerr
<< "error while opening input file '" <<
249 input_filename
<< "': " << strerror(errno
) << std::endl
;
255 while (fp
.getline(buff
,MAX_LINE
), fp
.good() && state
!= sEXIT
) {
260 if ((t
= strchr(buff
, '\n')))
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
;
270 } else if (strcmp(buff
, "ENDIF") == 0) {
271 if (IFDEFS
.size() == 0) {
272 std::cerr
<< "ENDIF without IF before on line " << linenum
<< std::endl
;
276 } else if (!IFDEFS
.size() || isDefined(IFDEFS
.top()))
281 if ((strlen(buff
) == 0) || (!strncmp(buff
, "#", 1))) {
282 /* ignore empty and comment lines */
284 } else if (!strncmp(buff
, "NAME:", 5)) {
285 char *name
, *aliasname
;
287 if ((name
= strtok(buff
+ 5, WS
)) == NULL
) {
288 std::cerr
<< "Error in input file\n";
292 entries
.push_back(name
);
294 while ((aliasname
= strtok(NULL
, WS
)) != NULL
)
295 entries
.back().alias
.push_front(aliasname
);
298 } else if (!strcmp(buff
, "EOF")) {
300 } else if (!strcmp(buff
, "COMMENT_START")) {
301 entries
.push_back("comment");
302 entries
.back().loc
= "none";
305 std::cerr
<< "Error on line " << linenum
<< std::endl
<<
306 "--> " << buff
<< std::endl
;
313 Entry
&curr
= entries
.back();
315 if ((strlen(buff
) == 0) || (!strncmp(buff
, "#", 1))) {
316 /* ignore empty and comment lines */
318 } else if (!strncmp(buff
, "COMMENT:", 8)) {
321 while (isspace((unsigned char)*ptr
))
325 } else if (!strncmp(buff
, "DEFAULT:", 8)) {
328 while (isspace((unsigned char)*ptr
))
331 curr
.defaults
.preset
.push_back(ptr
);
332 } else if (!strncmp(buff
, "DEFAULT_IF_NONE:", 16)) {
335 while (isspace((unsigned char)*ptr
))
338 curr
.defaults
.if_none
.push_back(ptr
);
339 } else if (!strncmp(buff
, "POSTSCRIPTUM:", 13)) {
342 while (isspace((unsigned char)*ptr
))
345 curr
.defaults
.postscriptum
.push_back(ptr
);
346 } else if (!strncmp(buff
, "DEFAULT_DOC:", 12)) {
349 while (isspace((unsigned char)*ptr
))
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
;
360 } else if (!strncmp(buff
, "TYPE:", 5)) {
361 if ((ptr
= strtok(buff
+ 5, WS
)) == NULL
) {
362 std::cerr
<< "Error on line " << linenum
<< std::endl
;
366 /* hack to support arrays, rather than pointers */
367 if (0 == strcmp(ptr
+ strlen(ptr
) - 2, "[]")) {
369 *(ptr
+ strlen(ptr
) - 2) = '\0';
372 checkDepend(curr
.name
, ptr
, types
, entries
);
374 } else if (!strncmp(buff
, "IFDEF:", 6)) {
375 if ((ptr
= strtok(buff
+ 6, WS
)) == NULL
) {
376 std::cerr
<< "Error on line " << linenum
<< std::endl
;
381 } else if (!strcmp(buff
, "DOC_START")) {
383 } else if (!strcmp(buff
, "DOC_NONE")) {
386 std::cerr
<< "Error on line " << linenum
<< std::endl
;
393 if (!strcmp(buff
, "DOC_END") || !strcmp(buff
, "COMMENT_END")) {
395 } else if (!strcmp(buff
, "NOCOMMENT_START")) {
397 } else { // if (buff != NULL) {
398 assert(buff
!= NULL
);
399 entries
.back().doc
.push_back(buff
);
404 if (!strcmp(buff
, "NOCOMMENT_END")) {
406 } else { // if (buff != NULL) {
407 assert(buff
!= NULL
);
408 entries
.back().nocomment
.push_back(buff
);
413 assert(0); /* should never get here */
419 if (state
!= sEXIT
) {
420 std::cerr
<< "Error: unexpected EOF\n";
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 *-------------------------------------------------------------------*/
434 /* Open output x.c file */
436 std::ofstream
fout(output_filename
,std::ostream::out
);
438 std::cerr
<< "error while opening output .c file '" <<
439 output_filename
<< "': " << strerror(errno
) << std::endl
;
444 " * Generated automatically from " << input_filename
<< " by " <<
447 " * Abstract: This file contains routines used to configure the\n"
448 " * variables in the squid server.\n"
452 rc
= gen_default(entries
, fout
);
454 gen_default_if_none(entries
, fout
);
456 gen_default_postscriptum(entries
, fout
);
458 gen_parse(entries
, fout
);
460 gen_dump(entries
, fout
);
462 gen_free(entries
, fout
);
466 /* Open output x.conf file */
467 fout
.open(conf_filename
,std::ostream::out
);
469 std::cerr
<< "error while opening output conf file '" <<
470 output_filename
<< "': " << strerror(errno
) << std::endl
;
474 gen_conf(entries
, fout
, 1);
478 fout
.open(conf_filename_short
,std::ostream::out
);
480 std::cerr
<< "error while opening output short conf file '" <<
481 output_filename
<< "': " << strerror(errno
) << std::endl
;
484 gen_conf(entries
, fout
, 0);
491 gen_default(const EntryList
&head
, std::ostream
&fout
)
494 fout
<< "static void" << std::endl
<<
495 "default_line(const char *s)" << 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
<<
506 " cfg_filename = \"Default Configuration\";" << std::endl
<<
507 " config_lineno = 0;" << std::endl
;
509 for (EntryList::const_iterator entry
= head
.begin(); entry
!= head
.end(); ++entry
) {
510 assert(entry
->name
.size());
512 if (!entry
->name
.compare("comment"))
515 if (!entry
->type
.compare("obsolete"))
518 if (!entry
->loc
.size()) {
519 std::cerr
<< "NO LOCATION FOR " << entry
->name
<< std::endl
;
524 if (!entry
->defaults
.preset
.size() && entry
->defaults
.if_none
.empty()) {
525 std::cerr
<< "NO DEFAULT FOR " << entry
->name
<< std::endl
;
530 if (!entry
->defaults
.preset
.size() || entry
->defaults
.preset
.front().compare("none") == 0) {
531 fout
<< " // No default for " << entry
->name
<< std::endl
;
533 if (entry
->ifdef
.size())
534 fout
<< "#if " << entry
->ifdef
<< std::endl
;
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
;
540 if (entry
->ifdef
.size())
541 fout
<< "#endif" << std::endl
;
545 fout
<< " cfg_filename = NULL;" << std::endl
<<
546 "}" << std::endl
<< std::endl
;
551 gen_default_if_none(const EntryList
&head
, std::ostream
&fout
)
553 fout
<< "static void" << std::endl
<<
554 "defaults_if_none(void)" << std::endl
<<
556 " cfg_filename = \"Default Configuration (if absent)\";" << std::endl
<<
557 " config_lineno = 0;" << std::endl
;
559 for (EntryList::const_iterator entry
= head
.begin(); entry
!= head
.end(); ++entry
) {
560 assert(entry
->name
.size());
562 if (!entry
->loc
.size())
565 if (entry
->defaults
.if_none
.empty())
568 if (!entry
->defaults
.preset
.empty()) {
569 std::cerr
<< "ERROR: " << entry
->name
<< " has preset defaults. DEFAULT_IF_NONE cannot be true." << std::endl
;
573 if (entry
->ifdef
.size())
574 fout
<< "#if " << entry
->ifdef
<< std::endl
;
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
;
581 if (entry
->ifdef
.size())
582 fout
<< "#endif" << std::endl
;
585 fout
<< " cfg_filename = NULL;" << std::endl
<<
586 "}" << std::endl
<< std::endl
;
589 /// append configuration options specified by POSTSCRIPTUM lines
591 gen_default_postscriptum(const EntryList
&head
, std::ostream
&fout
)
593 fout
<< "static void" << std::endl
<<
594 "defaults_postscriptum(void)" << std::endl
<<
596 " cfg_filename = \"Default Configuration (postscriptum)\";" << std::endl
<<
597 " config_lineno = 0;" << std::endl
;
599 for (EntryList::const_iterator entry
= head
.begin(); entry
!= head
.end(); ++entry
) {
600 assert(entry
->name
.size());
602 if (!entry
->loc
.size())
605 if (entry
->defaults
.postscriptum
.empty())
608 if (entry
->ifdef
.size())
609 fout
<< "#if " << entry
->ifdef
<< std::endl
;
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
;
614 if (entry
->ifdef
.size())
615 fout
<< "#endif" << std::endl
;
618 fout
<< " cfg_filename = NULL;" << std::endl
<<
619 "}" << std::endl
<< std::endl
;
623 Entry::genParseAlias(const std::string
&aName
, std::ostream
&fout
) const
625 fout
<< " if (!strcmp(token, \"" << aName
<< "\")) {" << std::endl
;
627 fout
<< "#if " << ifdef
<< std::endl
;
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
;
635 fout
<< " parse_obsolete(token);";
636 } else if (!loc
.size() || loc
.compare("none") == 0) {
637 fout
<< "parse_" << type
<< "();";
639 fout
<< "parse_" << type
<< "(&" << loc
<< (array_flag
? "[0]" : "") << ");";
644 "#else" << std::endl
<<
645 " debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), \"ERROR: '" << name
<< "' requires " << available_if(ifdef
) << "\");" << std::endl
<<
646 "#endif" << std::endl
;
648 fout
<< " return 1;" << std::endl
;
649 fout
<< " };" << std::endl
;
653 Entry::genParse(std::ostream
&fout
) const
655 if (name
.compare("comment") == 0)
658 // Once for the current directive name
659 genParseAlias(name
, fout
);
661 // All accepted aliases
662 for (EntryAliasList::const_iterator a
= alias
.begin(); a
!= alias
.end(); ++a
) {
663 genParseAlias(*a
, fout
);
668 gen_parse(const EntryList
&head
, std::ostream
&fout
)
672 "parse_line(char *buff)\n"
675 "\tif ((token = strtok(buff, w_space)) == NULL) \n"
676 "\t\treturn 1;\t/* ignore empty lines */\n";
678 for (EntryList::const_iterator e
= head
.begin(); e
!= head
.end(); ++e
)
681 fout
<< "\treturn 0; /* failure */\n"
687 gen_dump(const EntryList
&head
, std::ostream
&fout
)
690 "static void" << std::endl
<<
691 "dump_config(StoreEntry *entry)" << std::endl
<<
693 " debugs(5, 4, HERE);" << std::endl
;
695 for (EntryList::const_iterator e
= head
.begin(); e
!= head
.end(); ++e
) {
697 if (!e
->loc
.size() || e
->loc
.compare("none") == 0)
700 if (e
->name
.compare("comment") == 0)
704 fout
<< "#if " << e
->ifdef
<< std::endl
;
706 fout
<< " dump_" << e
->type
<< "(entry, \"" << e
->name
<< "\", " << e
->loc
<< ");" << std::endl
;
709 fout
<< "#endif" << std::endl
;
712 fout
<< "}" << std::endl
<< std::endl
;
716 gen_free(const EntryList
&head
, std::ostream
&fout
)
719 "static void" << std::endl
<<
720 "free_all(void)" << std::endl
<<
722 " debugs(5, 4, HERE);" << std::endl
;
724 for (EntryList::const_iterator e
= head
.begin(); e
!= head
.end(); ++e
) {
725 if (!e
->loc
.size() || e
->loc
.compare("none") == 0)
728 if (e
->name
.compare("comment") == 0)
732 fout
<< "#if " << e
->ifdef
<< std::endl
;
734 fout
<< " free_" << e
->type
<< "(&" << e
->loc
<< (e
->array_flag
? "[0]" : "") << ");" << std::endl
;
737 fout
<< "#endif" << std::endl
;
740 fout
<< "}" << std::endl
<< std::endl
;
744 isDefined(const std::string
&name
)
749 for (int i
= 0; defines
[i
].name
; ++i
) {
750 if (name
.compare(defines
[i
].name
) == 0)
751 return defines
[i
].defined
;
758 available_if(const std::string
&name
)
762 for (int i
= 0; defines
[i
].name
; ++i
) {
763 if (name
.compare(defines
[i
].name
) == 0)
764 return defines
[i
].enable
;
771 gen_conf(const EntryList
&head
, std::ostream
&fout
, bool verbose_output
)
773 for (EntryList::const_iterator entry
= head
.begin(); entry
!= head
.end(); ++entry
) {
779 if (!entry
->name
.compare("comment"))
781 else if (!entry
->name
.compare("obsolete"))
783 else if (verbose_output
) {
784 fout
<< "# TAG: " << entry
->name
;
786 if (entry
->comment
.size())
787 fout
<< "\t" << entry
->comment
;
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
<<
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
;
809 if (entry
->defaults
.docs
.size()) {
810 // Display the DEFAULT_DOC line(s)
811 def
= entry
->defaults
.docs
;
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());
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());
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");
832 if (verbose_output
&& def
.size()) {
833 fout
<< "#Default:\n";
835 fout
<< "# " << def
.front() << std::endl
;
838 if (entry
->doc
.empty() && entry
->nocomment
.empty())
842 if (verbose_output
&& entry
->nocomment
.size())
843 fout
<< "#" << std::endl
;
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) != '#')
849 fout
<< *line
<< std::endl
;
853 if (verbose_output
&& entry
->doc
.size()) {