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