Home | History | Annotate | Line # | Download | only in etc
      1   1.1  christos #! /usr/bin/perl -w
      2   1.1  christos 
      3  1.11  christos #   Copyright (C) 1999-2024 Free Software Foundation, Inc.
      4   1.1  christos 
      5   1.1  christos # This file is part of GCC.
      6   1.1  christos 
      7   1.1  christos # GCC is free software; you can redistribute it and/or modify
      8   1.1  christos # it under the terms of the GNU General Public License as published by
      9   1.1  christos # the Free Software Foundation; either version 2, or (at your option)
     10   1.1  christos # any later version.
     11   1.1  christos 
     12   1.1  christos # GCC is distributed in the hope that it will be useful,
     13   1.1  christos # but WITHOUT ANY WARRANTY; without even the implied warranty of
     14   1.1  christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15   1.1  christos # GNU General Public License for more details.
     16   1.1  christos 
     17   1.1  christos # You should have received a copy of the GNU General Public License
     18   1.1  christos # along with GCC; see the file COPYING.  If not, write to
     19   1.1  christos # the Free Software Foundation, 51 Franklin Street, Fifth Floor,
     20   1.1  christos # Boston MA 02110-1301, USA.
     21   1.1  christos 
     22   1.1  christos # This does trivial (and I mean _trivial_) conversion of Texinfo
     23   1.1  christos # markup to Perl POD format.  It's intended to be used to extract
     24   1.1  christos # something suitable for a manpage from a Texinfo document.
     25   1.1  christos 
     26   1.1  christos $output = 0;
     27   1.1  christos $skipping = 0;
     28   1.1  christos %sects = ();
     29   1.1  christos $section = "";
     30   1.1  christos @icstack = ();
     31   1.1  christos @endwstack = ();
     32   1.1  christos @skstack = ();
     33   1.1  christos @instack = ();
     34   1.1  christos $shift = "";
     35   1.1  christos %defs = ();
     36   1.1  christos $fnno = 1;
     37   1.1  christos $inf = "";
     38   1.1  christos $ibase = "";
     39   1.1  christos @ipath = ();
     40   1.1  christos 
     41   1.1  christos while ($_ = shift) {
     42   1.1  christos     if (/^-D(.*)$/) {
     43   1.1  christos 	if ($1 ne "") {
     44   1.1  christos 	    $flag = $1;
     45   1.1  christos 	} else {
     46   1.1  christos 	    $flag = shift;
     47   1.1  christos 	}
     48   1.1  christos 	$value = "";
     49   1.1  christos 	($flag, $value) = ($flag =~ /^([^=]+)(?:=(.+))?/);
     50   1.1  christos 	die "no flag specified for -D\n"
     51   1.1  christos 	    unless $flag ne "";
     52   1.1  christos 	die "flags may only contain letters, digits, hyphens, dashes and underscores\n"
     53   1.1  christos 	    unless $flag =~ /^[a-zA-Z0-9_-]+$/;
     54   1.1  christos 	$defs{$flag} = $value;
     55   1.1  christos     } elsif (/^-I(.*)$/) {
     56   1.1  christos 	if ($1 ne "") {
     57   1.1  christos 	    $flag = $1;
     58   1.1  christos 	} else {
     59   1.1  christos 	    $flag = shift;
     60   1.1  christos 	}
     61   1.1  christos         push (@ipath, $flag);
     62  1.10  christos     } elsif (/^--no-split$/) {
     63  1.10  christos 	# ignore option for makeinfo compatibility
     64   1.1  christos     } elsif (/^-/) {
     65   1.1  christos 	usage();
     66   1.1  christos     } else {
     67   1.1  christos 	$in = $_, next unless defined $in;
     68   1.1  christos 	$out = $_, next unless defined $out;
     69   1.1  christos 	usage();
     70   1.1  christos     }
     71   1.1  christos }
     72   1.1  christos 
     73   1.1  christos if (defined $in) {
     74   1.1  christos     $inf = gensym();
     75   1.1  christos     open($inf, "<$in") or die "opening \"$in\": $!\n";
     76   1.1  christos     $ibase = $1 if $in =~ m|^(.+)/[^/]+$|;
     77   1.1  christos } else {
     78   1.1  christos     $inf = \*STDIN;
     79   1.1  christos }
     80   1.1  christos 
     81   1.1  christos if (defined $out) {
     82   1.1  christos     open(STDOUT, ">$out") or die "opening \"$out\": $!\n";
     83   1.1  christos }
     84   1.1  christos 
     85   1.1  christos while(defined $inf) {
     86   1.1  christos while(<$inf>) {
     87   1.1  christos     # Certain commands are discarded without further processing.
     88   1.1  christos     /^\@(?:
     89   1.1  christos 	 [a-z]+index		# @*index: useful only in complete manual
     90   1.1  christos 	 |need			# @need: useful only in printed manual
     91   1.1  christos 	 |(?:end\s+)?group	# @group .. @end group: ditto
     92   1.1  christos 	 |page			# @page: ditto
     93   1.1  christos 	 |node			# @node: useful only in .info file
     94   1.1  christos 	 |(?:end\s+)?ifnottex   # @ifnottex .. @end ifnottex: use contents
     95   1.1  christos 	)\b/x and next;
     96   1.1  christos 
     97   1.1  christos     chomp;
     98   1.1  christos 
     99   1.1  christos     # Look for filename and title markers.
    100   1.1  christos     /^\@setfilename\s+([^.]+)/ and $fn = $1, next;
    101   1.1  christos     /^\@settitle\s+([^.]+)/ and $tl = postprocess($1), next;
    102   1.1  christos 
    103   1.1  christos     # Identify a man title but keep only the one we are interested in.
    104   1.1  christos     /^\@c\s+man\s+title\s+([A-Za-z0-9-]+)\s+(.+)/ and do {
    105   1.1  christos 	if (exists $defs{$1}) {
    106   1.1  christos 	    $fn = $1;
    107   1.1  christos 	    $tl = postprocess($2);
    108   1.1  christos 	}
    109   1.1  christos 	next;
    110   1.1  christos     };
    111   1.1  christos 
    112   1.1  christos     # Look for blocks surrounded by @c man begin SECTION ... @c man end.
    113   1.1  christos     # This really oughta be @ifman ... @end ifman and the like, but such
    114   1.1  christos     # would require rev'ing all other Texinfo translators.
    115   1.1  christos     /^\@c\s+man\s+begin\s+([A-Z]+)\s+([A-Za-z0-9-]+)/ and do {
    116   1.1  christos 	$output = 1 if exists $defs{$2};
    117   1.1  christos         $sect = $1;
    118   1.1  christos 	next;
    119   1.1  christos     };
    120   1.1  christos     /^\@c\s+man\s+begin\s+([A-Z]+)/ and $sect = $1, $output = 1, next;
    121   1.1  christos     /^\@c\s+man\s+end/ and do {
    122   1.1  christos 	$sects{$sect} = "" unless exists $sects{$sect};
    123   1.1  christos 	$sects{$sect} .= postprocess($section);
    124   1.1  christos 	$section = "";
    125   1.1  christos 	$output = 0;
    126   1.1  christos 	next;
    127   1.1  christos     };
    128   1.1  christos 
    129   1.1  christos     # handle variables
    130   1.1  christos     /^\@set\s+([a-zA-Z0-9_-]+)\s*(.*)$/ and do {
    131   1.1  christos 	$defs{$1} = $2;
    132   1.1  christos 	next;
    133   1.1  christos     };
    134   1.1  christos     /^\@clear\s+([a-zA-Z0-9_-]+)/ and do {
    135   1.1  christos 	delete $defs{$1};
    136   1.1  christos 	next;
    137   1.1  christos     };
    138   1.1  christos 
    139   1.1  christos     next unless $output;
    140   1.1  christos 
    141   1.1  christos     # Discard comments.  (Can't do it above, because then we'd never see
    142   1.1  christos     # @c man lines.)
    143   1.1  christos     /^\@c\b/ and next;
    144   1.1  christos 
    145   1.1  christos     # End-block handler goes up here because it needs to operate even
    146   1.1  christos     # if we are skipping.
    147   1.1  christos     /^\@end\s+([a-z]+)/ and do {
    148   1.1  christos 	# Ignore @end foo, where foo is not an operation which may
    149   1.1  christos 	# cause us to skip, if we are presently skipping.
    150   1.1  christos 	my $ended = $1;
    151   1.1  christos 	next if $skipping && $ended !~ /^(?:ifset|ifclear|ignore|menu|iftex|copying)$/;
    152   1.1  christos 
    153   1.1  christos 	die "\@end $ended without \@$ended at line $.\n" unless defined $endw;
    154   1.1  christos 	die "\@$endw ended by \@end $ended at line $.\n" unless $ended eq $endw;
    155   1.1  christos 
    156   1.1  christos 	$endw = pop @endwstack;
    157   1.1  christos 
    158   1.1  christos 	if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
    159   1.1  christos 	    $skipping = pop @skstack;
    160   1.1  christos 	    next;
    161   1.1  christos 	} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
    162   1.1  christos 	    $shift = "";
    163   1.1  christos 	    $_ = "";	# need a paragraph break
    164   1.1  christos 	} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
    165   1.1  christos 	    $_ = "\n=back\n";
    166   1.1  christos 	    $ic = pop @icstack;
    167   1.1  christos 	} elsif ($ended eq "multitable") {
    168   1.1  christos 	    $_ = "\n=back\n";
    169   1.1  christos 	} else {
    170   1.1  christos 	    die "unknown command \@end $ended at line $.\n";
    171   1.1  christos 	}
    172   1.1  christos     };
    173   1.1  christos 
    174   1.1  christos     # We must handle commands which can cause skipping even while we
    175   1.1  christos     # are skipping, otherwise we will not process nested conditionals
    176   1.1  christos     # correctly.
    177   1.1  christos     /^\@ifset\s+([a-zA-Z0-9_-]+)/ and do {
    178   1.1  christos 	push @endwstack, $endw;
    179   1.1  christos 	push @skstack, $skipping;
    180   1.1  christos 	$endw = "ifset";
    181   1.1  christos 	$skipping = 1 unless exists $defs{$1};
    182   1.1  christos 	next;
    183   1.1  christos     };
    184   1.1  christos 
    185   1.1  christos     /^\@ifclear\s+([a-zA-Z0-9_-]+)/ and do {
    186   1.1  christos 	push @endwstack, $endw;
    187   1.1  christos 	push @skstack, $skipping;
    188   1.1  christos 	$endw = "ifclear";
    189   1.1  christos 	$skipping = 1 if exists $defs{$1};
    190   1.1  christos 	next;
    191   1.1  christos     };
    192   1.1  christos 
    193   1.1  christos     /^\@(ignore|menu|iftex|copying)\b/ and do {
    194   1.1  christos 	push @endwstack, $endw;
    195   1.1  christos 	push @skstack, $skipping;
    196   1.1  christos 	$endw = $1;
    197   1.1  christos 	$skipping = 1;
    198   1.1  christos 	next;
    199   1.1  christos     };
    200   1.1  christos 
    201   1.1  christos     next if $skipping;
    202   1.1  christos 
    203   1.1  christos     # Character entities.  First the ones that can be replaced by raw text
    204   1.1  christos     # or discarded outright:
    205   1.1  christos     s/\@copyright\{\}/(c)/g;
    206   1.1  christos     s/\@dots\{\}/.../g;
    207   1.1  christos     s/\@enddots\{\}/..../g;
    208   1.1  christos     s/\@([.!? ])/$1/g;
    209   1.1  christos     s/\@[:-]//g;
    210   1.1  christos     s/\@bullet(?:\{\})?/*/g;
    211   1.1  christos     s/\@TeX\{\}/TeX/g;
    212   1.1  christos     s/\@pounds\{\}/\#/g;
    213   1.1  christos     s/\@minus(?:\{\})?/-/g;
    214   1.1  christos     s/\\,/,/g;
    215   1.1  christos 
    216   1.1  christos     # Now the ones that have to be replaced by special escapes
    217   1.1  christos     # (which will be turned back into text by unmunge())
    218   1.1  christos     s/&/&amp;/g;
    219   1.1  christos     s/\@\{/&lbrace;/g;
    220   1.1  christos     s/\@\}/&rbrace;/g;
    221   1.1  christos     s/\@\@/&at;/g;
    222   1.1  christos 
    223   1.1  christos     # Inside a verbatim block, handle @var specially.
    224   1.1  christos     if ($shift ne "") {
    225   1.1  christos 	s/\@var\{([^\}]*)\}/<$1>/g;
    226   1.1  christos     }
    227   1.1  christos 
    228   1.1  christos     # POD doesn't interpret E<> inside a verbatim block.
    229   1.1  christos     if ($shift eq "") {
    230   1.1  christos 	s/</&lt;/g;
    231   1.1  christos 	s/>/&gt;/g;
    232   1.1  christos     } else {
    233   1.1  christos 	s/</&LT;/g;
    234   1.1  christos 	s/>/&GT;/g;
    235   1.1  christos     }
    236   1.1  christos 
    237   1.1  christos     # Single line command handlers.
    238   1.1  christos 
    239   1.1  christos     /^\@include\s+(.+)$/ and do {
    240   1.1  christos 	push @instack, $inf;
    241   1.1  christos 	$inf = gensym();
    242   1.1  christos 	$file = postprocess($1);
    243   1.1  christos 
    244   1.1  christos 	# Try cwd and $ibase, then explicit -I paths.
    245   1.1  christos 	$done = 0;
    246   1.1  christos 	foreach $path ("", $ibase, @ipath) {
    247   1.1  christos 	    $mypath = $file;
    248   1.1  christos 	    $mypath = $path . "/" . $mypath if ($path ne "");
    249   1.1  christos 	    open($inf, "<" . $mypath) and ($done = 1, last);
    250   1.1  christos 	}
    251   1.1  christos 	die "cannot find $file" if !$done;
    252   1.1  christos 	next;
    253   1.1  christos     };
    254   1.1  christos 
    255   1.1  christos     /^\@(?:section|unnumbered|unnumberedsec|center)\s+(.+)$/
    256   1.1  christos 	and $_ = "\n=head2 $1\n";
    257   1.1  christos     /^\@subsection\s+(.+)$/
    258   1.1  christos 	and $_ = "\n=head3 $1\n";
    259   1.1  christos     /^\@subsubsection\s+(.+)$/
    260   1.1  christos 	and $_ = "\n=head4 $1\n";
    261   1.1  christos 
    262   1.1  christos     # Block command handlers:
    263   1.1  christos     /^\@itemize(?:\s+(\@[a-z]+|\*|-))?/ and do {
    264   1.1  christos 	push @endwstack, $endw;
    265   1.1  christos 	push @icstack, $ic;
    266   1.1  christos 	if (defined $1) {
    267   1.1  christos 	    $ic = $1;
    268   1.1  christos 	} else {
    269   1.1  christos 	    $ic = '*';
    270   1.1  christos 	}
    271   1.1  christos 	$_ = "\n=over 4\n";
    272   1.1  christos 	$endw = "itemize";
    273   1.1  christos     };
    274   1.1  christos 
    275   1.1  christos     /^\@enumerate(?:\s+([a-zA-Z0-9]+))?/ and do {
    276   1.1  christos 	push @endwstack, $endw;
    277   1.1  christos 	push @icstack, $ic;
    278   1.1  christos 	if (defined $1) {
    279   1.1  christos 	    $ic = $1 . ".";
    280   1.1  christos 	} else {
    281   1.1  christos 	    $ic = "1.";
    282   1.1  christos 	}
    283   1.1  christos 	$_ = "\n=over 4\n";
    284   1.1  christos 	$endw = "enumerate";
    285   1.1  christos     };
    286   1.1  christos 
    287   1.1  christos     /^\@multitable\s.*/ and do {
    288   1.1  christos 	push @endwstack, $endw;
    289   1.1  christos 	$endw = "multitable";
    290   1.1  christos 	$_ = "\n=over 4\n";
    291   1.1  christos     };
    292   1.1  christos 
    293   1.1  christos     /^\@([fv]?table)\s+(\@[a-z]+)/ and do {
    294   1.1  christos 	push @endwstack, $endw;
    295   1.1  christos 	push @icstack, $ic;
    296   1.1  christos 	$endw = $1;
    297   1.1  christos 	$ic = $2;
    298   1.1  christos 	$ic =~ s/\@(?:samp|strong|key|gcctabopt|env)/B/;
    299   1.1  christos 	$ic =~ s/\@(?:code|kbd)/C/;
    300   1.1  christos 	$ic =~ s/\@(?:dfn|var|emph|cite|i)/I/;
    301   1.1  christos 	$ic =~ s/\@(?:file)/F/;
    302   1.1  christos 	$_ = "\n=over 4\n";
    303   1.1  christos     };
    304   1.1  christos 
    305   1.1  christos     /^\@((?:small)?example|display)/ and do {
    306   1.1  christos 	push @endwstack, $endw;
    307   1.1  christos 	$endw = $1;
    308   1.1  christos 	$shift = "\t";
    309   1.1  christos 	$_ = "";	# need a paragraph break
    310   1.1  christos     };
    311   1.1  christos 
    312   1.1  christos     /^\@item\s+(.*\S)\s*$/ and $endw eq "multitable" and do {
    313   1.1  christos 	@columns = ();
    314   1.1  christos 	for $column (split (/\s*\@tab\s*/, $1)) {
    315   1.1  christos 	    # @strong{...} is used a @headitem work-alike
    316   1.6  christos 	    $column =~ s/^\@strong\{(.*)\}$/$1/;
    317   1.1  christos 	    push @columns, $column;
    318   1.1  christos 	}
    319   1.1  christos 	$_ = "\n=item ".join (" : ", @columns)."\n";
    320   1.1  christos     };
    321   1.1  christos 
    322   1.1  christos     /^\@itemx?\s*(.+)?$/ and do {
    323   1.1  christos 	if (defined $1) {
    324   1.1  christos 	    # Entity escapes prevent munging by the <> processing below.
    325   1.1  christos 	    $_ = "\n=item $ic\&LT;$1\&GT;\n";
    326   1.1  christos 	} else {
    327   1.1  christos 	    $_ = "\n=item $ic\n";
    328   1.1  christos 	    $ic =~ y/A-Ya-y/B-Zb-z/;
    329   1.1  christos 	    $ic =~ s/(\d+)/$1 + 1/eg;
    330   1.1  christos 	}
    331   1.1  christos     };
    332   1.1  christos 
    333   1.1  christos     $section .= $shift.$_."\n";
    334   1.1  christos }
    335   1.1  christos # End of current file.
    336   1.1  christos close($inf);
    337   1.1  christos $inf = pop @instack;
    338   1.1  christos }
    339   1.1  christos 
    340   1.1  christos die "No filename or title\n" unless defined $fn && defined $tl;
    341   1.1  christos 
    342   1.1  christos $sects{NAME} = "$fn \- $tl\n";
    343   1.1  christos $sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
    344   1.1  christos 
    345   1.6  christos for $sect (qw(NAME SYNOPSIS TARGET DESCRIPTION OPTIONS ENVIRONMENT FILES
    346   1.1  christos 	      BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
    347   1.1  christos     if(exists $sects{$sect}) {
    348   1.1  christos 	$head = $sect;
    349   1.1  christos 	$head =~ s/SEEALSO/SEE ALSO/;
    350   1.1  christos 	print "=head1 $head\n\n";
    351   1.1  christos 	print scalar unmunge ($sects{$sect});
    352   1.1  christos 	print "\n";
    353   1.1  christos     }
    354   1.1  christos }
    355   1.1  christos 
    356   1.1  christos sub usage
    357   1.1  christos {
    358   1.1  christos     die "usage: $0 [-D toggle...] [infile [outfile]]\n";
    359   1.1  christos }
    360   1.1  christos 
    361   1.1  christos sub postprocess
    362   1.1  christos {
    363   1.1  christos     local $_ = $_[0];
    364   1.1  christos 
    365   1.1  christos     # @value{foo} is replaced by whatever 'foo' is defined as.
    366   1.1  christos     while (m/(\@value\{([a-zA-Z0-9_-]+)\})/g) {
    367   1.1  christos 	if (! exists $defs{$2}) {
    368   1.1  christos 	    print STDERR "Option $2 not defined\n";
    369   1.1  christos 	    s/\Q$1\E//;
    370   1.1  christos 	} else {
    371   1.1  christos 	    $value = $defs{$2};
    372   1.1  christos 	    s/\Q$1\E/$value/;
    373   1.1  christos 	}
    374   1.1  christos     }
    375   1.1  christos 
    376   1.1  christos     # Formatting commands.
    377   1.1  christos     # Temporary escape for @r.
    378   1.1  christos     s/\@r\{([^\}]*)\}/R<$1>/g;
    379   1.1  christos     s/\@(?:dfn|var|emph|cite|i)\{([^\}]*)\}/I<$1>/g;
    380   1.1  christos     s/\@(?:code|kbd)\{([^\}]*)\}/C<$1>/g;
    381   1.1  christos     s/\@(?:gccoptlist|samp|strong|key|option|env|command|b)\{([^\}]*)\}/B<$1>/g;
    382   1.1  christos     s/\@sc\{([^\}]*)\}/\U$1/g;
    383   1.1  christos     s/\@file\{([^\}]*)\}/F<$1>/g;
    384   1.1  christos     s/\@w\{([^\}]*)\}/S<$1>/g;
    385   1.1  christos     s/\@(?:dmn|math)\{([^\}]*)\}/$1/g;
    386   1.9  christos     s/\@t\{([^\}]*)\}/$1/g;
    387   1.1  christos 
    388   1.1  christos     # keep references of the form @ref{...}, print them bold
    389   1.1  christos     s/\@(?:ref)\{([^\}]*)\}/B<$1>/g;
    390   1.1  christos 
    391   1.1  christos     # Change double single quotes to double quotes.
    392   1.1  christos     s/''/"/g;
    393   1.1  christos     s/``/"/g;
    394   1.1  christos 
    395   1.1  christos     # Cross references are thrown away, as are @noindent and @refill.
    396   1.1  christos     # (@noindent is impossible in .pod, and @refill is unnecessary.)
    397   1.1  christos     # @* is also impossible in .pod; we discard it and any newline that
    398   1.1  christos     # follows it.  Similarly, our macro @gol must be discarded.
    399   1.1  christos 
    400   1.1  christos     s/\(?\@xref\{(?:[^\}]*)\}(?:[^.<]|(?:<[^<>]*>))*\.\)?//g;
    401   1.1  christos     s/\s+\(\@pxref\{(?:[^\}]*)\}\)//g;
    402   1.1  christos     s/;\s+\@pxref\{(?:[^\}]*)\}//g;
    403   1.1  christos     s/\@noindent\s*//g;
    404   1.1  christos     s/\@refill//g;
    405   1.1  christos     s/\@gol//g;
    406   1.1  christos     s/\@\*\s*\n?//g;
    407   1.1  christos 
    408   1.1  christos     # Anchors are thrown away
    409   1.1  christos     s/\@anchor\{(?:[^\}]*)\}//g;
    410   1.1  christos 
    411   1.1  christos     # @uref can take one, two, or three arguments, with different
    412   1.1  christos     # semantics each time.  @url and @email are just like @uref with
    413   1.1  christos     # one argument, for our purposes.
    414   1.1  christos     s/\@(?:uref|url|email)\{([^\},]*)\}/&lt;B<$1>&gt;/g;
    415   1.1  christos     s/\@uref\{([^\},]*),([^\},]*)\}/$2 (C<$1>)/g;
    416   1.1  christos     s/\@uref\{([^\},]*),([^\},]*),([^\},]*)\}/$3/g;
    417   1.1  christos 
    418   1.1  christos     # Un-escape <> at this point.
    419   1.1  christos     s/&LT;/</g;
    420   1.1  christos     s/&GT;/>/g;
    421   1.1  christos 
    422   1.1  christos     # Now un-nest all B<>, I<>, R<>.  Theoretically we could have
    423   1.1  christos     # indefinitely deep nesting; in practice, one level suffices.
    424   1.1  christos     1 while s/([BIR])<([^<>]*)([BIR])<([^<>]*)>/$1<$2>$3<$4>$1</g;
    425   1.1  christos 
    426   1.1  christos     # Replace R<...> with bare ...; eliminate empty markup, B<>;
    427   1.1  christos     # shift white space at the ends of [BI]<...> expressions outside
    428   1.1  christos     # the expression.
    429   1.1  christos     s/R<([^<>]*)>/$1/g;
    430   1.1  christos     s/[BI]<>//g;
    431   1.1  christos     s/([BI])<(\s+)([^>]+)>/$2$1<$3>/g;
    432   1.1  christos     s/([BI])<([^>]+?)(\s+)>/$1<$2>$3/g;
    433   1.1  christos 
    434   1.1  christos     # Extract footnotes.  This has to be done after all other
    435   1.1  christos     # processing because otherwise the regexp will choke on formatting
    436   1.1  christos     # inside @footnote.
    437   1.1  christos     while (/\@footnote/g) {
    438   1.1  christos 	s/\@footnote\{([^\}]+)\}/[$fnno]/;
    439   1.1  christos 	add_footnote($1, $fnno);
    440   1.1  christos 	$fnno++;
    441   1.1  christos     }
    442   1.1  christos 
    443   1.1  christos     return $_;
    444   1.1  christos }
    445   1.1  christos 
    446   1.1  christos sub unmunge
    447   1.1  christos {
    448   1.1  christos     # Replace escaped symbols with their equivalents.
    449   1.1  christos     local $_ = $_[0];
    450   1.1  christos 
    451   1.1  christos     s/&lt;/E<lt>/g;
    452   1.1  christos     s/&gt;/E<gt>/g;
    453   1.1  christos     s/&lbrace;/\{/g;
    454   1.1  christos     s/&rbrace;/\}/g;
    455   1.1  christos     s/&at;/\@/g;
    456   1.1  christos     s/&amp;/&/g;
    457   1.1  christos     return $_;
    458   1.1  christos }
    459   1.1  christos 
    460   1.1  christos sub add_footnote
    461   1.1  christos {
    462   1.1  christos     unless (exists $sects{FOOTNOTES}) {
    463   1.1  christos 	$sects{FOOTNOTES} = "\n=over 4\n\n";
    464   1.1  christos     }
    465   1.1  christos 
    466   1.1  christos     $sects{FOOTNOTES} .= "=item $fnno.\n\n"; $fnno++;
    467   1.1  christos     $sects{FOOTNOTES} .= $_[0];
    468   1.1  christos     $sects{FOOTNOTES} .= "\n\n";
    469   1.1  christos }
    470   1.1  christos 
    471   1.1  christos # stolen from Symbol.pm
    472   1.1  christos {
    473   1.1  christos     my $genseq = 0;
    474   1.1  christos     sub gensym
    475   1.1  christos     {
    476   1.1  christos 	my $name = "GEN" . $genseq++;
    477   1.1  christos 	my $ref = \*{$name};
    478   1.1  christos 	delete $::{$name};
    479   1.1  christos 	return $ref;
    480   1.1  christos     }
    481   1.1  christos }
    482