Annotation of htdocs/list2html.pl, Revision 1.27
1.1 abs 1: #!/usr/bin/env perl
2: #
1.27 ! soren 3: # $Id: list2html.pl,v 1.26 1999/10/28 23:31:17 abs Exp $
1.3 abs 4: # Process *.list files into indexed *.html files. (abs)
1.1 abs 5: # Looks for these compulsary tags:
6: # <LIST> Include generated list of entries here.
1.3 abs 7: # <SECTION>Text Introduces new section, before DATE or ENTRY
1.1 abs 8: # <ENDLIST> Optional tag for end of all special entries
9: #
1.3 abs 10: # Plus these optional tags: (You will probably want to use <DATE> or <ENTRY>)
1.2 abs 11: # <DATE>tag date Text Change entry, expanded to title & added to list
12: # <ENTRY>tag Text New entry, expanded to title and added to list
13: # <ENTRYLINK>url Text Link added to list, removed from main text
1.1 abs 14: # <HEADING>Text Standard heading at top of document
15: # <BASELINKS> Standard links at base of document
1.11 abs 16: # <TROW>Text: Text Table row, with two text fields
1.1 abs 17: #
18: # Continuation lines are understood (useful for the special tags)
1.6 abs 19: #
20: # Additional links:
21: # ([\w.+]+)\((\d)\) -> manpages eg: ls(1)
22: # <([-\w.]+@[-\w.]+)> -> email address eg: <user@host>
1.25 abs 23: # <PKGSRC>category/name -> link to pkgsrc README.html
1.9 abs 24: #
1.14 abs 25: # (c) 1999 DKBrownlee. All rights reserved. This file may be used to update
26: # the information on the NetBSD website. If you want to use it for any other
27: # purpose, ask me first.. abs@mono.org
1.9 abs 28: #
1.1 abs 29:
30: use strict;
1.21 abs 31: use Getopt::Std;
1.1 abs 32: $^W=1;
33: my($verbose,%extras,$months_previous);
1.21 abs 34: my($version,%opt);
1.1 abs 35:
1.8 abs 36: $months_previous=9; # previous months to display for DATE entries
37:
1.27 ! soren 38: $version='$Revision: 1.26 $';
1.21 abs 39: $version =~ /([\d.]+)/ && ($version=$1);
40:
41: if (!&getopts('a:m:hV',\%opt) || $opt{'h'} || ( !$opt{'V'} && @ARGV != 2) )
1.5 abs 42:
43: {
44: print "list2html.pl [opts] infile outfile
45: [opts] -a xxx Define 'arch=xxx' when linking to manpages
1.8 abs 46: -m xxx Set months to display for <DATE> (default $months_previous)
1.5 abs 47: -h This help.
1.21 abs 48: -V Display version and exit ($version - David Brownlee/abs)
1.5 abs 49:
1.25 abs 50: list2html.pl processes .list files into .html, parsing various special tags.
1.5 abs 51: .list files are intended to reduce the effort required to maintain files such
52: as FAQs, and change logs. More details given at the start of list2html.pl.
53: ";
54: exit;
55: }
1.21 abs 56: if ($opt{'V'})
57: { print "$version\n"; exit; }
1.5 abs 58:
1.1 abs 59: $verbose=1;
1.21 abs 60: if ($opt{'m'})
61: { $months_previous=$opt{'m'}; }
1.8 abs 62: $months_previous=&get_minmonth($months_previous);
1.1 abs 63:
64: %extras=(
65: '<HEADING>\s*(.*)','
66: <table><tr><td>
67: <a href="$HOME/Misc/daemon-copy.html">
1.22 itojun 68: <img align="center" src="$HOME/images/BSD-demon.jpg" border=0
1.19 abs 69: width=146 height=129 alt="BSD demon"></a>
1.1 abs 70: </td><td align=center>
71: <h1>NetBSD Documentation:</h1>
72: <h1>$TITLE</h1>
73: </td></tr></table>
74: <p>
75: ', '<BASELINKS>','
76: <table width="100%"><tr>
77: <td>
78: <table><tr>
79: <td>
80: <a href="$HOME/index.html">
1.22 itojun 81: <img src="$HOME/images/NetBSD-banner.jpg" width=91 height=42
1.23 darcy 82: border="0" alt="NetBSD Home"></a>
1.1 abs 83: </td><td>
84: <a href="$HOME/index.html">Home Page</a>
85: </td>
86: </tr></table>
87: </td><td>
88: <table><tr>
89: <td>
90: <a href="$DOCUMENTATION/index.html"> <img
1.22 itojun 91: src="$HOME/images/NetBSD-banner.jpg" width=91 height=42
1.23 darcy 92: alt="NetBSD Documentation"
93: border="0"></a>
1.1 abs 94: </td><td>
95: <a href="$DOCUMENTATION/index.html">Documentation top level</a>
96: </td>
97: </tr></table>
98: </td>
99: </tr></table>
100: '
101: );
102:
103: # XXX Should DTRT with faqs not under Documentation
104:
1.3 abs 105: &makelist(@ARGV,&extras_generate(%extras));
1.1 abs 106: exit;
107:
1.5 abs 108: sub check_date
109: {
110: my($date)=@_;
111: my($month,$when);
112: my(%months)=('Jan' => 1, 'Feb' => 2, 'Mar' => 3,
113: 'Apr' => 4, 'May' => 5, 'Jun' => 6,
114: 'Jul' => 7, 'Aug' => 8, 'Sep' => 9,
115: 'Oct' => 10, 'Nov' => 11, 'Dec' => 12 );
116:
117: if ($date !~ /(\S+)\s*(\d+)/)
118: { &fail("Unable to parse date '$date'"); }
119: if (!defined($month=$months{$1}))
120: {
121: &warn("Unable to parse month '$1'");
122: $month=12;
123: }
124: $when=sprintf("%04d%02d",$2,$month);
125: ( $when>$months_previous );
126: }
127:
1.24 abs 128: sub extract_tags
129: {
130: my($file,@tags)=@_;
131: my($tag,%map);
132:
133: if (!open(FILE,$file))
134: { return(undef); }
135: while (<FILE>)
136: {
137: foreach $tag (@tags)
138: {
139: if ( /($tag)/ )
140: { $map{$tag}=$1; }
141: }
142: }
143: close(FILE);
144: %map;
145: }
146:
1.5 abs 147: sub extras_generate
148: {
149: my(%extras)=@_;
150: my($pathtodoc,$str);
151:
152: if( $0 !~ m#(.*)/[^/]+.pl# )
153: { &fail("Unable to extract path from '$0'"); }
154: $pathtodoc="$1/Documentation";
155: foreach $str ( keys %extras )
156: {
157: $extras{$str} =~ s#\$HOME#$pathtodoc/..#g;
158: $extras{$str} =~ s#\$DOCUMENTATION#$pathtodoc#g;
159: }
160: (%extras);
161: }
162:
163: sub extras_process
164: {
165: my($data,%extras)=@_;
166: my($key,$title,$value);
167:
168: foreach $key ( keys %extras )
169: {
170: $value=$extras{$key};
171: if( $data =~ /$key/ )
172: {
173: if( defined($1) )
174: {
175: $title=$1;
176: $value=~s#\$TITLE#$title#g;
177: }
178: $data=~s/$key.*/$value/;
179: }
180: }
181: $data;
182: }
183:
184: sub fail
185: {
186: print STDERR "ABORTING: ",@_,"\n";
187: exit 3
188: }
189:
1.8 abs 190: sub get_minmonth
191: {
192: my($monthsback)=@_;
193: my($year,$month);
194:
195: ($month,$year)=(localtime(time))[4,5];
196:
197: ++$month;
198: $month-=$monthsback;
199: while( $month<1 )
200: {
201: $month+=12;
202: --$year;
203: }
204: sprintf("%04d%02d",$year+1900,$month);
205: }
206:
1.17 abs 207: # Collect $list containing forward links as we go. In general each entry will
208: # generate something in $list and some expanded data in the main $data.
209: #
1.3 abs 210: sub makelist
1.1 abs 211: {
212: my($infile,$outfile,%extras)=@_;
213: my($data,$section,$href,$header,$list,$pre,%tags,$date_month);
1.2 abs 214: my($date_num,$date_num_used,$entry_num,$ignore,$in_entry,$endlist);
1.18 abs 215: my($title_font) = "<font face=\"helvetica, arial, sans-serif\">";
216: my($end_title_font) = "</font>";
1.24 abs 217: my(%rcsmap)=&extract_tags($outfile,'\$NetBSD.*\$');
218: my($rcstag);
1.1 abs 219:
1.7 abs 220: $list='';
1.1 abs 221:
222: $data=$date_month='';
223: $entry_num=$date_num=$date_num_used=0;
224: open(FILE,$infile) || die("Unable to open '$infile': $!");
225: foreach( <FILE> )
226: {
1.24 abs 227: foreach $rcstag (%rcsmap)
228: { s/$rcstag/$rcsmap{$rcstag}/; }
1.16 abs 229: if( defined($pre) ) # Handle continuation lines
1.1 abs 230: { $_=$pre.$_; $pre=undef; }
1.2 abs 231:
1.16 abs 232: if( substr($_,-2) eq "\\\n" ) # Handle continuation lines
1.1 abs 233: {
234: s/\\\n$//;
235: $pre=$_;
236: next;
237: }
238:
239: if( m#^<DATE>\s*(.+\S)# ) # Changes
240: {
241: my($year,$month,$link);
242:
1.2 abs 243: if ($in_entry)
244: {
245: $data.="</dd></dl></p>\n";
246: $in_entry=undef;
247: }
1.1 abs 248: $ignore=undef;
249: ++$date_num;
250: $header=$1;
1.2 abs 251: if( $header !~ /^([-a-z0-9_.+]+)\s+(\d+) (\S+) (\d+) - (\S.*)/ )
1.1 abs 252: { &fail("'$header' not in expected 'date - event' format"); }
253: $href=$1;
1.2 abs 254: $header="$5 ($2 $3)";
255: $month="$3 $4";
256: $link=$5;
1.1 abs 257: if( defined($tags{$href}) )
258: { &fail("Duplicate name tag '$href'"); }
259: $tags{$href}=1;
260: if (!&check_date($month))
261: { $ignore=1; }
262: else
263: {
1.2 abs 264: $_='';
1.1 abs 265: ++$date_num_used;
266: if( $month ne $date_month )
267: {
268: if( $date_month ne '' )
1.18 abs 269: { $list.="</ul>$end_title_font\n"; }
270: $list.="<h3>$month</h3>\n$title_font<ul>\n";
1.2 abs 271: $_.="<hr><h2>$month</h2><hr>\n";
1.1 abs 272: $date_month=$month;
273: }
274:
1.18 abs 275: $_.= "<p><dl><dt>\n$title_font".
1.2 abs 276: "<h3><a name=\"$href\">$header</a> <font size=\"-1\">".
1.18 abs 277: "(<a href=\"#top\">top</a>)</font></h3>\n".
278: "$end_title_font\n</dt><dd>";
1.1 abs 279: $list.="<li><a href=\"#$href\">$link</a></li>\n";
1.7 abs 280: $in_entry=1;
1.1 abs 281: }
282: }
1.2 abs 283:
284: elsif( m#^<ENTRY>\s*(.+\S)# )
1.1 abs 285: {
1.2 abs 286: if ($in_entry)
287: {
288: $data.="</dd></dl></p>\n";
289: $in_entry=undef;
290: }
1.25 abs 291:
1.1 abs 292: $ignore=undef;
293: ++$entry_num;
294: if( !defined($section) )
1.2 abs 295: { &fail("<ENTRY> before <SECTION> tag"); }
1.1 abs 296: $_=$1;
1.20 abs 297: if( ! /^([-a-z0-9_.+,]+)\s+(.*)/ )
298: { &fail("Invalid <ENTRY> ($_), not ([-a-z0-9_.+,]+)\s+(.*)"); }
1.1 abs 299: $href=$1;
300: $header=$2;
1.2 abs 301: if( defined($tags{$href}) )
302: { &fail("Duplicate name tag '$href'"); }
303: $tags{$href}=1;
1.1 abs 304:
1.15 abs 305: $_ = "<p><dl><dt>\n$title_font".
1.2 abs 306: "<h3><a name=\"$href\">$header</a>\n<font size=\"-1\">".
1.15 abs 307: "(<a href=\"#top\">top</a>)</font></h3>$end_title_font\n".
308: "</dt><dd>\n";
309: $list.="<li><a href=\"#$href\">".
1.18 abs 310: "$header".
1.15 abs 311: "</a></li>\n";
1.2 abs 312: $in_entry=1;
1.1 abs 313: &verbose("\t$href\n");
314: }
1.2 abs 315:
316: elsif( m#^<ENTRYLINK>\s*(.+\S)# )
1.1 abs 317: {
318: $ignore=undef;
319: ++$entry_num;
320: if( !defined($section) )
1.2 abs 321: { &fail("<ENTRYLINK> before <SECTION> tag"); }
1.1 abs 322: $_=$1;
1.2 abs 323: if( ! m#^(\S+)\s+(.*)# )
324: { &fail("Invalid <ENTRYLINK> ($_), not (\S+)\s+(.*)"); }
1.1 abs 325: $href=$1;
326: $header=$2;
1.2 abs 327: $_ = '';
328: $list.="<li><a href=\"$href\">$header</a></li>\n";
1.1 abs 329: &verbose("\t$href\n");
330: }
1.2 abs 331:
1.1 abs 332: elsif( m#^<SECTION>\s*(.+\S)# )
333: {
1.2 abs 334: if ($in_entry)
335: {
336: $data.="</dd></dl></p>\n";
337: $in_entry=undef;
338: }
1.7 abs 339: else # In case no entries
340: { $data =~ s#<hr>\n<h2>.*</h2><hr>\n*$##; }
1.1 abs 341: $ignore=undef;
342: if( defined($section) )
1.16 abs 343: {
1.18 abs 344: $list.="</ul>$end_title_font\n";
1.16 abs 345: $section=$1;
1.18 abs 346: $list.="<h2>$section</h2>\n$title_font<ul>\n";
1.16 abs 347: }
348: else
1.17 abs 349: { # If we have never seen <SECTION> remember top link!
1.16 abs 350: $section=$1;
1.18 abs 351: $list.="<h2><a name=\"top\">$section</a></h2>\n".
352: "$title_font<ul>\n";
1.16 abs 353: }
1.2 abs 354: $_="<hr>\n<h2>$section</h2><hr>";
1.1 abs 355: &verbose(" $section\n");
1.11 abs 356: }
357: elsif( m#^<TROW>\s*(.*)# )
358: {
359: $_=$1;
360: if( ! m#^([^:]+:)\s+(.*)# )
361: { &fail("<TROW> should match ([^:]+:)\s+(.*)"); }
362: $ignore=undef;
1.12 abs 363: $_ = "<tr><th valign=top align=right>$1</th>\n <td>$2</td></tr>";
1.1 abs 364: }
1.2 abs 365:
1.1 abs 366: elsif( m#^<ENDLIST># )
367: {
1.2 abs 368: if ($in_entry)
369: {
370: $data.="</dd></dl></p>\n";
371: $in_entry=undef;
372: }
373: if ($endlist)
374: { &fail("Duplicate <ENDLIST>"); }
375: $endlist=1;
1.1 abs 376: $ignore=undef;
1.3 abs 377: $_="<hr>\n";
1.1 abs 378: }
1.2 abs 379:
1.4 abs 380: # Foul hack to avoid incorrect installboot(8) references
381: # May fail valid links also. Only until i386 vs alpha manpage resolved.
1.5 abs 382: if( ! $ignore )
383: { $data.=&sub_external_links($_); }
1.1 abs 384: }
385:
386: close(FILE);
1.18 abs 387: $list.="</ul>$end_title_font\n";
1.2 abs 388: if (!$endlist)
389: { &fail("Missing <ENDLIST> tag"); }
390: if ($data !~ s/<LIST>/$list/)
1.1 abs 391: { &fail("Unable to locate <LIST> tag"); }
1.7 abs 392: $_="\n\n<!-- DO NOT EDIT THIS FILE. EDIT '$infile' AND RUN 'make' -->\n";
393: if ($data !~ s/(<head[^>]*>)/$1$_/i)
394: { &fail("Unable to locate <head> tag"); }
395:
1.1 abs 396: open(FILE,">$outfile") || die("Unable to write '$outfile': $!");
397: print FILE &extras_process($data,%extras);
398: close(FILE);
399: if( $date_num )
400: {
401: print "$date_num date entr",($date_num==1)?'y':'ies';
402: if ($date_num_used != $date_num)
403: { print " ($date_num_used used)"; }
404: print ".\n";
405: }
406: if( $entry_num )
407: { print "$entry_num entr",($entry_num==1)?'y':'ies',".\n"; }
408: }
409:
1.5 abs 410: sub sub_external_links
1.1 abs 411: {
1.5 abs 412: my($text)=@_;
413: my($link);
1.1 abs 414:
1.5 abs 415: $link='http://www.flame.org/cgi-bin/uncgi/hman?';
1.1 abs 416:
1.21 abs 417: if ($opt{'a'})
418: { $link.="arch=$opt{'a'}&"; }
1.10 abs 419:
420: # Man page references. As of 1.4 matches every page except '[' and 'w'.
421: #
1.5 abs 422: $text =~
1.10 abs 423: s#([a-zA-Z_][-\w.+]*[\w+])\((\d)\)#<a href="${link}page=$1&sect=$2">$1($2)</a>#g;
1.25 abs 424:
1.27 ! soren 425: # Expand <PKGSRC>category/name entries
1.25 abs 426: #
1.26 abs 427: $text =~ s#<PKGSRC>((\w+/|)([^\s<>]+\w))#<a href="ftp://ftp.netbsd.org/pub/NetBSD/packages/pkgsrc/$1/README.html">$3</a>#g;
1.25 abs 428:
1.10 abs 429: # Expand <user@host> email addresses
430: #
1.13 abs 431: $text =~ s#<([-\w.]+@[-\w.]+)>#<a href="mailto:$1"><$1></a>#g;
1.25 abs 432:
1.5 abs 433: $text;
1.1 abs 434: }
435:
436: sub verbose
437: { $verbose && print @_; }
1.8 abs 438:
439: sub warn
440: { print "WARNING: ",@_; }
CVSweb <webmaster@jp.NetBSD.org>