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