TIVI-153: add as dependency for iputils
[profile/ivi/docbook-utils.git] / helpers / docbook2texi-spec.pl
1 =head1 NAME
2
3 docbook2texi-spec - convert DocBook Books to a Texinfo document
4
5 =head1 DESCRIPTION
6
7 This is a sgmlspl spec file that produces a Texinfo file
8 from DocBook markup.
9
10 =head1 LIMITATIONS
11
12 Trying docbook2info on non-DocBook or non-conformant SGML results in
13 undefined behavior. :-)
14
15 This program is a slow, dodgy Perl script.  
16
17 =head1 COPYRIGHT
18
19 Copyright (C) 1998-1999 Steve Cheng <steve@ggi-project.org>
20
21 This program is free software; you can redistribute it and/or modify it
22 under the terms of the GNU General Public License as published by the Free
23 Software Foundation; either version 2, or (at your option) any later
24 version.
25
26 You should have received a copy of the GNU General Public License along with
27 this program; see the file COPYING.  If not, please write to the Free
28 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
29
30 =cut
31
32 # $Id: docbook2texi-spec.pl,v 1.1 2000/07/21 20:22:30 rosalia Exp $
33
34 use SGMLS;                      # Use the SGMLS package.
35 use SGMLS::Output;              # Use stack-based output.
36 use SGMLS::Refs;
37
38 ########################################################################
39 # SGMLSPL script produced automatically by the script sgmlspl.pl
40 #
41 # Document Type: BOOK
42 # Edited by: me :)
43 ########################################################################
44
45
46 $nocollapse_whitespace = 0;     # Current whitespace collapse counter.
47 $newline_last = 1;              # At beginning of line?
48
49 $skip_inline = 0;
50 $id_counter = 1;
51 $raw_cdata = 0;
52
53 $basename = shift || "db2texi";
54
55 sgml('start', sub {
56         $Refs = new SGMLS::Refs("$basename.refs");
57 });
58 sgml('end', sub {
59         $Refs->warn();
60 });
61
62
63 ########################################################################
64 #
65 # Output helpers 
66 #
67 ########################################################################
68
69 sub save_cdata
70 {
71         $raw_cdata++;
72         push_output('string');
73 }
74                 
75 # Copied from docbook2man.
76 # Texinfo's newline rules aren't so stringent, so
77 # perhaps we can do away with at least some of these cases for speed.
78
79 sub texi_sgml
80 {
81         if(ref($_[1]) eq 'CODE') {
82                 return &sgml;
83         }
84         
85         my $s = $_[1];
86
87         $s =~ s/\\/\\\\/g;
88         $s =~ s/'/\\'/g;
89
90         # \n at the beginning means start at beginning of line
91         if($s =~ s/^\n//) {
92                 $sub = 'sub { output "\n" unless $newline_last++; ';
93                 if($s eq '') { 
94                         sgml($_[0], eval('sub { output "\n" unless $newline_last++; }'));
95                 } elsif($s =~ /\n$/) {
96                         sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last++; output '$s'; }"));
97                 } else {
98                         sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last; output '$s'; \$newline_last = 0; }"));
99                 }
100         } else {
101                 if($s =~ /\n$/) {
102                         sgml($_[0], eval("sub { output '$s'; \$newline_last = 1; }"));
103                 } else {
104                         sgml($_[0], eval("sub { output '$s'; \$newline_last = 0; }"));
105                 }
106         }
107 }
108
109 sub texi_output
110 {
111         $_ = shift;
112         if(s/^\n//) {
113                 output "\n" unless $newline_last++;
114         }
115         return if $_ eq '';
116         
117         output $_;
118
119         if(@_) {
120                 output @_;
121                 $newline_last = (pop(@_) =~ /\n$/);
122         } else {
123                 $newline_last = ($_ =~ /\n$/)
124         }
125 }
126
127 # Fold lines into one, quote some characters
128 sub fold_string
129 {
130         $_ = shift;
131         
132         for($_[0]) {
133                 tr/\t/\n  /;
134                 s/\@/\@\@/g;
135                 s/\{/\@\{/g;
136                 s/\}/\@\}/g;
137         }
138         
139         # Trim whitespace from beginning and end.
140         s/^ +//;
141         s/ +$//;
142
143         return $_;
144 }
145
146 # Another version of sgml(), for 'inline' @-commands,
147 # and prevent nesting them.
148 sub _inline
149 {
150         my ($gi, $tcmd) = @_;
151         
152         $tcmd =~ s/\\/\\\\/g;
153         $tcmd =~ s/'/\\'/g;
154
155         sgml($gi, eval("sub { output '${tcmd}\{' unless \$raw_cdata or \$skip_inline++ }"));
156         
157         $gi =~ s/^</<\//;
158         sgml($gi, eval("sub { output '}' unless \$raw_cdata or --\$skip_inline }"));
159 }
160
161
162 sub generate_id {
163         return "ID" . $id_counter++;
164 }
165     
166
167
168
169 ########################################################################
170 #
171 # Metadata
172 #
173 ########################################################################
174
175 sub author_start {
176         if($_[0]->within('BOOKINFO')) {
177                 save_cdata();
178         }
179 }
180 sub author_end {
181         if($_[0]->within('BOOKINFO')) {
182                 texi_output('@author{' . fold_string(pop_output()) . "\}\n");
183                 $raw_cdata--;
184         }
185 }
186
187 sgml('<AUTHOR>', \&author_start);
188 sgml('</AUTHOR>', \&author_end);
189 sgml('<EDITOR>', \&author_start);
190 sgml('</EDITOR>', \&author_end);
191 sgml('<COLLAB>', \&author_start);
192 sgml('</COLLAB>', \&author_end);
193 sgml('<CORPAUTHOR>', \&author_start);
194 sgml('</CORPAUTHOR>', \&author_end);
195 sgml('<OTHERCREDIT>', \&author_start);
196 sgml('</OTHERCREDIT>', \&author_end);
197
198 sgml('</FIRSTNAME>', ' ');
199 sgml('</SURNAME>', ' ');
200 sgml('</HONORIFIC>', ' ');
201 sgml('</LINEAGE>', ' ');
202 sgml('</OTHERNAME>', ' ');
203 sgml('</AFFILIATION>', ' ');
204
205 # Ignore content.
206 sgml('<CONTRIB>', sub { push_output('nul') });
207 sgml('</CONTRIB>', sub { pop_output });
208 sgml('<AUTHORBLURB>', sub { push_output('nul') });
209 sgml('</AUTHORBLURB>', sub { pop_output });
210
211 sgml('<DOCINFO>', sub { push_output('nul'); });
212 sgml('</DOCINFO>', sub { pop_output(); });
213 sgml('<REFSECT1INFO>', sub { push_output('nul'); });
214 sgml('</REFSECT1INFO>', sub { pop_output(); });
215 sgml('<REFSECT2INFO>', sub { push_output('nul'); });
216 sgml('</REFSECT2INFO>', sub { pop_output(); });
217 sgml('<REFSECT3INFO>', sub { push_output('nul'); });
218 sgml('</REFSECT3INFO>', sub { pop_output(); });
219
220 sgml('<TITLEABBREV>', sub { push_output('nul') });
221 sgml('</TITLEABBREV>', sub { pop_output() });
222
223 texi_sgml('<LEGALNOTICE>', "\n\@page\n\@vskip 0pt plus 1fill\n");
224
225 sgml('<BOOKINFO>', sub {
226         texi_output("\n\@titlepage\n");
227         texi_output('@title{', $doc_title, "\}\n");
228 });
229 #texi_sgml('</BOOKINFO>', "\n\@end titlepage\n");
230 texi_sgml('</BOOKINFO>', sub {
231         texi_output "\n\@end titlepage\n\n";
232         texi_output "\@node Top\n\@top\n\n";
233
234         # Generate top menu for BOOK.
235         $_[0]->parent->ext->{'output_toc'} = 1;
236                 
237         # This is so that elements below can find me.
238         $_[0]->parent->ext->{'id'} = $_[0]->parent->attribute('ID')->value || generate_id();
239 });
240
241 sgml('<TITLE>', \&save_cdata);
242 sgml('</TITLE>', sub { 
243         my $title = fold_string(pop_output());
244         $raw_cdata--;
245         
246         if($_[0]->in('BOOKINFO')) {
247                 texi_output("\n\@subtitle{", $title, "\}\n");
248         }
249         elsif(exists $_[0]->parent->ext->{'title'}) {
250                 # By far the easiest case.  Just fold the string as
251                 # above, and then set the parent element's variable.
252                 $_[0]->parent->ext->{'title'} = $title;
253         }
254         elsif(exists $_[0]->parent->ext->{'nodesection'}) {
255                 # Start new node, since we now know its title.
256
257                 # This node.
258                 $me = $_[0]->parent;
259                 
260                 my $nodename = fold_string($me->attribute('XREFLABEL')->value) || $title;
261                 $nodename =~ s/,/ /;
262                 
263                 texi_output("\n\n\@node $nodename\n");
264
265                 # The heading such as @chapter $title.
266                 texi_output($me->ext->{'nodesection'}, " $title\n");
267
268                 # This is so that elements below can find me.
269                 my $id = $me->attribute('ID')->value || generate_id();
270                 $me->ext->{'id'} = $id;
271
272                 # Don't overwrite info from previous parse.
273                 if($Refs->get($id) eq '') {
274                         $Refs->put($id, $nodename);
275                 
276                         # Add myself to parent node's list of nodes.
277                         my $pid = $me->parent->ext->{'id'};
278                         $Refs->put($pid, $Refs->get($pid) . ",$id");
279                 }
280         }
281         else {
282                 if($_[0]->in('BOOK')) {
283                         $doc_title = $title;
284                 }
285                 output $title, "\n";
286                 $newline_last++;
287         }
288 });
289
290 # Appendix
291 # Article
292
293
294
295
296
297
298
299
300
301 ########################################################################
302 #
303 # Major sectioning elements
304 #
305 ########################################################################
306
307 sgml('<BOOK>', "\\input texinfo\n\@settitle ");
308 texi_sgml('</BOOK>', "\n\n\@bye\n");
309
310 # Start a new section with new node.  
311 # Most of the handling is at </TITLE>.
312 sub start_node
313 {
314         $_[0]->ext->{'nodesection'} = $_[1];
315
316         # Flag that the first child node ...
317         $_[0]->ext->{'output_toc'} = 1;
318         
319         # ... need to output a list of nodes.
320         if($_[0]->parent->ext->{'output_toc'}) {
321                 $_[0]->parent->ext->{'output_toc'} = 0;
322                 
323                 my @nodes = split(/,/, $Refs->get($_[0]->parent->ext->{'id'}));
324                 shift @nodes;
325
326                 texi_output("\n\n\@menu\n");
327
328                 foreach(@nodes) {
329                         my ($nodename) = split(/,/, $Refs->get($_));
330                         output "* ", $nodename, "::\n";
331                 }
332
333                 texi_output("\n\n\@end menu\n");
334         }
335 }
336
337 sgml('<PREFACE>', sub { start_node $_[0], '@chapter'; });
338 sgml('<CHAPTER>', sub { start_node $_[0], '@chapter'; });
339
340 sgml('<SECT1>', sub { start_node $_[0], '@section'; });
341 sgml('<SECT2>', sub { start_node $_[0], '@subsection'; });
342 sgml('<SECT3>', sub { start_node $_[0], '@subsubsection'; });
343 sgml('<SECT4>', sub { start_node $_[0], '@subsubsection'; });
344 sgml('<SECT5>', sub { start_node $_[0], '@subsubsection'; });
345
346
347 ########################################################################
348 #
349 # Reference pages
350 #
351 ########################################################################
352
353 sgml('<REFENTRY>', sub {
354         # Determine what it is under ...
355         # FIXME! Add more of these parents!
356         if($_[0]->in('CHAPTER')) {
357                 start_node $_[0], '@section';
358         } elsif($_[0]->in('SECT1')) {
359                 start_node $_[0], '@subsection';
360         } else {
361                 # From Sect2 and after
362                 start_node $_[0], '@subsubsection';
363         }
364 });
365
366 sgml('<REFENTRYTITLE>', sub { 
367         if($_[0]->in('REFMETA')) { 
368                 save_cdata();
369         }
370 });
371 sgml('</REFENTRYTITLE>', sub { 
372         if($_[0]->in('REFMETA')) { 
373                 my $title = fold_string(pop_output());
374                 $raw_cdata--;
375
376                 # This node.
377                 my $me = $_[0]->parent->parent;
378                                 
379                 my $nodename = fold_string($me->attribute('XREFLABEL')->value) || $title;
380                 $nodename =~ s/,/ /;
381                 
382                 texi_output("\n\n\@node $nodename\n");
383
384                 # The heading such as @chapter $title.
385                 texi_output($me->ext->{'nodesection'}, " $title\n");
386
387                 # This is so that elements below can find me.
388                 my $id = $me->attribute('ID')->value || generate_id();
389                 $me->ext->{'id'} = $id;
390
391                 # Don't overwrite info from previous parse.
392                 if($Refs->get($id) eq '') {
393                         $Refs->put($id, $nodename);
394                 
395                         # Add myself to parent node's list of nodes.
396                         my $pid = $me->parent->ext->{'id'};
397                         $Refs->put($pid, $Refs->get($pid) . ",$id");
398                 }
399         }
400 });
401
402 sgml('<MANVOLNUM>', sub { 
403         if($_[0]->in('REFMETA')) { push_output('nul') }
404         else                     { texi_output '(' }
405 });
406 sgml('</MANVOLNUM>', sub { 
407         if($_[0]->in('REFMETA')) { pop_output() }
408         else                     { texi_output ')' }
409 });
410
411 sgml('<REFMISCINFO>', sub { push_output('nul') });
412 sgml('</REFMISCINFO>', sub { pop_output() });
413
414 sgml('<REFNAMEDIV>', sub { 
415         $_[0]->ext->{'first_refname'} = 1;
416
417         # FIXME! Add more of these parents!
418         if($_[0]->parent->in('CHAPTER')) {
419                 texi_output "\n\n\@unnumberedsubsec Name\n";
420         } else {
421                 texi_output "\n\n\@unnumberedsubsubsec Name\n";
422         }
423 });
424
425 sgml('<REFNAME>', sub {
426         if($_[0]->parent->ext->{'first_refname'}) {
427                 $_[0]->parent->ext->{'first_refname'} = 0;
428                 return;
429         }
430         output ", ";
431 });
432
433 sgml('<REFPURPOSE>', " --- ");
434
435 # RefDescriptor
436
437 sgml('<REFSYNOPSISDIV>', sub { 
438         # FIXME! Add more of these parents!
439         if($_[0]->parent->in('CHAPTER')) {
440                 texi_output "\n\@unnumberedsubsec Synopsis\n";
441         } else {
442                 texi_output "\n\@unnumberedsubsubsec Synopsis\n";
443         }
444 });
445
446 sgml('<REFSECT1>', sub {
447         # FIXME! Add more of these parents!
448         if($_[0]->parent->in('CHAPTER')) {
449                 texi_output "\n\n\@unnumberedsubsec ";
450         } else {
451                 texi_output "\\nn\@unnumberedsubsubsec ";
452         }
453 });
454
455 sgml('<REFSECT2>', sub { start_node $_[0], '@unnumberedsubsubsec' });
456 sgml('<REFSECT3>', sub { start_node $_[0], '@unnumberedsubsubsec' });
457
458
459
460
461
462 ########################################################################
463 #
464 # Synopses
465 #
466 ########################################################################
467
468 sgml('<FUNCSYNOPSIS>', sub { $skip_inline++ });
469 sgml('</FUNCSYNOPSIS>', sub { $skip_inline-- });
470 sgml('<CMDSYNOPSIS>', sub { $skip_inline++ });
471 sgml('</CMDSYNOPSIS>', sub { $skip_inline-- });
472
473 sgml('<FUNCPROTOTYPE>', "\n\n");
474
475 # Arguments to functions.  This is C convention.
476 texi_sgml('<PARAMDEF>', '(');
477 texi_sgml('</PARAMDEF>', ');');
478 texi_sgml('<VOID>', '(void);');
479
480 ## ARG: should be bold, but not needed.
481 #
482
483
484
485
486
487
488
489 ########################################################################
490 #
491 # 'Useful highlighting' 
492 #
493 ########################################################################
494
495
496 _inline('<CITETITLE>', '@cite');
497 _inline('<EMAIL>', '@email');
498 _inline('<FIRSTTERM>', '@dfn');
499 _inline('<FILENAME>', '@file');
500
501 _inline('<ACCEL>', '@key');
502 _inline('<KEYCAP>', '@key');
503 _inline('<KEYCOMBO>', '@key');
504 _inline('<KEYSYM>', '@key');
505 _inline('<USERINPUT>', '@kbd');
506
507 _inline('<LITERAL>', '@samp');
508 _inline('<MARKUP>', '@samp');
509 _inline('<SGMLTAG>', '@samp');
510 _inline('<TOKEN>', '@samp');
511
512 _inline('<CLASSNAME>', '@code');
513 _inline('<ENVAR>', '@code');
514 _inline('<FUNCTION>', '@code');
515 _inline('<PARAMETER>', '@code'); # not always
516 _inline('<RETURNVALUE>', '@code');
517 _inline('<STRUCTFIELD>', '@code');
518 _inline('<STRUCTNAME>', '@code');
519 _inline('<SYMBOL>', '@code');
520 _inline('<TYPE>', '@code');
521
522 _inline('<ACRONYM>', '@sc');
523 _inline('<EMPHASIS>', '@emph');
524
525 # Only in certain contexts
526 #sgml('<REPLACEABLE>'
527
528 sgml('<OPTIONAL>', "[");
529 sgml('</OPTIONAL>', "]");
530
531 sgml('<COMMENT>', "[Comment: ");
532 sgml('</COMMENT>', "]");
533
534 # ACTION
535 # ALT
536
537 # AUTHOR
538 # AUTHORINITIALS
539
540 # ABBREV
541 # CITATION
542 # FOREIGNPHRASE
543 # PHRASE
544 # QUOTE
545 # WORDASWORD
546
547 # COMPUTEROUTPUT
548 # LITERAL
549 # MARKUP
550 # PROMPT
551 # RETURNVALUE
552 # SGMLTAG
553 # TOKEN
554
555 # DATABASE
556 # HARDWARE
557 # INTERFACE
558 # MEDIALABEL
559 # SYSTEMITEM
560
561 sgml('<CITEREFENTRY>', sub { $skip_inline++ });
562 sgml('</CITEREFENTRY>', sub { $skip_inline-- });
563
564
565
566 ########################################################################
567 #
568 # 'Block' elements 
569 #
570 ########################################################################
571
572 sub para_start {
573         output "\n" unless $newline_last++;
574
575         if($_[0]->parent->ext->{'nobreak'}) {
576                 # Usually this is the FIRST element of
577                 # an @item, so we MUST not do a full
578                 # paragraph break.
579                 $_[0]->parent->ext->{'nobreak'} = 0;
580         } else {
581                 output "\n";
582         }
583 }
584
585 # Actually applies to a few other block elements as well
586 sub para_end {
587         output "\n" unless $newline_last++; 
588 }
589
590 sgml('<PARA>', \&para_start);
591 sgml('<SIMPARA>', \&para_end);
592
593 texi_sgml('<EXAMPLE>', "\n\@unnumberedsubsubsec ");
594 texi_sgml('</EXAMPLE>', "\n\n");
595
596
597
598 ########################################################################
599 #
600 # Verbatim displays. 
601 #
602 ########################################################################
603
604 sub verbatim_on {
605         texi_output("\n\n");
606         texi_output("\@example\n") unless $no_collapase++;
607 }
608
609 sub verbatim_off {
610         texi_output("\n\n");
611         texi_output("\@end example\n") unless --$no_collapase;
612 }
613
614 texi_sgml('<PROGRAMLISTING>', \&verbatim_on); 
615 texi_sgml('</PROGRAMLISTING>', \&verbatim_off);
616 texi_sgml('<SCREEN>', \&verbatim_on); 
617 texi_sgml('</SCREEN>', \&verbatim_off);
618 texi_sgml('<LITERALLAYOUT>', \&verbatim_on); 
619 texi_sgml('</LITERALLAYOUT>', \&verbatim_off);
620 texi_sgml('<SYNOPSIS>', \&verbatim_on); 
621 texi_sgml('</SYNOPSIS>', \&verbatim_off);
622
623
624
625 ########################################################################
626 #
627 # Admonitions and other 'outside flow'
628 #
629 ########################################################################
630
631 ## These are supposed to be set off from the text, so 
632 ## proper indentation is not so important.
633 #
634 #sub admonition_end {
635 #       output "\n" unless $newline_last++;
636 #       output ".sp\n";
637 #}
638 #
639 #$admonition_end = *admonition_end{CODE};
640 #
641
642 # FIXME! Lotsa things!
643
644 #sgml('<NOTE>', "\n\n\@cartouche\nNote: ");
645 #sgml('</NOTE>', "\n\n\@end cartouche\n");
646 #sgml('<WARNING>', "\n\n\@cartouche\nWarning: ");
647 #sgml('</WARNING>', "\n\n\@end cartouche\n");
648 #sgml('<TIP>', "\n\n\@cartouche\nTip: ");
649 #sgml('</TIP>', "\n\n\@end cartouche\n");
650 #sgml('<CAUTION>', "\n\n\@cartouche\nCaution: ");
651 #sgml('</CAUTION>', "\n\n\@end cartouche\n");
652 #sgml('<IMPORTANT>', "\n\n\@cartouche\nImportant: ");
653 #sgml('</IMPORTANT>', "\n\n\@end cartouche\n");
654
655 #sgml('<NOTE>', sub {
656 #       output "\n" unless $newline_last++;
657 #       output ".PP\n";
658 #       output ".B Note: \n";
659 #       $listitem_first = 1;
660 #});
661 #sgml('</NOTE>', $admonition_end);
662
663
664
665
666 ########################################################################
667 #
668 # Lists
669 #
670 ########################################################################
671
672 texi_sgml('<VARIABLELIST>', "\n\@table \@asis\n");
673 texi_sgml('</VARIABLELIST>', "\n\@end table\n");
674 texi_sgml('<ORDEREDLIST>', "\n\@enumerate\n");
675 texi_sgml('</ORDEREDLIST>', "\n\@end enumerate\n");
676 texi_sgml('<ITEMIZEDLIST>', "\n\@itemize \@bullet\n");
677 texi_sgml('</ITEMIZEDLIST>', "\n\@end itemize\n");
678
679 sgml('<VARLISTENTRY>', sub { 
680         $_[0]->ext->{'first_term'} = 1;
681 });
682
683 sgml('<TERM>', sub { 
684         if($_[0]->parent->ext->{'first_term'}) {
685                 $_[0]->parent->ext->{'first_term'} = 0;
686                 texi_output "\n\n\@item ";
687         } else {
688                 texi_output "\n\n\@itemx ";
689         }
690         save_cdata();
691 });
692 sgml('</TERM>', sub { 
693         output fold_string(pop_output()) . "\n";
694         $newline_last = 1;
695         $raw_cdata--;
696 });
697
698 sgml('<LISTITEM>', sub {
699         texi_output "\n\n\@item\n" unless $_[0]->in('VARLISTENTRY');
700         $_[0]->ext->{'nobreak'} = 1;
701 });
702
703 sgml('<SIMPLELIST>', sub { 
704         $_[0]->ext->{'first_member'} = 1;
705 });
706
707 sgml('<MEMBER>', sub {
708         my $listtype = $_[0]->parent->attribute(TYPE)->value;
709         
710         if($listtype =~ /Inline/i) {
711                 if($_[0]->parent->ext->{'first_member'}) {
712                         # If this is the first member don't put any commas
713                         $_[0]->parent->ext->{'first_member'} = 0;
714                 } else {
715                         output ", ";
716                 }
717         } elsif($listtype =~ /Vert/i) {
718                 texi_output("\n\n");
719         }
720 });
721
722
723
724
725
726 ########################################################################
727 #
728 # Stuff we don't know how to handle (yet) 
729 #
730 ########################################################################
731
732 # Address blocks:
733
734 # Credit stuff:
735 # ACKNO
736 # ADDRESS
737 # AFFILIATION
738 # ARTPAGENUMS
739 # ATTRIBUTION
740 # AUTHORBLURB
741 # AUTHORGROUP
742 # OTHERCREDIT
743 # HONORIFIC
744
745 # Other document metadata:
746 # Element: BOOKINFO
747 # Element: RELEASEINFO
748
749
750
751 # DocInfo
752 # ArtHeader
753
754 # Areas:
755 # AREA
756 # AREASET
757 # AREASPEC
758
759
760 texi_sgml('<BEGINPAGE>', "\n\@page\n");
761
762 #BeginPage
763 #IndexTerm
764
765
766
767
768 ########################################################################
769 #
770 # Linkage, cross references
771 #
772 ########################################################################
773
774 ## Print the URL
775 sgml('<ULINK>', sub {
776         if($skip_inline++) { return; }  # hopefully doesn't happen
777         output '@uref{', output $_[0]->attribute('URL'), ', '
778 });
779 sgml('</ULINK>', sub {
780         output '}' unless --$skip_inline;
781 });
782
783 sgml('<XREF>', sub {
784         my $id = $_[0]->attribute('LINKEND')->value;
785         my ($nodename) = split(/,/, $Refs->get($id));
786
787         if($nodename) {
788                 texi_output("\@xref\{$nodename\}");
789         } else {
790                 $blank_xrefs++;
791                 texi_output "[XRef to $id]";
792         }
793 });
794
795
796 # Anchor
797
798
799
800
801 ########################################################################
802 #
803 # Other handlers 
804 #
805 ########################################################################
806
807 sgml('|[lt    ]|', "<");
808 sgml('|[gt    ]|', ">");
809 sgml('|[amp   ]|', "&");
810
811 #
812 # Default handlers (uncomment these if needed).  Right now, these are set
813 # up to gag on any unrecognised elements, sdata, processing-instructions,
814 # or entities.
815 #
816 # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
817 # sgml('end_element','');
818
819 sgml('cdata', sub
820
821         for($_[0]) {
822                 s/\@/\@\@/g;
823                 s/\{/\@\{/g;
824                 s/\}/\@\}/g;
825         }
826         $newline_last = 0;
827         output $_[0];
828 });
829
830 sgml('re', sub
831 {
832         if($nocollapse_whitespace || !$newline_last) {
833                 output "\n";
834         }
835
836         $newline_last = 1;
837 });
838
839 sgml('re', "\n");
840 sgml('sdata',sub { die "Unknown SDATA: " . $_[0]; });
841 sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
842 sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
843 sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
844 sgml('end_subdoc','');
845 # sgml('conforming','');
846
847 1;
848