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