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