3 #=======================================================================
5 # File ID: 9f049aca-5d3b-11df-8f49-90e6ba3022ac
10 # ©opyleft 2002– Øyvind A. Holm <sunny@sunbase.org>
11 # License: GNU General Public License version 2 or later, see end of
12 # file for legal stuff.
13 #=======================================================================
34 $progname =~ s/^.*\/(.*?)$/$1/;
35 our $VERSION = '0.1.0';
37 Getopt
::Long
::Configure
('bundling');
40 'all|a' => \
$Opt{'help'},
41 'help|h' => \
$Opt{'help'},
42 'no-number|n' => \
$Opt{'no-number'},
43 'quiet|q+' => \
$Opt{'quiet'},
44 'startlevel|l=i' => "",
45 'verbose|v+' => \
$Opt{'verbose'},
46 'version' => \
$Opt{'version'},
48 ) || die("$progname: Option error. Use -h for help.\n");
50 $Opt{'verbose'} -= $Opt{'quiet'};
51 $Opt{'help'} && usage
(0);
52 if ($Opt{'version'}) {
65 my @header_num = qw{0};
70 if ($Opt{'startlevel'} =~ /^\d+$/) {
71 if ($Opt{'startlevel'} < 1) {
72 die("$progname: Number passed to -l has to be bigger than zero\n");
74 $start_level = $Opt{'startlevel'};
77 die("$progname: -l wants a number\n")
83 if (!/ nohhi /i && /^(.*)<(h)(\d+)(.*?)>(.*)$/i) {
85 my ($Pref, $H, $header_level, $Elem, $Rest) = ($1, $2, $3, $4, $5);
86 if ($header_level >= $start_level) {
88 splice(@header_num, $header_level-1)
89 if ($header_level < $last_level);
90 if ($header_level - $last_level > 1) {
91 warn("$progname: Line $.: Header skip " .
92 "($last_level to $header_level)\n");
93 for (my $Tmp = 0; $Tmp < $header_level-2; $Tmp++) {
94 defined($header_num[$Tmp]) || ($header_num[$Tmp] = "");
97 $header_num[$header_level-2]++;
98 my $tall_str = join(".", @header_num);
99 my $name_str = ($Rest =~ /<!-- hhiname (\S+) -->/i)
103 if (defined($name_used{$name_str})) {
104 warn("$progname: Line $.: \"$name_str\": " .
105 "Section name already used\n");
107 $name_used{$name_str} = 1;
109 if ($Rest =~ m
#^(<a (name|id)=".*?">[\d\.]+</a>\s+)(.*?)$#i) {
111 } elsif ($Rest =~ m
#^([\d\.]+)\s*(.*?)$#i) {
114 ($tall_str .= ".") if ($header_level == 2);
115 if ($Opt{'no-number'} || $Rest =~ /<!-- nohhinum -->/i) {
117 $_ = "${Pref}<${H}${header_level}${Elem}>$Rest\n";
119 $_ = "${Pref}<${H}${header_level}${Elem}>" .
120 "<a id=\"$name_str\">$tall_str</a> $Rest\n";
122 if (!/<!-- nohhitoc -->/i || $Opt{'all'}) {
123 push(@Toc, $skip_num ?
"<${H}${header_level}${Elem}>$Rest"
124 : "<${H}${header_level}${Elem}>" .
125 "<b><a href=\"#$name_str\">" .
126 "$tall_str</a></b> $Rest");
128 $last_level = $header_level;
132 } elsif (/<!-- hhitoc -->/i) {
133 # Contents area found, skip everything until a "<!-- /hhitoc
140 if (m
#<!-- /hhitoc -->#i) {
146 $Found && die("$progname: Line $line_num: " .
147 "Missing terminating <!-- /hhitoc -->\n");
155 for my $Line (@Data) {
156 # Send everything to stdout with optional contents inserted {{{
157 if ($Line =~ /^(\s*)(<!-- hhitoc -->)(.*)$/i) {
158 my ($Indent, $HT, $End) = ($1, $2, $3);
159 print("$Line$Indent<ul>\n$Indent<!-- \x7B\x7B\x7B -->\n");
161 my ($Cnt, $Txt) = (0, "");
165 if (/<h(\d+).*?>(.*)<\/h\d
+>/i
) {
166 ($Cnt, $Txt) = ($1, $2);
167 my $Diff = $Cnt-$Old;
168 $Ex = ""; # "\t" x $Cnt; # FIXME: Temporary disabled
170 if ($Old && $Diff > 0) {
171 for (my $T = $Diff; $T; $T--) {
172 print("$Indent$Ex<ul>\n");
174 } elsif ($Old && $Diff < 0) {
175 print("$Indent$Ex</li>\n");
176 for (my $T = $Diff; $T; $T++) {
177 print("$Indent$Ex</ul>\n$Indent$Ex</li>\n");
180 print("$Indent$Ex</li>\n");
182 print("$Indent$Ex<li><span>$Txt</span>\n");
187 for (; $Cnt > 1; $Cnt--) {
188 msg
(2, "Cnt = \"$Cnt\"\n");
189 print("$Indent$Ex</li>\n");
190 ($Cnt == 2) && print("$Indent<!-- \x7D\x7D\x7D -->\n");
191 print("$Indent$Ex</ul>\n");
204 # Print program version {{{
205 print("$progname $VERSION\n");
211 # Send the help message to stdout {{{
214 if ($Opt{'verbose'}) {
220 Usage: $progname [options] [file [files [...]]]
222 Parses HTML source and creates section numbers in headers and inserts a
223 table of contents in a defined area. Refer to the POD at the end of the
224 Perl file for complete info.
229 Include all headers in the table of contents, even those marked with
234 Start indexing at this level number. Default: 2.
238 Be more quiet. Can be repeated to increase silence.
240 Increase level of verbosity. Can be repeated.
242 Print version information.
250 # Print a status message to stderr based on verbosity level {{{
251 my ($verbose_level, $Txt) = @_;
253 if ($Opt{'verbose'} >= $verbose_level) {
254 print(STDERR
"$progname: $Txt\n");
262 # Plain Old Documentation (POD) {{{
268 hhi - Html Header Indexer
272 hhi [options] [file [files [...]]]
276 The hhi(1) command (re)numbers the headers of HTML source and is able to
277 create a table of contents in a defined area.
278 Lines containing C<E<lt>!-- nohhi --E<gt>> will be ignored and lines
279 containg C<E<lt>!-- nohhitoc --E<gt>> will be numbered, but not included
281 An optional table of contents will be included between the lines
286 Any text between those two lines will be replaced.
288 Every header will be have an index number inserted into the beginning of
289 the header title, e.g.:
291 <h1>Header of document</h1>
292 <h2>Table of contents</h2> <!-- nohhi -->
295 <h2>Subsection #1</h2>
296 <h3>Subsubsection #1.1</h3>
297 <h4>Header excluded from the index</h4> <!-- nohhitoc -->
298 <h2>Subsection #2</h2>
299 <h2>Section with specified name</h2> <!-- hhiname secname -->
303 <h1>Header of document</h1>
304 <h2>Table of contents</h2> <!-- nohhi -->
307 <li><b><a href="#h-1">1.</a></b> Subsection #1
309 <li><b><a href="#h-1.1">1.1</a></b> Subsubsection #1.1
313 <li><b><a href="#h-2">2.</a></b> Subsection #2
315 <li><b><a href="#secname">3.</a></b> Section with specified name
319 <h2><a id="h-1">1.</a> Subsection #1</h2>
320 <h3><a id="h-1.1">1.1</a> Subsubsection #1.1</h3>
321 <h4><a id="h-1.1.1">1.1.1</a> Header excluded from the index</h4> <!-- nohhitoc -->
322 <h2><a id="h-2">2.</a> Subsection #2</h2>
323 <h2><a id="secname">3.</a> Section with specified name</h2> <!-- hhiname secname -->
325 To avoid creation of names like I<1.2..4>, header levels should not be
326 skipped, do not let a E<lt>h4E<gt> follow a E<lt>h2E<gt> without a
327 E<lt>h3E<gt> in between.
333 =item B<-a>, B<--all>
335 Include all headers in the contents, even those marked with S<E<lt>!--
338 =item B<-l x>, B<--startlevel x>
340 Start indexing at level x.
341 Default value is 2, leaving E<lt>h1E<gt> headers untouched.
343 ==item B<-n>, B<--no-number>
345 Don’t insert section numbers into headers.
355 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
359 Copyleft ©2002- Øyvind A. Holm E<lt>sunny@sunbase.orgE<gt>
360 This is free software; see the file F<COPYING> for legalese stuff.
364 This program is free software: you can redistribute it and/or modify it
365 under the terms of the GNU General Public License as published by the
366 Free Software Foundation, either version 2 of the License, or (at your
367 option) any later version.
369 This program is distributed in the hope that it will be useful, but
370 WITHOUT ANY WARRANTY; without even the implied warranty of
371 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
372 See the GNU General Public License for more details.
374 You should have received a copy of the GNU General Public License along
376 If not, see L<http://www.gnu.org/licenses/>.
384 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :