]> git.ipfire.org Git - thirdparty/squid.git/blame - scripts/www/build-cfg-help.pl
Bug 3130: helpers are crashing too rapidly
[thirdparty/squid.git] / scripts / www / build-cfg-help.pl
CommitLineData
c05220db 1#!/usr/bin/perl -w
2
3use strict;
4use IO::File;
5use Getopt::Long;
d3cf1774 6use File::Basename;
c05220db 7
8# This mess is designed to parse the squid config template file
9# cf.data.pre and generate a set of HTML pages to use as documentation.
10#
11# Adrian Chadd <adrian@squid-cache.org>
12#
262a0e14 13# $Id$
c05220db 14
15#
16# The template file is reasonably simple to parse. There's a number of
17# directives which delineate sections but there's no section delineation.
18# A section will "look" somewhat like this, most of the time:
19# NAME: <name>
20# IFDEF: <the ifdef bit>
21# TYPE: <the config type>
22# DEFAULT: <the default value>
c58a4b53 23# DEFAULT_IF_NONE: <alternative default value>
c05220db 24# LOC: <location in the Config struct>
25# DOC_START
26# documentation goes here
27# NOCOMMENT_START
28# stuff which goes verbatim into the config file goes here
29# NOCOMMENT_END
30# DOC_END
31#
32# Now, we can't assume its going to be nicely nested, so I'll say that
33# sections are delineated by NAME: lines, and then stuff is marked up
34# appropriately.
35#
36# Then we have to fake paragraph markups as well for the documentation.
37# We can at least use <PRE> type markups for the NOCOMMENT_START/_END stuff.
38
39#
40# Configuration sections are actually broken up by COMMENT_START/COMMENT_END
41# bits, which we can use in the top-level index page. Nifty!
42#
43
44# XXX NAME: can actually have multiple entries on it; we should generate
45# XXX a configuration index entry for each, linking back to the one entry.
46# XXX I'll probably just choose the first entry in the list.
47
48#
49# This code is ugly, but meh. We'll keep reading, line by line, and appending
50# lines into 'state' variables until the next NAME comes up. We'll then
51# shuffle everything off to a function to generate the page.
52
53
54my ($state) = "";
55my (%option);
56my (%all_names);
57my ($comment);
d3cf1774 58my (%defines);
c05220db 59
97a616ca 60my $version = "3.1.0";
c05220db 61my $verbose = '';
62my $path = "/tmp";
63my $format = "splithtml";
64my $pagetemplate;
65
66my ($index) = new IO::File;
67
d3cf1774 68my $top = dirname($0);
c05220db 69
70GetOptions(
71 'verbose' => \$verbose, 'v' => \$verbose,
72 'out=s' => \$path,
73 'version=s' => \$version,
74 'format=s' => \$format
75 );
76
77if ($format eq "splithtml") {
78 $pagetemplate = "template.html";
79} elsif ($format eq "singlehtml") {
80 $pagetemplate = "template_single.html";
81}
82
d3cf1774 83# Load defines
84my ($df) = new IO::File;
85
86$df->open("$top/../../src/cf_gen_defines", "r") || die;
87while(<$df>) {
88 $defines{$1} = $2 if /define\["([^"]*)"\]="([^"]*)"/;
89}
90close $df;
91undef $df;
92
c05220db 93# XXX should implement this!
94sub uriescape($)
95{
96 my ($line) = @_;
97 return $line;
98}
99
100sub filename($)
101{
102 my ($name) = @_;
103 return $path . "/" . $name . ".html";
104}
105
106sub htmlescape($)
107{
108 my ($line) = @_;
109 return "" if !defined $line;
590eb22f 110 $line =~ s/&/\&amp;/g;
111 $line =~ s/</\&lt;/g;
112 $line =~ s/>/\&gt;/g;
113 $line =~ s/[^\x{20}-\x{7e}\s]/sprintf ("&#%d;", ord ($1))/ge;
c05220db 114 return $line;
115}
116
117sub section_link($)
118{
119 return uriescape($_[0]).".html" if $format eq "splithtml";
120 return "#".$_[0] if $format eq "singlehtml";
121}
122
123sub toc_link($)
124{
125 return "index.html#toc_".uriescape($_[0]) if $format eq "splithtml";
126 return "#toc_".uriescape($_[0]) if $format eq "singlehtml";
127}
128
129sub alpha_link($)
130{
131 return "index_all.html#toc_".uriescape($_[0]);
132}
133
134#
135# Yes, we could just read the template file in once..!
136#
137sub generate_page($$)
138{
139 my ($template, $data) = @_;
140 my $fh;
141 my $fh_open = 0;
142 # XXX should make sure the config option is a valid unix filename!
143 if ($format eq "splithtml") {
144 my ($fn) = filename($data->{'name'});
145 $fh = new IO::File;
146 $fh->open($fn, "w") || die "Couldn't open $fn: $!\n";
147 $fh_open = 1;
148 } else {
149 $fh = $index;
150 }
151
d3cf1774 152 $data->{"ifdef"} = $defines{$data->{"ifdef"}} if (exists $data->{"ifdef"} && exists $defines{$data->{"ifdef"}});
c05220db 153
154 my ($th) = new IO::File;
155 $th->open($template, "r") || die "Couldn't open $template: $!\n";
156
157 # add in the local variables
158 $data->{"title"} = $data->{"name"};
159 $data->{"ldoc"} = $data->{"doc"};
160 $data->{"toc_link"} = toc_link($data->{"name"});
161 $data->{"alpha_link"} = alpha_link($data->{"name"});
162 if (exists $data->{"aliases"}) {
163 $data->{"aliaslist"} = join(", ", @{$data->{"aliases"}});
164 }
165 # XXX can't do this and then HTML escape..
166 # $data->{"ldoc"} =~ s/\n\n/<\/p>\n<p>\n/;
167 # XXX and the end-of-line formatting to turn single \n's into <BR>\n's.
168
169 while (<$th>) {
170 # Do variable substitution
171 s/%(.*?)%/htmlescape($data->{$1})/ge;
172 print $fh $_;
173 }
174 close $th;
175 undef $th;
176
177 if ($fh_open) {
178 close $fh;
179 undef $fh;
180 }
181}
182
183$index->open(filename("index"), "w") || die "Couldn't open ".filename("index").": $!\n" if ($format eq "splithtml");
184$index->open($path, "w") || die "Couldn't open ".filename("index").": $!\n" if ($format eq "singlehtml");
185print $index <<EOF
186<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
187<html xmlns="http://www.w3.org/1999/xhtml">
188<head>
50c3114d 189 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
c05220db 190 <title>Squid $version configuration file</title>
191 <meta name="keywords" content="squid squid.conf config configure" />
192 <meta name="description" content="Squid $version" />
a948a1b7 193 <link rel="stylesheet" type="text/css" href="http://www.squid-cache.org/default.css" />
194 <link rel="stylesheet" type="text/css" href="http://www.squid-cache.org/cfgman.css" />
c05220db 195</head>
196<body>
197EOF
198;
199
200
201my ($name, $data);
202my (@chained);
203
204my $in_options = 0;
0cb398b1 205sub start_option($$)
c05220db 206{
0cb398b1 207 my ($name, $type) = @_;
c05220db 208 if (!$in_options) {
209 print $index "<ul>\n";
210 $in_options = 1;
211 }
0cb398b1 212 return if $type eq "obsolete";
c05220db 213 print $index ' <li><a href="' . htmlescape(section_link($name)) . '" name="toc_' . htmlescape($name) . '">' . htmlescape($name) . "</a></li>\n";
214}
215sub end_options()
216{
217 return if !$in_options;
218 print $index "</ul>\n";
219 $in_options = 0;
220}
d3cf1774 221sub section_heading($)
222{
223 my ($comment) = @_;
224 print $index "<pre>\n";
225 print $index $comment;
226 print $index "</pre>\n";
227}
c05220db 228while (<>) {
229 chomp;
230 last if (/^EOF$/);
231 if ($_ =~ /^NAME: (.*)$/) {
232 my (@aliases) = split(/ /, $1);
233 $data = {};
234 $data->{'version'} = $version;
235 foreach (@aliases) {
236 $all_names{$_} = $data;
237 }
238
239 $name = shift @aliases;
240
241 $option{$name} = $data;
242 $data->{'name'} = $name;
243 $data->{'aliases'} = \@aliases;
244
c05220db 245 print "DEBUG: new option: $name\n" if $verbose;
246 } elsif ($_ =~ /^COMMENT: (.*)$/) {
247 $data->{"comment"} = $1;
248 } elsif ($_ =~ /^TYPE: (.*)$/) {
249 $data->{"type"} = $1;
0cb398b1 250 start_option($data->{"name"}, $data->{"type"});
c05220db 251 } elsif ($_ =~ /^DEFAULT: (.*)$/) {
252 if ($1 eq "none") {
253 $data->{"default"} = "$1";
254 } else {
255 $data->{"default"} = "$name $1";
256 }
c58a4b53
AJ
257 } elsif ($_ =~ /^DEFAULT_IF_NONE: (.*)$/) {
258 $data->{"default"} = "$name $1";
c05220db 259 } elsif ($_ =~ /^LOC:(.*)$/) {
260 $data->{"loc"} = $1;
261 $data->{"loc"} =~ s/^[\s\t]*//;
262 } elsif ($_ =~ /^DOC_START$/) {
263 $state = "doc";
264 } elsif ($_ =~ /^DOC_END$/) {
265 $state = "";
266 my $othername;
267 foreach $othername (@chained) {
268 $option{$othername}{'doc'} = $data->{'doc'};
269 }
270 undef @chained;
271 } elsif ($_ =~ /^DOC_NONE$/) {
272 push(@chained, $name);
273 } elsif ($_ =~ /^NOCOMMENT_START$/) {
274 $state = "nocomment";
275 } elsif ($_ =~ /^DEFAULT_IF_NONE: (.*)$/) {
276 $data->{"default_if_none"} = $1;
277 } elsif ($_ =~ /^NOCOMMENT_END$/) {
278 $state = "";
279 } elsif ($_ =~ /^IFDEF: (.*)$/) {
280 $data->{"ifdef"} = $1;
281 } elsif ($_ =~ /^#/ && $state eq "doc") {
282 $data->{"config"} .= $_ . "\n";
283 } elsif ($state eq "nocomment") {
284 $data->{"config"} .= $_ . "\n";
285 } elsif ($state eq "doc") {
286 $data->{"doc"} .= $_ . "\n";
287 } elsif ($_ =~ /^COMMENT_START$/) {
288 end_options;
289 $state = "comment";
290 $comment = "";
291 } elsif ($_ =~ /^COMMENT_END$/) {
d3cf1774 292 section_heading($comment);
c05220db 293 } elsif ($state eq "comment") {
294 $comment .= $_ . "\n";
295 } elsif (/^#/) {
296 next;
297 } elsif ($_ ne "") {
298 print "NOTICE: unknown line '$_'\n";
299 }
300}
301end_options;
c05220db 302print $index "<p><a href=\"index_all.html\">Alphabetic index</a></p>\n" if $format eq "splithtml";
303print $index "<p><a href=\"#index\">Alphabetic index</a></p>\n" if $format eq "singlehtml";
304print $index "<hr />\n" if $format eq "singlehtml";
305
306# and now, build the option pages
307my (@names) = keys %option;
308foreach $name (@names) {
76f44481 309 next if $option{$name}->{'type'} eq "obsolete";
d3cf1774 310 generate_page("${top}/${pagetemplate}", $option{$name});
c05220db 311}
312
313# and now, the alpabetic index file!
314my $fh;
315my $fh_open = 0;
316
317if ($format eq "splithtml") {
318 $fh = new IO::File;
319 my ($indexname) = filename("index_all");
320 $fh->open($indexname, "w") || die "Couldn't open $indexname for writing: $!\n";
321 $fh_open = 1;
322 print $fh <<EOF
323<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
324<html xmlns="http://www.w3.org/1999/xhtml">
325<head>
50c3114d 326 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
c05220db 327 <title>Squid $version configuration file</title>
328 <meta name="keywords" content="squid squid.conf config configure" />
329 <meta name="description" content="Squid $version" />
a948a1b7 330 <link rel="stylesheet" type="text/css" href="http://www.squid-cache.org/default.css" />
331 <link rel="stylesheet" type="text/css" href="http://www.squid-cache.org/cfgman.css" />
c05220db 332</head>
333<body>
334 <div id="header">
335 <div id="logo">
336 <h1><a href="http://www.squid-cache.org/"><span>Squid-</span>Cache.org</a></h1>
337 <h2>Optimising Web Delivery</h2>
338 </div>
339 </div>
340
341 <p>| <a href="index.html">Table of contents</a> |</p>
342
343 <h1>Alphabetic index of all options</h1>
344EOF
345;
346} elsif ($format eq "singlehtml") {
347 $fh = $index;
348 print $fh "<h2><a name=\"index\">Alphabetic index of all options</a></h2>\n";
349}
350
351print $fh "<ul>\n";
352
353foreach $name (sort keys %all_names) {
354 my ($data) = $all_names{$name};
76f44481 355 next if $data->{'type'} eq "obsolete";
c05220db 356 print $fh ' <li><a href="' . uriescape($data->{'name'}) . '.html" name="toc_' . htmlescape($name) . '">' . htmlescape($name) . "</a></li>\n";
357}
358
359print $fh "</ul>\n";
360if ($fh_open) {
361print $fh <<EOF
362 <p>| <a href="index.html">Table of contents</a> |</p>
363 </body>
364</html>
365EOF
366;
367$fh->close;
368}
369undef $fh;
370
371print $index <<EOF
372 </body>
373</html>
374EOF
375;
376$index->close;
377undef $index;