Home | History | Annotate | Line # | Download | only in doc
texi2html revision 1.1
      1  1.1  christos #!/usr/local/bin/perl
      2  1.1  christos 'di ';
      3  1.1  christos 'ig 00 ';
      4  1.1  christos #+##############################################################################
      5  1.1  christos #                                                                              #
      6  1.1  christos # File: texi2html                                                              #
      7  1.1  christos #                                                                              #
      8  1.1  christos # Description: Program to transform most Texinfo documents to HTML             #
      9  1.1  christos #                                                                              #
     10  1.1  christos #-##############################################################################
     11  1.1  christos 
     12  1.1  christos # @(#)texi2html	1.52b 01/05/98	Written (mainly) by Lionel Cons, Lionel.Cons (at] cern.ch
     13  1.1  christos # 1.52a: Use acute accent instead of apostrophe. Add support for ISO-8859-1
     14  1.1  christos #        characters with cedilla, circumflex etc.
     15  1.1  christos # 1.52b: Add option -expandtex. Expand @ifhtml by default, not @ifinfo.
     16  1.1  christos #        Use Unicode quotation marks instead of grave and acute accents.
     17  1.1  christos #        Emit charset=UTF-8 declaration.
     18  1.1  christos 
     19  1.1  christos # The man page for this program is included at the end of this file and can be
     20  1.1  christos # viewed using the command 'nroff -man texi2html'.
     21  1.1  christos # Please read the copyright at the end of the man page.
     22  1.1  christos 
     23  1.1  christos #+++############################################################################
     24  1.1  christos #                                                                              #
     25  1.1  christos # Constants                                                                    #
     26  1.1  christos #                                                                              #
     27  1.1  christos #---############################################################################
     28  1.1  christos 
     29  1.1  christos $DEBUG_TOC   =  1;
     30  1.1  christos $DEBUG_INDEX =  2;
     31  1.1  christos $DEBUG_BIB   =  4;
     32  1.1  christos $DEBUG_GLOSS =  8;
     33  1.1  christos $DEBUG_DEF   = 16;
     34  1.1  christos $DEBUG_HTML  = 32;
     35  1.1  christos $DEBUG_USER  = 64;
     36  1.1  christos 
     37  1.1  christos $BIBRE = '\[[\w\/-]+\]';		# RE for a bibliography reference
     38  1.1  christos $FILERE = '[\/\w.+-]+';			# RE for a file name
     39  1.1  christos $VARRE = '[^\s\{\}]+';			# RE for a variable name
     40  1.1  christos $NODERE = '[^@{}:\'`",]+';		# RE for a node name
     41  1.1  christos $NODESRE = '[^@{}:\'`"]+';		# RE for a list of node names
     42  1.1  christos $XREFRE = '[^@{}]+';			# RE for a xref (should use NODERE)
     43  1.1  christos 
     44  1.1  christos $ERROR = "***";			        # prefix for errors and warnings
     45  1.1  christos $THISPROG = "texi2html 1.52b";			# program name and version
     46  1.1  christos $HOMEPAGE = "http://wwwinfo.cern.ch/dis/texi2html/"; # program home page
     47  1.1  christos $TODAY = &pretty_date;			# like "20 September 1993"
     48  1.1  christos $SPLITTAG = "<!-- SPLIT HERE -->\n";	# tag to know where to split
     49  1.1  christos $PROTECTTAG = "_ThisIsProtected_";	# tag to recognize protected sections
     50  1.1  christos $html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//EN">';
     51  1.1  christos 
     52  1.1  christos #
     53  1.1  christos # language dependent constants
     54  1.1  christos #
     55  1.1  christos #$LDC_SEE = 'see';
     56  1.1  christos #$LDC_SECTION = 'section';
     57  1.1  christos #$LDC_IN = 'in';
     58  1.1  christos #$LDC_TOC = 'Table of Contents';
     59  1.1  christos #$LDC_GOTO = 'Go to the';
     60  1.1  christos #$LDC_FOOT = 'Footnotes';
     61  1.1  christos # TODO: @def* shortcuts
     62  1.1  christos 
     63  1.1  christos #
     64  1.1  christos # pre-defined indices
     65  1.1  christos #
     66  1.1  christos %predefined_index = (
     67  1.1  christos 		    'cp', 'c',
     68  1.1  christos 		    'fn', 'f',
     69  1.1  christos 		    'vr', 'v',
     70  1.1  christos 		    'ky', 'k',
     71  1.1  christos 		    'pg', 'p',
     72  1.1  christos 		    'tp', 't',
     73  1.1  christos 	            );
     74  1.1  christos 
     75  1.1  christos #
     76  1.1  christos # valid indices
     77  1.1  christos #
     78  1.1  christos %valid_index = (
     79  1.1  christos 		    'c', 1,
     80  1.1  christos 		    'f', 1,
     81  1.1  christos 		    'v', 1,
     82  1.1  christos 		    'k', 1,
     83  1.1  christos 		    'p', 1,
     84  1.1  christos 		    't', 1,
     85  1.1  christos 		);
     86  1.1  christos 
     87  1.1  christos #
     88  1.1  christos # texinfo section names to level
     89  1.1  christos #
     90  1.1  christos %sec2level = (
     91  1.1  christos 	      'top', 0,
     92  1.1  christos 	      'chapter', 1,
     93  1.1  christos 	      'unnumbered', 1,
     94  1.1  christos 	      'majorheading', 1,
     95  1.1  christos 	      'chapheading', 1,
     96  1.1  christos 	      'appendix', 1,
     97  1.1  christos 	      'section', 2,
     98  1.1  christos 	      'unnumberedsec', 2,
     99  1.1  christos 	      'heading', 2,
    100  1.1  christos 	      'appendixsec', 2,
    101  1.1  christos 	      'appendixsection', 2,
    102  1.1  christos 	      'subsection', 3,
    103  1.1  christos 	      'unnumberedsubsec', 3,
    104  1.1  christos 	      'subheading', 3,
    105  1.1  christos 	      'appendixsubsec', 3,
    106  1.1  christos 	      'subsubsection', 4,
    107  1.1  christos 	      'unnumberedsubsubsec', 4,
    108  1.1  christos 	      'subsubheading', 4,
    109  1.1  christos 	      'appendixsubsubsec', 4,
    110  1.1  christos 	      );
    111  1.1  christos 
    112  1.1  christos #
    113  1.1  christos # accent map, TeX command to ISO name
    114  1.1  christos #
    115  1.1  christos %accent_map = (
    116  1.1  christos 	       '"',  'uml',
    117  1.1  christos 	       '~',  'tilde',
    118  1.1  christos 	       '^',  'circ',
    119  1.1  christos 	       '`',  'grave',
    120  1.1  christos 	       '\'', 'acute',
    121  1.1  christos 	       );
    122  1.1  christos 
    123  1.1  christos #
    124  1.1  christos # texinfo "simple things" (@foo) to HTML ones
    125  1.1  christos #
    126  1.1  christos %simple_map = (
    127  1.1  christos 	       # cf. makeinfo.c
    128  1.1  christos 	       "*", "<BR>",		# HTML+
    129  1.1  christos 	       " ", " ",
    130  1.1  christos 	       "\n", "\n",
    131  1.1  christos 	       "|", "",
    132  1.1  christos 	       # spacing commands
    133  1.1  christos 	       ":", "",
    134  1.1  christos 	       "!", "!",
    135  1.1  christos 	       "?", "?",
    136  1.1  christos 	       ".", ".",
    137  1.1  christos 	       "-", "",
    138  1.1  christos 	       );
    139  1.1  christos 
    140  1.1  christos #
    141  1.1  christos # texinfo "things" (@foo{}) to HTML ones
    142  1.1  christos #
    143  1.1  christos %things_map = (
    144  1.1  christos 	       'TeX', 'TeX',
    145  1.1  christos 	       'br', '<P>',		# paragraph break
    146  1.1  christos 	       'bullet', '*',
    147  1.1  christos 	       'copyright', '(C)',
    148  1.1  christos 	       'dots', '...',
    149  1.1  christos 	       'equiv', '==',
    150  1.1  christos 	       'error', 'error-->',
    151  1.1  christos 	       'expansion', '==>',
    152  1.1  christos 	       'minus', '-',
    153  1.1  christos 	       'point', '-!-',
    154  1.1  christos 	       'print', '-|',
    155  1.1  christos 	       'result', '=>',
    156  1.1  christos 	       'today', $TODAY,
    157  1.1  christos 	       'aa', '&aring;',
    158  1.1  christos 	       'AA', '&Aring;',
    159  1.1  christos 	       'ae', '&aelig;',
    160  1.1  christos 	       'AE', '&AElig;',
    161  1.1  christos 	       'o',  '&oslash;',
    162  1.1  christos 	       'O',  '&Oslash;',
    163  1.1  christos 	       'ss', '&szlig;',
    164  1.1  christos 	       'exclamdown', '&iexcl;',
    165  1.1  christos 	       'questiondown', '&iquest;',
    166  1.1  christos 	       'pounds', '&pound;'
    167  1.1  christos 	       );
    168  1.1  christos 
    169  1.1  christos #
    170  1.1  christos # texinfo styles (@foo{bar}) to HTML ones
    171  1.1  christos #
    172  1.1  christos %style_map = (
    173  1.1  christos 	      'asis', '',
    174  1.1  christos 	      'b', 'B',
    175  1.1  christos 	      'cite', 'CITE',
    176  1.1  christos 	      'code', 'CODE',
    177  1.1  christos 	      'ctrl', '&do_ctrl',	# special case
    178  1.1  christos 	      'dfn', 'EM',		# DFN tag is illegal in the standard
    179  1.1  christos 	      'dmn', '',		# useless
    180  1.1  christos 	      'email', '&do_email',     # insert a clickable email address
    181  1.1  christos 	      'emph', 'EM',
    182  1.1  christos 	      'file', '"TT',		# will put quotes, cf. &apply_style
    183  1.1  christos 	      'i', 'I',
    184  1.1  christos 	      'kbd', 'KBD',
    185  1.1  christos 	      'key', 'KBD',
    186  1.1  christos 	      'math', 'EM',
    187  1.1  christos 	      'r', '',			# unsupported
    188  1.1  christos 	      'samp', '"SAMP',		# will put quotes, cf. &apply_style
    189  1.1  christos 	      'sc', '&do_sc',		# special case
    190  1.1  christos 	      'strong', 'STRONG',
    191  1.1  christos 	      't', 'TT',
    192  1.1  christos 	      'titlefont', '',		# useless
    193  1.1  christos 	      'uref', '&do_uref',       # insert a clickable URL
    194  1.1  christos 	      'url', '&do_url',         # insert a clickable URL
    195  1.1  christos 	      'var', 'VAR',
    196  1.1  christos 	      'w', '',			# unsupported
    197  1.1  christos 	      '"', '&do_diaeresis',
    198  1.1  christos 	      '\'', '&do_acuteaccent',	# doesn't work??
    199  1.1  christos 	      '\`', '&do_graveaccent',	# doesn't work??
    200  1.1  christos 	      '~', '&do_tildeaccent',
    201  1.1  christos 	      ',', '&do_cedilla',
    202  1.1  christos 	      '^', '&do_circumflex',
    203  1.1  christos 	      );
    204  1.1  christos 
    205  1.1  christos #
    206  1.1  christos # texinfo format (@foo/@end foo) to HTML ones
    207  1.1  christos #
    208  1.1  christos %format_map = (
    209  1.1  christos 	       'display', 'PRE',
    210  1.1  christos 	       'example', 'PRE',
    211  1.1  christos 	       'format', 'PRE',
    212  1.1  christos 	       'lisp', 'PRE',
    213  1.1  christos 	       'quotation', 'BLOCKQUOTE',
    214  1.1  christos 	       'smallexample', 'PRE',
    215  1.1  christos 	       'smalllisp', 'PRE',
    216  1.1  christos 	       # lists
    217  1.1  christos 	       'itemize', 'UL',
    218  1.1  christos 	       'enumerate', 'OL',
    219  1.1  christos 	       # poorly supported
    220  1.1  christos 	       'flushleft', 'PRE',
    221  1.1  christos 	       'flushright', 'PRE',
    222  1.1  christos 	       );
    223  1.1  christos 
    224  1.1  christos #
    225  1.1  christos # texinfo definition shortcuts to real ones
    226  1.1  christos #
    227  1.1  christos %def_map = (
    228  1.1  christos 	    # basic commands
    229  1.1  christos 	    'deffn', 0,
    230  1.1  christos 	    'defvr', 0,
    231  1.1  christos 	    'deftypefn', 0,
    232  1.1  christos 	    'deftypevr', 0,
    233  1.1  christos 	    'defcv', 0,
    234  1.1  christos 	    'defop', 0,
    235  1.1  christos 	    'deftp', 0,
    236  1.1  christos 	    # basic x commands
    237  1.1  christos 	    'deffnx', 0,
    238  1.1  christos 	    'defvrx', 0,
    239  1.1  christos 	    'deftypefnx', 0,
    240  1.1  christos 	    'deftypevrx', 0,
    241  1.1  christos 	    'defcvx', 0,
    242  1.1  christos 	    'defopx', 0,
    243  1.1  christos 	    'deftpx', 0,
    244  1.1  christos 	    # shortcuts
    245  1.1  christos 	    'defun', 'deffn Function',
    246  1.1  christos 	    'defmac', 'deffn Macro',
    247  1.1  christos 	    'defspec', 'deffn {Special Form}',
    248  1.1  christos 	    'defvar', 'defvr Variable',
    249  1.1  christos 	    'defopt', 'defvr {User Option}',
    250  1.1  christos 	    'deftypefun', 'deftypefn Function',
    251  1.1  christos 	    'deftypevar', 'deftypevr Variable',
    252  1.1  christos 	    'defivar', 'defcv {Instance Variable}',
    253  1.1  christos 	    'defmethod', 'defop Method',
    254  1.1  christos 	    # x shortcuts
    255  1.1  christos 	    'defunx', 'deffnx Function',
    256  1.1  christos 	    'defmacx', 'deffnx Macro',
    257  1.1  christos 	    'defspecx', 'deffnx {Special Form}',
    258  1.1  christos 	    'defvarx', 'defvrx Variable',
    259  1.1  christos 	    'defoptx', 'defvrx {User Option}',
    260  1.1  christos 	    'deftypefunx', 'deftypefnx Function',
    261  1.1  christos 	    'deftypevarx', 'deftypevrx Variable',
    262  1.1  christos 	    'defivarx', 'defcvx {Instance Variable}',
    263  1.1  christos 	    'defmethodx', 'defopx Method',
    264  1.1  christos 	    );
    265  1.1  christos 
    266  1.1  christos #
    267  1.1  christos # things to skip
    268  1.1  christos #
    269  1.1  christos %to_skip = (
    270  1.1  christos 	    # comments
    271  1.1  christos 	    'c', 1,
    272  1.1  christos 	    'comment', 1,
    273  1.1  christos 	    # useless
    274  1.1  christos 	    'contents', 1,
    275  1.1  christos 	    'shortcontents', 1,
    276  1.1  christos 	    'summarycontents', 1,
    277  1.1  christos 	    'footnotestyle', 1,
    278  1.1  christos 	    'end ifclear', 1,
    279  1.1  christos 	    'end ifset', 1,
    280  1.1  christos 	    'titlepage', 1,
    281  1.1  christos 	    'end titlepage', 1,
    282  1.1  christos 	    # unsupported commands (formatting)
    283  1.1  christos 	    'afourpaper', 1,
    284  1.1  christos 	    'cropmarks', 1,
    285  1.1  christos 	    'finalout', 1,
    286  1.1  christos 	    'headings', 1,
    287  1.1  christos 	    'need', 1,
    288  1.1  christos 	    'page', 1,
    289  1.1  christos 	    'setchapternewpage', 1,
    290  1.1  christos 	    'everyheading', 1,
    291  1.1  christos 	    'everyfooting', 1,
    292  1.1  christos 	    'evenheading', 1,
    293  1.1  christos 	    'evenfooting', 1,
    294  1.1  christos 	    'oddheading', 1,
    295  1.1  christos 	    'oddfooting', 1,
    296  1.1  christos 	    'smallbook', 1,
    297  1.1  christos 	    'vskip', 1,
    298  1.1  christos 	    'filbreak', 1,
    299  1.1  christos 	    'paragraphindent', 1,
    300  1.1  christos 	    # unsupported formats
    301  1.1  christos 	    'cartouche', 1,
    302  1.1  christos 	    'end cartouche', 1,
    303  1.1  christos 	    'group', 1,
    304  1.1  christos 	    'end group', 1,
    305  1.1  christos 	    );
    306  1.1  christos 
    307  1.1  christos #+++############################################################################
    308  1.1  christos #                                                                              #
    309  1.1  christos # Argument parsing, initialisation                                             #
    310  1.1  christos #                                                                              #
    311  1.1  christos #---############################################################################
    312  1.1  christos 
    313  1.1  christos %value = ();				# hold texinfo variables, see also -D
    314  1.1  christos 
    315  1.1  christos $use_bibliography = 1;
    316  1.1  christos $use_acc = 0;
    317  1.1  christos $debug = 0;
    318  1.1  christos $doctype = '';
    319  1.1  christos $check = 0;
    320  1.1  christos $expandinfo = 0;
    321  1.1  christos $expandtex = 0;
    322  1.1  christos $use_glossary = 0;
    323  1.1  christos $invisible_mark = '';
    324  1.1  christos $use_iso = 0;
    325  1.1  christos @include_dirs = ();
    326  1.1  christos $show_menu = 0;
    327  1.1  christos $number_sections = 0;
    328  1.1  christos $split_node = 0;
    329  1.1  christos $split_chapter = 0;
    330  1.1  christos $monolithic = 0;
    331  1.1  christos $verbose = 0;
    332  1.1  christos $usage = <<EOT;
    333  1.1  christos This is $THISPROG
    334  1.1  christos To convert a Texinfo file to HMTL: $0 [options] file
    335  1.1  christos   where options can be:
    336  1.1  christos     -expandinfo    : use \@ifinfo sections, not \@ifhtml
    337  1.1  christos     -expandtex     : use \@iftex sections, not \@ifhtml
    338  1.1  christos     -glossary      : handle a glossary
    339  1.1  christos     -invisible name: use 'name' as an invisible anchor
    340  1.1  christos     -Dname         : define name like with \@set
    341  1.1  christos     -I dir         : search also for files in 'dir'
    342  1.1  christos     -menu          : handle menus
    343  1.1  christos     -monolithic    : output only one file including ToC
    344  1.1  christos     -number        : number sections
    345  1.1  christos     -split_chapter : split on main sections
    346  1.1  christos     -split_node    : split on nodes
    347  1.1  christos     -usage         : print usage instructions
    348  1.1  christos     -verbose       : verbose output
    349  1.1  christos To check converted files: $0 -check [-verbose] files
    350  1.1  christos EOT
    351  1.1  christos 
    352  1.1  christos while (@ARGV && $ARGV[0] =~ /^-/) {
    353  1.1  christos     $_ = shift(@ARGV);
    354  1.1  christos     if (/^-acc$/)            { $use_acc = 1; next; }
    355  1.1  christos     if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift(@ARGV); next; }
    356  1.1  christos     if (/^-doctype$/)        { $doctype = shift(@ARGV); next; }
    357  1.1  christos     if (/^-c(heck)?$/)       { $check = 1; next; }
    358  1.1  christos     if (/^-expandi(nfo)?$/)  { $expandinfo = 1; next; }
    359  1.1  christos     if (/^-expandt(ex)?$/)   { $expandtex = 1; next; }
    360  1.1  christos     if (/^-g(lossary)?$/)    { $use_glossary = 1; next; }
    361  1.1  christos     if (/^-i(nvisible)?$/)   { $invisible_mark = shift(@ARGV); next; }
    362  1.1  christos     if (/^-iso$/)            { $use_iso = 1; next; }
    363  1.1  christos     if (/^-D(.+)?$/)         { $value{$1 || shift(@ARGV)} = 1; next; }
    364  1.1  christos     if (/^-I(.+)?$/)         { push(@include_dirs, $1 || shift(@ARGV)); next; }
    365  1.1  christos     if (/^-m(enu)?$/)        { $show_menu = 1; next; }
    366  1.1  christos     if (/^-mono(lithic)?$/)  { $monolithic = 1; next; }
    367  1.1  christos     if (/^-n(umber)?$/)      { $number_sections = 1; next; }
    368  1.1  christos     if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) {
    369  1.1  christos 	if ($2 =~ /^n/) {
    370  1.1  christos 	    $split_node = 1;
    371  1.1  christos 	} else {
    372  1.1  christos 	    $split_chapter = 1;
    373  1.1  christos 	}
    374  1.1  christos 	next;
    375  1.1  christos     }
    376  1.1  christos     if (/^-v(erbose)?$/)     { $verbose = 1; next; }
    377  1.1  christos     die $usage;
    378  1.1  christos }
    379  1.1  christos if ($check) {
    380  1.1  christos     die $usage unless @ARGV > 0;
    381  1.1  christos     &check;
    382  1.1  christos     exit;
    383  1.1  christos }
    384  1.1  christos 
    385  1.1  christos if (($split_node || $split_chapter) && $monolithic) {
    386  1.1  christos     warn "Can't use -monolithic with -split, -monolithic ignored.\n";
    387  1.1  christos     $monolithic = 0;
    388  1.1  christos }
    389  1.1  christos if ($expandinfo) {
    390  1.1  christos     $to_skip{'ifinfo'}++;
    391  1.1  christos     $to_skip{'end ifinfo'}++;
    392  1.1  christos     $to_skip{'ifnottex'}++;
    393  1.1  christos     $to_skip{'end ifnottex'}++;
    394  1.1  christos     $to_skip{'ifnothtml'}++;
    395  1.1  christos     $to_skip{'end ifnothtml'}++;
    396  1.1  christos } elsif ($expandtex) {
    397  1.1  christos     $to_skip{'ifnotinfo'}++;
    398  1.1  christos     $to_skip{'end ifnotinfo'}++;
    399  1.1  christos     $to_skip{'iftex'}++;
    400  1.1  christos     $to_skip{'end iftex'}++;
    401  1.1  christos     $to_skip{'ifnothtml'}++;
    402  1.1  christos     $to_skip{'end ifnothtml'}++;
    403  1.1  christos } else {
    404  1.1  christos     $to_skip{'ifnotinfo'}++;
    405  1.1  christos     $to_skip{'end ifnotinfo'}++;
    406  1.1  christos     $to_skip{'ifnottex'}++;
    407  1.1  christos     $to_skip{'end ifnottex'}++;
    408  1.1  christos     $to_skip{'ifhtml'}++;
    409  1.1  christos     $to_skip{'end ifhtml'}++;
    410  1.1  christos }
    411  1.1  christos $invisible_mark = '<IMG SRC="invisible.xbm">' if $invisible_mark eq 'xbm';
    412  1.1  christos die $usage unless @ARGV == 1;
    413  1.1  christos $docu = shift(@ARGV);
    414  1.1  christos if ($docu =~ /.*\//) {
    415  1.1  christos     chop($docu_dir = $&);
    416  1.1  christos     $docu_name = $';
    417  1.1  christos } else {
    418  1.1  christos     $docu_dir = '.';
    419  1.1  christos     $docu_name = $docu;
    420  1.1  christos }
    421  1.1  christos unshift(@include_dirs, $docu_dir);
    422  1.1  christos $docu_name =~ s/\.te?x(i|info)?$//;	# basename of the document
    423  1.1  christos 
    424  1.1  christos $docu_doc = "$docu_name.html";		# document's contents
    425  1.1  christos if ($monolithic) {
    426  1.1  christos     $docu_toc = $docu_foot = $docu_doc;
    427  1.1  christos } else {
    428  1.1  christos     $docu_toc  = "${docu_name}_toc.html";  # document's table of contents
    429  1.1  christos     $docu_foot = "${docu_name}_foot.html"; # document's footnotes
    430  1.1  christos }
    431  1.1  christos 
    432  1.1  christos #
    433  1.1  christos # variables
    434  1.1  christos #
    435  1.1  christos $value{'html'} = 1;			# predefine html (the output format)
    436  1.1  christos $value{'texi2html'} = '1.52b';		# predefine texi2html (the translator)
    437  1.1  christos # _foo: internal to track @foo
    438  1.1  christos foreach ('_author', '_title', '_subtitle',
    439  1.1  christos 	 '_settitle', '_setfilename') {
    440  1.1  christos     $value{$_} = '';		        # prevent -w warnings
    441  1.1  christos }
    442  1.1  christos %node2sec = ();				# node to section name
    443  1.1  christos %node2href = ();			# node to HREF
    444  1.1  christos %bib2href = ();				# bibliography reference to HREF
    445  1.1  christos %gloss2href = ();			# glossary term to HREF
    446  1.1  christos @sections = ();				# list of sections
    447  1.1  christos %tag2pro = ();				# protected sections
    448  1.1  christos 
    449  1.1  christos #
    450  1.1  christos # initial indexes
    451  1.1  christos #
    452  1.1  christos $bib_num = 0;
    453  1.1  christos $foot_num = 0;
    454  1.1  christos $gloss_num = 0;
    455  1.1  christos $idx_num = 0;
    456  1.1  christos $sec_num = 0;
    457  1.1  christos $doc_num = 0;
    458  1.1  christos $html_num = 0;
    459  1.1  christos 
    460  1.1  christos #
    461  1.1  christos # can I use ISO8879 characters? (HTML+)
    462  1.1  christos #
    463  1.1  christos if ($use_iso) {
    464  1.1  christos     $things_map{'bullet'} = "&bull;";
    465  1.1  christos     $things_map{'copyright'} = "&copy;";
    466  1.1  christos     $things_map{'dots'} = "&hellip;";
    467  1.1  christos     $things_map{'equiv'} = "&equiv;";
    468  1.1  christos     $things_map{'expansion'} = "&rarr;";
    469  1.1  christos     $things_map{'point'} = "&lowast;";
    470  1.1  christos     $things_map{'result'} = "&rArr;";
    471  1.1  christos }
    472  1.1  christos 
    473  1.1  christos #
    474  1.1  christos # read texi2html extensions (if any)
    475  1.1  christos #
    476  1.1  christos $extensions = 'texi2html.ext'; # extensions in working directory
    477  1.1  christos if (-f $extensions) {
    478  1.1  christos     print "# reading extensions from $extensions\n" if $verbose;
    479  1.1  christos     require($extensions);
    480  1.1  christos }
    481  1.1  christos ($progdir = $0) =~ s/[^\/]+$//;
    482  1.1  christos if ($progdir && ($progdir ne './')) {
    483  1.1  christos     $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
    484  1.1  christos     if (-f $extensions) {
    485  1.1  christos 	print "# reading extensions from $extensions\n" if $verbose;
    486  1.1  christos 	require($extensions);
    487  1.1  christos     }
    488  1.1  christos }
    489  1.1  christos 
    490  1.1  christos print "# reading from $docu\n" if $verbose;
    491  1.1  christos 
    492  1.1  christos #+++############################################################################
    493  1.1  christos #                                                                              #
    494  1.1  christos # Pass 1: read source, handle command, variable, simple substitution           #
    495  1.1  christos #                                                                              #
    496  1.1  christos #---############################################################################
    497  1.1  christos 
    498  1.1  christos @lines = ();				# whole document
    499  1.1  christos @toc_lines = ();			# table of contents
    500  1.1  christos $toplevel = 0;			        # top level seen in hierarchy
    501  1.1  christos $curlevel = 0;				# current level in TOC
    502  1.1  christos $node = '';				# current node name
    503  1.1  christos $in_table = 0;				# am I inside a table
    504  1.1  christos $table_type = '';			# type of table ('', 'f', 'v', 'multi')
    505  1.1  christos @tables = ();			        # nested table support
    506  1.1  christos $in_bibliography = 0;			# am I inside a bibliography
    507  1.1  christos $in_glossary = 0;			# am I inside a glossary
    508  1.1  christos $in_top = 0;				# am I inside the top node
    509  1.1  christos $in_pre = 0;				# am I inside a preformatted section
    510  1.1  christos $in_list = 0;				# am I inside a list
    511  1.1  christos $in_html = 0;				# am I inside an HTML section
    512  1.1  christos $first_line = 1;		        # is it the first line
    513  1.1  christos $dont_html = 0;				# don't protect HTML on this line
    514  1.1  christos $split_num = 0;				# split index
    515  1.1  christos $deferred_ref = '';			# deferred reference for indexes
    516  1.1  christos @html_stack = ();			# HTML elements stack
    517  1.1  christos $html_element = '';			# current HTML element
    518  1.1  christos &html_reset;
    519  1.1  christos 
    520  1.1  christos # build code for simple substitutions
    521  1.1  christos # the maps used (%simple_map and %things_map) MUST be aware of this
    522  1.1  christos # watch out for regexps, / and escaped characters!
    523  1.1  christos $subst_code = '';
    524  1.1  christos foreach (keys(%simple_map)) {
    525  1.1  christos     ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
    526  1.1  christos     $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
    527  1.1  christos }
    528  1.1  christos foreach (keys(%things_map)) {
    529  1.1  christos     $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
    530  1.1  christos }
    531  1.1  christos if ($use_acc) {
    532  1.1  christos     # accentuated characters
    533  1.1  christos     foreach (keys(%accent_map)) {
    534  1.1  christos 	if ($_ eq "`") {
    535  1.1  christos 	    $subst_code .= "s/$;3";
    536  1.1  christos 	} elsif ($_ eq "'") {
    537  1.1  christos 	    $subst_code .= "s/$;4";
    538  1.1  christos 	} else {
    539  1.1  christos 	    $subst_code .= "s/\\\@\\$_";
    540  1.1  christos 	}
    541  1.1  christos 	$subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n";
    542  1.1  christos     }
    543  1.1  christos }
    544  1.1  christos eval("sub simple_substitutions { $subst_code }");
    545  1.1  christos 
    546  1.1  christos &init_input;
    547  1.1  christos while ($_ = &next_line) {
    548  1.1  christos     #
    549  1.1  christos     # remove \input on the first lines only
    550  1.1  christos     #
    551  1.1  christos     if ($first_line) {
    552  1.1  christos 	next if /^\\input/;
    553  1.1  christos 	$first_line = 0;
    554  1.1  christos     }
    555  1.1  christos     #
    556  1.1  christos     # parse texinfo tags
    557  1.1  christos     #
    558  1.1  christos     $tag = '';
    559  1.1  christos     $end_tag = '';
    560  1.1  christos     if (/^\@end\s+(\w+)\b/) {
    561  1.1  christos 	$end_tag = $1;
    562  1.1  christos     } elsif (/^\@(\w+)\b/) {
    563  1.1  christos 	$tag = $1;
    564  1.1  christos     }
    565  1.1  christos     #
    566  1.1  christos     # handle @ifhtml / @end ifhtml
    567  1.1  christos     #
    568  1.1  christos     if ($in_html) {
    569  1.1  christos 	if ($end_tag eq 'ifhtml') {
    570  1.1  christos 	    $in_html = 0;
    571  1.1  christos 	} else {
    572  1.1  christos 	    $tag2pro{$in_html} .= $_;
    573  1.1  christos 	}
    574  1.1  christos 	next;
    575  1.1  christos     } elsif ($tag eq 'ifhtml') {
    576  1.1  christos 	$in_html = $PROTECTTAG . ++$html_num;
    577  1.1  christos 	push(@lines, $in_html);
    578  1.1  christos 	next;
    579  1.1  christos     }
    580  1.1  christos     #
    581  1.1  christos     # try to skip the line
    582  1.1  christos     #
    583  1.1  christos     if ($end_tag) {
    584  1.1  christos 	next if $to_skip{"end $end_tag"};
    585  1.1  christos     } elsif ($tag) {
    586  1.1  christos 	next if $to_skip{$tag};
    587  1.1  christos 	last if $tag eq 'bye';
    588  1.1  christos     }
    589  1.1  christos     if ($in_top) {
    590  1.1  christos 	# parsing the top node
    591  1.1  christos 	if ($tag eq 'node' || $tag eq 'include' || $sec2level{$tag}) {
    592  1.1  christos 	    # no more in top
    593  1.1  christos 	    $in_top = 0;
    594  1.1  christos 	} else {
    595  1.1  christos 	    # skip it
    596  1.1  christos 	    next;
    597  1.1  christos 	}
    598  1.1  christos     }
    599  1.1  christos     #
    600  1.1  christos     # try to remove inlined comments
    601  1.1  christos     # syntax from tex-mode.el comment-start-skip
    602  1.1  christos     #
    603  1.1  christos     s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/;
    604  1.1  christos     # non-@ substitutions cf. texinfmt.el
    605  1.1  christos     unless ($in_pre) {
    606  1.1  christos 	s/``//g;
    607  1.1  christos 	s/''//g;
    608  1.1  christos 	s/([\w ])---([\w ])/$1--$2/g;
    609  1.1  christos     }
    610  1.1  christos     #
    611  1.1  christos     # analyze the tag
    612  1.1  christos     #
    613  1.1  christos     if ($tag) {
    614  1.1  christos 	# skip lines
    615  1.1  christos 	&skip_until($tag), next if $tag eq 'ignore';
    616  1.1  christos 	if ($expandinfo) {
    617  1.1  christos 	    &skip_until($tag), next if $tag eq 'ifnotinfo';
    618  1.1  christos 	    &skip_until($tag), next if $tag eq 'iftex';
    619  1.1  christos 	    &skip_until($tag), next if $tag eq 'ifhtml';
    620  1.1  christos 	} elsif ($expandtex) {
    621  1.1  christos 	    &skip_until($tag), next if $tag eq 'ifinfo';
    622  1.1  christos 	    &skip_until($tag), next if $tag eq 'ifnottex';
    623  1.1  christos 	    &skip_until($tag), next if $tag eq 'ifhtml';
    624  1.1  christos 	} else {
    625  1.1  christos 	    &skip_until($tag), next if $tag eq 'ifinfo';
    626  1.1  christos 	    &skip_until($tag), next if $tag eq 'iftex';
    627  1.1  christos 	    &skip_until($tag), next if $tag eq 'ifnothtml';
    628  1.1  christos 	}
    629  1.1  christos 	&skip_until($tag), next if $tag eq 'tex';
    630  1.1  christos 	# handle special tables
    631  1.1  christos 	if ($tag =~ /^(|f|v|multi)table$/) {
    632  1.1  christos 	    $table_type = $1;
    633  1.1  christos 	    $tag = 'table';
    634  1.1  christos 	}
    635  1.1  christos 	# special cases
    636  1.1  christos 	if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+top\s*,/i)) {
    637  1.1  christos 	    $in_top = 1;
    638  1.1  christos 	    @lines = (); # ignore all lines before top (title page garbage)
    639  1.1  christos 	    next;
    640  1.1  christos 	} elsif ($tag eq 'node') {
    641  1.1  christos 	    $in_top = 0;
    642  1.1  christos 	    warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o;
    643  1.1  christos 	    $_ = &protect_html($_); # if node contains '&' for instance
    644  1.1  christos 	    s/^\@node\s+//;
    645  1.1  christos 	    ($node) = split(/,/);
    646  1.1  christos 	    &normalise_node($node);
    647  1.1  christos 	    if ($split_node) {
    648  1.1  christos 		&next_doc;
    649  1.1  christos 		push(@lines, $SPLITTAG) if $split_num++;
    650  1.1  christos 		push(@sections, $node);
    651  1.1  christos 	    }
    652  1.1  christos 	    next;
    653  1.1  christos 	} elsif ($tag eq 'include') {
    654  1.1  christos 	    if (/^\@include\s+($FILERE)\s*$/o) {
    655  1.1  christos 		$file = $1;
    656  1.1  christos 		unless (-e $file) {
    657  1.1  christos 		    foreach $dir (@include_dirs) {
    658  1.1  christos 			$file = "$dir/$1";
    659  1.1  christos 			last if -e $file;
    660  1.1  christos 		    }
    661  1.1  christos 		}
    662  1.1  christos 		if (-e $file) {
    663  1.1  christos 		    &open($file);
    664  1.1  christos 		    print "# including $file\n" if $verbose;
    665  1.1  christos 		} else {
    666  1.1  christos 		    warn "$ERROR Can't find $file, skipping";
    667  1.1  christos 		}
    668  1.1  christos 	    } else {
    669  1.1  christos 		warn "$ERROR Bad include line: $_";
    670  1.1  christos 	    }
    671  1.1  christos 	    next;
    672  1.1  christos 	} elsif ($tag eq 'ifclear') {
    673  1.1  christos 	    if (/^\@ifclear\s+($VARRE)\s*$/o) {
    674  1.1  christos 		next unless defined($value{$1});
    675  1.1  christos 		&skip_until($tag);
    676  1.1  christos 	    } else {
    677  1.1  christos 		warn "$ERROR Bad ifclear line: $_";
    678  1.1  christos 	    }
    679  1.1  christos 	    next;
    680  1.1  christos 	} elsif ($tag eq 'ifset') {
    681  1.1  christos 	    if (/^\@ifset\s+($VARRE)\s*$/o) {
    682  1.1  christos 		next if defined($value{$1});
    683  1.1  christos 		&skip_until($tag);
    684  1.1  christos 	    } else {
    685  1.1  christos 		warn "$ERROR Bad ifset line: $_";
    686  1.1  christos 	    }
    687  1.1  christos 	    next;
    688  1.1  christos 	} elsif ($tag eq 'menu') {
    689  1.1  christos 	    unless ($show_menu) {
    690  1.1  christos 		&skip_until($tag);
    691  1.1  christos 		next;
    692  1.1  christos 	    }
    693  1.1  christos 	    &html_push_if($tag);
    694  1.1  christos 	    push(@lines, &html_debug("\n", __LINE__));
    695  1.1  christos 	} elsif ($format_map{$tag}) {
    696  1.1  christos 	    $in_pre = 1 if $format_map{$tag} eq 'PRE';
    697  1.1  christos 	    &html_push_if($format_map{$tag});
    698  1.1  christos 	    push(@lines, &html_debug("\n", __LINE__));
    699  1.1  christos 	    $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ;
    700  1.1  christos 	    push(@lines, &debug("<$format_map{$tag}>\n", __LINE__));
    701  1.1  christos 	    next;
    702  1.1  christos 	} elsif ($tag eq 'table') {
    703  1.1  christos 	    if (/^\@(|f|v|multi)table\s+\@(\w+)/) {
    704  1.1  christos 		$in_table = $2;
    705  1.1  christos 		unshift(@tables, join($;, $table_type, $in_table));
    706  1.1  christos 		if ($table_type eq "multi") {
    707  1.1  christos 		    push(@lines, &debug("<TABLE BORDER>\n", __LINE__));
    708  1.1  christos 		    &html_push_if('TABLE');
    709  1.1  christos 		} else {
    710  1.1  christos 		    push(@lines, &debug("<DL COMPACT>\n", __LINE__));
    711  1.1  christos 		    &html_push_if('DL');
    712  1.1  christos 		}
    713  1.1  christos 		push(@lines, &html_debug("\n", __LINE__));
    714  1.1  christos 	    } else {
    715  1.1  christos 		warn "$ERROR Bad table line: $_";
    716  1.1  christos 	    }
    717  1.1  christos 	    next;
    718  1.1  christos 	} elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
    719  1.1  christos 	    if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
    720  1.1  christos 		eval("*${1}index = *${2}index");
    721  1.1  christos 	    } else {
    722  1.1  christos 		warn "$ERROR Bad syn*index line: $_";
    723  1.1  christos 	    }
    724  1.1  christos 	    next;
    725  1.1  christos 	} elsif ($tag eq 'sp') {
    726  1.1  christos 	    push(@lines, &debug("<P>\n", __LINE__));
    727  1.1  christos 	    next;
    728  1.1  christos 	} elsif ($tag eq 'setref') {
    729  1.1  christos 	    &protect_html; # if setref contains '&' for instance
    730  1.1  christos 	    if (/^\@$tag\s*{($NODERE)}\s*$/) {
    731  1.1  christos 		$setref = $1;
    732  1.1  christos 		$setref =~ s/\s+/ /g; # normalize
    733  1.1  christos 		$setref =~ s/ $//;
    734  1.1  christos 		$node2sec{$setref} = $name;
    735  1.1  christos 		$node2href{$setref} = "$docu_doc#$docid";
    736  1.1  christos 	    } else {
    737  1.1  christos 		warn "$ERROR Bad setref line: $_";
    738  1.1  christos 	    }
    739  1.1  christos 	    next;
    740  1.1  christos 	} elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') {
    741  1.1  christos 	    if (/^\@$tag\s+(\w\w)\s*$/) {
    742  1.1  christos 		$valid_index{$1} = 1;
    743  1.1  christos 	    } else {
    744  1.1  christos 		warn "$ERROR Bad defindex line: $_";
    745  1.1  christos 	    }
    746  1.1  christos 	    next;
    747  1.1  christos 	} elsif (defined($def_map{$tag})) {
    748  1.1  christos 	    if ($def_map{$tag}) {
    749  1.1  christos 		s/^\@$tag\s+//;
    750  1.1  christos 		$tag = $def_map{$tag};
    751  1.1  christos 		$_ = "\@$tag $_";
    752  1.1  christos 		$tag =~ s/\s.*//;
    753  1.1  christos 	    }
    754  1.1  christos 	} elsif (defined($user_sub{$tag})) {
    755  1.1  christos 	    s/^\@$tag\s+//;
    756  1.1  christos 	    $sub = $user_sub{$tag};
    757  1.1  christos 	    print "# user $tag = $sub, arg: $_" if $debug & $DEBUG_USER;
    758  1.1  christos 	    if (defined(&$sub)) {
    759  1.1  christos 		chop($_);
    760  1.1  christos 		&$sub($_);
    761  1.1  christos 	    } else {
    762  1.1  christos 		warn "$ERROR Bad user sub for $tag: $sub\n";
    763  1.1  christos 	    }
    764  1.1  christos 	    next;
    765  1.1  christos 	}
    766  1.1  christos 	if (defined($def_map{$tag})) {
    767  1.1  christos 	    s/^\@$tag\s+//;
    768  1.1  christos 	    if ($tag =~ /x$/) {
    769  1.1  christos 		# extra definition line
    770  1.1  christos 		$tag = $`;
    771  1.1  christos 		$is_extra = 1;
    772  1.1  christos 	    } else {
    773  1.1  christos 		$is_extra = 0;
    774  1.1  christos 	    }
    775  1.1  christos 	    while (/\{([^\{\}]*)\}/) {
    776  1.1  christos 		# this is a {} construct
    777  1.1  christos 		($before, $contents, $after) = ($`, $1, $');
    778  1.1  christos 		# protect spaces
    779  1.1  christos 		$contents =~ s/\s+/$;9/g;
    780  1.1  christos 		# restore $_ protecting {}
    781  1.1  christos 		$_ = "$before$;7$contents$;8$after";
    782  1.1  christos 	    }
    783  1.1  christos 	    @args = split(/\s+/, &protect_html($_));
    784  1.1  christos 	    foreach (@args) {
    785  1.1  christos 		s/$;9/ /g;	# unprotect spaces
    786  1.1  christos 		s/$;7/\{/g;	# ... {
    787  1.1  christos 		s/$;8/\}/g;	# ... }
    788  1.1  christos 	    }
    789  1.1  christos 	    $type = shift(@args);
    790  1.1  christos 	    $type =~ s/^\{(.*)\}$/$1/;
    791  1.1  christos 	    print "# def ($tag): {$type} ", join(', ', @args), "\n"
    792  1.1  christos 		if $debug & $DEBUG_DEF;
    793  1.1  christos 	    $type .= ':'; # it's nicer like this
    794  1.1  christos 	    $name = shift(@args);
    795  1.1  christos 	    $name =~ s/^\{(.*)\}$/$1/;
    796  1.1  christos 	    if ($is_extra) {
    797  1.1  christos 		$_ = &debug("<DT>", __LINE__);
    798  1.1  christos 	    } else {
    799  1.1  christos 		$_ = &debug("<DL>\n<DT>", __LINE__);
    800  1.1  christos 	    }
    801  1.1  christos 	    if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
    802  1.1  christos 		$_ .= "<U>$type</U> <B>$name</B>";
    803  1.1  christos 		$_ .= " <I>@args</I>" if @args;
    804  1.1  christos 	    } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
    805  1.1  christos 		     || $tag eq 'defcv' || $tag eq 'defop') {
    806  1.1  christos 		$ftype = $name;
    807  1.1  christos 		$name = shift(@args);
    808  1.1  christos 		$name =~ s/^\{(.*)\}$/$1/;
    809  1.1  christos 		$_ .= "<U>$type</U> $ftype <B>$name</B>";
    810  1.1  christos 		$_ .= " <I>@args</I>" if @args;
    811  1.1  christos 	    } else {
    812  1.1  christos 		warn "$ERROR Unknown definition type: $tag\n";
    813  1.1  christos 		$_ .= "<U>$type</U> <B>$name</B>";
    814  1.1  christos 		$_ .= " <I>@args</I>" if @args;
    815  1.1  christos 	    }
    816  1.1  christos  	    $_ .= &debug("\n<DD>", __LINE__);
    817  1.1  christos 	    $name = &unprotect_html($name);
    818  1.1  christos 	    if ($tag eq 'deffn' || $tag eq 'deftypefn') {
    819  1.1  christos 		unshift(@input_spool, "\@findex $name\n");
    820  1.1  christos 	    } elsif ($tag eq 'defop') {
    821  1.1  christos 		unshift(@input_spool, "\@findex $name on $ftype\n");
    822  1.1  christos 	    } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
    823  1.1  christos 		unshift(@input_spool, "\@vindex $name\n");
    824  1.1  christos 	    } else {
    825  1.1  christos 		unshift(@input_spool, "\@tindex $name\n");
    826  1.1  christos 	    }
    827  1.1  christos 	    $dont_html = 1;
    828  1.1  christos 	}
    829  1.1  christos     } elsif ($end_tag) {
    830  1.1  christos 	if ($format_map{$end_tag}) {
    831  1.1  christos 	    $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
    832  1.1  christos 	    $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ;
    833  1.1  christos 	    &html_pop_if('LI', 'P');
    834  1.1  christos 	    &html_pop_if();
    835  1.1  christos 	    push(@lines, &debug("</$format_map{$end_tag}>\n", __LINE__));
    836  1.1  christos 	    push(@lines, &html_debug("\n", __LINE__));
    837  1.1  christos 	} elsif ($end_tag =~ /^(|f|v|multi)table$/) {
    838  1.1  christos 	    unless (@tables) {
    839  1.1  christos 		warn "$ERROR \@end $end_tag without \@*table\n";
    840  1.1  christos 		next;
    841  1.1  christos 	    }
    842  1.1  christos 	    ($table_type, $in_table) = split($;, shift(@tables));
    843  1.1  christos 	    unless ($1 eq $table_type) {
    844  1.1  christos 		warn "$ERROR \@end $end_tag without matching \@$end_tag\n";
    845  1.1  christos 		next;
    846  1.1  christos 	    }
    847  1.1  christos 	    if ($table_type eq "multi") {
    848  1.1  christos 		push(@lines, "</TR></TABLE>\n");
    849  1.1  christos 		&html_pop_if('TR');
    850  1.1  christos 	    } else {
    851  1.1  christos 		push(@lines, "</DL>\n");
    852  1.1  christos 		&html_pop_if('DD');
    853  1.1  christos 	    }
    854  1.1  christos 	    &html_pop_if();
    855  1.1  christos 	    if (@tables) {
    856  1.1  christos 		($table_type, $in_table) = split($;, $tables[0]);
    857  1.1  christos 	    } else {
    858  1.1  christos 		$in_table = 0;
    859  1.1  christos 	    }
    860  1.1  christos 	} elsif (defined($def_map{$end_tag})) {
    861  1.1  christos  	    push(@lines, &debug("</DL>\n", __LINE__));
    862  1.1  christos 	} elsif ($end_tag eq 'menu') {
    863  1.1  christos 	    &html_pop_if();
    864  1.1  christos 	    push(@lines, $_); # must keep it for pass 2
    865  1.1  christos 	}
    866  1.1  christos 	next;
    867  1.1  christos     }
    868  1.1  christos     #
    869  1.1  christos     # misc things
    870  1.1  christos     #
    871  1.1  christos     # protect texi and HTML things
    872  1.1  christos     &protect_texi;
    873  1.1  christos     $_ = &protect_html($_) unless $dont_html;
    874  1.1  christos     $dont_html = 0;
    875  1.1  christos     # substitution (unsupported things)
    876  1.1  christos     s/^\@center\s+//g;
    877  1.1  christos     s/^\@exdent\s+//g;
    878  1.1  christos     s/\@noindent\s+//g;
    879  1.1  christos     s/\@refill\s+//g;
    880  1.1  christos     # other substitutions
    881  1.1  christos     &simple_substitutions;
    882  1.1  christos     s/\@value{($VARRE)}/$value{$1}/eg;
    883  1.1  christos     s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
    884  1.1  christos     #
    885  1.1  christos     # analyze the tag again
    886  1.1  christos     #
    887  1.1  christos     if ($tag) {
    888  1.1  christos 	if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) {
    889  1.1  christos 	    if (/^\@$tag\s+(.+)$/) {
    890  1.1  christos 		$name = $1;
    891  1.1  christos 		$name =~ s/\s+$//;
    892  1.1  christos 		$level = $sec2level{$tag};
    893  1.1  christos 		$name = &update_sec_num($tag, $level) . "  $name"
    894  1.1  christos 		    if $number_sections && $tag !~ /^unnumbered/;
    895  1.1  christos 		if ($tag =~ /heading$/) {
    896  1.1  christos 		    push(@lines, &html_debug("\n", __LINE__));
    897  1.1  christos 		    if ($html_element ne 'body') {
    898  1.1  christos 			# We are in a nice pickle here. We are trying to get a H? heading
    899  1.1  christos 			# even though we are not in the body level. So, we convert it to a
    900  1.1  christos 			# nice, bold, line by itself.
    901  1.1  christos 			$_ = &debug("\n\n<P><STRONG>$name</STRONG></P>\n\n", __LINE__);
    902  1.1  christos 		    } else {
    903  1.1  christos 			$_ = &debug("<H$level>$name</H$level>\n", __LINE__);
    904  1.1  christos 			&html_push_if('body');
    905  1.1  christos 		    }
    906  1.1  christos 		    print "# heading, section $name, level $level\n"
    907  1.1  christos 			if $debug & $DEBUG_TOC;
    908  1.1  christos 		} else {
    909  1.1  christos 		    if ($split_chapter) {
    910  1.1  christos 			unless ($toplevel) {
    911  1.1  christos 			    # first time we see a "section"
    912  1.1  christos 			    unless ($level == 1) {
    913  1.1  christos 				warn "$ERROR The first section found is not of level 1: $_";
    914  1.1  christos 				warn "$ERROR I'll split on sections of level $level...\n";
    915  1.1  christos 			    }
    916  1.1  christos 			    $toplevel = $level;
    917  1.1  christos 			}
    918  1.1  christos 			if ($level == $toplevel) {
    919  1.1  christos 			    &next_doc;
    920  1.1  christos 			    push(@lines, $SPLITTAG) if $split_num++;
    921  1.1  christos 			    push(@sections, $name);
    922  1.1  christos 			}
    923  1.1  christos 		    }
    924  1.1  christos 		    $sec_num++;
    925  1.1  christos 		    $docid = "SEC$sec_num";
    926  1.1  christos 		    $tocid = "TOC$sec_num";
    927  1.1  christos 		    # check biblio and glossary
    928  1.1  christos 		    $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i);
    929  1.1  christos 		    $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i);
    930  1.1  christos 		    # check node
    931  1.1  christos 		    if ($node) {
    932  1.1  christos 			if ($node2sec{$node}) {
    933  1.1  christos 			    warn "$ERROR Duplicate node found: $node\n";
    934  1.1  christos 			} else {
    935  1.1  christos 			    $node2sec{$node} = $name;
    936  1.1  christos 			    $node2href{$node} = "$docu_doc#$docid";
    937  1.1  christos 			    print "# node $node, section $name, level $level\n"
    938  1.1  christos 				if $debug & $DEBUG_TOC;
    939  1.1  christos 			}
    940  1.1  christos 			$node = '';
    941  1.1  christos 		    } else {
    942  1.1  christos 			print "# no node, section $name, level $level\n"
    943  1.1  christos 			    if $debug & $DEBUG_TOC;
    944  1.1  christos 		    }
    945  1.1  christos 		    # update TOC
    946  1.1  christos 		    while ($level > $curlevel) {
    947  1.1  christos 			$curlevel++;
    948  1.1  christos 			push(@toc_lines, "<UL>\n");
    949  1.1  christos 		    }
    950  1.1  christos 		    while ($level < $curlevel) {
    951  1.1  christos 			$curlevel--;
    952  1.1  christos 			push(@toc_lines, "</UL>\n");
    953  1.1  christos 		    }
    954  1.1  christos 		    $_ = "<LI>" . &anchor($tocid, "$docu_doc#$docid", $name, 1);
    955  1.1  christos 		    push(@toc_lines, &substitute_style($_));
    956  1.1  christos 		    # update DOC
    957  1.1  christos 		    push(@lines, &html_debug("\n", __LINE__));
    958  1.1  christos 		    &html_reset;
    959  1.1  christos 		    $_ =  "<H$level>".&anchor($docid, "$docu_toc#$tocid", $name)."</H$level>\n";
    960  1.1  christos 		    $_ = &debug($_, __LINE__);
    961  1.1  christos 		    push(@lines, &html_debug("\n", __LINE__));
    962  1.1  christos 		}
    963  1.1  christos 		# update DOC
    964  1.1  christos 		foreach $line (split(/\n+/, $_)) {
    965  1.1  christos 		    push(@lines, "$line\n");
    966  1.1  christos 		}
    967  1.1  christos 		next;
    968  1.1  christos 	    } else {
    969  1.1  christos 		warn "$ERROR Bad section line: $_";
    970  1.1  christos 	    }
    971  1.1  christos 	} else {
    972  1.1  christos 	    # track variables
    973  1.1  christos 	    $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o;
    974  1.1  christos 	    delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o;
    975  1.1  christos 	    # store things
    976  1.1  christos 	    $value{'_setfilename'}   = $1, next if /^\@setfilename\s+(.*)$/;
    977  1.1  christos 	    $value{'_settitle'}      = $1, next if /^\@settitle\s+(.*)$/;
    978  1.1  christos 	    $value{'_author'}   .= "$1\n", next if /^\@author\s+(.*)$/;
    979  1.1  christos 	    $value{'_subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/;
    980  1.1  christos 	    $value{'_title'}    .= "$1\n", next if /^\@title\s+(.*)$/;
    981  1.1  christos 	    # index
    982  1.1  christos 	    if (/^\@(..?)index\s+/) {
    983  1.1  christos 		unless ($valid_index{$1}) {
    984  1.1  christos 		    warn "$ERROR Undefined index command: $_";
    985  1.1  christos 		    next;
    986  1.1  christos 		}
    987  1.1  christos 		$id = 'IDX' . ++$idx_num;
    988  1.1  christos 		$index = $1 . 'index';
    989  1.1  christos 		$what = &substitute_style($');
    990  1.1  christos 		$what =~ s/\s+$//;
    991  1.1  christos 		print "# found $index for '$what' id $id\n"
    992  1.1  christos 		    if $debug & $DEBUG_INDEX;
    993  1.1  christos 		eval(<<EOC);
    994  1.1  christos 		if (defined(\$$index\{\$what\})) {
    995  1.1  christos 		    \$$index\{\$what\} .= "$;$docu_doc#$id";
    996  1.1  christos 		} else {
    997  1.1  christos 		    \$$index\{\$what\} = "$docu_doc#$id";
    998  1.1  christos 		}
    999  1.1  christos EOC
   1000  1.1  christos 		#
   1001  1.1  christos 		# dirty hack to see if I can put an invisible anchor...
   1002  1.1  christos 		#
   1003  1.1  christos 		if ($html_element eq 'P' ||
   1004  1.1  christos 		    $html_element eq 'LI' ||
   1005  1.1  christos 		    $html_element eq 'DT' ||
   1006  1.1  christos 		    $html_element eq 'DD' ||
   1007  1.1  christos 		    $html_element eq 'ADDRESS' ||
   1008  1.1  christos 		    $html_element eq 'B' ||
   1009  1.1  christos 		    $html_element eq 'BLOCKQUOTE' ||
   1010  1.1  christos 		    $html_element eq 'PRE' ||
   1011  1.1  christos 		    $html_element eq 'SAMP') {
   1012  1.1  christos                     push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
   1013  1.1  christos                 } elsif ($html_element eq 'body') {
   1014  1.1  christos 		    push(@lines, &debug("<P>\n", __LINE__));
   1015  1.1  christos                     push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
   1016  1.1  christos 		    &html_push('P');
   1017  1.1  christos 		} elsif ($html_element eq 'DL' ||
   1018  1.1  christos 			 $html_element eq 'UL' ||
   1019  1.1  christos 			 $html_element eq 'OL' ) {
   1020  1.1  christos 		    $deferred_ref .= &anchor($id, '', $invisible_mark, !$in_pre) . " ";
   1021  1.1  christos 		}
   1022  1.1  christos 		next;
   1023  1.1  christos 	    }
   1024  1.1  christos 	    # list item
   1025  1.1  christos 	    if (/^\@itemx?\s+/) {
   1026  1.1  christos 		$what = $';
   1027  1.1  christos 		$what =~ s/\s+$//;
   1028  1.1  christos 		if ($in_bibliography && $use_bibliography) {
   1029  1.1  christos 		    if ($what =~ /^$BIBRE$/o) {
   1030  1.1  christos 			$id = 'BIB' . ++$bib_num;
   1031  1.1  christos 			$bib2href{$what} = "$docu_doc#$id";
   1032  1.1  christos 			print "# found bibliography for '$what' id $id\n"
   1033  1.1  christos 			    if $debug & $DEBUG_BIB;
   1034  1.1  christos 			$what = &anchor($id, '', $what);
   1035  1.1  christos 		    }
   1036  1.1  christos 		} elsif ($in_glossary && $use_glossary) {
   1037  1.1  christos 		    $id = 'GLOSS' . ++$gloss_num;
   1038  1.1  christos 		    $entry = $what;
   1039  1.1  christos 		    $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
   1040  1.1  christos 		    $gloss2href{$entry} = "$docu_doc#$id";
   1041  1.1  christos 		    print "# found glossary for '$entry' id $id\n"
   1042  1.1  christos 			if $debug & $DEBUG_GLOSS;
   1043  1.1  christos 		    $what = &anchor($id, '', $what);
   1044  1.1  christos 		}
   1045  1.1  christos 		&html_pop_if('P');
   1046  1.1  christos 		if ($html_element eq 'DL' || $html_element eq 'DD') {
   1047  1.1  christos 		    if ($things_map{$in_table} && !$what) {
   1048  1.1  christos 			# special case to allow @table @bullet for instance
   1049  1.1  christos 			push(@lines, &debug("<DT>$things_map{$in_table}\n", __LINE__));
   1050  1.1  christos 		    } else {
   1051  1.1  christos 			push(@lines, &debug("<DT>\@$in_table\{$what\}\n", __LINE__));
   1052  1.1  christos 		    }
   1053  1.1  christos 		    push(@lines, "<DD>");
   1054  1.1  christos 		    &html_push('DD') unless $html_element eq 'DD';
   1055  1.1  christos 		    if ($table_type) { # add also an index
   1056  1.1  christos 			unshift(@input_spool, "\@${table_type}index $what\n");
   1057  1.1  christos 		    }
   1058  1.1  christos 		} elsif ($html_element eq 'TABLE') {
   1059  1.1  christos 		    push(@lines, &debug("<TR><TD>$what</TD>\n", __LINE__));
   1060  1.1  christos 		    &html_push('TR');
   1061  1.1  christos 		} elsif ($html_element eq 'TR') {
   1062  1.1  christos 		    push(@lines, &debug("</TR>\n", __LINE__));
   1063  1.1  christos 		    push(@lines, &debug("<TR><TD>$what</TD>\n", __LINE__));
   1064  1.1  christos 		} else {
   1065  1.1  christos 		    push(@lines, &debug("<LI>$what\n", __LINE__));
   1066  1.1  christos 		    &html_push('LI') unless $html_element eq 'LI';
   1067  1.1  christos 		}
   1068  1.1  christos 		push(@lines, &html_debug("\n", __LINE__));
   1069  1.1  christos 		if ($deferred_ref) {
   1070  1.1  christos 		    push(@lines, &debug("$deferred_ref\n", __LINE__));
   1071  1.1  christos 		    $deferred_ref = '';
   1072  1.1  christos 		}
   1073  1.1  christos 		next;
   1074  1.1  christos 	    } elsif (/^\@tab\s+(.*)$/) {
   1075  1.1  christos 		push(@lines, "<TD>$1</TD>\n");
   1076  1.1  christos 		next;
   1077  1.1  christos 	    }
   1078  1.1  christos 	}
   1079  1.1  christos     }
   1080  1.1  christos     # paragraph separator
   1081  1.1  christos     if ($_ eq "\n") {
   1082  1.1  christos 	next if $#lines >= 0 && $lines[$#lines] eq "\n";
   1083  1.1  christos 	if ($html_element eq 'P') {
   1084  1.1  christos 	    push(@lines, "\n");
   1085  1.1  christos 	    $_ = &debug("</P>\n", __LINE__);
   1086  1.1  christos 	    &html_pop;
   1087  1.1  christos 	}
   1088  1.1  christos     } elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE') {
   1089  1.1  christos 	push(@lines, "<P>\n");
   1090  1.1  christos 	&html_push('P');
   1091  1.1  christos 	$_ = &debug($_, __LINE__);
   1092  1.1  christos     }
   1093  1.1  christos     # otherwise
   1094  1.1  christos     push(@lines, $_);
   1095  1.1  christos }
   1096  1.1  christos 
   1097  1.1  christos # finish TOC
   1098  1.1  christos $level = 0;
   1099  1.1  christos while ($level < $curlevel) {
   1100  1.1  christos     $curlevel--;
   1101  1.1  christos     push(@toc_lines, "</UL>\n");
   1102  1.1  christos }
   1103  1.1  christos 
   1104  1.1  christos print "# end of pass 1\n" if $verbose;
   1105  1.1  christos 
   1106  1.1  christos #+++############################################################################
   1107  1.1  christos #                                                                              #
   1108  1.1  christos # Pass 2/3: handle style, menu, index, cross-reference                         #
   1109  1.1  christos #                                                                              #
   1110  1.1  christos #---############################################################################
   1111  1.1  christos 
   1112  1.1  christos @lines2 = ();				# whole document (2nd pass)
   1113  1.1  christos @lines3 = ();				# whole document (3rd pass)
   1114  1.1  christos $in_menu = 0;				# am I inside a menu
   1115  1.1  christos 
   1116  1.1  christos while (@lines) {
   1117  1.1  christos     $_ = shift(@lines);
   1118  1.1  christos     #
   1119  1.1  christos     # special case (protected sections)
   1120  1.1  christos     #
   1121  1.1  christos     if (/^$PROTECTTAG/o) {
   1122  1.1  christos 	push(@lines2, $_);
   1123  1.1  christos 	next;
   1124  1.1  christos     }
   1125  1.1  christos     #
   1126  1.1  christos     # menu
   1127  1.1  christos     #
   1128  1.1  christos     $in_menu = 1, push(@lines2, &debug("<UL>\n", __LINE__)), next if /^\@menu\b/;
   1129  1.1  christos     $in_menu = 0, push(@lines2, &debug("</UL>\n", __LINE__)), next if /^\@end\s+menu\b/;
   1130  1.1  christos     if ($in_menu) {
   1131  1.1  christos 	if (/^\*\s+($NODERE)::/o) {
   1132  1.1  christos 	    $descr = $';
   1133  1.1  christos 	    chop($descr);
   1134  1.1  christos 	    &menu_entry($1, $1, $descr);
   1135  1.1  christos 	} elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
   1136  1.1  christos 	    $descr = $';
   1137  1.1  christos 	    chop($descr);
   1138  1.1  christos 	    &menu_entry($1, $2, $descr);
   1139  1.1  christos 	} elsif (/^\*/) {
   1140  1.1  christos 	    warn "$ERROR Bad menu line: $_";
   1141  1.1  christos 	} else { # description continued?
   1142  1.1  christos 	    push(@lines2, $_);
   1143  1.1  christos 	}
   1144  1.1  christos 	next;
   1145  1.1  christos     }
   1146  1.1  christos     #
   1147  1.1  christos     # printindex
   1148  1.1  christos     #
   1149  1.1  christos     if (/^\@printindex\s+(\w\w)\b/) {
   1150  1.1  christos 	local($index, *ary, @keys, $key, $letter, $last_letter, @refs);
   1151  1.1  christos 	if ($predefined_index{$1}) {
   1152  1.1  christos 	    $index = $predefined_index{$1} . 'index';
   1153  1.1  christos 	} else {
   1154  1.1  christos 	    $index = $1 . 'index';
   1155  1.1  christos 	}
   1156  1.1  christos 	eval("*ary = *$index");
   1157  1.1  christos 	@keys = keys(%ary);
   1158  1.1  christos 	foreach $key (@keys) {
   1159  1.1  christos 	    $_ = $key;
   1160  1.1  christos 	    1 while s/<(\w+)>\`(.*)\&acute;<\/\1>/$2/; # remove HTML tags with quotes
   1161  1.1  christos 	    1 while s/<(\w+)>(.*)<\/\1>/$2/;     # remove HTML tags
   1162  1.1  christos 	    $_ = &unprotect_html($_);
   1163  1.1  christos 	    &unprotect_texi;
   1164  1.1  christos 	    tr/A-Z/a-z/; # lowercase
   1165  1.1  christos 	    $key2alpha{$key} = $_;
   1166  1.1  christos 	    print "# index $key sorted as $_\n"
   1167  1.1  christos 		if $key ne $_ && $debug & $DEBUG_INDEX;
   1168  1.1  christos 	}
   1169  1.1  christos 	push(@lines2, "Jump to:\n");
   1170  1.1  christos 	$last_letter = undef;
   1171  1.1  christos 	foreach $key (sort byalpha @keys) {
   1172  1.1  christos 	    $letter = substr($key2alpha{$key}, 0, 1);
   1173  1.1  christos 	    $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
   1174  1.1  christos 	    if (!defined($last_letter) || $letter ne $last_letter) {
   1175  1.1  christos 		push(@lines2, "-\n") if defined($last_letter);
   1176  1.1  christos 		push(@lines2, "<A HREF=\"#$index\_$letter\">" . &protect_html($letter) . "</A>\n");
   1177  1.1  christos 		$last_letter = $letter;
   1178  1.1  christos 	    }
   1179  1.1  christos 	}
   1180  1.1  christos 	push(@lines2, "<P>\n");
   1181  1.1  christos 	$last_letter = undef;
   1182  1.1  christos 	foreach $key (sort byalpha @keys) {
   1183  1.1  christos 	    $letter = substr($key2alpha{$key}, 0, 1);
   1184  1.1  christos 	    $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
   1185  1.1  christos 	    if (!defined($last_letter) || $letter ne $last_letter) {
   1186  1.1  christos 		push(@lines2, "</DIR>\n") if defined($last_letter);
   1187  1.1  christos 		push(@lines2, "<H2><A NAME=\"$index\_$letter\">" . &protect_html($letter) . "</A></H2>\n");
   1188  1.1  christos 		push(@lines2, "<DIR>\n");
   1189  1.1  christos 		$last_letter = $letter;
   1190  1.1  christos 	    }
   1191  1.1  christos 	    @refs = ();
   1192  1.1  christos 	    foreach (split(/$;/, $ary{$key})) {
   1193  1.1  christos 		push(@refs, &anchor('', $_, $key, 0));
   1194  1.1  christos 	    }
   1195  1.1  christos 	    push(@lines2, "<LI>" . join(", ", @refs) . "\n");
   1196  1.1  christos 	}
   1197  1.1  christos 	push(@lines2, "</DIR>\n") if defined($last_letter);
   1198  1.1  christos 	next;
   1199  1.1  christos     }
   1200  1.1  christos     #
   1201  1.1  christos     # simple style substitutions
   1202  1.1  christos     #
   1203  1.1  christos     $_ = &substitute_style($_);
   1204  1.1  christos     #
   1205  1.1  christos     # xref
   1206  1.1  christos     #
   1207  1.1  christos     while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
   1208  1.1  christos 	# note: Texinfo may accept other characters
   1209  1.1  christos 	($type, $nodes, $full) = ($1, $2, $3);
   1210  1.1  christos 	($before, $after) = ($`, $');
   1211  1.1  christos 	if (! $full && $after) {
   1212  1.1  christos 	    warn "$ERROR Bad xref (no ending } on line): $_";
   1213  1.1  christos 	    $_ = "$before$;0${type}ref\{$nodes$after";
   1214  1.1  christos 	    next; # while xref
   1215  1.1  christos 	}
   1216  1.1  christos 	if ($type eq 'x') {
   1217  1.1  christos 	    $type = 'See ';
   1218  1.1  christos 	} elsif ($type eq 'px') {
   1219  1.1  christos 	    $type = 'see ';
   1220  1.1  christos 	} elsif ($type eq 'info') {
   1221  1.1  christos 	    $type = 'See Info';
   1222  1.1  christos 	} else {
   1223  1.1  christos 	    $type = '';
   1224  1.1  christos 	}
   1225  1.1  christos 	unless ($full) {
   1226  1.1  christos 	    $next = shift(@lines);
   1227  1.1  christos 	    $next = &substitute_style($next);
   1228  1.1  christos 	    chop($nodes); # remove final newline
   1229  1.1  christos 	    if ($next =~ /\}/) { # split on 2 lines
   1230  1.1  christos 		$nodes .= " $`";
   1231  1.1  christos 		$after = $';
   1232  1.1  christos 	    } else {
   1233  1.1  christos 		$nodes .= " $next";
   1234  1.1  christos 		$next = shift(@lines);
   1235  1.1  christos 		$next = &substitute_style($next);
   1236  1.1  christos 		chop($nodes);
   1237  1.1  christos 		if ($next =~ /\}/) { # split on 3 lines
   1238  1.1  christos 		    $nodes .= " $`";
   1239  1.1  christos 		    $after = $';
   1240  1.1  christos 		} else {
   1241  1.1  christos 		    warn "$ERROR Bad xref (no ending }): $_";
   1242  1.1  christos 		    $_ = "$before$;0xref\{$nodes$after";
   1243  1.1  christos 		    unshift(@lines, $next);
   1244  1.1  christos 		    next; # while xref
   1245  1.1  christos 		}
   1246  1.1  christos 	    }
   1247  1.1  christos 	}
   1248  1.1  christos 	$nodes =~ s/\s+/ /g; # remove useless spaces
   1249  1.1  christos 	@args = split(/\s*,\s*/, $nodes);
   1250  1.1  christos 	$node = $args[0]; # the node is always the first arg
   1251  1.1  christos 	&normalise_node($node);
   1252  1.1  christos 	$sec = $node2sec{$node};
   1253  1.1  christos 	if (@args == 5) { # reference to another manual
   1254  1.1  christos 	    $sec = $args[2] || $node;
   1255  1.1  christos 	    $man = $args[4] || $args[3];
   1256  1.1  christos 	    $_ = "${before}${type}section $sec in \@cite{$man}$after";
   1257  1.1  christos 	} elsif ($type =~ /Info/) { # inforef
   1258  1.1  christos 	    warn "$ERROR Wrong number of arguments: $_" unless @args == 3;
   1259  1.1  christos 	    ($nn, $_, $in) = @args;
   1260  1.1  christos 	    $_ = "${before}${type} file $in, node $nn$after";
   1261  1.1  christos 	} elsif ($sec) {
   1262  1.1  christos 	    $href = $node2href{$node};
   1263  1.1  christos 	    $_ = "${before}${type}section " . &anchor('', $href, $sec) . $after;
   1264  1.1  christos 	} else {
   1265  1.1  christos 	    warn "$ERROR Undefined node ($node): $_";
   1266  1.1  christos 	    $_ = "$before$;0xref{$nodes}$after";
   1267  1.1  christos 	}
   1268  1.1  christos     }
   1269  1.1  christos     #
   1270  1.1  christos     # try to guess bibliography references or glossary terms
   1271  1.1  christos     #
   1272  1.1  christos     unless (/^<H\d><A NAME=\"SEC\d/) {
   1273  1.1  christos 	if ($use_bibliography) {
   1274  1.1  christos 	    $done = '';
   1275  1.1  christos 	    while (/$BIBRE/o) {
   1276  1.1  christos 		($pre, $what, $post) = ($`, $&, $');
   1277  1.1  christos 		$href = $bib2href{$what};
   1278  1.1  christos 		if (defined($href) && $post !~ /^[^<]*<\/A>/) {
   1279  1.1  christos 		    $done .= $pre . &anchor('', $href, $what);
   1280  1.1  christos 		} else {
   1281  1.1  christos 		    $done .= "$pre$what";
   1282  1.1  christos 		}
   1283  1.1  christos 		$_ = $post;
   1284  1.1  christos 	    }
   1285  1.1  christos 	    $_ = $done . $_;
   1286  1.1  christos 	}
   1287  1.1  christos 	if ($use_glossary) {
   1288  1.1  christos 	    $done = '';
   1289  1.1  christos 	    while (/\b\w+\b/) {
   1290  1.1  christos 		($pre, $what, $post) = ($`, $&, $');
   1291  1.1  christos 		$entry = $what;
   1292  1.1  christos 		$entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
   1293  1.1  christos 		$href = $gloss2href{$entry};
   1294  1.1  christos 		if (defined($href) && $post !~ /^[^<]*<\/A>/) {
   1295  1.1  christos 		    $done .= $pre . &anchor('', $href, $what);
   1296  1.1  christos 		} else {
   1297  1.1  christos 		    $done .= "$pre$what";
   1298  1.1  christos 		}
   1299  1.1  christos 		$_ = $post;
   1300  1.1  christos 	    }
   1301  1.1  christos 	    $_ = $done . $_;
   1302  1.1  christos 	}
   1303  1.1  christos     }
   1304  1.1  christos     # otherwise
   1305  1.1  christos     push(@lines2, $_);
   1306  1.1  christos }
   1307  1.1  christos print "# end of pass 2\n" if $verbose;
   1308  1.1  christos 
   1309  1.1  christos #
   1310  1.1  christos # split style substitutions
   1311  1.1  christos #
   1312  1.1  christos while (@lines2) {
   1313  1.1  christos     $_ = shift(@lines2);
   1314  1.1  christos     #
   1315  1.1  christos     # special case (protected sections)
   1316  1.1  christos     #
   1317  1.1  christos     if (/^$PROTECTTAG/o) {
   1318  1.1  christos 	push(@lines3, $_);
   1319  1.1  christos 	next;
   1320  1.1  christos     }
   1321  1.1  christos     #
   1322  1.1  christos     # split style substitutions
   1323  1.1  christos     #
   1324  1.1  christos     $old = '';
   1325  1.1  christos     while ($old ne $_) {
   1326  1.1  christos         $old = $_;
   1327  1.1  christos 	if (/\@(\w+|"|\~|,|\^)\{/) {
   1328  1.1  christos 	    ($before, $style, $after) = ($`, $1, $');
   1329  1.1  christos 	    if (defined($style_map{$style})) {
   1330  1.1  christos 		$_ = $after;
   1331  1.1  christos 		$text = '';
   1332  1.1  christos 		$after = '';
   1333  1.1  christos 		$failed = 1;
   1334  1.1  christos 		while (@lines2) {
   1335  1.1  christos 		    if (/\}/) {
   1336  1.1  christos 			$text .= $`;
   1337  1.1  christos 			$after = $';
   1338  1.1  christos 			$failed = 0;
   1339  1.1  christos 			last;
   1340  1.1  christos 		    } else {
   1341  1.1  christos 			$text .= $_;
   1342  1.1  christos 			$_ = shift(@lines2);
   1343  1.1  christos 		    }
   1344  1.1  christos 		}
   1345  1.1  christos 		if ($failed) {
   1346  1.1  christos 		    die "* Bad syntax (\@$style) after: $before\n";
   1347  1.1  christos 		} else {
   1348  1.1  christos 		    $text = &apply_style($style, $text);
   1349  1.1  christos 		    $_ = "$before$text$after";
   1350  1.1  christos 		}
   1351  1.1  christos 	    }
   1352  1.1  christos 	}
   1353  1.1  christos     }
   1354  1.1  christos     # otherwise
   1355  1.1  christos     push(@lines3, $_);
   1356  1.1  christos }
   1357  1.1  christos print "# end of pass 3\n" if $verbose;
   1358  1.1  christos 
   1359  1.1  christos #+++############################################################################
   1360  1.1  christos #                                                                              #
   1361  1.1  christos # Pass 4: foot notes, final cleanup                                            #
   1362  1.1  christos #                                                                              #
   1363  1.1  christos #---############################################################################
   1364  1.1  christos 
   1365  1.1  christos @foot_lines = ();			# footnotes
   1366  1.1  christos @doc_lines = ();			# final document
   1367  1.1  christos $end_of_para = 0;			# true if last line is <P>
   1368  1.1  christos 
   1369  1.1  christos while (@lines3) {
   1370  1.1  christos     $_ = shift(@lines3);
   1371  1.1  christos     #
   1372  1.1  christos     # special case (protected sections)
   1373  1.1  christos     #
   1374  1.1  christos     if (/^$PROTECTTAG/o) {
   1375  1.1  christos 	push(@doc_lines, $_);
   1376  1.1  christos 	$end_of_para = 0;
   1377  1.1  christos 	next;
   1378  1.1  christos     }
   1379  1.1  christos     #
   1380  1.1  christos     # footnotes
   1381  1.1  christos     #
   1382  1.1  christos     while (/\@footnote([^\{\s]+)\{/) {
   1383  1.1  christos 	($before, $d, $after) = ($`, $1, $');
   1384  1.1  christos 	$_ = $after;
   1385  1.1  christos 	$text = '';
   1386  1.1  christos 	$after = '';
   1387  1.1  christos 	$failed = 1;
   1388  1.1  christos 	while (@lines3) {
   1389  1.1  christos 	    if (/\}/) {
   1390  1.1  christos 		$text .= $`;
   1391  1.1  christos 		$after = $';
   1392  1.1  christos 		$failed = 0;
   1393  1.1  christos 		last;
   1394  1.1  christos 	    } else {
   1395  1.1  christos 		$text .= $_;
   1396  1.1  christos 		$_ = shift(@lines3);
   1397  1.1  christos 	    }
   1398  1.1  christos 	}
   1399  1.1  christos 	if ($failed) {
   1400  1.1  christos 	    die "* Bad syntax (\@footnote) after: $before\n";
   1401  1.1  christos 	} else {
   1402  1.1  christos 	    $foot_num++;
   1403  1.1  christos 	    $docid  = "DOCF$foot_num";
   1404  1.1  christos 	    $footid = "FOOT$foot_num";
   1405  1.1  christos 	    $foot = "($foot_num)";
   1406  1.1  christos 	    push(@foot_lines, "<H3>" . &anchor($footid, "$d#$docid", $foot) . "</H3>\n");
   1407  1.1  christos 	    $text = "<P>$text" unless $text =~ /^\s*<P>/;
   1408  1.1  christos 	    push(@foot_lines, "$text\n");
   1409  1.1  christos 	    $_ = $before . &anchor($docid, "$docu_foot#$footid", $foot) . $after;
   1410  1.1  christos 	}
   1411  1.1  christos     }
   1412  1.1  christos     #
   1413  1.1  christos     # remove unnecessary <P>
   1414  1.1  christos     #
   1415  1.1  christos     if (/^\s*<P>\s*$/) {
   1416  1.1  christos 	next if $end_of_para++;
   1417  1.1  christos     } else {
   1418  1.1  christos 	$end_of_para = 0;
   1419  1.1  christos     }
   1420  1.1  christos     # otherwise
   1421  1.1  christos     push(@doc_lines, $_);
   1422  1.1  christos }
   1423  1.1  christos print "# end of pass 4\n" if $verbose;
   1424  1.1  christos 
   1425  1.1  christos #+++############################################################################
   1426  1.1  christos #                                                                              #
   1427  1.1  christos # Pass 5: print things                                                         #
   1428  1.1  christos #                                                                              #
   1429  1.1  christos #---############################################################################
   1430  1.1  christos 
   1431  1.1  christos $header = <<EOT;
   1432  1.1  christos <!-- This HTML file has been created by $THISPROG
   1433  1.1  christos      from $docu on $TODAY -->
   1434  1.1  christos EOT
   1435  1.1  christos 
   1436  1.1  christos $full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
   1437  1.1  christos $title = $value{'_settitle'} || $full_title;
   1438  1.1  christos $_ = &substitute_style($full_title);
   1439  1.1  christos &unprotect_texi;
   1440  1.1  christos s/\n$//; # rmv last \n (if any)
   1441  1.1  christos $full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1>\n";
   1442  1.1  christos 
   1443  1.1  christos #
   1444  1.1  christos # print ToC
   1445  1.1  christos #
   1446  1.1  christos if (!$monolithic && @toc_lines) {
   1447  1.1  christos     if (open(FILE, "> $docu_toc")) {
   1448  1.1  christos 	print "# creating $docu_toc...\n" if $verbose;
   1449  1.1  christos 	&print_toplevel_header("$title - Table of Contents");
   1450  1.1  christos 	&print_ruler;
   1451  1.1  christos 	&print(*toc_lines, FILE);
   1452  1.1  christos 	&print_toplevel_footer;
   1453  1.1  christos 	close(FILE);
   1454  1.1  christos     } else {
   1455  1.1  christos 	warn "$ERROR Can't write to $docu_toc: $!\n";
   1456  1.1  christos     }
   1457  1.1  christos }
   1458  1.1  christos 
   1459  1.1  christos #
   1460  1.1  christos # print footnotes
   1461  1.1  christos #
   1462  1.1  christos if (!$monolithic && @foot_lines) {
   1463  1.1  christos     if (open(FILE, "> $docu_foot")) {
   1464  1.1  christos 	print "# creating $docu_foot...\n" if $verbose;
   1465  1.1  christos 	&print_toplevel_header("$title - Footnotes");
   1466  1.1  christos 	&print_ruler;
   1467  1.1  christos         &print(*foot_lines, FILE);
   1468  1.1  christos 	&print_toplevel_footer;
   1469  1.1  christos 	close(FILE);
   1470  1.1  christos     } else {
   1471  1.1  christos 	warn "$ERROR Can't write to $docu_foot: $!\n";
   1472  1.1  christos     }
   1473  1.1  christos }
   1474  1.1  christos 
   1475  1.1  christos #
   1476  1.1  christos # print document
   1477  1.1  christos #
   1478  1.1  christos if ($split_chapter || $split_node) { # split
   1479  1.1  christos     $doc_num = 0;
   1480  1.1  christos     $last_num = scalar(@sections);
   1481  1.1  christos     $first_doc = &doc_name(1);
   1482  1.1  christos     $last_doc = &doc_name($last_num);
   1483  1.1  christos     while (@sections) {
   1484  1.1  christos 	$section = shift(@sections);
   1485  1.1  christos 	&next_doc;
   1486  1.1  christos 	if (open(FILE, "> $docu_doc")) {
   1487  1.1  christos 	    print "# creating $docu_doc...\n" if $verbose;
   1488  1.1  christos 	    &print_header("$title - $section");
   1489  1.1  christos 	    $prev_doc = ($doc_num == 1 ? undef : &doc_name($doc_num - 1));
   1490  1.1  christos 	    $next_doc = ($doc_num == $last_num ? undef : &doc_name($doc_num + 1));
   1491  1.1  christos 	    $navigation = "Go to the ";
   1492  1.1  christos 	    $navigation .= ($prev_doc ? &anchor('', $first_doc, "first") : "first");
   1493  1.1  christos 	    $navigation .= ", ";
   1494  1.1  christos 	    $navigation .= ($prev_doc ? &anchor('', $prev_doc, "previous") : "previous");
   1495  1.1  christos 	    $navigation .= ", ";
   1496  1.1  christos 	    $navigation .= ($next_doc ? &anchor('', $next_doc, "next") : "next");
   1497  1.1  christos 	    $navigation .= ", ";
   1498  1.1  christos 	    $navigation .= ($next_doc ? &anchor('', $last_doc, "last") : "last");
   1499  1.1  christos 	    $navigation .= " section, " . &anchor('', $docu_toc, "table of contents") . ".\n";
   1500  1.1  christos 	    print FILE $navigation;
   1501  1.1  christos 	    &print_ruler;
   1502  1.1  christos 	    # find corresponding lines
   1503  1.1  christos             @tmp_lines = ();
   1504  1.1  christos             while (@doc_lines) {
   1505  1.1  christos 		$_ = shift(@doc_lines);
   1506  1.1  christos 		last if ($_ eq $SPLITTAG);
   1507  1.1  christos 		push(@tmp_lines, $_);
   1508  1.1  christos 	    }
   1509  1.1  christos             &print(*tmp_lines, FILE);
   1510  1.1  christos 	    &print_ruler;
   1511  1.1  christos 	    print FILE $navigation;
   1512  1.1  christos 	    &print_footer;
   1513  1.1  christos 	    close(FILE);
   1514  1.1  christos 	} else {
   1515  1.1  christos 	    warn "$ERROR Can't write to $docu_doc: $!\n";
   1516  1.1  christos 	}
   1517  1.1  christos     }
   1518  1.1  christos } else { # not split
   1519  1.1  christos     if (open(FILE, "> $docu_doc")) {
   1520  1.1  christos 	print "# creating $docu_doc...\n" if $verbose;
   1521  1.1  christos 	if ($monolithic || !@toc_lines) {
   1522  1.1  christos 	    &print_toplevel_header($title);
   1523  1.1  christos 	} else {
   1524  1.1  christos 	    &print_header($title);
   1525  1.1  christos 	    print FILE $full_title;
   1526  1.1  christos 	}
   1527  1.1  christos 	if ($monolithic && @toc_lines) {
   1528  1.1  christos 	    &print_ruler;
   1529  1.1  christos  	    print FILE "<H1>Table of Contents</H1>\n";
   1530  1.1  christos  	    &print(*toc_lines, FILE);
   1531  1.1  christos 	}
   1532  1.1  christos 	&print_ruler;
   1533  1.1  christos         &print(*doc_lines, FILE);
   1534  1.1  christos 	if ($monolithic && @foot_lines) {
   1535  1.1  christos 	    &print_ruler;
   1536  1.1  christos  	    print FILE "<H1>Footnotes</H1>\n";
   1537  1.1  christos  	    &print(*foot_lines, FILE);
   1538  1.1  christos 	}
   1539  1.1  christos 	if ($monolithic || !@toc_lines) {
   1540  1.1  christos 	    &print_toplevel_footer;
   1541  1.1  christos 	} else {
   1542  1.1  christos 	    &print_footer;
   1543  1.1  christos 	}
   1544  1.1  christos 	close(FILE);
   1545  1.1  christos     } else {
   1546  1.1  christos 	warn "$ERROR Can't write to $docu_doc: $!\n";
   1547  1.1  christos     }
   1548  1.1  christos }
   1549  1.1  christos 
   1550  1.1  christos print "# that's all folks\n" if $verbose;
   1551  1.1  christos 
   1552  1.1  christos #+++############################################################################
   1553  1.1  christos #                                                                              #
   1554  1.1  christos # Low level functions                                                          #
   1555  1.1  christos #                                                                              #
   1556  1.1  christos #---############################################################################
   1557  1.1  christos 
   1558  1.1  christos sub update_sec_num {
   1559  1.1  christos     local($name, $level) = @_;
   1560  1.1  christos 
   1561  1.1  christos     $level--; # here we start at 0
   1562  1.1  christos     if ($name =~ /^appendix/) {
   1563  1.1  christos 	# appendix style
   1564  1.1  christos 	if (defined(@appendix_sec_num)) {
   1565  1.1  christos 	    &incr_sec_num($level, @appendix_sec_num);
   1566  1.1  christos 	} else {
   1567  1.1  christos 	    @appendix_sec_num = ('A', 0, 0, 0);
   1568  1.1  christos 	}
   1569  1.1  christos 	return(join('.', @appendix_sec_num[0..$level]));
   1570  1.1  christos     } else {
   1571  1.1  christos 	# normal style
   1572  1.1  christos 	if (defined(@normal_sec_num)) {
   1573  1.1  christos 	    &incr_sec_num($level, @normal_sec_num);
   1574  1.1  christos 	} else {
   1575  1.1  christos 	    @normal_sec_num = (1, 0, 0, 0);
   1576  1.1  christos 	}
   1577  1.1  christos 	return(join('.', @normal_sec_num[0..$level]));
   1578  1.1  christos     }
   1579  1.1  christos }
   1580  1.1  christos 
   1581  1.1  christos sub incr_sec_num {
   1582  1.1  christos     local($level, $l);
   1583  1.1  christos     $level = shift(@_);
   1584  1.1  christos     $_[$level]++;
   1585  1.1  christos     foreach $l ($level+1 .. 3) {
   1586  1.1  christos 	$_[$l] = 0;
   1587  1.1  christos     }
   1588  1.1  christos }
   1589  1.1  christos 
   1590  1.1  christos sub check {
   1591  1.1  christos     local($_, %seen, %context, $before, $match, $after);
   1592  1.1  christos 
   1593  1.1  christos     while (<>) {
   1594  1.1  christos 	if (/\@(\*|\.|\:|\@|\{|\})/) {
   1595  1.1  christos 	    $seen{$&}++;
   1596  1.1  christos 	    $context{$&} .= "> $_" if $verbose;
   1597  1.1  christos 	    $_ = "$`XX$'";
   1598  1.1  christos 	    redo;
   1599  1.1  christos 	}
   1600  1.1  christos 	if (/\@(\w+)/) {
   1601  1.1  christos 	    ($before, $match, $after) = ($`, $&, $');
   1602  1.1  christos 	    if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
   1603  1.1  christos 		$seen{'e-mail address'}++;
   1604  1.1  christos 		$context{'e-mail address'} .= "> $_" if $verbose;
   1605  1.1  christos 	    } else {
   1606  1.1  christos 		$seen{$match}++;
   1607  1.1  christos 		$context{$match} .= "> $_" if $verbose;
   1608  1.1  christos 	    }
   1609  1.1  christos 	    $match =~ s/^\@/X/;
   1610  1.1  christos 	    $_ = "$before$match$after";
   1611  1.1  christos 	    redo;
   1612  1.1  christos 	}
   1613  1.1  christos     }
   1614  1.1  christos     
   1615  1.1  christos     foreach (sort(keys(%seen))) {
   1616  1.1  christos 	if ($verbose) {
   1617  1.1  christos 	    print "$_\n";
   1618  1.1  christos 	    print $context{$_};
   1619  1.1  christos 	} else {
   1620  1.1  christos 	    print "$_ ($seen{$_})\n";
   1621  1.1  christos 	}
   1622  1.1  christos     }
   1623  1.1  christos }
   1624  1.1  christos 
   1625  1.1  christos sub open {
   1626  1.1  christos     local($name) = @_;
   1627  1.1  christos 
   1628  1.1  christos     ++$fh_name;
   1629  1.1  christos     if (open($fh_name, $name)) {
   1630  1.1  christos 	unshift(@fhs, $fh_name);
   1631  1.1  christos     } else {
   1632  1.1  christos 	warn "$ERROR Can't read file $name: $!\n";
   1633  1.1  christos     }
   1634  1.1  christos }
   1635  1.1  christos 
   1636  1.1  christos sub init_input {
   1637  1.1  christos     @fhs = ();			# hold the file handles to read
   1638  1.1  christos     @input_spool = ();		# spooled lines to read
   1639  1.1  christos     $fh_name = 'FH000';
   1640  1.1  christos     &open($docu);
   1641  1.1  christos }
   1642  1.1  christos 
   1643  1.1  christos sub next_line {
   1644  1.1  christos     local($fh, $line);
   1645  1.1  christos 
   1646  1.1  christos     if (@input_spool) {
   1647  1.1  christos 	$line = shift(@input_spool);
   1648  1.1  christos 	return($line);
   1649  1.1  christos     }
   1650  1.1  christos     while (@fhs) {
   1651  1.1  christos 	$fh = $fhs[0];
   1652  1.1  christos 	$line = <$fh>;
   1653  1.1  christos 	return($line) if $line;
   1654  1.1  christos 	close($fh);
   1655  1.1  christos 	shift(@fhs);
   1656  1.1  christos     }
   1657  1.1  christos     return(undef);
   1658  1.1  christos }
   1659  1.1  christos 
   1660  1.1  christos # used in pass 1, use &next_line
   1661  1.1  christos sub skip_until {
   1662  1.1  christos     local($tag) = @_;
   1663  1.1  christos     local($_);
   1664  1.1  christos 
   1665  1.1  christos     while ($_ = &next_line) {
   1666  1.1  christos 	return if /^\@end\s+$tag\s*$/;
   1667  1.1  christos     }
   1668  1.1  christos     die "* Failed to find '$tag' after: " . $lines[$#lines];
   1669  1.1  christos }
   1670  1.1  christos 
   1671  1.1  christos #
   1672  1.1  christos # HTML stacking to have a better HTML output
   1673  1.1  christos #
   1674  1.1  christos 
   1675  1.1  christos sub html_reset {
   1676  1.1  christos     @html_stack = ('html');
   1677  1.1  christos     $html_element = 'body';
   1678  1.1  christos }
   1679  1.1  christos 
   1680  1.1  christos sub html_push {
   1681  1.1  christos     local($what) = @_;
   1682  1.1  christos     push(@html_stack, $html_element);
   1683  1.1  christos     $html_element = $what;
   1684  1.1  christos }
   1685  1.1  christos 
   1686  1.1  christos sub html_push_if {
   1687  1.1  christos     local($what) = @_;
   1688  1.1  christos     push(@html_stack, $html_element)
   1689  1.1  christos 	if ($html_element && $html_element ne 'P');
   1690  1.1  christos     $html_element = $what;
   1691  1.1  christos }
   1692  1.1  christos 
   1693  1.1  christos sub html_pop {
   1694  1.1  christos     $html_element = pop(@html_stack);
   1695  1.1  christos }
   1696  1.1  christos 
   1697  1.1  christos sub html_pop_if {
   1698  1.1  christos     local($elt);
   1699  1.1  christos 
   1700  1.1  christos     if (@_) {
   1701  1.1  christos 	foreach $elt (@_) {
   1702  1.1  christos 	    if ($elt eq $html_element) {
   1703  1.1  christos 		$html_element = pop(@html_stack) if @html_stack;
   1704  1.1  christos 		last;
   1705  1.1  christos 	    }
   1706  1.1  christos 	}
   1707  1.1  christos     } else {
   1708  1.1  christos 	$html_element = pop(@html_stack) if @html_stack;
   1709  1.1  christos     }
   1710  1.1  christos }
   1711  1.1  christos 
   1712  1.1  christos sub html_debug {
   1713  1.1  christos     local($what, $line) = @_;
   1714  1.1  christos     return("<!-- $line @html_stack, $html_element -->$what")
   1715  1.1  christos 	if $debug & $DEBUG_HTML;
   1716  1.1  christos     return($what);
   1717  1.1  christos }
   1718  1.1  christos 
   1719  1.1  christos # to debug the output...
   1720  1.1  christos sub debug {
   1721  1.1  christos     local($what, $line) = @_;
   1722  1.1  christos     return("<!-- $line -->$what")
   1723  1.1  christos 	if $debug & $DEBUG_HTML;
   1724  1.1  christos     return($what);
   1725  1.1  christos }
   1726  1.1  christos 
   1727  1.1  christos sub normalise_node {
   1728  1.1  christos     $_[0] =~ s/\s+/ /g;
   1729  1.1  christos     $_[0] =~ s/ $//;
   1730  1.1  christos     $_[0] =~ s/^ //;
   1731  1.1  christos }
   1732  1.1  christos 
   1733  1.1  christos sub menu_entry {
   1734  1.1  christos     local($entry, $node, $descr) = @_;
   1735  1.1  christos     local($href);
   1736  1.1  christos 
   1737  1.1  christos     &normalise_node($node);
   1738  1.1  christos     $href = $node2href{$node};
   1739  1.1  christos     if ($href) {
   1740  1.1  christos 	$descr =~ s/^\s+//;
   1741  1.1  christos 	$descr = ": $descr" if $descr;
   1742  1.1  christos 	push(@lines2, "<LI>" . &anchor('', $href, $entry) . "$descr\n");
   1743  1.1  christos     } else {
   1744  1.1  christos 	warn "$ERROR Undefined node ($node): $_";
   1745  1.1  christos     }
   1746  1.1  christos }
   1747  1.1  christos 
   1748  1.1  christos sub do_ctrl { "^$_[0]" }
   1749  1.1  christos 
   1750  1.1  christos sub do_email {
   1751  1.1  christos     local($addr, $text) = split(/,\s*/, $_[0]);
   1752  1.1  christos 
   1753  1.1  christos     $text = $addr unless $text;
   1754  1.1  christos     &anchor('', "mailto:$addr", $text);
   1755  1.1  christos }
   1756  1.1  christos 
   1757  1.1  christos sub do_sc { "\U$_[0]\E" }
   1758  1.1  christos 
   1759  1.1  christos sub do_uref {
   1760  1.1  christos     local($url, $text) = split(/,\s*/, $_[0]);
   1761  1.1  christos 
   1762  1.1  christos     $text = $url unless $text;
   1763  1.1  christos     &anchor('', $url, $text);
   1764  1.1  christos }
   1765  1.1  christos 
   1766  1.1  christos sub do_url { &anchor('', $_[0], $_[0]) }
   1767  1.1  christos 
   1768  1.1  christos sub do_diaeresis { return "&$_[0]uml;"; }
   1769  1.1  christos sub do_acuteaccent { return "&$_[0]acute;"; }
   1770  1.1  christos sub do_graveaccent { return "&$_[0]grave;"; }
   1771  1.1  christos sub do_tildeaccent { return "&$_[0]tilde;"; }
   1772  1.1  christos sub do_cedilla { return "&$_[0]cedil;"; }
   1773  1.1  christos sub do_circumflex { return "&$_[0]circ;"; }
   1774  1.1  christos 
   1775  1.1  christos sub apply_style {
   1776  1.1  christos     local($texi_style, $text) = @_;
   1777  1.1  christos     local($style);
   1778  1.1  christos 
   1779  1.1  christos     $style = $style_map{$texi_style};
   1780  1.1  christos     if (defined($style)) { # known style
   1781  1.1  christos 	if ($style =~ /^\"/) { # add quotes
   1782  1.1  christos 	    $style = $';
   1783  1.1  christos 	    $text = "\&lsquo;$text\&rsquo;";
   1784  1.1  christos 	}
   1785  1.1  christos 	if ($style =~ /^\&/) { # custom
   1786  1.1  christos 	    $style = $';
   1787  1.1  christos 	    $text = &$style($text);
   1788  1.1  christos 	} elsif ($style) { # good style
   1789  1.1  christos 	    $text = "<$style>$text</$style>";
   1790  1.1  christos 	} else { # no style
   1791  1.1  christos 	}
   1792  1.1  christos     } else { # unknown style
   1793  1.1  christos 	$text = undef;
   1794  1.1  christos     }
   1795  1.1  christos     return($text);
   1796  1.1  christos }
   1797  1.1  christos 
   1798  1.1  christos # remove Texinfo styles
   1799  1.1  christos sub remove_style {
   1800  1.1  christos     local($_) = @_;
   1801  1.1  christos     s/\@\w+{([^\{\}]+)}/$1/g;
   1802  1.1  christos     return($_);
   1803  1.1  christos }
   1804  1.1  christos 
   1805  1.1  christos sub substitute_style {
   1806  1.1  christos     local($_) = @_;
   1807  1.1  christos     local($changed, $done, $style, $text);
   1808  1.1  christos 
   1809  1.1  christos     $changed = 1;
   1810  1.1  christos     while ($changed) {
   1811  1.1  christos 	$changed = 0;
   1812  1.1  christos 	$done = '';
   1813  1.1  christos 	while (/\@(\w+|"|\~|,|\^){([^\{\}]+)}/) {
   1814  1.1  christos 	    $text = &apply_style($1, $2);
   1815  1.1  christos 	    if ($text) {
   1816  1.1  christos 		$_ = "$`$text$'";
   1817  1.1  christos 		$changed = 1;
   1818  1.1  christos 	    } else {
   1819  1.1  christos 		$done .= "$`\@$1";
   1820  1.1  christos 		$_ = "{$2}$'";
   1821  1.1  christos 	    }
   1822  1.1  christos 	}
   1823  1.1  christos         $_ = $done . $_;
   1824  1.1  christos     }
   1825  1.1  christos     return($_);
   1826  1.1  christos }
   1827  1.1  christos 
   1828  1.1  christos sub anchor {
   1829  1.1  christos     local($name, $href, $text, $newline) = @_;
   1830  1.1  christos     local($result);
   1831  1.1  christos 
   1832  1.1  christos     $result = "<A";
   1833  1.1  christos     $result .= " NAME=\"$name\"" if $name;
   1834  1.1  christos     $result .= " HREF=\"$href\"" if $href;
   1835  1.1  christos     $result .= ">$text</A>";
   1836  1.1  christos     $result .= "\n" if $newline;
   1837  1.1  christos     return($result);
   1838  1.1  christos }
   1839  1.1  christos 
   1840  1.1  christos sub pretty_date {
   1841  1.1  christos     local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
   1842  1.1  christos 
   1843  1.1  christos     @MoY = ('January', 'Febuary', 'March', 'April', 'May', 'June',
   1844  1.1  christos 	    'July', 'August', 'September', 'October', 'November', 'December');
   1845  1.1  christos     ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
   1846  1.1  christos     $year += ($year < 70) ? 2000 : 1900;
   1847  1.1  christos     return("$mday $MoY[$mon] $year");
   1848  1.1  christos }
   1849  1.1  christos 
   1850  1.1  christos sub doc_name {
   1851  1.1  christos     local($num) = @_;
   1852  1.1  christos 
   1853  1.1  christos     return("${docu_name}_$num.html");
   1854  1.1  christos }
   1855  1.1  christos 
   1856  1.1  christos sub next_doc {
   1857  1.1  christos     $docu_doc = &doc_name(++$doc_num);
   1858  1.1  christos }
   1859  1.1  christos 
   1860  1.1  christos sub print {
   1861  1.1  christos     local(*lines, $fh) = @_;
   1862  1.1  christos     local($_);
   1863  1.1  christos 
   1864  1.1  christos     while (@lines) {
   1865  1.1  christos 	$_ = shift(@lines);
   1866  1.1  christos 	if (/^$PROTECTTAG/o) {
   1867  1.1  christos 	    $_ = $tag2pro{$_};
   1868  1.1  christos 	} else {
   1869  1.1  christos 	    &unprotect_texi;
   1870  1.1  christos 	}
   1871  1.1  christos 	print $fh $_;
   1872  1.1  christos     }
   1873  1.1  christos }
   1874  1.1  christos 
   1875  1.1  christos sub print_ruler {
   1876  1.1  christos     print FILE "<P><HR><P>\n";
   1877  1.1  christos }
   1878  1.1  christos 
   1879  1.1  christos sub print_header {
   1880  1.1  christos     local($_);
   1881  1.1  christos 
   1882  1.1  christos     # clean the title
   1883  1.1  christos     $_ = &remove_style($_[0]);
   1884  1.1  christos     &unprotect_texi;
   1885  1.1  christos     # print the header
   1886  1.1  christos     if ($doctype eq 'html2') {
   1887  1.1  christos 	print FILE $html2_doctype;
   1888  1.1  christos     } elsif ($doctype) {
   1889  1.1  christos 	print FILE $doctype;
   1890  1.1  christos     }
   1891  1.1  christos     print FILE <<EOT;
   1892  1.1  christos <HTML>
   1893  1.1  christos <HEAD>
   1894  1.1  christos $header
   1895  1.1  christos <META HTTP-EQUIV="content-type" CONTENT="text/html; charset=UTF-8">
   1896  1.1  christos <TITLE>$_</TITLE>
   1897  1.1  christos </HEAD>
   1898  1.1  christos <BODY>
   1899  1.1  christos EOT
   1900  1.1  christos }
   1901  1.1  christos 
   1902  1.1  christos sub print_toplevel_header {
   1903  1.1  christos     local($_);
   1904  1.1  christos 
   1905  1.1  christos     &print_header; # pass given arg...
   1906  1.1  christos     print FILE $full_title;
   1907  1.1  christos     if ($value{'_subtitle'}) {
   1908  1.1  christos 	$value{'_subtitle'} =~ s/\n+$//;
   1909  1.1  christos 	foreach (split(/\n/, $value{'_subtitle'})) {
   1910  1.1  christos 	    $_ = &substitute_style($_);
   1911  1.1  christos 	    &unprotect_texi;
   1912  1.1  christos 	    print FILE "<H2>$_</H2>\n";
   1913  1.1  christos 	}
   1914  1.1  christos     }
   1915  1.1  christos     if ($value{'_author'}) {
   1916  1.1  christos 	$value{'_author'} =~ s/\n+$//;
   1917  1.1  christos 	foreach (split(/\n/, $value{'_author'})) {
   1918  1.1  christos 	    $_ = &substitute_style($_);
   1919  1.1  christos 	    &unprotect_texi;
   1920  1.1  christos 	    s/[\w.-]+\@[\w.-]+/<A HREF="mailto:$&">$&<\/A>/g;
   1921  1.1  christos 	    print FILE "<ADDRESS>$_</ADDRESS>\n";
   1922  1.1  christos 	}
   1923  1.1  christos     }
   1924  1.1  christos     print FILE "<P>\n";
   1925  1.1  christos }
   1926  1.1  christos 
   1927  1.1  christos sub print_footer {
   1928  1.1  christos     print FILE <<EOT;
   1929  1.1  christos </BODY>
   1930  1.1  christos </HTML>
   1931  1.1  christos EOT
   1932  1.1  christos }
   1933  1.1  christos 
   1934  1.1  christos sub print_toplevel_footer {
   1935  1.1  christos     &print_ruler;
   1936  1.1  christos     print FILE <<EOT;
   1937  1.1  christos This document was generated on $TODAY using the
   1938  1.1  christos <A HREF=\"$HOMEPAGE\">texi2html</A>
   1939  1.1  christos translator version 1.52b.</P>
   1940  1.1  christos EOT
   1941  1.1  christos     &print_footer;
   1942  1.1  christos }
   1943  1.1  christos 
   1944  1.1  christos sub protect_texi {
   1945  1.1  christos     # protect @ { } ` '
   1946  1.1  christos     s/\@\@/$;0/go;
   1947  1.1  christos     s/\@\{/$;1/go;
   1948  1.1  christos     s/\@\}/$;2/go;
   1949  1.1  christos     s/\@\`/$;3/go;
   1950  1.1  christos     s/\@\'/$;4/go;
   1951  1.1  christos }
   1952  1.1  christos 
   1953  1.1  christos sub protect_html {
   1954  1.1  christos     local($what) = @_;
   1955  1.1  christos     # protect & < >
   1956  1.1  christos     $what =~ s/\&/\&\#38;/g;
   1957  1.1  christos     $what =~ s/\</\&\#60;/g;
   1958  1.1  christos     $what =~ s/\>/\&\#62;/g;
   1959  1.1  christos     # but recognize some HTML things
   1960  1.1  christos     $what =~ s/\&\#60;\/A\&\#62;/<\/A>/g;	      # </A>
   1961  1.1  christos     $what =~ s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g;     # <A [^&]+>
   1962  1.1  christos     $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;/<IMG $1>/g; # <IMG [^&]+>
   1963  1.1  christos     return($what);
   1964  1.1  christos }
   1965  1.1  christos 
   1966  1.1  christos sub unprotect_texi {
   1967  1.1  christos     s/$;0/\@/go;
   1968  1.1  christos     s/$;1/\{/go;
   1969  1.1  christos     s/$;2/\}/go;
   1970  1.1  christos     s/$;3/\`/go;
   1971  1.1  christos     s/$;4/\'/go;
   1972  1.1  christos }
   1973  1.1  christos 
   1974  1.1  christos sub unprotect_html {
   1975  1.1  christos     local($what) = @_;
   1976  1.1  christos     $what =~ s/\&\#38;/\&/g;
   1977  1.1  christos     $what =~ s/\&\#60;/\</g;
   1978  1.1  christos     $what =~ s/\&\#62;/\>/g;
   1979  1.1  christos     return($what);
   1980  1.1  christos }
   1981  1.1  christos 
   1982  1.1  christos sub byalpha {
   1983  1.1  christos     $key2alpha{$a} cmp $key2alpha{$b};
   1984  1.1  christos }
   1985  1.1  christos 
   1986  1.1  christos ##############################################################################
   1987  1.1  christos 
   1988  1.1  christos 	# These next few lines are legal in both Perl and nroff.
   1989  1.1  christos 
   1990  1.1  christos .00 ;			# finish .ig
   1991  1.1  christos  
   1992  1.1  christos 'di			\" finish diversion--previous line must be blank
   1993  1.1  christos .nr nl 0-1		\" fake up transition to first page again
   1994  1.1  christos .nr % 0			\" start at page 1
   1995  1.1  christos '; __END__ ############# From here on it's a standard manual page ############
   1996  1.1  christos .TH TEXI2HTML 1 "01/05/98"
   1997  1.1  christos .AT 3
   1998  1.1  christos .SH NAME
   1999  1.1  christos texi2html \- a Texinfo to HTML converter
   2000  1.1  christos .SH SYNOPSIS
   2001  1.1  christos .B texi2html [options] file
   2002  1.1  christos .PP
   2003  1.1  christos .B texi2html -check [-verbose] files
   2004  1.1  christos .SH DESCRIPTION
   2005  1.1  christos .I Texi2html
   2006  1.1  christos converts the given Texinfo file to a set of HTML files. It tries to handle
   2007  1.1  christos most of the Texinfo commands. It creates hypertext links for cross-references,
   2008  1.1  christos footnotes...
   2009  1.1  christos .PP
   2010  1.1  christos It also tries to add links from a reference to its corresponding entry in the
   2011  1.1  christos bibliography (if any). It may also handle a glossary (see the
   2012  1.1  christos .B \-glossary
   2013  1.1  christos option).
   2014  1.1  christos .PP
   2015  1.1  christos .I Texi2html
   2016  1.1  christos creates several files depending on the contents of the Texinfo file and on
   2017  1.1  christos the chosen options (see FILES).
   2018  1.1  christos .PP
   2019  1.1  christos The HTML files created by
   2020  1.1  christos .I texi2html
   2021  1.1  christos are closer to TeX than to Info, that's why
   2022  1.1  christos .I texi2html
   2023  1.1  christos converts @ifhtml sections and not @ifinfo or @iftex ones by default. You can
   2024  1.1  christos change this with the \-expandinfo or \-expandtex options.
   2025  1.1  christos .SH OPTIONS
   2026  1.1  christos .TP 12
   2027  1.1  christos .B \-check
   2028  1.1  christos Check the given file and give the list of all things that may be Texinfo commands.
   2029  1.1  christos This may be used to check the output of
   2030  1.1  christos .I texi2html
   2031  1.1  christos to find the Texinfo commands that have been left in the HTML file.
   2032  1.1  christos .TP
   2033  1.1  christos .B \-expandinfo
   2034  1.1  christos Expand @ifinfo sections, not @ifhtml ones.
   2035  1.1  christos .TP
   2036  1.1  christos .B \-expandtex
   2037  1.1  christos Expand @iftex sections, not @ifhtml ones.
   2038  1.1  christos .TP
   2039  1.1  christos .B \-glossary
   2040  1.1  christos Use the section named 'Glossary' to build a list of terms and put links in the HTML
   2041  1.1  christos document from each term toward its definition.
   2042  1.1  christos .TP
   2043  1.1  christos .B \-invisible \fIname\fP
   2044  1.1  christos Use \fIname\fP to create invisible destination anchors for index links
   2045  1.1  christos (you can for instance use the invisible.xbm file shipped with this program).
   2046  1.1  christos This is a workaround for a known bug of many WWW browsers, including netscape.
   2047  1.1  christos .TP
   2048  1.1  christos .B \-I \fIdir\fP
   2049  1.1  christos Look also in \fIdir\fP to find included files.
   2050  1.1  christos .TP
   2051  1.1  christos .B \-menu
   2052  1.1  christos Show the Texinfo menus; by default they are ignored.
   2053  1.1  christos .TP
   2054  1.1  christos .B \-monolithic
   2055  1.1  christos Output only one file, including the table of contents and footnotes.
   2056  1.1  christos .TP
   2057  1.1  christos .B \-number
   2058  1.1  christos Number the sections.
   2059  1.1  christos .TP
   2060  1.1  christos .B \-split_chapter
   2061  1.1  christos Split the output into several HTML files (one per main section:
   2062  1.1  christos chapter, appendix...).
   2063  1.1  christos .TP
   2064  1.1  christos .B \-split_node
   2065  1.1  christos Split the output into several HTML files (one per node).
   2066  1.1  christos .TP
   2067  1.1  christos .B \-usage
   2068  1.1  christos Print usage instructions, listing the current available command-line options.
   2069  1.1  christos .TP
   2070  1.1  christos .B \-verbose
   2071  1.1  christos Give a verbose output. Can be used with the
   2072  1.1  christos .B \-check
   2073  1.1  christos option.
   2074  1.1  christos .PP
   2075  1.1  christos .SH FILES
   2076  1.1  christos By default
   2077  1.1  christos .I texi2html
   2078  1.1  christos creates the following files (foo being the name of the Texinfo file):
   2079  1.1  christos .TP 16
   2080  1.1  christos .B foo_toc.html
   2081  1.1  christos The table of contents.
   2082  1.1  christos .TP
   2083  1.1  christos .B foo.html
   2084  1.1  christos The document's contents.
   2085  1.1  christos .TP
   2086  1.1  christos .B foo_foot.html
   2087  1.1  christos The footnotes (if any).
   2088  1.1  christos .PP
   2089  1.1  christos When used with the
   2090  1.1  christos .B \-split
   2091  1.1  christos option, it creates several files (one per chapter or node), named
   2092  1.1  christos .B foo_n.html
   2093  1.1  christos (n being the indice of the chapter or node), instead of the single
   2094  1.1  christos .B foo.html
   2095  1.1  christos file.
   2096  1.1  christos .PP
   2097  1.1  christos When used with the
   2098  1.1  christos .B \-monolithic
   2099  1.1  christos option, it creates only one file:
   2100  1.1  christos .B foo.html
   2101  1.1  christos .SH VARIABLES
   2102  1.1  christos .I texi2html
   2103  1.1  christos predefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
   2104  1.1  christos .SH ADDITIONAL COMMANDS
   2105  1.1  christos .I texi2html
   2106  1.1  christos implements the following non-Texinfo commands (maybe they are in Texinfo now...):
   2107  1.1  christos .TP 16
   2108  1.1  christos .B @ifhtml
   2109  1.1  christos This indicates the start of an HTML section, this section will passed through
   2110  1.1  christos without any modification.
   2111  1.1  christos .TP
   2112  1.1  christos .B @end ifhtml
   2113  1.1  christos This indicates the end of an HTML section.
   2114  1.1  christos .SH VERSION
   2115  1.1  christos This is \fItexi2html\fP version 1.52b, 01/05/98.
   2116  1.1  christos .PP
   2117  1.1  christos The latest version of \fItexi2html\fP can be found in WWW, cf. URL
   2118  1.1  christos http://wwwinfo.cern.ch/dis/texi2html/
   2119  1.1  christos .SH AUTHOR
   2120  1.1  christos The main author is Lionel Cons, CERN IT/DIS/OSE, Lionel.Cons (at] cern.ch.
   2121  1.1  christos Many other people around the net contributed to this program.
   2122  1.1  christos .SH COPYRIGHT
   2123  1.1  christos This program is the intellectual property of the European
   2124  1.1  christos Laboratory for Particle Physics (known as CERN). No guarantee whatsoever is
   2125  1.1  christos provided by CERN. No liability whatsoever is accepted for any loss or damage
   2126  1.1  christos of any kind resulting from any defect or inaccuracy in this information or
   2127  1.1  christos code.
   2128  1.1  christos .PP
   2129  1.1  christos CERN, 1211 Geneva 23, Switzerland
   2130  1.1  christos .SH "SEE ALSO"
   2131  1.1  christos GNU Texinfo Documentation Format,
   2132  1.1  christos HyperText Markup Language (HTML),
   2133  1.1  christos World Wide Web (WWW).
   2134  1.1  christos .SH BUGS
   2135  1.1  christos This program does not understand all Texinfo commands (yet).
   2136  1.1  christos .ex
   2137