xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/doc/texi2html (revision 95b39c65ca575fb40c6bb7083e0eb7ec28eabef1)
1946379e7Schristos#!/usr/local/bin/perl
2946379e7Schristos'di ';
3946379e7Schristos'ig 00 ';
4946379e7Schristos#+##############################################################################
5946379e7Schristos#                                                                              #
6946379e7Schristos# File: texi2html                                                              #
7946379e7Schristos#                                                                              #
8946379e7Schristos# Description: Program to transform most Texinfo documents to HTML             #
9946379e7Schristos#                                                                              #
10946379e7Schristos#-##############################################################################
11946379e7Schristos
12946379e7Schristos# @(#)texi2html	1.52b 01/05/98	Written (mainly) by Lionel Cons, Lionel.Cons@cern.ch
13946379e7Schristos# 1.52a: Use acute accent instead of apostrophe. Add support for ISO-8859-1
14946379e7Schristos#        characters with cedilla, circumflex etc.
15946379e7Schristos# 1.52b: Add option -expandtex. Expand @ifhtml by default, not @ifinfo.
16946379e7Schristos#        Use Unicode quotation marks instead of grave and acute accents.
17946379e7Schristos#        Emit charset=UTF-8 declaration.
18946379e7Schristos
19946379e7Schristos# The man page for this program is included at the end of this file and can be
20946379e7Schristos# viewed using the command 'nroff -man texi2html'.
21946379e7Schristos# Please read the copyright at the end of the man page.
22946379e7Schristos
23946379e7Schristos#+++############################################################################
24946379e7Schristos#                                                                              #
25946379e7Schristos# Constants                                                                    #
26946379e7Schristos#                                                                              #
27946379e7Schristos#---############################################################################
28946379e7Schristos
29946379e7Schristos$DEBUG_TOC   =  1;
30946379e7Schristos$DEBUG_INDEX =  2;
31946379e7Schristos$DEBUG_BIB   =  4;
32946379e7Schristos$DEBUG_GLOSS =  8;
33946379e7Schristos$DEBUG_DEF   = 16;
34946379e7Schristos$DEBUG_HTML  = 32;
35946379e7Schristos$DEBUG_USER  = 64;
36946379e7Schristos
37946379e7Schristos$BIBRE = '\[[\w\/-]+\]';		# RE for a bibliography reference
38946379e7Schristos$FILERE = '[\/\w.+-]+';			# RE for a file name
39946379e7Schristos$VARRE = '[^\s\{\}]+';			# RE for a variable name
40946379e7Schristos$NODERE = '[^@{}:\'`",]+';		# RE for a node name
41946379e7Schristos$NODESRE = '[^@{}:\'`"]+';		# RE for a list of node names
42946379e7Schristos$XREFRE = '[^@{}]+';			# RE for a xref (should use NODERE)
43946379e7Schristos
44946379e7Schristos$ERROR = "***";			        # prefix for errors and warnings
45946379e7Schristos$THISPROG = "texi2html 1.52b";			# program name and version
46946379e7Schristos$HOMEPAGE = "http://wwwinfo.cern.ch/dis/texi2html/"; # program home page
47946379e7Schristos$TODAY = &pretty_date;			# like "20 September 1993"
48946379e7Schristos$SPLITTAG = "<!-- SPLIT HERE -->\n";	# tag to know where to split
49946379e7Schristos$PROTECTTAG = "_ThisIsProtected_";	# tag to recognize protected sections
50946379e7Schristos$html2_doctype = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0 Strict Level 2//EN">';
51946379e7Schristos
52946379e7Schristos#
53946379e7Schristos# language dependent constants
54946379e7Schristos#
55946379e7Schristos#$LDC_SEE = 'see';
56946379e7Schristos#$LDC_SECTION = 'section';
57946379e7Schristos#$LDC_IN = 'in';
58946379e7Schristos#$LDC_TOC = 'Table of Contents';
59946379e7Schristos#$LDC_GOTO = 'Go to the';
60946379e7Schristos#$LDC_FOOT = 'Footnotes';
61946379e7Schristos# TODO: @def* shortcuts
62946379e7Schristos
63946379e7Schristos#
64946379e7Schristos# pre-defined indices
65946379e7Schristos#
66946379e7Schristos%predefined_index = (
67946379e7Schristos		    'cp', 'c',
68946379e7Schristos		    'fn', 'f',
69946379e7Schristos		    'vr', 'v',
70946379e7Schristos		    'ky', 'k',
71946379e7Schristos		    'pg', 'p',
72946379e7Schristos		    'tp', 't',
73946379e7Schristos	            );
74946379e7Schristos
75946379e7Schristos#
76946379e7Schristos# valid indices
77946379e7Schristos#
78946379e7Schristos%valid_index = (
79946379e7Schristos		    'c', 1,
80946379e7Schristos		    'f', 1,
81946379e7Schristos		    'v', 1,
82946379e7Schristos		    'k', 1,
83946379e7Schristos		    'p', 1,
84946379e7Schristos		    't', 1,
85946379e7Schristos		);
86946379e7Schristos
87946379e7Schristos#
88946379e7Schristos# texinfo section names to level
89946379e7Schristos#
90946379e7Schristos%sec2level = (
91946379e7Schristos	      'top', 0,
92946379e7Schristos	      'chapter', 1,
93946379e7Schristos	      'unnumbered', 1,
94946379e7Schristos	      'majorheading', 1,
95946379e7Schristos	      'chapheading', 1,
96946379e7Schristos	      'appendix', 1,
97946379e7Schristos	      'section', 2,
98946379e7Schristos	      'unnumberedsec', 2,
99946379e7Schristos	      'heading', 2,
100946379e7Schristos	      'appendixsec', 2,
101946379e7Schristos	      'appendixsection', 2,
102946379e7Schristos	      'subsection', 3,
103946379e7Schristos	      'unnumberedsubsec', 3,
104946379e7Schristos	      'subheading', 3,
105946379e7Schristos	      'appendixsubsec', 3,
106946379e7Schristos	      'subsubsection', 4,
107946379e7Schristos	      'unnumberedsubsubsec', 4,
108946379e7Schristos	      'subsubheading', 4,
109946379e7Schristos	      'appendixsubsubsec', 4,
110946379e7Schristos	      );
111946379e7Schristos
112946379e7Schristos#
113946379e7Schristos# accent map, TeX command to ISO name
114946379e7Schristos#
115946379e7Schristos%accent_map = (
116946379e7Schristos	       '"',  'uml',
117946379e7Schristos	       '~',  'tilde',
118946379e7Schristos	       '^',  'circ',
119946379e7Schristos	       '`',  'grave',
120946379e7Schristos	       '\'', 'acute',
121946379e7Schristos	       );
122946379e7Schristos
123946379e7Schristos#
124946379e7Schristos# texinfo "simple things" (@foo) to HTML ones
125946379e7Schristos#
126946379e7Schristos%simple_map = (
127946379e7Schristos	       # cf. makeinfo.c
128946379e7Schristos	       "*", "<BR>",		# HTML+
129946379e7Schristos	       " ", " ",
130946379e7Schristos	       "\n", "\n",
131946379e7Schristos	       "|", "",
132946379e7Schristos	       # spacing commands
133946379e7Schristos	       ":", "",
134946379e7Schristos	       "!", "!",
135946379e7Schristos	       "?", "?",
136946379e7Schristos	       ".", ".",
137946379e7Schristos	       "-", "",
138946379e7Schristos	       );
139946379e7Schristos
140946379e7Schristos#
141946379e7Schristos# texinfo "things" (@foo{}) to HTML ones
142946379e7Schristos#
143946379e7Schristos%things_map = (
144946379e7Schristos	       'TeX', 'TeX',
145946379e7Schristos	       'br', '<P>',		# paragraph break
146946379e7Schristos	       'bullet', '*',
147946379e7Schristos	       'copyright', '(C)',
148946379e7Schristos	       'dots', '...',
149946379e7Schristos	       'equiv', '==',
150946379e7Schristos	       'error', 'error-->',
151946379e7Schristos	       'expansion', '==>',
152946379e7Schristos	       'minus', '-',
153946379e7Schristos	       'point', '-!-',
154946379e7Schristos	       'print', '-|',
155946379e7Schristos	       'result', '=>',
156946379e7Schristos	       'today', $TODAY,
157946379e7Schristos	       'aa', '&aring;',
158946379e7Schristos	       'AA', '&Aring;',
159946379e7Schristos	       'ae', '&aelig;',
160946379e7Schristos	       'AE', '&AElig;',
161946379e7Schristos	       'o',  '&oslash;',
162946379e7Schristos	       'O',  '&Oslash;',
163946379e7Schristos	       'ss', '&szlig;',
164946379e7Schristos	       'exclamdown', '&iexcl;',
165946379e7Schristos	       'questiondown', '&iquest;',
166946379e7Schristos	       'pounds', '&pound;'
167946379e7Schristos	       );
168946379e7Schristos
169946379e7Schristos#
170946379e7Schristos# texinfo styles (@foo{bar}) to HTML ones
171946379e7Schristos#
172946379e7Schristos%style_map = (
173946379e7Schristos	      'asis', '',
174946379e7Schristos	      'b', 'B',
175946379e7Schristos	      'cite', 'CITE',
176946379e7Schristos	      'code', 'CODE',
177946379e7Schristos	      'ctrl', '&do_ctrl',	# special case
178946379e7Schristos	      'dfn', 'EM',		# DFN tag is illegal in the standard
179946379e7Schristos	      'dmn', '',		# useless
180946379e7Schristos	      'email', '&do_email',     # insert a clickable email address
181946379e7Schristos	      'emph', 'EM',
182946379e7Schristos	      'file', '"TT',		# will put quotes, cf. &apply_style
183946379e7Schristos	      'i', 'I',
184946379e7Schristos	      'kbd', 'KBD',
185946379e7Schristos	      'key', 'KBD',
186946379e7Schristos	      'math', 'EM',
187946379e7Schristos	      'r', '',			# unsupported
188946379e7Schristos	      'samp', '"SAMP',		# will put quotes, cf. &apply_style
189946379e7Schristos	      'sc', '&do_sc',		# special case
190946379e7Schristos	      'strong', 'STRONG',
191946379e7Schristos	      't', 'TT',
192946379e7Schristos	      'titlefont', '',		# useless
193946379e7Schristos	      'uref', '&do_uref',       # insert a clickable URL
194946379e7Schristos	      'url', '&do_url',         # insert a clickable URL
195946379e7Schristos	      'var', 'VAR',
196946379e7Schristos	      'w', '',			# unsupported
197946379e7Schristos	      '"', '&do_diaeresis',
198946379e7Schristos	      '\'', '&do_acuteaccent',	# doesn't work??
199946379e7Schristos	      '\`', '&do_graveaccent',	# doesn't work??
200946379e7Schristos	      '~', '&do_tildeaccent',
201946379e7Schristos	      ',', '&do_cedilla',
202946379e7Schristos	      '^', '&do_circumflex',
203946379e7Schristos	      );
204946379e7Schristos
205946379e7Schristos#
206946379e7Schristos# texinfo format (@foo/@end foo) to HTML ones
207946379e7Schristos#
208946379e7Schristos%format_map = (
209946379e7Schristos	       'display', 'PRE',
210946379e7Schristos	       'example', 'PRE',
211946379e7Schristos	       'format', 'PRE',
212946379e7Schristos	       'lisp', 'PRE',
213946379e7Schristos	       'quotation', 'BLOCKQUOTE',
214946379e7Schristos	       'smallexample', 'PRE',
215946379e7Schristos	       'smalllisp', 'PRE',
216946379e7Schristos	       # lists
217946379e7Schristos	       'itemize', 'UL',
218946379e7Schristos	       'enumerate', 'OL',
219946379e7Schristos	       # poorly supported
220946379e7Schristos	       'flushleft', 'PRE',
221946379e7Schristos	       'flushright', 'PRE',
222946379e7Schristos	       );
223946379e7Schristos
224946379e7Schristos#
225946379e7Schristos# texinfo definition shortcuts to real ones
226946379e7Schristos#
227946379e7Schristos%def_map = (
228946379e7Schristos	    # basic commands
229946379e7Schristos	    'deffn', 0,
230946379e7Schristos	    'defvr', 0,
231946379e7Schristos	    'deftypefn', 0,
232946379e7Schristos	    'deftypevr', 0,
233946379e7Schristos	    'defcv', 0,
234946379e7Schristos	    'defop', 0,
235946379e7Schristos	    'deftp', 0,
236946379e7Schristos	    # basic x commands
237946379e7Schristos	    'deffnx', 0,
238946379e7Schristos	    'defvrx', 0,
239946379e7Schristos	    'deftypefnx', 0,
240946379e7Schristos	    'deftypevrx', 0,
241946379e7Schristos	    'defcvx', 0,
242946379e7Schristos	    'defopx', 0,
243946379e7Schristos	    'deftpx', 0,
244946379e7Schristos	    # shortcuts
245946379e7Schristos	    'defun', 'deffn Function',
246946379e7Schristos	    'defmac', 'deffn Macro',
247946379e7Schristos	    'defspec', 'deffn {Special Form}',
248946379e7Schristos	    'defvar', 'defvr Variable',
249946379e7Schristos	    'defopt', 'defvr {User Option}',
250946379e7Schristos	    'deftypefun', 'deftypefn Function',
251946379e7Schristos	    'deftypevar', 'deftypevr Variable',
252946379e7Schristos	    'defivar', 'defcv {Instance Variable}',
253946379e7Schristos	    'defmethod', 'defop Method',
254946379e7Schristos	    # x shortcuts
255946379e7Schristos	    'defunx', 'deffnx Function',
256946379e7Schristos	    'defmacx', 'deffnx Macro',
257946379e7Schristos	    'defspecx', 'deffnx {Special Form}',
258946379e7Schristos	    'defvarx', 'defvrx Variable',
259946379e7Schristos	    'defoptx', 'defvrx {User Option}',
260946379e7Schristos	    'deftypefunx', 'deftypefnx Function',
261946379e7Schristos	    'deftypevarx', 'deftypevrx Variable',
262946379e7Schristos	    'defivarx', 'defcvx {Instance Variable}',
263946379e7Schristos	    'defmethodx', 'defopx Method',
264946379e7Schristos	    );
265946379e7Schristos
266946379e7Schristos#
267946379e7Schristos# things to skip
268946379e7Schristos#
269946379e7Schristos%to_skip = (
270946379e7Schristos	    # comments
271946379e7Schristos	    'c', 1,
272946379e7Schristos	    'comment', 1,
273946379e7Schristos	    # useless
274946379e7Schristos	    'contents', 1,
275946379e7Schristos	    'shortcontents', 1,
276946379e7Schristos	    'summarycontents', 1,
277946379e7Schristos	    'footnotestyle', 1,
278946379e7Schristos	    'end ifclear', 1,
279946379e7Schristos	    'end ifset', 1,
280946379e7Schristos	    'titlepage', 1,
281946379e7Schristos	    'end titlepage', 1,
282946379e7Schristos	    # unsupported commands (formatting)
283946379e7Schristos	    'afourpaper', 1,
284946379e7Schristos	    'cropmarks', 1,
285946379e7Schristos	    'finalout', 1,
286946379e7Schristos	    'headings', 1,
287946379e7Schristos	    'need', 1,
288946379e7Schristos	    'page', 1,
289946379e7Schristos	    'setchapternewpage', 1,
290946379e7Schristos	    'everyheading', 1,
291946379e7Schristos	    'everyfooting', 1,
292946379e7Schristos	    'evenheading', 1,
293946379e7Schristos	    'evenfooting', 1,
294946379e7Schristos	    'oddheading', 1,
295946379e7Schristos	    'oddfooting', 1,
296946379e7Schristos	    'smallbook', 1,
297946379e7Schristos	    'vskip', 1,
298946379e7Schristos	    'filbreak', 1,
299946379e7Schristos	    'paragraphindent', 1,
300946379e7Schristos	    # unsupported formats
301946379e7Schristos	    'cartouche', 1,
302946379e7Schristos	    'end cartouche', 1,
303946379e7Schristos	    'group', 1,
304946379e7Schristos	    'end group', 1,
305946379e7Schristos	    );
306946379e7Schristos
307946379e7Schristos#+++############################################################################
308946379e7Schristos#                                                                              #
309946379e7Schristos# Argument parsing, initialisation                                             #
310946379e7Schristos#                                                                              #
311946379e7Schristos#---############################################################################
312946379e7Schristos
313946379e7Schristos%value = ();				# hold texinfo variables, see also -D
314946379e7Schristos
315946379e7Schristos$use_bibliography = 1;
316946379e7Schristos$use_acc = 0;
317946379e7Schristos$debug = 0;
318946379e7Schristos$doctype = '';
319946379e7Schristos$check = 0;
320946379e7Schristos$expandinfo = 0;
321946379e7Schristos$expandtex = 0;
322946379e7Schristos$use_glossary = 0;
323946379e7Schristos$invisible_mark = '';
324946379e7Schristos$use_iso = 0;
325946379e7Schristos@include_dirs = ();
326946379e7Schristos$show_menu = 0;
327946379e7Schristos$number_sections = 0;
328946379e7Schristos$split_node = 0;
329946379e7Schristos$split_chapter = 0;
330946379e7Schristos$monolithic = 0;
331946379e7Schristos$verbose = 0;
332946379e7Schristos$usage = <<EOT;
333946379e7SchristosThis is $THISPROG
334946379e7SchristosTo convert a Texinfo file to HMTL: $0 [options] file
335946379e7Schristos  where options can be:
336946379e7Schristos    -expandinfo    : use \@ifinfo sections, not \@ifhtml
337946379e7Schristos    -expandtex     : use \@iftex sections, not \@ifhtml
338946379e7Schristos    -glossary      : handle a glossary
339946379e7Schristos    -invisible name: use 'name' as an invisible anchor
340946379e7Schristos    -Dname         : define name like with \@set
341946379e7Schristos    -I dir         : search also for files in 'dir'
342946379e7Schristos    -menu          : handle menus
343946379e7Schristos    -monolithic    : output only one file including ToC
344946379e7Schristos    -number        : number sections
345946379e7Schristos    -split_chapter : split on main sections
346946379e7Schristos    -split_node    : split on nodes
347946379e7Schristos    -usage         : print usage instructions
348946379e7Schristos    -verbose       : verbose output
349946379e7SchristosTo check converted files: $0 -check [-verbose] files
350946379e7SchristosEOT
351946379e7Schristos
352946379e7Schristoswhile (@ARGV && $ARGV[0] =~ /^-/) {
353946379e7Schristos    $_ = shift(@ARGV);
354946379e7Schristos    if (/^-acc$/)            { $use_acc = 1; next; }
355946379e7Schristos    if (/^-d(ebug)?(\d+)?$/) { $debug = $2 || shift(@ARGV); next; }
356946379e7Schristos    if (/^-doctype$/)        { $doctype = shift(@ARGV); next; }
357946379e7Schristos    if (/^-c(heck)?$/)       { $check = 1; next; }
358946379e7Schristos    if (/^-expandi(nfo)?$/)  { $expandinfo = 1; next; }
359946379e7Schristos    if (/^-expandt(ex)?$/)   { $expandtex = 1; next; }
360946379e7Schristos    if (/^-g(lossary)?$/)    { $use_glossary = 1; next; }
361946379e7Schristos    if (/^-i(nvisible)?$/)   { $invisible_mark = shift(@ARGV); next; }
362946379e7Schristos    if (/^-iso$/)            { $use_iso = 1; next; }
363946379e7Schristos    if (/^-D(.+)?$/)         { $value{$1 || shift(@ARGV)} = 1; next; }
364946379e7Schristos    if (/^-I(.+)?$/)         { push(@include_dirs, $1 || shift(@ARGV)); next; }
365946379e7Schristos    if (/^-m(enu)?$/)        { $show_menu = 1; next; }
366946379e7Schristos    if (/^-mono(lithic)?$/)  { $monolithic = 1; next; }
367946379e7Schristos    if (/^-n(umber)?$/)      { $number_sections = 1; next; }
368946379e7Schristos    if (/^-s(plit)?_?(n(ode)?|c(hapter)?)?$/) {
369946379e7Schristos	if ($2 =~ /^n/) {
370946379e7Schristos	    $split_node = 1;
371946379e7Schristos	} else {
372946379e7Schristos	    $split_chapter = 1;
373946379e7Schristos	}
374946379e7Schristos	next;
375946379e7Schristos    }
376946379e7Schristos    if (/^-v(erbose)?$/)     { $verbose = 1; next; }
377946379e7Schristos    die $usage;
378946379e7Schristos}
379946379e7Schristosif ($check) {
380946379e7Schristos    die $usage unless @ARGV > 0;
381946379e7Schristos    &check;
382946379e7Schristos    exit;
383946379e7Schristos}
384946379e7Schristos
385946379e7Schristosif (($split_node || $split_chapter) && $monolithic) {
386946379e7Schristos    warn "Can't use -monolithic with -split, -monolithic ignored.\n";
387946379e7Schristos    $monolithic = 0;
388946379e7Schristos}
389946379e7Schristosif ($expandinfo) {
390946379e7Schristos    $to_skip{'ifinfo'}++;
391946379e7Schristos    $to_skip{'end ifinfo'}++;
392946379e7Schristos    $to_skip{'ifnottex'}++;
393946379e7Schristos    $to_skip{'end ifnottex'}++;
394946379e7Schristos    $to_skip{'ifnothtml'}++;
395946379e7Schristos    $to_skip{'end ifnothtml'}++;
396946379e7Schristos} elsif ($expandtex) {
397946379e7Schristos    $to_skip{'ifnotinfo'}++;
398946379e7Schristos    $to_skip{'end ifnotinfo'}++;
399946379e7Schristos    $to_skip{'iftex'}++;
400946379e7Schristos    $to_skip{'end iftex'}++;
401946379e7Schristos    $to_skip{'ifnothtml'}++;
402946379e7Schristos    $to_skip{'end ifnothtml'}++;
403946379e7Schristos} else {
404946379e7Schristos    $to_skip{'ifnotinfo'}++;
405946379e7Schristos    $to_skip{'end ifnotinfo'}++;
406946379e7Schristos    $to_skip{'ifnottex'}++;
407946379e7Schristos    $to_skip{'end ifnottex'}++;
408946379e7Schristos    $to_skip{'ifhtml'}++;
409946379e7Schristos    $to_skip{'end ifhtml'}++;
410946379e7Schristos}
411946379e7Schristos$invisible_mark = '<IMG SRC="invisible.xbm">' if $invisible_mark eq 'xbm';
412946379e7Schristosdie $usage unless @ARGV == 1;
413946379e7Schristos$docu = shift(@ARGV);
414946379e7Schristosif ($docu =~ /.*\//) {
415946379e7Schristos    chop($docu_dir = $&);
416946379e7Schristos    $docu_name = $';
417946379e7Schristos} else {
418946379e7Schristos    $docu_dir = '.';
419946379e7Schristos    $docu_name = $docu;
420946379e7Schristos}
421946379e7Schristosunshift(@include_dirs, $docu_dir);
422946379e7Schristos$docu_name =~ s/\.te?x(i|info)?$//;	# basename of the document
423946379e7Schristos
424946379e7Schristos$docu_doc = "$docu_name.html";		# document's contents
425946379e7Schristosif ($monolithic) {
426946379e7Schristos    $docu_toc = $docu_foot = $docu_doc;
427946379e7Schristos} else {
428946379e7Schristos    $docu_toc  = "${docu_name}_toc.html";  # document's table of contents
429946379e7Schristos    $docu_foot = "${docu_name}_foot.html"; # document's footnotes
430946379e7Schristos}
431946379e7Schristos
432946379e7Schristos#
433946379e7Schristos# variables
434946379e7Schristos#
435946379e7Schristos$value{'html'} = 1;			# predefine html (the output format)
436946379e7Schristos$value{'texi2html'} = '1.52b';		# predefine texi2html (the translator)
437946379e7Schristos# _foo: internal to track @foo
438946379e7Schristosforeach ('_author', '_title', '_subtitle',
439946379e7Schristos	 '_settitle', '_setfilename') {
440946379e7Schristos    $value{$_} = '';		        # prevent -w warnings
441946379e7Schristos}
442946379e7Schristos%node2sec = ();				# node to section name
443946379e7Schristos%node2href = ();			# node to HREF
444946379e7Schristos%bib2href = ();				# bibliography reference to HREF
445946379e7Schristos%gloss2href = ();			# glossary term to HREF
446946379e7Schristos@sections = ();				# list of sections
447946379e7Schristos%tag2pro = ();				# protected sections
448946379e7Schristos
449946379e7Schristos#
450946379e7Schristos# initial indexes
451946379e7Schristos#
452946379e7Schristos$bib_num = 0;
453946379e7Schristos$foot_num = 0;
454946379e7Schristos$gloss_num = 0;
455946379e7Schristos$idx_num = 0;
456946379e7Schristos$sec_num = 0;
457946379e7Schristos$doc_num = 0;
458946379e7Schristos$html_num = 0;
459946379e7Schristos
460946379e7Schristos#
461946379e7Schristos# can I use ISO8879 characters? (HTML+)
462946379e7Schristos#
463946379e7Schristosif ($use_iso) {
464946379e7Schristos    $things_map{'bullet'} = "&bull;";
465946379e7Schristos    $things_map{'copyright'} = "&copy;";
466946379e7Schristos    $things_map{'dots'} = "&hellip;";
467946379e7Schristos    $things_map{'equiv'} = "&equiv;";
468946379e7Schristos    $things_map{'expansion'} = "&rarr;";
469946379e7Schristos    $things_map{'point'} = "&lowast;";
470946379e7Schristos    $things_map{'result'} = "&rArr;";
471946379e7Schristos}
472946379e7Schristos
473946379e7Schristos#
474946379e7Schristos# read texi2html extensions (if any)
475946379e7Schristos#
476946379e7Schristos$extensions = 'texi2html.ext'; # extensions in working directory
477946379e7Schristosif (-f $extensions) {
478946379e7Schristos    print "# reading extensions from $extensions\n" if $verbose;
479946379e7Schristos    require($extensions);
480946379e7Schristos}
481946379e7Schristos($progdir = $0) =~ s/[^\/]+$//;
482946379e7Schristosif ($progdir && ($progdir ne './')) {
483946379e7Schristos    $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
484946379e7Schristos    if (-f $extensions) {
485946379e7Schristos	print "# reading extensions from $extensions\n" if $verbose;
486946379e7Schristos	require($extensions);
487946379e7Schristos    }
488946379e7Schristos}
489946379e7Schristos
490946379e7Schristosprint "# reading from $docu\n" if $verbose;
491946379e7Schristos
492946379e7Schristos#+++############################################################################
493946379e7Schristos#                                                                              #
494946379e7Schristos# Pass 1: read source, handle command, variable, simple substitution           #
495946379e7Schristos#                                                                              #
496946379e7Schristos#---############################################################################
497946379e7Schristos
498946379e7Schristos@lines = ();				# whole document
499946379e7Schristos@toc_lines = ();			# table of contents
500946379e7Schristos$toplevel = 0;			        # top level seen in hierarchy
501946379e7Schristos$curlevel = 0;				# current level in TOC
502946379e7Schristos$node = '';				# current node name
503946379e7Schristos$in_table = 0;				# am I inside a table
504946379e7Schristos$table_type = '';			# type of table ('', 'f', 'v', 'multi')
505946379e7Schristos@tables = ();			        # nested table support
506946379e7Schristos$in_bibliography = 0;			# am I inside a bibliography
507946379e7Schristos$in_glossary = 0;			# am I inside a glossary
508946379e7Schristos$in_top = 0;				# am I inside the top node
509946379e7Schristos$in_pre = 0;				# am I inside a preformatted section
510946379e7Schristos$in_list = 0;				# am I inside a list
511946379e7Schristos$in_html = 0;				# am I inside an HTML section
512946379e7Schristos$first_line = 1;		        # is it the first line
513946379e7Schristos$dont_html = 0;				# don't protect HTML on this line
514946379e7Schristos$split_num = 0;				# split index
515946379e7Schristos$deferred_ref = '';			# deferred reference for indexes
516946379e7Schristos@html_stack = ();			# HTML elements stack
517946379e7Schristos$html_element = '';			# current HTML element
518946379e7Schristos&html_reset;
519946379e7Schristos
520946379e7Schristos# build code for simple substitutions
521946379e7Schristos# the maps used (%simple_map and %things_map) MUST be aware of this
522946379e7Schristos# watch out for regexps, / and escaped characters!
523946379e7Schristos$subst_code = '';
524946379e7Schristosforeach (keys(%simple_map)) {
525946379e7Schristos    ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars
526946379e7Schristos    $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n";
527946379e7Schristos}
528946379e7Schristosforeach (keys(%things_map)) {
529946379e7Schristos    $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n";
530946379e7Schristos}
531946379e7Schristosif ($use_acc) {
532946379e7Schristos    # accentuated characters
533946379e7Schristos    foreach (keys(%accent_map)) {
534946379e7Schristos	if ($_ eq "`") {
535946379e7Schristos	    $subst_code .= "s/$;3";
536946379e7Schristos	} elsif ($_ eq "'") {
537946379e7Schristos	    $subst_code .= "s/$;4";
538946379e7Schristos	} else {
539946379e7Schristos	    $subst_code .= "s/\\\@\\$_";
540946379e7Schristos	}
541946379e7Schristos	$subst_code .= "([aeiou])/&\${1}$accent_map{$_};/gi;\n";
542946379e7Schristos    }
543946379e7Schristos}
544946379e7Schristoseval("sub simple_substitutions { $subst_code }");
545946379e7Schristos
546946379e7Schristos&init_input;
547946379e7Schristoswhile ($_ = &next_line) {
548946379e7Schristos    #
549946379e7Schristos    # remove \input on the first lines only
550946379e7Schristos    #
551946379e7Schristos    if ($first_line) {
552946379e7Schristos	next if /^\\input/;
553946379e7Schristos	$first_line = 0;
554946379e7Schristos    }
555946379e7Schristos    #
556946379e7Schristos    # parse texinfo tags
557946379e7Schristos    #
558946379e7Schristos    $tag = '';
559946379e7Schristos    $end_tag = '';
560946379e7Schristos    if (/^\@end\s+(\w+)\b/) {
561946379e7Schristos	$end_tag = $1;
562946379e7Schristos    } elsif (/^\@(\w+)\b/) {
563946379e7Schristos	$tag = $1;
564946379e7Schristos    }
565946379e7Schristos    #
566946379e7Schristos    # handle @ifhtml / @end ifhtml
567946379e7Schristos    #
568946379e7Schristos    if ($in_html) {
569946379e7Schristos	if ($end_tag eq 'ifhtml') {
570946379e7Schristos	    $in_html = 0;
571946379e7Schristos	} else {
572946379e7Schristos	    $tag2pro{$in_html} .= $_;
573946379e7Schristos	}
574946379e7Schristos	next;
575946379e7Schristos    } elsif ($tag eq 'ifhtml') {
576946379e7Schristos	$in_html = $PROTECTTAG . ++$html_num;
577946379e7Schristos	push(@lines, $in_html);
578946379e7Schristos	next;
579946379e7Schristos    }
580946379e7Schristos    #
581946379e7Schristos    # try to skip the line
582946379e7Schristos    #
583946379e7Schristos    if ($end_tag) {
584946379e7Schristos	next if $to_skip{"end $end_tag"};
585946379e7Schristos    } elsif ($tag) {
586946379e7Schristos	next if $to_skip{$tag};
587946379e7Schristos	last if $tag eq 'bye';
588946379e7Schristos    }
589946379e7Schristos    if ($in_top) {
590946379e7Schristos	# parsing the top node
591946379e7Schristos	if ($tag eq 'node' || $tag eq 'include' || $sec2level{$tag}) {
592946379e7Schristos	    # no more in top
593946379e7Schristos	    $in_top = 0;
594946379e7Schristos	} else {
595946379e7Schristos	    # skip it
596946379e7Schristos	    next;
597946379e7Schristos	}
598946379e7Schristos    }
599946379e7Schristos    #
600946379e7Schristos    # try to remove inlined comments
601946379e7Schristos    # syntax from tex-mode.el comment-start-skip
602946379e7Schristos    #
603946379e7Schristos    s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/;
604946379e7Schristos    # non-@ substitutions cf. texinfmt.el
605946379e7Schristos    unless ($in_pre) {
606946379e7Schristos	s/``/“/g;
607946379e7Schristos	s/''/”/g;
608946379e7Schristos	s/([\w ])---([\w ])/$1--$2/g;
609946379e7Schristos    }
610946379e7Schristos    #
611946379e7Schristos    # analyze the tag
612946379e7Schristos    #
613946379e7Schristos    if ($tag) {
614946379e7Schristos	# skip lines
615946379e7Schristos	&skip_until($tag), next if $tag eq 'ignore';
616946379e7Schristos	if ($expandinfo) {
617946379e7Schristos	    &skip_until($tag), next if $tag eq 'ifnotinfo';
618946379e7Schristos	    &skip_until($tag), next if $tag eq 'iftex';
619946379e7Schristos	    &skip_until($tag), next if $tag eq 'ifhtml';
620946379e7Schristos	} elsif ($expandtex) {
621946379e7Schristos	    &skip_until($tag), next if $tag eq 'ifinfo';
622946379e7Schristos	    &skip_until($tag), next if $tag eq 'ifnottex';
623946379e7Schristos	    &skip_until($tag), next if $tag eq 'ifhtml';
624946379e7Schristos	} else {
625946379e7Schristos	    &skip_until($tag), next if $tag eq 'ifinfo';
626946379e7Schristos	    &skip_until($tag), next if $tag eq 'iftex';
627946379e7Schristos	    &skip_until($tag), next if $tag eq 'ifnothtml';
628946379e7Schristos	}
629946379e7Schristos	&skip_until($tag), next if $tag eq 'tex';
630946379e7Schristos	# handle special tables
631946379e7Schristos	if ($tag =~ /^(|f|v|multi)table$/) {
632946379e7Schristos	    $table_type = $1;
633946379e7Schristos	    $tag = 'table';
634946379e7Schristos	}
635946379e7Schristos	# special cases
636946379e7Schristos	if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+top\s*,/i)) {
637946379e7Schristos	    $in_top = 1;
638946379e7Schristos	    @lines = (); # ignore all lines before top (title page garbage)
639946379e7Schristos	    next;
640946379e7Schristos	} elsif ($tag eq 'node') {
641946379e7Schristos	    $in_top = 0;
642946379e7Schristos	    warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o;
643946379e7Schristos	    $_ = &protect_html($_); # if node contains '&' for instance
644946379e7Schristos	    s/^\@node\s+//;
645946379e7Schristos	    ($node) = split(/,/);
646946379e7Schristos	    &normalise_node($node);
647946379e7Schristos	    if ($split_node) {
648946379e7Schristos		&next_doc;
649946379e7Schristos		push(@lines, $SPLITTAG) if $split_num++;
650946379e7Schristos		push(@sections, $node);
651946379e7Schristos	    }
652946379e7Schristos	    next;
653946379e7Schristos	} elsif ($tag eq 'include') {
654946379e7Schristos	    if (/^\@include\s+($FILERE)\s*$/o) {
655946379e7Schristos		$file = $1;
656946379e7Schristos		unless (-e $file) {
657946379e7Schristos		    foreach $dir (@include_dirs) {
658946379e7Schristos			$file = "$dir/$1";
659946379e7Schristos			last if -e $file;
660946379e7Schristos		    }
661946379e7Schristos		}
662946379e7Schristos		if (-e $file) {
663946379e7Schristos		    &open($file);
664946379e7Schristos		    print "# including $file\n" if $verbose;
665946379e7Schristos		} else {
666946379e7Schristos		    warn "$ERROR Can't find $file, skipping";
667946379e7Schristos		}
668946379e7Schristos	    } else {
669946379e7Schristos		warn "$ERROR Bad include line: $_";
670946379e7Schristos	    }
671946379e7Schristos	    next;
672946379e7Schristos	} elsif ($tag eq 'ifclear') {
673946379e7Schristos	    if (/^\@ifclear\s+($VARRE)\s*$/o) {
674946379e7Schristos		next unless defined($value{$1});
675946379e7Schristos		&skip_until($tag);
676946379e7Schristos	    } else {
677946379e7Schristos		warn "$ERROR Bad ifclear line: $_";
678946379e7Schristos	    }
679946379e7Schristos	    next;
680946379e7Schristos	} elsif ($tag eq 'ifset') {
681946379e7Schristos	    if (/^\@ifset\s+($VARRE)\s*$/o) {
682946379e7Schristos		next if defined($value{$1});
683946379e7Schristos		&skip_until($tag);
684946379e7Schristos	    } else {
685946379e7Schristos		warn "$ERROR Bad ifset line: $_";
686946379e7Schristos	    }
687946379e7Schristos	    next;
688946379e7Schristos	} elsif ($tag eq 'menu') {
689946379e7Schristos	    unless ($show_menu) {
690946379e7Schristos		&skip_until($tag);
691946379e7Schristos		next;
692946379e7Schristos	    }
693946379e7Schristos	    &html_push_if($tag);
694946379e7Schristos	    push(@lines, &html_debug("\n", __LINE__));
695946379e7Schristos	} elsif ($format_map{$tag}) {
696946379e7Schristos	    $in_pre = 1 if $format_map{$tag} eq 'PRE';
697946379e7Schristos	    &html_push_if($format_map{$tag});
698946379e7Schristos	    push(@lines, &html_debug("\n", __LINE__));
699946379e7Schristos	    $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ;
700946379e7Schristos	    push(@lines, &debug("<$format_map{$tag}>\n", __LINE__));
701946379e7Schristos	    next;
702946379e7Schristos	} elsif ($tag eq 'table') {
703946379e7Schristos	    if (/^\@(|f|v|multi)table\s+\@(\w+)/) {
704946379e7Schristos		$in_table = $2;
705946379e7Schristos		unshift(@tables, join($;, $table_type, $in_table));
706946379e7Schristos		if ($table_type eq "multi") {
707946379e7Schristos		    push(@lines, &debug("<TABLE BORDER>\n", __LINE__));
708946379e7Schristos		    &html_push_if('TABLE');
709946379e7Schristos		} else {
710946379e7Schristos		    push(@lines, &debug("<DL COMPACT>\n", __LINE__));
711946379e7Schristos		    &html_push_if('DL');
712946379e7Schristos		}
713946379e7Schristos		push(@lines, &html_debug("\n", __LINE__));
714946379e7Schristos	    } else {
715946379e7Schristos		warn "$ERROR Bad table line: $_";
716946379e7Schristos	    }
717946379e7Schristos	    next;
718946379e7Schristos	} elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') {
719946379e7Schristos	    if (/^\@$tag\s+(\w)\w\s+(\w)\w\s*$/) {
720946379e7Schristos		eval("*${1}index = *${2}index");
721946379e7Schristos	    } else {
722946379e7Schristos		warn "$ERROR Bad syn*index line: $_";
723946379e7Schristos	    }
724946379e7Schristos	    next;
725946379e7Schristos	} elsif ($tag eq 'sp') {
726946379e7Schristos	    push(@lines, &debug("<P>\n", __LINE__));
727946379e7Schristos	    next;
728946379e7Schristos	} elsif ($tag eq 'setref') {
729946379e7Schristos	    &protect_html; # if setref contains '&' for instance
730946379e7Schristos	    if (/^\@$tag\s*{($NODERE)}\s*$/) {
731946379e7Schristos		$setref = $1;
732946379e7Schristos		$setref =~ s/\s+/ /g; # normalize
733946379e7Schristos		$setref =~ s/ $//;
734946379e7Schristos		$node2sec{$setref} = $name;
735946379e7Schristos		$node2href{$setref} = "$docu_doc#$docid";
736946379e7Schristos	    } else {
737946379e7Schristos		warn "$ERROR Bad setref line: $_";
738946379e7Schristos	    }
739946379e7Schristos	    next;
740946379e7Schristos	} elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') {
741946379e7Schristos	    if (/^\@$tag\s+(\w\w)\s*$/) {
742946379e7Schristos		$valid_index{$1} = 1;
743946379e7Schristos	    } else {
744946379e7Schristos		warn "$ERROR Bad defindex line: $_";
745946379e7Schristos	    }
746946379e7Schristos	    next;
747946379e7Schristos	} elsif (defined($def_map{$tag})) {
748946379e7Schristos	    if ($def_map{$tag}) {
749946379e7Schristos		s/^\@$tag\s+//;
750946379e7Schristos		$tag = $def_map{$tag};
751946379e7Schristos		$_ = "\@$tag $_";
752946379e7Schristos		$tag =~ s/\s.*//;
753946379e7Schristos	    }
754946379e7Schristos	} elsif (defined($user_sub{$tag})) {
755946379e7Schristos	    s/^\@$tag\s+//;
756946379e7Schristos	    $sub = $user_sub{$tag};
757946379e7Schristos	    print "# user $tag = $sub, arg: $_" if $debug & $DEBUG_USER;
758946379e7Schristos	    if (defined(&$sub)) {
759946379e7Schristos		chop($_);
760946379e7Schristos		&$sub($_);
761946379e7Schristos	    } else {
762946379e7Schristos		warn "$ERROR Bad user sub for $tag: $sub\n";
763946379e7Schristos	    }
764946379e7Schristos	    next;
765946379e7Schristos	}
766946379e7Schristos	if (defined($def_map{$tag})) {
767946379e7Schristos	    s/^\@$tag\s+//;
768946379e7Schristos	    if ($tag =~ /x$/) {
769946379e7Schristos		# extra definition line
770946379e7Schristos		$tag = $`;
771946379e7Schristos		$is_extra = 1;
772946379e7Schristos	    } else {
773946379e7Schristos		$is_extra = 0;
774946379e7Schristos	    }
775946379e7Schristos	    while (/\{([^\{\}]*)\}/) {
776946379e7Schristos		# this is a {} construct
777946379e7Schristos		($before, $contents, $after) = ($`, $1, $');
778946379e7Schristos		# protect spaces
779946379e7Schristos		$contents =~ s/\s+/$;9/g;
780946379e7Schristos		# restore $_ protecting {}
781946379e7Schristos		$_ = "$before$;7$contents$;8$after";
782946379e7Schristos	    }
783946379e7Schristos	    @args = split(/\s+/, &protect_html($_));
784946379e7Schristos	    foreach (@args) {
785946379e7Schristos		s/$;9/ /g;	# unprotect spaces
786946379e7Schristos		s/$;7/\{/g;	# ... {
787946379e7Schristos		s/$;8/\}/g;	# ... }
788946379e7Schristos	    }
789946379e7Schristos	    $type = shift(@args);
790946379e7Schristos	    $type =~ s/^\{(.*)\}$/$1/;
791946379e7Schristos	    print "# def ($tag): {$type} ", join(', ', @args), "\n"
792946379e7Schristos		if $debug & $DEBUG_DEF;
793946379e7Schristos	    $type .= ':'; # it's nicer like this
794946379e7Schristos	    $name = shift(@args);
795946379e7Schristos	    $name =~ s/^\{(.*)\}$/$1/;
796946379e7Schristos	    if ($is_extra) {
797946379e7Schristos		$_ = &debug("<DT>", __LINE__);
798946379e7Schristos	    } else {
799946379e7Schristos		$_ = &debug("<DL>\n<DT>", __LINE__);
800946379e7Schristos	    }
801946379e7Schristos	    if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') {
802946379e7Schristos		$_ .= "<U>$type</U> <B>$name</B>";
803946379e7Schristos		$_ .= " <I>@args</I>" if @args;
804946379e7Schristos	    } elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr'
805946379e7Schristos		     || $tag eq 'defcv' || $tag eq 'defop') {
806946379e7Schristos		$ftype = $name;
807946379e7Schristos		$name = shift(@args);
808946379e7Schristos		$name =~ s/^\{(.*)\}$/$1/;
809946379e7Schristos		$_ .= "<U>$type</U> $ftype <B>$name</B>";
810946379e7Schristos		$_ .= " <I>@args</I>" if @args;
811946379e7Schristos	    } else {
812946379e7Schristos		warn "$ERROR Unknown definition type: $tag\n";
813946379e7Schristos		$_ .= "<U>$type</U> <B>$name</B>";
814946379e7Schristos		$_ .= " <I>@args</I>" if @args;
815946379e7Schristos	    }
816946379e7Schristos 	    $_ .= &debug("\n<DD>", __LINE__);
817946379e7Schristos	    $name = &unprotect_html($name);
818946379e7Schristos	    if ($tag eq 'deffn' || $tag eq 'deftypefn') {
819946379e7Schristos		unshift(@input_spool, "\@findex $name\n");
820946379e7Schristos	    } elsif ($tag eq 'defop') {
821946379e7Schristos		unshift(@input_spool, "\@findex $name on $ftype\n");
822946379e7Schristos	    } elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') {
823946379e7Schristos		unshift(@input_spool, "\@vindex $name\n");
824946379e7Schristos	    } else {
825946379e7Schristos		unshift(@input_spool, "\@tindex $name\n");
826946379e7Schristos	    }
827946379e7Schristos	    $dont_html = 1;
828946379e7Schristos	}
829946379e7Schristos    } elsif ($end_tag) {
830946379e7Schristos	if ($format_map{$end_tag}) {
831946379e7Schristos	    $in_pre = 0 if $format_map{$end_tag} eq 'PRE';
832946379e7Schristos	    $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ;
833946379e7Schristos	    &html_pop_if('LI', 'P');
834946379e7Schristos	    &html_pop_if();
835946379e7Schristos	    push(@lines, &debug("</$format_map{$end_tag}>\n", __LINE__));
836946379e7Schristos	    push(@lines, &html_debug("\n", __LINE__));
837946379e7Schristos	} elsif ($end_tag =~ /^(|f|v|multi)table$/) {
838946379e7Schristos	    unless (@tables) {
839946379e7Schristos		warn "$ERROR \@end $end_tag without \@*table\n";
840946379e7Schristos		next;
841946379e7Schristos	    }
842946379e7Schristos	    ($table_type, $in_table) = split($;, shift(@tables));
843946379e7Schristos	    unless ($1 eq $table_type) {
844946379e7Schristos		warn "$ERROR \@end $end_tag without matching \@$end_tag\n";
845946379e7Schristos		next;
846946379e7Schristos	    }
847946379e7Schristos	    if ($table_type eq "multi") {
848946379e7Schristos		push(@lines, "</TR></TABLE>\n");
849946379e7Schristos		&html_pop_if('TR');
850946379e7Schristos	    } else {
851946379e7Schristos		push(@lines, "</DL>\n");
852946379e7Schristos		&html_pop_if('DD');
853946379e7Schristos	    }
854946379e7Schristos	    &html_pop_if();
855946379e7Schristos	    if (@tables) {
856946379e7Schristos		($table_type, $in_table) = split($;, $tables[0]);
857946379e7Schristos	    } else {
858946379e7Schristos		$in_table = 0;
859946379e7Schristos	    }
860946379e7Schristos	} elsif (defined($def_map{$end_tag})) {
861946379e7Schristos 	    push(@lines, &debug("</DL>\n", __LINE__));
862946379e7Schristos	} elsif ($end_tag eq 'menu') {
863946379e7Schristos	    &html_pop_if();
864946379e7Schristos	    push(@lines, $_); # must keep it for pass 2
865946379e7Schristos	}
866946379e7Schristos	next;
867946379e7Schristos    }
868946379e7Schristos    #
869946379e7Schristos    # misc things
870946379e7Schristos    #
871946379e7Schristos    # protect texi and HTML things
872946379e7Schristos    &protect_texi;
873946379e7Schristos    $_ = &protect_html($_) unless $dont_html;
874946379e7Schristos    $dont_html = 0;
875946379e7Schristos    # substitution (unsupported things)
876946379e7Schristos    s/^\@center\s+//g;
877946379e7Schristos    s/^\@exdent\s+//g;
878946379e7Schristos    s/\@noindent\s+//g;
879946379e7Schristos    s/\@refill\s+//g;
880946379e7Schristos    # other substitutions
881946379e7Schristos    &simple_substitutions;
882946379e7Schristos    s/\@value{($VARRE)}/$value{$1}/eg;
883946379e7Schristos    s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4
884946379e7Schristos    #
885946379e7Schristos    # analyze the tag again
886946379e7Schristos    #
887946379e7Schristos    if ($tag) {
888946379e7Schristos	if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) {
889946379e7Schristos	    if (/^\@$tag\s+(.+)$/) {
890946379e7Schristos		$name = $1;
891946379e7Schristos		$name =~ s/\s+$//;
892946379e7Schristos		$level = $sec2level{$tag};
893946379e7Schristos		$name = &update_sec_num($tag, $level) . "  $name"
894946379e7Schristos		    if $number_sections && $tag !~ /^unnumbered/;
895946379e7Schristos		if ($tag =~ /heading$/) {
896946379e7Schristos		    push(@lines, &html_debug("\n", __LINE__));
897946379e7Schristos		    if ($html_element ne 'body') {
898946379e7Schristos			# We are in a nice pickle here. We are trying to get a H? heading
899946379e7Schristos			# even though we are not in the body level. So, we convert it to a
900946379e7Schristos			# nice, bold, line by itself.
901946379e7Schristos			$_ = &debug("\n\n<P><STRONG>$name</STRONG></P>\n\n", __LINE__);
902946379e7Schristos		    } else {
903946379e7Schristos			$_ = &debug("<H$level>$name</H$level>\n", __LINE__);
904946379e7Schristos			&html_push_if('body');
905946379e7Schristos		    }
906946379e7Schristos		    print "# heading, section $name, level $level\n"
907946379e7Schristos			if $debug & $DEBUG_TOC;
908946379e7Schristos		} else {
909946379e7Schristos		    if ($split_chapter) {
910946379e7Schristos			unless ($toplevel) {
911946379e7Schristos			    # first time we see a "section"
912946379e7Schristos			    unless ($level == 1) {
913946379e7Schristos				warn "$ERROR The first section found is not of level 1: $_";
914946379e7Schristos				warn "$ERROR I'll split on sections of level $level...\n";
915946379e7Schristos			    }
916946379e7Schristos			    $toplevel = $level;
917946379e7Schristos			}
918946379e7Schristos			if ($level == $toplevel) {
919946379e7Schristos			    &next_doc;
920946379e7Schristos			    push(@lines, $SPLITTAG) if $split_num++;
921946379e7Schristos			    push(@sections, $name);
922946379e7Schristos			}
923946379e7Schristos		    }
924946379e7Schristos		    $sec_num++;
925946379e7Schristos		    $docid = "SEC$sec_num";
926946379e7Schristos		    $tocid = "TOC$sec_num";
927946379e7Schristos		    # check biblio and glossary
928946379e7Schristos		    $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i);
929946379e7Schristos		    $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i);
930946379e7Schristos		    # check node
931946379e7Schristos		    if ($node) {
932946379e7Schristos			if ($node2sec{$node}) {
933946379e7Schristos			    warn "$ERROR Duplicate node found: $node\n";
934946379e7Schristos			} else {
935946379e7Schristos			    $node2sec{$node} = $name;
936946379e7Schristos			    $node2href{$node} = "$docu_doc#$docid";
937946379e7Schristos			    print "# node $node, section $name, level $level\n"
938946379e7Schristos				if $debug & $DEBUG_TOC;
939946379e7Schristos			}
940946379e7Schristos			$node = '';
941946379e7Schristos		    } else {
942946379e7Schristos			print "# no node, section $name, level $level\n"
943946379e7Schristos			    if $debug & $DEBUG_TOC;
944946379e7Schristos		    }
945946379e7Schristos		    # update TOC
946946379e7Schristos		    while ($level > $curlevel) {
947946379e7Schristos			$curlevel++;
948946379e7Schristos			push(@toc_lines, "<UL>\n");
949946379e7Schristos		    }
950946379e7Schristos		    while ($level < $curlevel) {
951946379e7Schristos			$curlevel--;
952946379e7Schristos			push(@toc_lines, "</UL>\n");
953946379e7Schristos		    }
954946379e7Schristos		    $_ = "<LI>" . &anchor($tocid, "$docu_doc#$docid", $name, 1);
955946379e7Schristos		    push(@toc_lines, &substitute_style($_));
956946379e7Schristos		    # update DOC
957946379e7Schristos		    push(@lines, &html_debug("\n", __LINE__));
958946379e7Schristos		    &html_reset;
959946379e7Schristos		    $_ =  "<H$level>".&anchor($docid, "$docu_toc#$tocid", $name)."</H$level>\n";
960946379e7Schristos		    $_ = &debug($_, __LINE__);
961946379e7Schristos		    push(@lines, &html_debug("\n", __LINE__));
962946379e7Schristos		}
963946379e7Schristos		# update DOC
964946379e7Schristos		foreach $line (split(/\n+/, $_)) {
965946379e7Schristos		    push(@lines, "$line\n");
966946379e7Schristos		}
967946379e7Schristos		next;
968946379e7Schristos	    } else {
969946379e7Schristos		warn "$ERROR Bad section line: $_";
970946379e7Schristos	    }
971946379e7Schristos	} else {
972946379e7Schristos	    # track variables
973946379e7Schristos	    $value{$1} = $2, next if /^\@set\s+($VARRE)\s+(.*)$/o;
974946379e7Schristos	    delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o;
975946379e7Schristos	    # store things
976946379e7Schristos	    $value{'_setfilename'}   = $1, next if /^\@setfilename\s+(.*)$/;
977946379e7Schristos	    $value{'_settitle'}      = $1, next if /^\@settitle\s+(.*)$/;
978946379e7Schristos	    $value{'_author'}   .= "$1\n", next if /^\@author\s+(.*)$/;
979946379e7Schristos	    $value{'_subtitle'} .= "$1\n", next if /^\@subtitle\s+(.*)$/;
980946379e7Schristos	    $value{'_title'}    .= "$1\n", next if /^\@title\s+(.*)$/;
981946379e7Schristos	    # index
982946379e7Schristos	    if (/^\@(..?)index\s+/) {
983946379e7Schristos		unless ($valid_index{$1}) {
984946379e7Schristos		    warn "$ERROR Undefined index command: $_";
985946379e7Schristos		    next;
986946379e7Schristos		}
987946379e7Schristos		$id = 'IDX' . ++$idx_num;
988946379e7Schristos		$index = $1 . 'index';
989946379e7Schristos		$what = &substitute_style($');
990946379e7Schristos		$what =~ s/\s+$//;
991946379e7Schristos		print "# found $index for '$what' id $id\n"
992946379e7Schristos		    if $debug & $DEBUG_INDEX;
993946379e7Schristos		eval(<<EOC);
994946379e7Schristos		if (defined(\$$index\{\$what\})) {
995946379e7Schristos		    \$$index\{\$what\} .= "$;$docu_doc#$id";
996946379e7Schristos		} else {
997946379e7Schristos		    \$$index\{\$what\} = "$docu_doc#$id";
998946379e7Schristos		}
999946379e7SchristosEOC
1000946379e7Schristos		#
1001946379e7Schristos		# dirty hack to see if I can put an invisible anchor...
1002946379e7Schristos		#
1003946379e7Schristos		if ($html_element eq 'P' ||
1004946379e7Schristos		    $html_element eq 'LI' ||
1005946379e7Schristos		    $html_element eq 'DT' ||
1006946379e7Schristos		    $html_element eq 'DD' ||
1007946379e7Schristos		    $html_element eq 'ADDRESS' ||
1008946379e7Schristos		    $html_element eq 'B' ||
1009946379e7Schristos		    $html_element eq 'BLOCKQUOTE' ||
1010946379e7Schristos		    $html_element eq 'PRE' ||
1011946379e7Schristos		    $html_element eq 'SAMP') {
1012946379e7Schristos                    push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
1013946379e7Schristos                } elsif ($html_element eq 'body') {
1014946379e7Schristos		    push(@lines, &debug("<P>\n", __LINE__));
1015946379e7Schristos                    push(@lines, &anchor($id, '', $invisible_mark, !$in_pre));
1016946379e7Schristos		    &html_push('P');
1017946379e7Schristos		} elsif ($html_element eq 'DL' ||
1018946379e7Schristos			 $html_element eq 'UL' ||
1019946379e7Schristos			 $html_element eq 'OL' ) {
1020946379e7Schristos		    $deferred_ref .= &anchor($id, '', $invisible_mark, !$in_pre) . " ";
1021946379e7Schristos		}
1022946379e7Schristos		next;
1023946379e7Schristos	    }
1024946379e7Schristos	    # list item
1025946379e7Schristos	    if (/^\@itemx?\s+/) {
1026946379e7Schristos		$what = $';
1027946379e7Schristos		$what =~ s/\s+$//;
1028946379e7Schristos		if ($in_bibliography && $use_bibliography) {
1029946379e7Schristos		    if ($what =~ /^$BIBRE$/o) {
1030946379e7Schristos			$id = 'BIB' . ++$bib_num;
1031946379e7Schristos			$bib2href{$what} = "$docu_doc#$id";
1032946379e7Schristos			print "# found bibliography for '$what' id $id\n"
1033946379e7Schristos			    if $debug & $DEBUG_BIB;
1034946379e7Schristos			$what = &anchor($id, '', $what);
1035946379e7Schristos		    }
1036946379e7Schristos		} elsif ($in_glossary && $use_glossary) {
1037946379e7Schristos		    $id = 'GLOSS' . ++$gloss_num;
1038946379e7Schristos		    $entry = $what;
1039946379e7Schristos		    $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
1040946379e7Schristos		    $gloss2href{$entry} = "$docu_doc#$id";
1041946379e7Schristos		    print "# found glossary for '$entry' id $id\n"
1042946379e7Schristos			if $debug & $DEBUG_GLOSS;
1043946379e7Schristos		    $what = &anchor($id, '', $what);
1044946379e7Schristos		}
1045946379e7Schristos		&html_pop_if('P');
1046946379e7Schristos		if ($html_element eq 'DL' || $html_element eq 'DD') {
1047946379e7Schristos		    if ($things_map{$in_table} && !$what) {
1048946379e7Schristos			# special case to allow @table @bullet for instance
1049946379e7Schristos			push(@lines, &debug("<DT>$things_map{$in_table}\n", __LINE__));
1050946379e7Schristos		    } else {
1051946379e7Schristos			push(@lines, &debug("<DT>\@$in_table\{$what\}\n", __LINE__));
1052946379e7Schristos		    }
1053946379e7Schristos		    push(@lines, "<DD>");
1054946379e7Schristos		    &html_push('DD') unless $html_element eq 'DD';
1055946379e7Schristos		    if ($table_type) { # add also an index
1056946379e7Schristos			unshift(@input_spool, "\@${table_type}index $what\n");
1057946379e7Schristos		    }
1058946379e7Schristos		} elsif ($html_element eq 'TABLE') {
1059946379e7Schristos		    push(@lines, &debug("<TR><TD>$what</TD>\n", __LINE__));
1060946379e7Schristos		    &html_push('TR');
1061946379e7Schristos		} elsif ($html_element eq 'TR') {
1062946379e7Schristos		    push(@lines, &debug("</TR>\n", __LINE__));
1063946379e7Schristos		    push(@lines, &debug("<TR><TD>$what</TD>\n", __LINE__));
1064946379e7Schristos		} else {
1065946379e7Schristos		    push(@lines, &debug("<LI>$what\n", __LINE__));
1066946379e7Schristos		    &html_push('LI') unless $html_element eq 'LI';
1067946379e7Schristos		}
1068946379e7Schristos		push(@lines, &html_debug("\n", __LINE__));
1069946379e7Schristos		if ($deferred_ref) {
1070946379e7Schristos		    push(@lines, &debug("$deferred_ref\n", __LINE__));
1071946379e7Schristos		    $deferred_ref = '';
1072946379e7Schristos		}
1073946379e7Schristos		next;
1074946379e7Schristos	    } elsif (/^\@tab\s+(.*)$/) {
1075946379e7Schristos		push(@lines, "<TD>$1</TD>\n");
1076946379e7Schristos		next;
1077946379e7Schristos	    }
1078946379e7Schristos	}
1079946379e7Schristos    }
1080946379e7Schristos    # paragraph separator
1081946379e7Schristos    if ($_ eq "\n") {
1082946379e7Schristos	next if $#lines >= 0 && $lines[$#lines] eq "\n";
1083946379e7Schristos	if ($html_element eq 'P') {
1084946379e7Schristos	    push(@lines, "\n");
1085946379e7Schristos	    $_ = &debug("</P>\n", __LINE__);
1086946379e7Schristos	    &html_pop;
1087946379e7Schristos	}
1088946379e7Schristos    } elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE') {
1089946379e7Schristos	push(@lines, "<P>\n");
1090946379e7Schristos	&html_push('P');
1091946379e7Schristos	$_ = &debug($_, __LINE__);
1092946379e7Schristos    }
1093946379e7Schristos    # otherwise
1094946379e7Schristos    push(@lines, $_);
1095946379e7Schristos}
1096946379e7Schristos
1097946379e7Schristos# finish TOC
1098946379e7Schristos$level = 0;
1099946379e7Schristoswhile ($level < $curlevel) {
1100946379e7Schristos    $curlevel--;
1101946379e7Schristos    push(@toc_lines, "</UL>\n");
1102946379e7Schristos}
1103946379e7Schristos
1104946379e7Schristosprint "# end of pass 1\n" if $verbose;
1105946379e7Schristos
1106946379e7Schristos#+++############################################################################
1107946379e7Schristos#                                                                              #
1108946379e7Schristos# Pass 2/3: handle style, menu, index, cross-reference                         #
1109946379e7Schristos#                                                                              #
1110946379e7Schristos#---############################################################################
1111946379e7Schristos
1112946379e7Schristos@lines2 = ();				# whole document (2nd pass)
1113946379e7Schristos@lines3 = ();				# whole document (3rd pass)
1114946379e7Schristos$in_menu = 0;				# am I inside a menu
1115946379e7Schristos
1116946379e7Schristoswhile (@lines) {
1117946379e7Schristos    $_ = shift(@lines);
1118946379e7Schristos    #
1119946379e7Schristos    # special case (protected sections)
1120946379e7Schristos    #
1121946379e7Schristos    if (/^$PROTECTTAG/o) {
1122946379e7Schristos	push(@lines2, $_);
1123946379e7Schristos	next;
1124946379e7Schristos    }
1125946379e7Schristos    #
1126946379e7Schristos    # menu
1127946379e7Schristos    #
1128946379e7Schristos    $in_menu = 1, push(@lines2, &debug("<UL>\n", __LINE__)), next if /^\@menu\b/;
1129946379e7Schristos    $in_menu = 0, push(@lines2, &debug("</UL>\n", __LINE__)), next if /^\@end\s+menu\b/;
1130946379e7Schristos    if ($in_menu) {
1131946379e7Schristos	if (/^\*\s+($NODERE)::/o) {
1132946379e7Schristos	    $descr = $';
1133946379e7Schristos	    chop($descr);
1134946379e7Schristos	    &menu_entry($1, $1, $descr);
1135946379e7Schristos	} elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) {
1136946379e7Schristos	    $descr = $';
1137946379e7Schristos	    chop($descr);
1138946379e7Schristos	    &menu_entry($1, $2, $descr);
1139946379e7Schristos	} elsif (/^\*/) {
1140946379e7Schristos	    warn "$ERROR Bad menu line: $_";
1141946379e7Schristos	} else { # description continued?
1142946379e7Schristos	    push(@lines2, $_);
1143946379e7Schristos	}
1144946379e7Schristos	next;
1145946379e7Schristos    }
1146946379e7Schristos    #
1147946379e7Schristos    # printindex
1148946379e7Schristos    #
1149946379e7Schristos    if (/^\@printindex\s+(\w\w)\b/) {
1150946379e7Schristos	local($index, *ary, @keys, $key, $letter, $last_letter, @refs);
1151946379e7Schristos	if ($predefined_index{$1}) {
1152946379e7Schristos	    $index = $predefined_index{$1} . 'index';
1153946379e7Schristos	} else {
1154946379e7Schristos	    $index = $1 . 'index';
1155946379e7Schristos	}
1156946379e7Schristos	eval("*ary = *$index");
1157946379e7Schristos	@keys = keys(%ary);
1158946379e7Schristos	foreach $key (@keys) {
1159946379e7Schristos	    $_ = $key;
1160946379e7Schristos	    1 while s/<(\w+)>\`(.*)\&acute;<\/\1>/$2/; # remove HTML tags with quotes
1161946379e7Schristos	    1 while s/<(\w+)>(.*)<\/\1>/$2/;     # remove HTML tags
1162946379e7Schristos	    $_ = &unprotect_html($_);
1163946379e7Schristos	    &unprotect_texi;
1164946379e7Schristos	    tr/A-Z/a-z/; # lowercase
1165946379e7Schristos	    $key2alpha{$key} = $_;
1166946379e7Schristos	    print "# index $key sorted as $_\n"
1167946379e7Schristos		if $key ne $_ && $debug & $DEBUG_INDEX;
1168946379e7Schristos	}
1169946379e7Schristos	push(@lines2, "Jump to:\n");
1170946379e7Schristos	$last_letter = undef;
1171946379e7Schristos	foreach $key (sort byalpha @keys) {
1172946379e7Schristos	    $letter = substr($key2alpha{$key}, 0, 1);
1173946379e7Schristos	    $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
1174946379e7Schristos	    if (!defined($last_letter) || $letter ne $last_letter) {
1175946379e7Schristos		push(@lines2, "-\n") if defined($last_letter);
1176946379e7Schristos		push(@lines2, "<A HREF=\"#$index\_$letter\">" . &protect_html($letter) . "</A>\n");
1177946379e7Schristos		$last_letter = $letter;
1178946379e7Schristos	    }
1179946379e7Schristos	}
1180946379e7Schristos	push(@lines2, "<P>\n");
1181946379e7Schristos	$last_letter = undef;
1182946379e7Schristos	foreach $key (sort byalpha @keys) {
1183946379e7Schristos	    $letter = substr($key2alpha{$key}, 0, 1);
1184946379e7Schristos	    $letter = substr($key2alpha{$key}, 0, 2) if $letter eq $;;
1185946379e7Schristos	    if (!defined($last_letter) || $letter ne $last_letter) {
1186946379e7Schristos		push(@lines2, "</DIR>\n") if defined($last_letter);
1187946379e7Schristos		push(@lines2, "<H2><A NAME=\"$index\_$letter\">" . &protect_html($letter) . "</A></H2>\n");
1188946379e7Schristos		push(@lines2, "<DIR>\n");
1189946379e7Schristos		$last_letter = $letter;
1190946379e7Schristos	    }
1191946379e7Schristos	    @refs = ();
1192946379e7Schristos	    foreach (split(/$;/, $ary{$key})) {
1193946379e7Schristos		push(@refs, &anchor('', $_, $key, 0));
1194946379e7Schristos	    }
1195946379e7Schristos	    push(@lines2, "<LI>" . join(", ", @refs) . "\n");
1196946379e7Schristos	}
1197946379e7Schristos	push(@lines2, "</DIR>\n") if defined($last_letter);
1198946379e7Schristos	next;
1199946379e7Schristos    }
1200946379e7Schristos    #
1201946379e7Schristos    # simple style substitutions
1202946379e7Schristos    #
1203946379e7Schristos    $_ = &substitute_style($_);
1204946379e7Schristos    #
1205946379e7Schristos    # xref
1206946379e7Schristos    #
1207946379e7Schristos    while (/\@(x|px|info|)ref{($XREFRE)(}?)/o) {
1208946379e7Schristos	# note: Texinfo may accept other characters
1209946379e7Schristos	($type, $nodes, $full) = ($1, $2, $3);
1210946379e7Schristos	($before, $after) = ($`, $');
1211946379e7Schristos	if (! $full && $after) {
1212946379e7Schristos	    warn "$ERROR Bad xref (no ending } on line): $_";
1213946379e7Schristos	    $_ = "$before$;0${type}ref\{$nodes$after";
1214946379e7Schristos	    next; # while xref
1215946379e7Schristos	}
1216946379e7Schristos	if ($type eq 'x') {
1217946379e7Schristos	    $type = 'See ';
1218946379e7Schristos	} elsif ($type eq 'px') {
1219946379e7Schristos	    $type = 'see ';
1220946379e7Schristos	} elsif ($type eq 'info') {
1221946379e7Schristos	    $type = 'See Info';
1222946379e7Schristos	} else {
1223946379e7Schristos	    $type = '';
1224946379e7Schristos	}
1225946379e7Schristos	unless ($full) {
1226946379e7Schristos	    $next = shift(@lines);
1227946379e7Schristos	    $next = &substitute_style($next);
1228946379e7Schristos	    chop($nodes); # remove final newline
1229946379e7Schristos	    if ($next =~ /\}/) { # split on 2 lines
1230946379e7Schristos		$nodes .= " $`";
1231946379e7Schristos		$after = $';
1232946379e7Schristos	    } else {
1233946379e7Schristos		$nodes .= " $next";
1234946379e7Schristos		$next = shift(@lines);
1235946379e7Schristos		$next = &substitute_style($next);
1236946379e7Schristos		chop($nodes);
1237946379e7Schristos		if ($next =~ /\}/) { # split on 3 lines
1238946379e7Schristos		    $nodes .= " $`";
1239946379e7Schristos		    $after = $';
1240946379e7Schristos		} else {
1241946379e7Schristos		    warn "$ERROR Bad xref (no ending }): $_";
1242946379e7Schristos		    $_ = "$before$;0xref\{$nodes$after";
1243946379e7Schristos		    unshift(@lines, $next);
1244946379e7Schristos		    next; # while xref
1245946379e7Schristos		}
1246946379e7Schristos	    }
1247946379e7Schristos	}
1248946379e7Schristos	$nodes =~ s/\s+/ /g; # remove useless spaces
1249946379e7Schristos	@args = split(/\s*,\s*/, $nodes);
1250946379e7Schristos	$node = $args[0]; # the node is always the first arg
1251946379e7Schristos	&normalise_node($node);
1252946379e7Schristos	$sec = $node2sec{$node};
1253946379e7Schristos	if (@args == 5) { # reference to another manual
1254946379e7Schristos	    $sec = $args[2] || $node;
1255946379e7Schristos	    $man = $args[4] || $args[3];
1256946379e7Schristos	    $_ = "${before}${type}section ‘$sec’ in \@cite{$man}$after";
1257946379e7Schristos	} elsif ($type =~ /Info/) { # inforef
1258946379e7Schristos	    warn "$ERROR Wrong number of arguments: $_" unless @args == 3;
1259946379e7Schristos	    ($nn, $_, $in) = @args;
1260946379e7Schristos	    $_ = "${before}${type} file ‘$in’, node ‘$nn’$after";
1261946379e7Schristos	} elsif ($sec) {
1262946379e7Schristos	    $href = $node2href{$node};
1263946379e7Schristos	    $_ = "${before}${type}section " . &anchor('', $href, $sec) . $after;
1264946379e7Schristos	} else {
1265946379e7Schristos	    warn "$ERROR Undefined node ($node): $_";
1266946379e7Schristos	    $_ = "$before$;0xref{$nodes}$after";
1267946379e7Schristos	}
1268946379e7Schristos    }
1269946379e7Schristos    #
1270946379e7Schristos    # try to guess bibliography references or glossary terms
1271946379e7Schristos    #
1272946379e7Schristos    unless (/^<H\d><A NAME=\"SEC\d/) {
1273946379e7Schristos	if ($use_bibliography) {
1274946379e7Schristos	    $done = '';
1275946379e7Schristos	    while (/$BIBRE/o) {
1276946379e7Schristos		($pre, $what, $post) = ($`, $&, $');
1277946379e7Schristos		$href = $bib2href{$what};
1278946379e7Schristos		if (defined($href) && $post !~ /^[^<]*<\/A>/) {
1279946379e7Schristos		    $done .= $pre . &anchor('', $href, $what);
1280946379e7Schristos		} else {
1281946379e7Schristos		    $done .= "$pre$what";
1282946379e7Schristos		}
1283946379e7Schristos		$_ = $post;
1284946379e7Schristos	    }
1285946379e7Schristos	    $_ = $done . $_;
1286946379e7Schristos	}
1287946379e7Schristos	if ($use_glossary) {
1288946379e7Schristos	    $done = '';
1289946379e7Schristos	    while (/\b\w+\b/) {
1290946379e7Schristos		($pre, $what, $post) = ($`, $&, $');
1291946379e7Schristos		$entry = $what;
1292946379e7Schristos		$entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/;
1293946379e7Schristos		$href = $gloss2href{$entry};
1294946379e7Schristos		if (defined($href) && $post !~ /^[^<]*<\/A>/) {
1295946379e7Schristos		    $done .= $pre . &anchor('', $href, $what);
1296946379e7Schristos		} else {
1297946379e7Schristos		    $done .= "$pre$what";
1298946379e7Schristos		}
1299946379e7Schristos		$_ = $post;
1300946379e7Schristos	    }
1301946379e7Schristos	    $_ = $done . $_;
1302946379e7Schristos	}
1303946379e7Schristos    }
1304946379e7Schristos    # otherwise
1305946379e7Schristos    push(@lines2, $_);
1306946379e7Schristos}
1307946379e7Schristosprint "# end of pass 2\n" if $verbose;
1308946379e7Schristos
1309946379e7Schristos#
1310946379e7Schristos# split style substitutions
1311946379e7Schristos#
1312946379e7Schristoswhile (@lines2) {
1313946379e7Schristos    $_ = shift(@lines2);
1314946379e7Schristos    #
1315946379e7Schristos    # special case (protected sections)
1316946379e7Schristos    #
1317946379e7Schristos    if (/^$PROTECTTAG/o) {
1318946379e7Schristos	push(@lines3, $_);
1319946379e7Schristos	next;
1320946379e7Schristos    }
1321946379e7Schristos    #
1322946379e7Schristos    # split style substitutions
1323946379e7Schristos    #
1324946379e7Schristos    $old = '';
1325946379e7Schristos    while ($old ne $_) {
1326946379e7Schristos        $old = $_;
1327946379e7Schristos	if (/\@(\w+|"|\~|,|\^)\{/) {
1328946379e7Schristos	    ($before, $style, $after) = ($`, $1, $');
1329946379e7Schristos	    if (defined($style_map{$style})) {
1330946379e7Schristos		$_ = $after;
1331946379e7Schristos		$text = '';
1332946379e7Schristos		$after = '';
1333946379e7Schristos		$failed = 1;
1334946379e7Schristos		while (@lines2) {
1335946379e7Schristos		    if (/\}/) {
1336946379e7Schristos			$text .= $`;
1337946379e7Schristos			$after = $';
1338946379e7Schristos			$failed = 0;
1339946379e7Schristos			last;
1340946379e7Schristos		    } else {
1341946379e7Schristos			$text .= $_;
1342946379e7Schristos			$_ = shift(@lines2);
1343946379e7Schristos		    }
1344946379e7Schristos		}
1345946379e7Schristos		if ($failed) {
1346946379e7Schristos		    die "* Bad syntax (\@$style) after: $before\n";
1347946379e7Schristos		} else {
1348946379e7Schristos		    $text = &apply_style($style, $text);
1349946379e7Schristos		    $_ = "$before$text$after";
1350946379e7Schristos		}
1351946379e7Schristos	    }
1352946379e7Schristos	}
1353946379e7Schristos    }
1354946379e7Schristos    # otherwise
1355946379e7Schristos    push(@lines3, $_);
1356946379e7Schristos}
1357946379e7Schristosprint "# end of pass 3\n" if $verbose;
1358946379e7Schristos
1359946379e7Schristos#+++############################################################################
1360946379e7Schristos#                                                                              #
1361946379e7Schristos# Pass 4: foot notes, final cleanup                                            #
1362946379e7Schristos#                                                                              #
1363946379e7Schristos#---############################################################################
1364946379e7Schristos
1365946379e7Schristos@foot_lines = ();			# footnotes
1366946379e7Schristos@doc_lines = ();			# final document
1367946379e7Schristos$end_of_para = 0;			# true if last line is <P>
1368946379e7Schristos
1369946379e7Schristoswhile (@lines3) {
1370946379e7Schristos    $_ = shift(@lines3);
1371946379e7Schristos    #
1372946379e7Schristos    # special case (protected sections)
1373946379e7Schristos    #
1374946379e7Schristos    if (/^$PROTECTTAG/o) {
1375946379e7Schristos	push(@doc_lines, $_);
1376946379e7Schristos	$end_of_para = 0;
1377946379e7Schristos	next;
1378946379e7Schristos    }
1379946379e7Schristos    #
1380946379e7Schristos    # footnotes
1381946379e7Schristos    #
1382946379e7Schristos    while (/\@footnote([^\{\s]+)\{/) {
1383946379e7Schristos	($before, $d, $after) = ($`, $1, $');
1384946379e7Schristos	$_ = $after;
1385946379e7Schristos	$text = '';
1386946379e7Schristos	$after = '';
1387946379e7Schristos	$failed = 1;
1388946379e7Schristos	while (@lines3) {
1389946379e7Schristos	    if (/\}/) {
1390946379e7Schristos		$text .= $`;
1391946379e7Schristos		$after = $';
1392946379e7Schristos		$failed = 0;
1393946379e7Schristos		last;
1394946379e7Schristos	    } else {
1395946379e7Schristos		$text .= $_;
1396946379e7Schristos		$_ = shift(@lines3);
1397946379e7Schristos	    }
1398946379e7Schristos	}
1399946379e7Schristos	if ($failed) {
1400946379e7Schristos	    die "* Bad syntax (\@footnote) after: $before\n";
1401946379e7Schristos	} else {
1402946379e7Schristos	    $foot_num++;
1403946379e7Schristos	    $docid  = "DOCF$foot_num";
1404946379e7Schristos	    $footid = "FOOT$foot_num";
1405946379e7Schristos	    $foot = "($foot_num)";
1406946379e7Schristos	    push(@foot_lines, "<H3>" . &anchor($footid, "$d#$docid", $foot) . "</H3>\n");
1407946379e7Schristos	    $text = "<P>$text" unless $text =~ /^\s*<P>/;
1408946379e7Schristos	    push(@foot_lines, "$text\n");
1409946379e7Schristos	    $_ = $before . &anchor($docid, "$docu_foot#$footid", $foot) . $after;
1410946379e7Schristos	}
1411946379e7Schristos    }
1412946379e7Schristos    #
1413946379e7Schristos    # remove unnecessary <P>
1414946379e7Schristos    #
1415946379e7Schristos    if (/^\s*<P>\s*$/) {
1416946379e7Schristos	next if $end_of_para++;
1417946379e7Schristos    } else {
1418946379e7Schristos	$end_of_para = 0;
1419946379e7Schristos    }
1420946379e7Schristos    # otherwise
1421946379e7Schristos    push(@doc_lines, $_);
1422946379e7Schristos}
1423946379e7Schristosprint "# end of pass 4\n" if $verbose;
1424946379e7Schristos
1425946379e7Schristos#+++############################################################################
1426946379e7Schristos#                                                                              #
1427946379e7Schristos# Pass 5: print things                                                         #
1428946379e7Schristos#                                                                              #
1429946379e7Schristos#---############################################################################
1430946379e7Schristos
1431946379e7Schristos$header = <<EOT;
1432946379e7Schristos<!-- This HTML file has been created by $THISPROG
1433946379e7Schristos     from $docu on $TODAY -->
1434946379e7SchristosEOT
1435946379e7Schristos
1436946379e7Schristos$full_title = $value{'_title'} || $value{'_settitle'} || "Untitled Document";
1437946379e7Schristos$title = $value{'_settitle'} || $full_title;
1438946379e7Schristos$_ = &substitute_style($full_title);
1439946379e7Schristos&unprotect_texi;
1440946379e7Schristoss/\n$//; # rmv last \n (if any)
1441946379e7Schristos$full_title = "<H1>" . join("</H1>\n<H1>", split(/\n/, $_)) . "</H1>\n";
1442946379e7Schristos
1443946379e7Schristos#
1444946379e7Schristos# print ToC
1445946379e7Schristos#
1446946379e7Schristosif (!$monolithic && @toc_lines) {
1447946379e7Schristos    if (open(FILE, "> $docu_toc")) {
1448946379e7Schristos	print "# creating $docu_toc...\n" if $verbose;
1449946379e7Schristos	&print_toplevel_header("$title - Table of Contents");
1450946379e7Schristos	&print_ruler;
1451946379e7Schristos	&print(*toc_lines, FILE);
1452946379e7Schristos	&print_toplevel_footer;
1453946379e7Schristos	close(FILE);
1454946379e7Schristos    } else {
1455946379e7Schristos	warn "$ERROR Can't write to $docu_toc: $!\n";
1456946379e7Schristos    }
1457946379e7Schristos}
1458946379e7Schristos
1459946379e7Schristos#
1460946379e7Schristos# print footnotes
1461946379e7Schristos#
1462946379e7Schristosif (!$monolithic && @foot_lines) {
1463946379e7Schristos    if (open(FILE, "> $docu_foot")) {
1464946379e7Schristos	print "# creating $docu_foot...\n" if $verbose;
1465946379e7Schristos	&print_toplevel_header("$title - Footnotes");
1466946379e7Schristos	&print_ruler;
1467946379e7Schristos        &print(*foot_lines, FILE);
1468946379e7Schristos	&print_toplevel_footer;
1469946379e7Schristos	close(FILE);
1470946379e7Schristos    } else {
1471946379e7Schristos	warn "$ERROR Can't write to $docu_foot: $!\n";
1472946379e7Schristos    }
1473946379e7Schristos}
1474946379e7Schristos
1475946379e7Schristos#
1476946379e7Schristos# print document
1477946379e7Schristos#
1478946379e7Schristosif ($split_chapter || $split_node) { # split
1479946379e7Schristos    $doc_num = 0;
1480946379e7Schristos    $last_num = scalar(@sections);
1481946379e7Schristos    $first_doc = &doc_name(1);
1482946379e7Schristos    $last_doc = &doc_name($last_num);
1483946379e7Schristos    while (@sections) {
1484946379e7Schristos	$section = shift(@sections);
1485946379e7Schristos	&next_doc;
1486946379e7Schristos	if (open(FILE, "> $docu_doc")) {
1487946379e7Schristos	    print "# creating $docu_doc...\n" if $verbose;
1488946379e7Schristos	    &print_header("$title - $section");
1489946379e7Schristos	    $prev_doc = ($doc_num == 1 ? undef : &doc_name($doc_num - 1));
1490946379e7Schristos	    $next_doc = ($doc_num == $last_num ? undef : &doc_name($doc_num + 1));
1491946379e7Schristos	    $navigation = "Go to the ";
1492946379e7Schristos	    $navigation .= ($prev_doc ? &anchor('', $first_doc, "first") : "first");
1493946379e7Schristos	    $navigation .= ", ";
1494946379e7Schristos	    $navigation .= ($prev_doc ? &anchor('', $prev_doc, "previous") : "previous");
1495946379e7Schristos	    $navigation .= ", ";
1496946379e7Schristos	    $navigation .= ($next_doc ? &anchor('', $next_doc, "next") : "next");
1497946379e7Schristos	    $navigation .= ", ";
1498946379e7Schristos	    $navigation .= ($next_doc ? &anchor('', $last_doc, "last") : "last");
1499946379e7Schristos	    $navigation .= " section, " . &anchor('', $docu_toc, "table of contents") . ".\n";
1500946379e7Schristos	    print FILE $navigation;
1501946379e7Schristos	    &print_ruler;
1502946379e7Schristos	    # find corresponding lines
1503946379e7Schristos            @tmp_lines = ();
1504946379e7Schristos            while (@doc_lines) {
1505946379e7Schristos		$_ = shift(@doc_lines);
1506946379e7Schristos		last if ($_ eq $SPLITTAG);
1507946379e7Schristos		push(@tmp_lines, $_);
1508946379e7Schristos	    }
1509946379e7Schristos            &print(*tmp_lines, FILE);
1510946379e7Schristos	    &print_ruler;
1511946379e7Schristos	    print FILE $navigation;
1512946379e7Schristos	    &print_footer;
1513946379e7Schristos	    close(FILE);
1514946379e7Schristos	} else {
1515946379e7Schristos	    warn "$ERROR Can't write to $docu_doc: $!\n";
1516946379e7Schristos	}
1517946379e7Schristos    }
1518946379e7Schristos} else { # not split
1519946379e7Schristos    if (open(FILE, "> $docu_doc")) {
1520946379e7Schristos	print "# creating $docu_doc...\n" if $verbose;
1521946379e7Schristos	if ($monolithic || !@toc_lines) {
1522946379e7Schristos	    &print_toplevel_header($title);
1523946379e7Schristos	} else {
1524946379e7Schristos	    &print_header($title);
1525946379e7Schristos	    print FILE $full_title;
1526946379e7Schristos	}
1527946379e7Schristos	if ($monolithic && @toc_lines) {
1528946379e7Schristos	    &print_ruler;
1529946379e7Schristos 	    print FILE "<H1>Table of Contents</H1>\n";
1530946379e7Schristos 	    &print(*toc_lines, FILE);
1531946379e7Schristos	}
1532946379e7Schristos	&print_ruler;
1533946379e7Schristos        &print(*doc_lines, FILE);
1534946379e7Schristos	if ($monolithic && @foot_lines) {
1535946379e7Schristos	    &print_ruler;
1536946379e7Schristos 	    print FILE "<H1>Footnotes</H1>\n";
1537946379e7Schristos 	    &print(*foot_lines, FILE);
1538946379e7Schristos	}
1539946379e7Schristos	if ($monolithic || !@toc_lines) {
1540946379e7Schristos	    &print_toplevel_footer;
1541946379e7Schristos	} else {
1542946379e7Schristos	    &print_footer;
1543946379e7Schristos	}
1544946379e7Schristos	close(FILE);
1545946379e7Schristos    } else {
1546946379e7Schristos	warn "$ERROR Can't write to $docu_doc: $!\n";
1547946379e7Schristos    }
1548946379e7Schristos}
1549946379e7Schristos
1550946379e7Schristosprint "# that's all folks\n" if $verbose;
1551946379e7Schristos
1552946379e7Schristos#+++############################################################################
1553946379e7Schristos#                                                                              #
1554946379e7Schristos# Low level functions                                                          #
1555946379e7Schristos#                                                                              #
1556946379e7Schristos#---############################################################################
1557946379e7Schristos
1558946379e7Schristossub update_sec_num {
1559946379e7Schristos    local($name, $level) = @_;
1560946379e7Schristos
1561946379e7Schristos    $level--; # here we start at 0
1562946379e7Schristos    if ($name =~ /^appendix/) {
1563946379e7Schristos	# appendix style
1564*95b39c65Schristos	if (@appendix_sec_num) {
1565946379e7Schristos	    &incr_sec_num($level, @appendix_sec_num);
1566946379e7Schristos	} else {
1567946379e7Schristos	    @appendix_sec_num = ('A', 0, 0, 0);
1568946379e7Schristos	}
1569946379e7Schristos	return(join('.', @appendix_sec_num[0..$level]));
1570946379e7Schristos    } else {
1571946379e7Schristos	# normal style
1572*95b39c65Schristos	if (@normal_sec_num) {
1573946379e7Schristos	    &incr_sec_num($level, @normal_sec_num);
1574946379e7Schristos	} else {
1575946379e7Schristos	    @normal_sec_num = (1, 0, 0, 0);
1576946379e7Schristos	}
1577946379e7Schristos	return(join('.', @normal_sec_num[0..$level]));
1578946379e7Schristos    }
1579946379e7Schristos}
1580946379e7Schristos
1581946379e7Schristossub incr_sec_num {
1582946379e7Schristos    local($level, $l);
1583946379e7Schristos    $level = shift(@_);
1584946379e7Schristos    $_[$level]++;
1585946379e7Schristos    foreach $l ($level+1 .. 3) {
1586946379e7Schristos	$_[$l] = 0;
1587946379e7Schristos    }
1588946379e7Schristos}
1589946379e7Schristos
1590946379e7Schristossub check {
1591946379e7Schristos    local($_, %seen, %context, $before, $match, $after);
1592946379e7Schristos
1593946379e7Schristos    while (<>) {
1594946379e7Schristos	if (/\@(\*|\.|\:|\@|\{|\})/) {
1595946379e7Schristos	    $seen{$&}++;
1596946379e7Schristos	    $context{$&} .= "> $_" if $verbose;
1597946379e7Schristos	    $_ = "$`XX$'";
1598946379e7Schristos	    redo;
1599946379e7Schristos	}
1600946379e7Schristos	if (/\@(\w+)/) {
1601946379e7Schristos	    ($before, $match, $after) = ($`, $&, $');
1602946379e7Schristos	    if ($before =~ /\b[\w-]+$/ && $after =~ /^[\w-.]*\b/) { # e-mail address
1603946379e7Schristos		$seen{'e-mail address'}++;
1604946379e7Schristos		$context{'e-mail address'} .= "> $_" if $verbose;
1605946379e7Schristos	    } else {
1606946379e7Schristos		$seen{$match}++;
1607946379e7Schristos		$context{$match} .= "> $_" if $verbose;
1608946379e7Schristos	    }
1609946379e7Schristos	    $match =~ s/^\@/X/;
1610946379e7Schristos	    $_ = "$before$match$after";
1611946379e7Schristos	    redo;
1612946379e7Schristos	}
1613946379e7Schristos    }
1614946379e7Schristos
1615946379e7Schristos    foreach (sort(keys(%seen))) {
1616946379e7Schristos	if ($verbose) {
1617946379e7Schristos	    print "$_\n";
1618946379e7Schristos	    print $context{$_};
1619946379e7Schristos	} else {
1620946379e7Schristos	    print "$_ ($seen{$_})\n";
1621946379e7Schristos	}
1622946379e7Schristos    }
1623946379e7Schristos}
1624946379e7Schristos
1625946379e7Schristossub open {
1626946379e7Schristos    local($name) = @_;
1627946379e7Schristos
1628946379e7Schristos    ++$fh_name;
1629946379e7Schristos    if (open($fh_name, $name)) {
1630946379e7Schristos	unshift(@fhs, $fh_name);
1631946379e7Schristos    } else {
1632946379e7Schristos	warn "$ERROR Can't read file $name: $!\n";
1633946379e7Schristos    }
1634946379e7Schristos}
1635946379e7Schristos
1636946379e7Schristossub init_input {
1637946379e7Schristos    @fhs = ();			# hold the file handles to read
1638946379e7Schristos    @input_spool = ();		# spooled lines to read
1639946379e7Schristos    $fh_name = 'FH000';
1640946379e7Schristos    &open($docu);
1641946379e7Schristos}
1642946379e7Schristos
1643946379e7Schristossub next_line {
1644946379e7Schristos    local($fh, $line);
1645946379e7Schristos
1646946379e7Schristos    if (@input_spool) {
1647946379e7Schristos	$line = shift(@input_spool);
1648946379e7Schristos	return($line);
1649946379e7Schristos    }
1650946379e7Schristos    while (@fhs) {
1651946379e7Schristos	$fh = $fhs[0];
1652946379e7Schristos	$line = <$fh>;
1653946379e7Schristos	return($line) if $line;
1654946379e7Schristos	close($fh);
1655946379e7Schristos	shift(@fhs);
1656946379e7Schristos    }
1657946379e7Schristos    return(undef);
1658946379e7Schristos}
1659946379e7Schristos
1660946379e7Schristos# used in pass 1, use &next_line
1661946379e7Schristossub skip_until {
1662946379e7Schristos    local($tag) = @_;
1663946379e7Schristos    local($_);
1664946379e7Schristos
1665946379e7Schristos    while ($_ = &next_line) {
1666946379e7Schristos	return if /^\@end\s+$tag\s*$/;
1667946379e7Schristos    }
1668946379e7Schristos    die "* Failed to find '$tag' after: " . $lines[$#lines];
1669946379e7Schristos}
1670946379e7Schristos
1671946379e7Schristos#
1672946379e7Schristos# HTML stacking to have a better HTML output
1673946379e7Schristos#
1674946379e7Schristos
1675946379e7Schristossub html_reset {
1676946379e7Schristos    @html_stack = ('html');
1677946379e7Schristos    $html_element = 'body';
1678946379e7Schristos}
1679946379e7Schristos
1680946379e7Schristossub html_push {
1681946379e7Schristos    local($what) = @_;
1682946379e7Schristos    push(@html_stack, $html_element);
1683946379e7Schristos    $html_element = $what;
1684946379e7Schristos}
1685946379e7Schristos
1686946379e7Schristossub html_push_if {
1687946379e7Schristos    local($what) = @_;
1688946379e7Schristos    push(@html_stack, $html_element)
1689946379e7Schristos	if ($html_element && $html_element ne 'P');
1690946379e7Schristos    $html_element = $what;
1691946379e7Schristos}
1692946379e7Schristos
1693946379e7Schristossub html_pop {
1694946379e7Schristos    $html_element = pop(@html_stack);
1695946379e7Schristos}
1696946379e7Schristos
1697946379e7Schristossub html_pop_if {
1698946379e7Schristos    local($elt);
1699946379e7Schristos
1700946379e7Schristos    if (@_) {
1701946379e7Schristos	foreach $elt (@_) {
1702946379e7Schristos	    if ($elt eq $html_element) {
1703946379e7Schristos		$html_element = pop(@html_stack) if @html_stack;
1704946379e7Schristos		last;
1705946379e7Schristos	    }
1706946379e7Schristos	}
1707946379e7Schristos    } else {
1708946379e7Schristos	$html_element = pop(@html_stack) if @html_stack;
1709946379e7Schristos    }
1710946379e7Schristos}
1711946379e7Schristos
1712946379e7Schristossub html_debug {
1713946379e7Schristos    local($what, $line) = @_;
1714946379e7Schristos    return("<!-- $line @html_stack, $html_element -->$what")
1715946379e7Schristos	if $debug & $DEBUG_HTML;
1716946379e7Schristos    return($what);
1717946379e7Schristos}
1718946379e7Schristos
1719946379e7Schristos# to debug the output...
1720946379e7Schristossub debug {
1721946379e7Schristos    local($what, $line) = @_;
1722946379e7Schristos    return("<!-- $line -->$what")
1723946379e7Schristos	if $debug & $DEBUG_HTML;
1724946379e7Schristos    return($what);
1725946379e7Schristos}
1726946379e7Schristos
1727946379e7Schristossub normalise_node {
1728946379e7Schristos    $_[0] =~ s/\s+/ /g;
1729946379e7Schristos    $_[0] =~ s/ $//;
1730946379e7Schristos    $_[0] =~ s/^ //;
1731946379e7Schristos}
1732946379e7Schristos
1733946379e7Schristossub menu_entry {
1734946379e7Schristos    local($entry, $node, $descr) = @_;
1735946379e7Schristos    local($href);
1736946379e7Schristos
1737946379e7Schristos    &normalise_node($node);
1738946379e7Schristos    $href = $node2href{$node};
1739946379e7Schristos    if ($href) {
1740946379e7Schristos	$descr =~ s/^\s+//;
1741946379e7Schristos	$descr = ": $descr" if $descr;
1742946379e7Schristos	push(@lines2, "<LI>" . &anchor('', $href, $entry) . "$descr\n");
1743946379e7Schristos    } else {
1744946379e7Schristos	warn "$ERROR Undefined node ($node): $_";
1745946379e7Schristos    }
1746946379e7Schristos}
1747946379e7Schristos
1748946379e7Schristossub do_ctrl { "^$_[0]" }
1749946379e7Schristos
1750946379e7Schristossub do_email {
1751946379e7Schristos    local($addr, $text) = split(/,\s*/, $_[0]);
1752946379e7Schristos
1753946379e7Schristos    $text = $addr unless $text;
1754946379e7Schristos    &anchor('', "mailto:$addr", $text);
1755946379e7Schristos}
1756946379e7Schristos
1757946379e7Schristossub do_sc { "\U$_[0]\E" }
1758946379e7Schristos
1759946379e7Schristossub do_uref {
1760946379e7Schristos    local($url, $text) = split(/,\s*/, $_[0]);
1761946379e7Schristos
1762946379e7Schristos    $text = $url unless $text;
1763946379e7Schristos    &anchor('', $url, $text);
1764946379e7Schristos}
1765946379e7Schristos
1766946379e7Schristossub do_url { &anchor('', $_[0], $_[0]) }
1767946379e7Schristos
1768946379e7Schristossub do_diaeresis { return "&$_[0]uml;"; }
1769946379e7Schristossub do_acuteaccent { return "&$_[0]acute;"; }
1770946379e7Schristossub do_graveaccent { return "&$_[0]grave;"; }
1771946379e7Schristossub do_tildeaccent { return "&$_[0]tilde;"; }
1772946379e7Schristossub do_cedilla { return "&$_[0]cedil;"; }
1773946379e7Schristossub do_circumflex { return "&$_[0]circ;"; }
1774946379e7Schristos
1775946379e7Schristossub apply_style {
1776946379e7Schristos    local($texi_style, $text) = @_;
1777946379e7Schristos    local($style);
1778946379e7Schristos
1779946379e7Schristos    $style = $style_map{$texi_style};
1780946379e7Schristos    if (defined($style)) { # known style
1781946379e7Schristos	if ($style =~ /^\"/) { # add quotes
1782946379e7Schristos	    $style = $';
1783946379e7Schristos	    $text = "\&lsquo;$text\&rsquo;";
1784946379e7Schristos	}
1785946379e7Schristos	if ($style =~ /^\&/) { # custom
1786946379e7Schristos	    $style = $';
1787946379e7Schristos	    $text = &$style($text);
1788946379e7Schristos	} elsif ($style) { # good style
1789946379e7Schristos	    $text = "<$style>$text</$style>";
1790946379e7Schristos	} else { # no style
1791946379e7Schristos	}
1792946379e7Schristos    } else { # unknown style
1793946379e7Schristos	$text = undef;
1794946379e7Schristos    }
1795946379e7Schristos    return($text);
1796946379e7Schristos}
1797946379e7Schristos
1798946379e7Schristos# remove Texinfo styles
1799946379e7Schristossub remove_style {
1800946379e7Schristos    local($_) = @_;
1801946379e7Schristos    s/\@\w+{([^\{\}]+)}/$1/g;
1802946379e7Schristos    return($_);
1803946379e7Schristos}
1804946379e7Schristos
1805946379e7Schristossub substitute_style {
1806946379e7Schristos    local($_) = @_;
1807946379e7Schristos    local($changed, $done, $style, $text);
1808946379e7Schristos
1809946379e7Schristos    $changed = 1;
1810946379e7Schristos    while ($changed) {
1811946379e7Schristos	$changed = 0;
1812946379e7Schristos	$done = '';
1813946379e7Schristos	while (/\@(\w+|"|\~|,|\^){([^\{\}]+)}/) {
1814946379e7Schristos	    $text = &apply_style($1, $2);
1815946379e7Schristos	    if ($text) {
1816946379e7Schristos		$_ = "$`$text$'";
1817946379e7Schristos		$changed = 1;
1818946379e7Schristos	    } else {
1819946379e7Schristos		$done .= "$`\@$1";
1820946379e7Schristos		$_ = "{$2}$'";
1821946379e7Schristos	    }
1822946379e7Schristos	}
1823946379e7Schristos        $_ = $done . $_;
1824946379e7Schristos    }
1825946379e7Schristos    return($_);
1826946379e7Schristos}
1827946379e7Schristos
1828946379e7Schristossub anchor {
1829946379e7Schristos    local($name, $href, $text, $newline) = @_;
1830946379e7Schristos    local($result);
1831946379e7Schristos
1832946379e7Schristos    $result = "<A";
1833946379e7Schristos    $result .= " NAME=\"$name\"" if $name;
1834946379e7Schristos    $result .= " HREF=\"$href\"" if $href;
1835946379e7Schristos    $result .= ">$text</A>";
1836946379e7Schristos    $result .= "\n" if $newline;
1837946379e7Schristos    return($result);
1838946379e7Schristos}
1839946379e7Schristos
1840946379e7Schristossub pretty_date {
1841946379e7Schristos    local(@MoY, $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
1842946379e7Schristos
1843946379e7Schristos    @MoY = ('January', 'Febuary', 'March', 'April', 'May', 'June',
1844946379e7Schristos	    'July', 'August', 'September', 'October', 'November', 'December');
1845946379e7Schristos    ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
1846946379e7Schristos    $year += ($year < 70) ? 2000 : 1900;
1847946379e7Schristos    return("$mday $MoY[$mon] $year");
1848946379e7Schristos}
1849946379e7Schristos
1850946379e7Schristossub doc_name {
1851946379e7Schristos    local($num) = @_;
1852946379e7Schristos
1853946379e7Schristos    return("${docu_name}_$num.html");
1854946379e7Schristos}
1855946379e7Schristos
1856946379e7Schristossub next_doc {
1857946379e7Schristos    $docu_doc = &doc_name(++$doc_num);
1858946379e7Schristos}
1859946379e7Schristos
1860946379e7Schristossub print {
1861946379e7Schristos    local(*lines, $fh) = @_;
1862946379e7Schristos    local($_);
1863946379e7Schristos
1864946379e7Schristos    while (@lines) {
1865946379e7Schristos	$_ = shift(@lines);
1866946379e7Schristos	if (/^$PROTECTTAG/o) {
1867946379e7Schristos	    $_ = $tag2pro{$_};
1868946379e7Schristos	} else {
1869946379e7Schristos	    &unprotect_texi;
1870946379e7Schristos	}
1871946379e7Schristos	print $fh $_;
1872946379e7Schristos    }
1873946379e7Schristos}
1874946379e7Schristos
1875946379e7Schristossub print_ruler {
1876946379e7Schristos    print FILE "<P><HR><P>\n";
1877946379e7Schristos}
1878946379e7Schristos
1879946379e7Schristossub print_header {
1880946379e7Schristos    local($_);
1881946379e7Schristos
1882946379e7Schristos    # clean the title
1883946379e7Schristos    $_ = &remove_style($_[0]);
1884946379e7Schristos    &unprotect_texi;
1885946379e7Schristos    # print the header
1886946379e7Schristos    if ($doctype eq 'html2') {
1887946379e7Schristos	print FILE $html2_doctype;
1888946379e7Schristos    } elsif ($doctype) {
1889946379e7Schristos	print FILE $doctype;
1890946379e7Schristos    }
1891946379e7Schristos    print FILE <<EOT;
1892946379e7Schristos<HTML>
1893946379e7Schristos<HEAD>
1894946379e7Schristos$header
1895946379e7Schristos<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=UTF-8">
1896946379e7Schristos<TITLE>$_</TITLE>
1897946379e7Schristos</HEAD>
1898946379e7Schristos<BODY>
1899946379e7SchristosEOT
1900946379e7Schristos}
1901946379e7Schristos
1902946379e7Schristossub print_toplevel_header {
1903946379e7Schristos    local($_);
1904946379e7Schristos
1905946379e7Schristos    &print_header; # pass given arg...
1906946379e7Schristos    print FILE $full_title;
1907946379e7Schristos    if ($value{'_subtitle'}) {
1908946379e7Schristos	$value{'_subtitle'} =~ s/\n+$//;
1909946379e7Schristos	foreach (split(/\n/, $value{'_subtitle'})) {
1910946379e7Schristos	    $_ = &substitute_style($_);
1911946379e7Schristos	    &unprotect_texi;
1912946379e7Schristos	    print FILE "<H2>$_</H2>\n";
1913946379e7Schristos	}
1914946379e7Schristos    }
1915946379e7Schristos    if ($value{'_author'}) {
1916946379e7Schristos	$value{'_author'} =~ s/\n+$//;
1917946379e7Schristos	foreach (split(/\n/, $value{'_author'})) {
1918946379e7Schristos	    $_ = &substitute_style($_);
1919946379e7Schristos	    &unprotect_texi;
1920946379e7Schristos	    s/[\w.-]+\@[\w.-]+/<A HREF="mailto:$&">$&<\/A>/g;
1921946379e7Schristos	    print FILE "<ADDRESS>$_</ADDRESS>\n";
1922946379e7Schristos	}
1923946379e7Schristos    }
1924946379e7Schristos    print FILE "<P>\n";
1925946379e7Schristos}
1926946379e7Schristos
1927946379e7Schristossub print_footer {
1928946379e7Schristos    print FILE <<EOT;
1929946379e7Schristos</BODY>
1930946379e7Schristos</HTML>
1931946379e7SchristosEOT
1932946379e7Schristos}
1933946379e7Schristos
1934946379e7Schristossub print_toplevel_footer {
1935946379e7Schristos    &print_ruler;
1936946379e7Schristos    print FILE <<EOT;
1937946379e7SchristosThis document was generated on $TODAY using the
1938946379e7Schristos<A HREF=\"$HOMEPAGE\">texi2html</A>
1939946379e7Schristostranslator version 1.52b.</P>
1940946379e7SchristosEOT
1941946379e7Schristos    &print_footer;
1942946379e7Schristos}
1943946379e7Schristos
1944946379e7Schristossub protect_texi {
1945946379e7Schristos    # protect @ { } ` '
1946946379e7Schristos    s/\@\@/$;0/go;
1947946379e7Schristos    s/\@\{/$;1/go;
1948946379e7Schristos    s/\@\}/$;2/go;
1949946379e7Schristos    s/\@\`/$;3/go;
1950946379e7Schristos    s/\@\'/$;4/go;
1951946379e7Schristos}
1952946379e7Schristos
1953946379e7Schristossub protect_html {
1954946379e7Schristos    local($what) = @_;
1955946379e7Schristos    # protect & < >
1956946379e7Schristos    $what =~ s/\&/\&\#38;/g;
1957946379e7Schristos    $what =~ s/\</\&\#60;/g;
1958946379e7Schristos    $what =~ s/\>/\&\#62;/g;
1959946379e7Schristos    # but recognize some HTML things
1960946379e7Schristos    $what =~ s/\&\#60;\/A\&\#62;/<\/A>/g;	      # </A>
1961946379e7Schristos    $what =~ s/\&\#60;A ([^\&]+)\&\#62;/<A $1>/g;     # <A [^&]+>
1962946379e7Schristos    $what =~ s/\&\#60;IMG ([^\&]+)\&\#62;/<IMG $1>/g; # <IMG [^&]+>
1963946379e7Schristos    return($what);
1964946379e7Schristos}
1965946379e7Schristos
1966946379e7Schristossub unprotect_texi {
1967946379e7Schristos    s/$;0/\@/go;
1968946379e7Schristos    s/$;1/\{/go;
1969946379e7Schristos    s/$;2/\}/go;
1970946379e7Schristos    s/$;3/\`/go;
1971946379e7Schristos    s/$;4/\'/go;
1972946379e7Schristos}
1973946379e7Schristos
1974946379e7Schristossub unprotect_html {
1975946379e7Schristos    local($what) = @_;
1976946379e7Schristos    $what =~ s/\&\#38;/\&/g;
1977946379e7Schristos    $what =~ s/\&\#60;/\</g;
1978946379e7Schristos    $what =~ s/\&\#62;/\>/g;
1979946379e7Schristos    return($what);
1980946379e7Schristos}
1981946379e7Schristos
1982946379e7Schristossub byalpha {
1983946379e7Schristos    $key2alpha{$a} cmp $key2alpha{$b};
1984946379e7Schristos}
1985946379e7Schristos
1986946379e7Schristos##############################################################################
1987946379e7Schristos
1988946379e7Schristos	# These next few lines are legal in both Perl and nroff.
1989946379e7Schristos
1990946379e7Schristos.00 ;			# finish .ig
1991946379e7Schristos
1992946379e7Schristos'di			\" finish diversion--previous line must be blank
1993946379e7Schristos.nr nl 0-1		\" fake up transition to first page again
1994946379e7Schristos.nr % 0			\" start at page 1
1995946379e7Schristos'; __END__ ############# From here on it's a standard manual page ############
1996946379e7Schristos.TH TEXI2HTML 1 "01/05/98"
1997946379e7Schristos.AT 3
1998946379e7Schristos.SH NAME
1999946379e7Schristostexi2html \- a Texinfo to HTML converter
2000946379e7Schristos.SH SYNOPSIS
2001946379e7Schristos.B texi2html [options] file
2002946379e7Schristos.PP
2003946379e7Schristos.B texi2html -check [-verbose] files
2004946379e7Schristos.SH DESCRIPTION
2005946379e7Schristos.I Texi2html
2006946379e7Schristosconverts the given Texinfo file to a set of HTML files. It tries to handle
2007946379e7Schristosmost of the Texinfo commands. It creates hypertext links for cross-references,
2008946379e7Schristosfootnotes...
2009946379e7Schristos.PP
2010946379e7SchristosIt also tries to add links from a reference to its corresponding entry in the
2011946379e7Schristosbibliography (if any). It may also handle a glossary (see the
2012946379e7Schristos.B \-glossary
2013946379e7Schristosoption).
2014946379e7Schristos.PP
2015946379e7Schristos.I Texi2html
2016946379e7Schristoscreates several files depending on the contents of the Texinfo file and on
2017946379e7Schristosthe chosen options (see FILES).
2018946379e7Schristos.PP
2019946379e7SchristosThe HTML files created by
2020946379e7Schristos.I texi2html
2021946379e7Schristosare closer to TeX than to Info, that's why
2022946379e7Schristos.I texi2html
2023946379e7Schristosconverts @ifhtml sections and not @ifinfo or @iftex ones by default. You can
2024946379e7Schristoschange this with the \-expandinfo or \-expandtex options.
2025946379e7Schristos.SH OPTIONS
2026946379e7Schristos.TP 12
2027946379e7Schristos.B \-check
2028946379e7SchristosCheck the given file and give the list of all things that may be Texinfo commands.
2029946379e7SchristosThis may be used to check the output of
2030946379e7Schristos.I texi2html
2031946379e7Schristosto find the Texinfo commands that have been left in the HTML file.
2032946379e7Schristos.TP
2033946379e7Schristos.B \-expandinfo
2034946379e7SchristosExpand @ifinfo sections, not @ifhtml ones.
2035946379e7Schristos.TP
2036946379e7Schristos.B \-expandtex
2037946379e7SchristosExpand @iftex sections, not @ifhtml ones.
2038946379e7Schristos.TP
2039946379e7Schristos.B \-glossary
2040946379e7SchristosUse the section named 'Glossary' to build a list of terms and put links in the HTML
2041946379e7Schristosdocument from each term toward its definition.
2042946379e7Schristos.TP
2043946379e7Schristos.B \-invisible \fIname\fP
2044946379e7SchristosUse \fIname\fP to create invisible destination anchors for index links
2045946379e7Schristos(you can for instance use the invisible.xbm file shipped with this program).
2046946379e7SchristosThis is a workaround for a known bug of many WWW browsers, including netscape.
2047946379e7Schristos.TP
2048946379e7Schristos.B \-I \fIdir\fP
2049946379e7SchristosLook also in \fIdir\fP to find included files.
2050946379e7Schristos.TP
2051946379e7Schristos.B \-menu
2052946379e7SchristosShow the Texinfo menus; by default they are ignored.
2053946379e7Schristos.TP
2054946379e7Schristos.B \-monolithic
2055946379e7SchristosOutput only one file, including the table of contents and footnotes.
2056946379e7Schristos.TP
2057946379e7Schristos.B \-number
2058946379e7SchristosNumber the sections.
2059946379e7Schristos.TP
2060946379e7Schristos.B \-split_chapter
2061946379e7SchristosSplit the output into several HTML files (one per main section:
2062946379e7Schristoschapter, appendix...).
2063946379e7Schristos.TP
2064946379e7Schristos.B \-split_node
2065946379e7SchristosSplit the output into several HTML files (one per node).
2066946379e7Schristos.TP
2067946379e7Schristos.B \-usage
2068946379e7SchristosPrint usage instructions, listing the current available command-line options.
2069946379e7Schristos.TP
2070946379e7Schristos.B \-verbose
2071946379e7SchristosGive a verbose output. Can be used with the
2072946379e7Schristos.B \-check
2073946379e7Schristosoption.
2074946379e7Schristos.PP
2075946379e7Schristos.SH FILES
2076946379e7SchristosBy default
2077946379e7Schristos.I texi2html
2078946379e7Schristoscreates the following files (foo being the name of the Texinfo file):
2079946379e7Schristos.TP 16
2080946379e7Schristos.B foo_toc.html
2081946379e7SchristosThe table of contents.
2082946379e7Schristos.TP
2083946379e7Schristos.B foo.html
2084946379e7SchristosThe document's contents.
2085946379e7Schristos.TP
2086946379e7Schristos.B foo_foot.html
2087946379e7SchristosThe footnotes (if any).
2088946379e7Schristos.PP
2089946379e7SchristosWhen used with the
2090946379e7Schristos.B \-split
2091946379e7Schristosoption, it creates several files (one per chapter or node), named
2092946379e7Schristos.B foo_n.html
2093946379e7Schristos(n being the indice of the chapter or node), instead of the single
2094946379e7Schristos.B foo.html
2095946379e7Schristosfile.
2096946379e7Schristos.PP
2097946379e7SchristosWhen used with the
2098946379e7Schristos.B \-monolithic
2099946379e7Schristosoption, it creates only one file:
2100946379e7Schristos.B foo.html
2101946379e7Schristos.SH VARIABLES
2102946379e7Schristos.I texi2html
2103946379e7Schristospredefines the following variables: \fBhtml\fP, \fBtexi2html\fP.
2104946379e7Schristos.SH ADDITIONAL COMMANDS
2105946379e7Schristos.I texi2html
2106946379e7Schristosimplements the following non-Texinfo commands (maybe they are in Texinfo now...):
2107946379e7Schristos.TP 16
2108946379e7Schristos.B @ifhtml
2109946379e7SchristosThis indicates the start of an HTML section, this section will passed through
2110946379e7Schristoswithout any modification.
2111946379e7Schristos.TP
2112946379e7Schristos.B @end ifhtml
2113946379e7SchristosThis indicates the end of an HTML section.
2114946379e7Schristos.SH VERSION
2115946379e7SchristosThis is \fItexi2html\fP version 1.52b, 01/05/98.
2116946379e7Schristos.PP
2117946379e7SchristosThe latest version of \fItexi2html\fP can be found in WWW, cf. URL
2118946379e7Schristoshttp://wwwinfo.cern.ch/dis/texi2html/
2119946379e7Schristos.SH AUTHOR
2120946379e7SchristosThe main author is Lionel Cons, CERN IT/DIS/OSE, Lionel.Cons@cern.ch.
2121946379e7SchristosMany other people around the net contributed to this program.
2122946379e7Schristos.SH COPYRIGHT
2123946379e7SchristosThis program is the intellectual property of the European
2124946379e7SchristosLaboratory for Particle Physics (known as CERN). No guarantee whatsoever is
2125946379e7Schristosprovided by CERN. No liability whatsoever is accepted for any loss or damage
2126946379e7Schristosof any kind resulting from any defect or inaccuracy in this information or
2127946379e7Schristoscode.
2128946379e7Schristos.PP
2129946379e7SchristosCERN, 1211 Geneva 23, Switzerland
2130946379e7Schristos.SH "SEE ALSO"
2131946379e7SchristosGNU Texinfo Documentation Format,
2132946379e7SchristosHyperText Markup Language (HTML),
2133946379e7SchristosWorld Wide Web (WWW).
2134946379e7Schristos.SH BUGS
2135946379e7SchristosThis program does not understand all Texinfo commands (yet).
2136946379e7Schristos.ex
2137