comparison misc/man2html @ 0:c7f6b056b673

First import of vendor version
author Peter Gervai <grin@grin.hu>
date Tue, 10 Mar 2009 13:49:58 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:c7f6b056b673
1 #! /usr/bin/perl
2 ##---------------------------------------------------------------------------##
3 ## File:
4 ## @(#) man2html 1.2 97/08/12 12:57:30 @(#)
5 ## Author:
6 ## Earl Hood, ehood@medusa.acs.uci.edu
7 ## Description:
8 ## man2html is a Perl program to convert formatted nroff output
9 ## to HTML.
10 ##
11 ## Recommend command-line options based on platform:
12 ##
13 ## Platform Options
14 ## ---------------------------------------------------------------------
15 ## c2mp <None, the defaults should be okay>
16 ## hp9000s700/800 -leftm 1 -topm 8
17 ## sun4 -sun
18 ## ---------------------------------------------------------------------
19 ##
20 ##---------------------------------------------------------------------------##
21 ## Copyright (C) 1995-1997 Earl Hood, ehood@medusa.acs.uci.edu
22 ##
23 ## This program is free software; you can redistribute it and/or modify
24 ## it under the terms of the GNU General Public License as published by
25 ## the Free Software Foundation; either version 2 of the License, or
26 ## (at your option) any later version.
27 ##
28 ## This program is distributed in the hope that it will be useful,
29 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
30 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 ## GNU General Public License for more details.
32 ##
33 ## You should have received a copy of the GNU General Public License
34 ## along with this program; if not, write to the Free Software
35 ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
36 ## 02111-1307, USA
37 ##---------------------------------------------------------------------------##
38
39 package Man2Html;
40
41 use Getopt::Long;
42
43 ($PROG = $0) =~ s/.*\///;
44 $VERSION = "3.0.1";
45
46 ## Input and outputs filehandles
47 $InFH = \*STDIN unless $InFH;
48 $OutFH = \*STDOUT unless $OutFH;
49
50 ## Backspace character: Used in overstriking detection
51 *bs = \"\b";
52
53 ## Hash of section titles and their HTML tag wrapper.
54 ## This list allows customization of what HTML tag is used for
55 ## a given section head.
56 ##
57 ## The section title can be a regular expression. Therefore, one must
58 ## be careful about quoting special characters.
59 ##
60 %SectionHead = (
61
62 '\S.*OPTIONS.*' => '<H2>',
63 'AUTHORS?' => '<H2>',
64 'BUGS' => '<H2>',
65 'COMPATIBILITY' => '<H2>',
66 'DEPENDENCIES' => '<H2>',
67 'DESCRIPTION' => '<H2>',
68 'DIAGNOSTICS' => '<H2>',
69 'ENVIRONMENT' => '<H2>',
70 'ERRORS' => '<H2>',
71 'EXAMPLES' => '<H2>',
72 'EXTERNAL INFLUENCES' => '<H2>',
73 'FILES' => '<H2>',
74 'LIMITATIONS' => '<H2>',
75 'NAME' => '<H2>',
76 'NOTES?' => '<H2>',
77 'OPTIONS' => '<H2>',
78 'REFERENCES' => '<H2>',
79 'RETURN VALUE' => '<H2>',
80 'SECTION.*:' => '<H2>',
81 'SEE ALSO' => '<H2>',
82 'STANDARDS CONFORMANCE' => '<H2>',
83 'STYLE CONVENTION' => '<H2>',
84 'SYNOPSIS' => '<H2>',
85 'SYNTAX' => '<H2>',
86 'WARNINGS' => '<H2>',
87 '\s+Section.*:' => '<H3>',
88
89 );
90
91 ## Fallback tag if above is not found
92 $HeadFallback = '<H2>';
93
94 ## Other gobals
95
96 $Bare = 0; # Skip printing HTML head/foot flag
97 $BTag = 'B'; # Overstrike tag
98 $CgiUrl = ''; # CGI URL expression
99 $Compress = 0; # Do blank line compression flag
100 $K = 0; # Do keyword search processing flag
101 $NoDepage = 0; # Do not strip page information
102 $NoHeads = 0; # Do no header detection flag
103 $SeeAlso = 0; # Do only SEE ALSO xrefs flag
104 $Solaris = 0; # Solaris keyword search processing flag
105 $Sun = 0; # Headers not overstriken flag
106 $Title = 'FIX ME'; # Title
107 $UTag = 'I'; # Underline tag
108 $ftsz = 7; # Bottome margin size
109 $hdsz = 7; # Top margin size
110 $leftm = ''; # Left margin pad
111 $leftmsz = 0; # Left margin size
112 $pgsz = 66; # Size of page size
113 $txsz = 52; # Text body length size
114
115 #############################################################################
116 ## Main Block
117 #############################################################################
118 {
119 if (get_cli_opts()) {
120 if ($K) {
121 man_k();
122 } else {
123 do_it();
124 }
125 } else {
126 usage();
127 }
128 }
129
130 #############################################################################
131 ## Subroutines
132 #############################################################################
133
134 sub do_it {
135
136 ## Define while loop and then eval it when used. The reason
137 ## is to avoid the regular expression reevaulation in the
138 ## section head detection code.
139
140 $doitcode =<<'EndOfDoItCode';
141
142 my($line, $tmp, $i, $head, $preindent, $see_also, $do);
143
144 $see_also = !$SeeAlso;
145 print $OutFH "<!-- Manpage converted by man2html $VERSION -->\n";
146 LOOP: while(!eof($InFH)) {
147 $blank = 0;
148 for ($i=0; $i < $hdsz; $i++) {
149 last LOOP unless defined($_ = <$InFH>);
150 }
151 for ($i=0; $i < $txsz; $i++) {
152 last LOOP unless defined($_ = <$InFH>);
153
154 ## Check if compress consecutive blank lines
155 if ($Compress and !/\S/) {
156 if ($blank) { next; } else { $blank = 1; }
157 } else {
158 $blank = 0;
159 }
160
161 ## Try to check if line space is needed at page boundaries ##
162 if (!$NoDepage && ($i==0 || $i==($txsz-1)) && !/^\s*$/) {
163 /^(\s*)/; $tmp = length($1);
164 if ($do) {
165 if ($tmp < $preindent) { print $OutFH "\n"; }
166 } else {
167 $do = 1;
168 }
169 $preindent = $tmp;
170 } else {
171 $do = 0; $preindent = 0;
172 }
173
174 ## Interpret line
175 $line = $_;
176 entitize(\$_); # Convert [$<>] to entity references
177
178 ## Check for 'SEE ALSO' link only
179 if (!$see_also && $CgiUrl && $SeeAlso) {
180 ($tmp = $line) =~ s/.\010//go;
181 if ($tmp =~ /^\s*SEE\s+ALSO\s*$/o) { $see_also = 1; }
182 else { $see_also = 0; }
183 }
184
185 ## Create anchor links for manpage references
186 s/((((.\010)+)?[\+_\.\w-])+\(((.\010)+)?
187 \d((.\010)+)?\w?\))
188 /make_xref($1)
189 /geox if $see_also;
190
191 ## Emphasize underlined words
192 # s/((_\010[^_])+[\.\(\)_]?(_\010[^_])+\)?)/emphasize($1)/oge;
193 # s/((_\010[^_])+([\.\(\)_]?(_\010[^_])+)?)/emphasize($1)/oge;
194 #
195 # The previous expressions were trying to be clever about
196 # detecting underlined text which contain non-alphanumeric
197 # characters. nroff will not underline non-alphanumeric
198 # characters in an underlined phrase, and the above was trying
199 # to detect that. It does not work all the time, and it
200 # screws up other text, so a simplified expression is used.
201
202 s/((_\010[^_])+)/emphasize($1)/oge;
203
204 $secth = 0;
205 ## Check for strong text and headings
206 if ($Sun || /.\010./o) {
207 if (!$NoHeads) {
208 $line =~ s/.\010//go;
209 $tmp = $HeadFallback;
210 EndOfDoItCode
211
212 ## Create switch statement for detecting a heading
213 ##
214 $doitcode .= "HEADSW: {\n";
215 foreach $head (keys %SectionHead) {
216 $doitcode .= join("", "\$tmp = '$SectionHead{$head}', ",
217 "\$secth = 1, last HEADSW ",
218 "if \$line =~ /^$leftm$head/o;\n");
219 }
220 $doitcode .= "}\n";
221
222 ## Rest of routine
223 ##
224 $doitcode .=<<'EndOfDoItCode';
225 if ($secth || $line =~ /^$leftm\S/o) {
226 chop $line;
227 $_ = $tmp . $line . $tmp;
228 s%<([^>]*)>$%</$1>%;
229 $_ = "\n</PRE>\n" . $_ . "<PRE>\n";
230 } else {
231 s/(((.\010)+.)+)/strongize($1)/oge;
232 }
233 } else {
234 s/(((.\010)+.)+)/strongize($1)/oge;
235 }
236 }
237 print $OutFH $_;
238 }
239
240 for ($i=0; $i < $ftsz; $i++) {
241 last LOOP unless defined($_ = <$InFH>);
242 }
243 }
244 EndOfDoItCode
245
246
247 ## Perform processing.
248
249 printhead() unless $Bare;
250 print $OutFH "<PRE>\n";
251 eval $doitcode; # $doitcode defined above
252 print $OutFH "</PRE>\n";
253 printtail() unless $Bare;
254 }
255
256 ##---------------------------------------------------------------------------
257 ##
258 sub get_cli_opts {
259 return 0 unless
260 GetOptions(
261 "bare", # Leave out HTML, HEAD, BODY tags.
262 "belem=s", # HTML Element for overstriked text (def: "B")
263 "botm=i", # Number of lines for bottom margin (def: 7)
264 "cgiurl=s", # CGI URL for linking to other manpages
265 "cgiurlexp=s", # CGI URL Perl expr for linking to other manpages
266 "compress", # Compress consecutive blank lines
267 "headmap=s", # Filename of user section head map file
268 "k", # Process input from 'man -k' output.
269 "leftm=i", # Character width of left margin (def: 0)
270 "nodepage", # Do not remove pagination lines
271 "noheads", # Do not detect for section heads
272 "pgsize=i", # Number of lines in a page (def: 66)
273 "seealso", # Link to other manpages only in the SEE ALSO section
274 "solaris", # Parse 'man -k' output from a solaris system
275 "sun", # Section heads are not overstriked in input
276 "title=s", # Title of manpage (def: Not defined)
277 "topm=i", # Number of lines for top margin (def: 7)
278 "uelem=s", # HTML Element for underlined text (def: "I")
279
280 "help" # Short usage message
281 );
282 return 0 if defined($opt_help);
283
284 $pgsz = $opt_pgsize || $pgsz;
285 if (defined($opt_nodepage)) {
286 $hdsz = 0;
287 $ftsz = 0;
288 } else {
289 $hdsz = $opt_topm if defined($opt_topm);
290 $ftsz = $opt_botm if defined($opt_botm);
291 }
292 $txsz = $pgsz - ($hdsz + $ftsz);
293 $leftmsz = $opt_leftm if defined($opt_leftm);
294 $leftm = ' ' x $leftmsz;
295
296 $Bare = defined($opt_bare);
297 $Compress = defined($opt_compress);
298 $K = defined($opt_k);
299 $NoDepage = defined($opt_nodepage);
300 $NoHeads = defined($opt_noheads);
301 $SeeAlso = defined($opt_seealso);
302 $Solaris = defined($opt_solaris);
303 $Sun = defined($opt_sun);
304
305 $Title = $opt_title || $Title;
306 $CgiUrl = $opt_cgiurlexp ||
307 ($opt_cgiurl ? qq{return "$opt_cgiurl"} : '');
308
309 $BTag = $opt_belem || $BTag;
310 $UTag = $opt_uelem || $UTag;
311 $BTag =~ s/[<>]//g;
312 $UTag =~ s/[<>]//g;
313
314 if (defined($opt_headmap)) {
315 require $opt_headmap or warn "Unable to read $opt_headmap\n";
316 }
317 1;
318 }
319
320 ##---------------------------------------------------------------------------
321 sub printhead {
322 print $OutFH <<EndOfMeta;
323 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
324 <HTML>
325 <HEAD>
326 <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
327 <TITLE>$Title</TITLE>
328 <META http-equiv="Content-Style-Type" content="text/css">
329 <STYLE type="text/css">
330 BODY {background-color:white; color:black}
331 ADDRESS {font-size:smaller}
332 IMG.logo {width:6em; vertical-align:middle}
333 </STYLE>
334 </HEAD>
335 <BODY>
336 EndOfMeta
337 }
338
339 ##---------------------------------------------------------------------------
340 sub printtail {
341 print $OutFH <<\EndOfRef;
342 <HR>
343 <ADDRESS>
344 Man(1) output converted with
345 <a href="http://www.oac.uci.edu/indiv/ehood/man2html.html">man2html</a>
346 modified for the DCC $Date 2001/04/29 03:22:18 $
347 <BR>
348 <A HREF="http://www.dcc-servers.net/dcc/">
349 <IMG SRC="http://logos.dcc-servers.net/border.png"
350 class=logo ALT="DCC logo">
351 </A>
352 <A HREF="http://validator.w3.org/check?uri=referer">
353 <IMG class=logo ALT="Valid HTML 4.01 Strict"
354 SRC="http://www.w3.org/Icons/valid-html401">
355 </A>
356 </ADDRESS>
357 </BODY>
358 </HTML>
359 EndOfRef
360 }
361
362 ##---------------------------------------------------------------------------
363 sub emphasize {
364 my($txt) = shift;
365 $txt =~ s/.\010//go;
366 $txt = "<$UTag>$txt</$UTag>";
367 $txt;
368 }
369
370 ##---------------------------------------------------------------------------
371 sub strongize {
372 my($txt) = shift;
373 $txt =~ s/.\010//go;
374 $txt = "<$BTag>$txt</$BTag>";
375 $txt;
376 }
377
378 ##---------------------------------------------------------------------------
379 sub entitize {
380 my($txt) = shift;
381
382 ## Check for special characters in overstrike text ##
383 $$txt =~ s/_\010\&/strike('_', '&')/geo;
384 $$txt =~ s/_\010</strike('_', '<')/geo;
385 $$txt =~ s/_\010>/strike('_', '>')/geo;
386
387 $$txt =~ s/(\&\010)+\&/strike('&', '&')/geo;
388 $$txt =~ s/(<\010)+</strike('<', '<')/geo;
389 $$txt =~ s/(>\010)+>/strike('>', '>')/geo;
390
391 ## Check for special characters in regular text. Must be careful
392 ## to check before/after character in expression because it might be
393 ## a special character.
394 $$txt =~ s/([^\010]\&[^\010])/htmlize2($1)/geo;
395 $$txt =~ s/([^\010]<[^\010])/htmlize2($1)/geo;
396 $$txt =~ s/([^\010]>[^\010])/htmlize2($1)/geo;
397 }
398
399 ##---------------------------------------------------------------------------
400 ## escape special characters in a string, in-place
401 ##
402 sub htmlize {
403 my($str) = shift;
404 $$str =~ s/&/\&amp;/g;
405 $$str =~ s/</\&lt;/g;
406 $$str =~ s/>/\&gt;/g;
407 $$str;
408 }
409
410 ##---------------------------------------------------------------------------
411 ## htmlize2() is used by entitize.
412 ##
413 sub htmlize2 {
414 my($str) = shift;
415 $str =~ s/&/\&amp;/g;
416 $str =~ s/</\&lt;/g;
417 $str =~ s/>/\&gt;/g;
418 $str;
419 }
420
421 ##---------------------------------------------------------------------------
422 ## strike converts HTML special characters in overstriked text
423 ## into entity references. The entities are overstriked so
424 ## strongize() and emphasize() will recognize the entity to be
425 ## wrapped in tags.
426 ##
427 sub strike {
428 my($w, $char) = @_;
429 my($ret);
430 if ($w eq '_') {
431 if ($char eq '&') {
432 $ret = "_$bs\&_${bs}a_${bs}m_${bs}p_${bs};";
433 } elsif ($char eq '<') {
434 $ret = "_$bs\&_${bs}l_${bs}t_${bs};";
435 } elsif ($char eq '>') {
436 $ret = "_$bs\&_${bs}g_${bs}t_${bs};";
437 } else {
438 warn qq|Unrecognized character, "$char", passed to strike()\n|;
439 }
440 } else {
441 if ($char eq '&') {
442 $ret = "\&$bs\&a${bs}am${bs}mp${bs}p;${bs};";
443 } elsif ($char eq '<') {
444 $ret = "\&$bs\&l${bs}lt${bs}t;${bs};";
445 } elsif ($char eq '>') {
446 $ret = "\&$bs\&g${bs}gt${bs}t;${bs};";
447 } else {
448 warn qq|Unrecognized character, "$char", passed to strike()\n|;
449 }
450 }
451 $ret;
452 }
453
454 ##---------------------------------------------------------------------------
455 ## make_xref() converts a manpage crossreference into a hyperlink.
456 ##
457 sub make_xref {
458 my $str = shift;
459 $str =~ s/.\010//go; # Remove overstriking
460
461 if ($CgiUrl) {
462 my($title,$section,$subsection) =
463 ($str =~ /([\+_\.\w-]+)\((\d)(\w?)\)/);
464
465 $title =~ s/\+/%2B/g;
466 my($href) = (eval $CgiUrl);
467 qq|<B><A HREF="$href">$str</A></B>|;
468 } else {
469 qq|<B>$str</B>|;
470 }
471 }
472
473 ##---------------------------------------------------------------------------
474 ## man_k() process a keyword search. The problem we have is there
475 ## is no standard for keyword search results from man. Solaris
476 ## systems have a different enough format to warrent dealing
477 ## with it as a special case. For other cases, we try our best.
478 ## Unfortunately, there are some lines of results that may be
479 ## skipped.
480 ##
481 sub man_k {
482 my($line,$refs,$section,$subsection,$desc,$i,
483 %Sec1, %Sec1sub, %Sec2, %Sec2sub, %Sec3, %Sec3sub,
484 %Sec4, %Sec4sub, %Sec5, %Sec5sub, %Sec6, %Sec6sub,
485 %Sec7, %Sec7sub, %Sec8, %Sec8sub, %Sec9, %Sec9sub,
486 %SecN, %SecNsub, %SecNsec);
487
488 printhead() unless $Bare;
489 print $OutFH "<!-- Man keyword results converted by ",
490 "man2html $VERSION -->\n";
491
492 while ($line = <$InFH>) {
493 next if $line !~ /\(\d\w?\)\s+-\s/; # check if line can be handled
494 ($refs,$section,$subsection,$desc) =
495 $line =~ /^\s*(.*)\((\d)(\w?)\)\s*-\s*(.*)$/;
496
497 if ($Solaris) {
498 $refs =~ s/^\s*([\+_\.\w-]+)\s+([\+_\.\w-]+)\s*$/$1/;
499 # <topic> <manpage>
500 } else {
501 $refs =~ s/\s(and|or)\s/,/gi; # Convert and/or to commas
502 $refs =~ s/^[^:\s]:\s*//; # Remove prefixed whatis path
503 }
504 $refs =~ s/\s//g; # Remove all whitespace
505 $refs =~ s/,/, /g; # Put space after comma
506 htmlize(\$desc); # Check for special chars in desc
507 $desc =~ s/^(.)/\U$1/; # Uppercase first letter in desc
508
509 if ($section eq '1') {
510 $Sec1{$refs} = $desc; $Sec1sub{$refs} = $subsection;
511 } elsif ($section eq '2') {
512 $Sec2{$refs} = $desc; $Sec2sub{$refs} = $subsection;
513 } elsif ($section eq '3') {
514 $Sec3{$refs} = $desc; $Sec3sub{$refs} = $subsection;
515 } elsif ($section eq '4') {
516 $Sec4{$refs} = $desc; $Sec4sub{$refs} = $subsection;
517 } elsif ($section eq '5') {
518 $Sec5{$refs} = $desc; $Sec5sub{$refs} = $subsection;
519 } elsif ($section eq '6') {
520 $Sec6{$refs} = $desc; $Sec6sub{$refs} = $subsection;
521 } elsif ($section eq '7') {
522 $Sec7{$refs} = $desc; $Sec7sub{$refs} = $subsection;
523 } elsif ($section eq '8') {
524 $Sec8{$refs} = $desc; $Sec8sub{$refs} = $subsection;
525 } elsif ($section eq '9') {
526 $Sec9{$refs} = $desc; $Sec9sub{$refs} = $subsection;
527 } else { # Catch all
528 $SecN{$refs} = $desc; $SecNsec{$refs} = $section;
529 $SecNsub{$refs} = $subsection;
530 }
531 }
532 print_mank_sec(\%Sec1, 1, \%Sec1sub);
533 print_mank_sec(\%Sec2, 2, \%Sec2sub);
534 print_mank_sec(\%Sec3, 3, \%Sec3sub);
535 print_mank_sec(\%Sec4, 4, \%Sec4sub);
536 print_mank_sec(\%Sec5, 5, \%Sec5sub);
537 print_mank_sec(\%Sec6, 6, \%Sec6sub);
538 print_mank_sec(\%Sec7, 7, \%Sec7sub);
539 print_mank_sec(\%Sec8, 8, \%Sec8sub);
540 print_mank_sec(\%Sec9, 9, \%Sec9sub);
541 print_mank_sec(\%SecN, 'N', \%SecNsub, \%SecNsec);
542
543 printtail() unless $Bare;
544 }
545 ##---------------------------------------------------------------------------
546 ## print_mank_sec() prints out manpage cross-refs of a specific section.
547 ##
548 sub print_mank_sec {
549 my($sec, $sect, $secsub, $secsec) = @_;
550 my(@array, @refs, $href, $item, $title, $subsection, $i, $section,
551 $xref);
552 $section = $sect;
553
554 @array = sort keys %$sec;
555 if ($#array >= 0) {
556 print $OutFH "<H2>Section $section</H2>\n",
557 "<DL COMPACT>\n";
558 foreach $item (@array) {
559 @refs = split(/,/, $item);
560 $section = $secsec->{$item} if $sect eq 'N';
561 $subsection = $secsub->{$item};
562 if ($CgiUrl) {
563 ($title = $refs[0]) =~ s/\(\)//g; # watch out for extra ()'s
564 $xref = eval $CgiUrl;
565 }
566 print $OutFH "<DT>\n";
567 $i = 0;
568 foreach (@refs) {
569 if ($CgiUrl) {
570 print $OutFH qq|<B><A HREF="$xref">$_</A></B>|;
571 } else {
572 print $OutFH $_;
573 }
574 print $OutFH ", " if $i < $#refs;
575 $i++;
576 }
577 print $OutFH " ($section$subsection)\n",
578 "</DT><DD>\n",
579 $sec->{$item}, "</DD>\n";
580 }
581 print $OutFH "</DL>\n";
582 }
583 }
584
585 ##---------------------------------------------------------------------------
586 ##
587 sub usage {
588 print $OutFH <<EndOfUsage;
589 Usage: $PROG [ options ] < infile > outfile
590 Options:
591 -bare : Do not put in HTML, HEAD, BODY tags
592 -belem <elem> : HTML Element for overstriked text (def: "B")
593 -botm <#> : Number of lines for bottom margin (def: 7)
594 -cgiurl <url> : URL for linking to other manpages
595 -cgiurlexp <url> : Perl expression URL for linking to other manpages
596 -compress : Compress consective blank lines
597 -headmap <file> : Filename of user section head map file
598 -help : This message
599 -k : Process a keyword search result
600 -leftm <#> : Character width of left margin (def: 0)
601 -nodepage : Do not remove pagination lines
602 -noheads : Turn off section head detection
603 -pgsize <#> : Number of lines in a page (def: 66)
604 -seealso : Link to other manpages only in the SEE ALSO section
605 -solaris : Process keyword search result in Solaris format
606 -sun : Section heads are not overstriked in input
607 -title <string> : Title of manpage (def: Not defined)
608 -topm <#> : Number of lines for top margin (def: 7)
609 -uelem <elem> : HTML Element for underlined text (def: "I")
610
611 Description:
612 $PROG takes formatted manpages from STDIN and converts it to HTML sent
613 to STDOUT. The -topm and -botm arguments are the number of lines to the
614 main body text and NOT to the running headers/footers.
615
616 Version:
617 $VERSION
618 Copyright (C) 1995-1997 Earl Hood, ehood\@medusa.acs.uci.edu
619 $PROG comes with ABSOLUTELY NO WARRANTY and $PROG may be copied only
620 under the terms of the GNU General Public License, which may be found in
621 the $PROG distribution.
622
623 EndOfUsage
624 exit 0;
625 }