3 docbook2texi-spec - convert DocBook Books to a Texinfo document
7 This is a sgmlspl spec file that produces a Texinfo file
12 Trying docbook2info on non-DocBook or non-conformant SGML results in
13 undefined behavior. :-)
15 This program is a slow, dodgy Perl script.
19 Copyright (C) 1998-1999 Steve Cheng <steve@ggi-project.org>
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
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.
32 # $Id: docbook2texi-spec.pl,v 1.1 2000/07/21 20:22:30 rosalia Exp $
34 use SGMLS; # Use the SGMLS package.
35 use SGMLS::Output; # Use stack-based output.
38 ########################################################################
39 # SGMLSPL script produced automatically by the script sgmlspl.pl
43 ########################################################################
46 $nocollapse_whitespace = 0; # Current whitespace collapse counter.
47 $newline_last = 1; # At beginning of line?
53 $basename = shift || "db2texi";
56 $Refs = new SGMLS::Refs("$basename.refs");
63 ########################################################################
67 ########################################################################
72 push_output('string');
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.
81 if(ref($_[1]) eq 'CODE') {
90 # \n at the beginning means start at beginning of line
92 $sub = 'sub { output "\n" unless $newline_last++; ';
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'; }"));
98 sgml($_[0], eval("sub { output \"\\n\" unless \$newline_last; output '$s'; \$newline_last = 0; }"));
102 sgml($_[0], eval("sub { output '$s'; \$newline_last = 1; }"));
104 sgml($_[0], eval("sub { output '$s'; \$newline_last = 0; }"));
113 output "\n" unless $newline_last++;
121 $newline_last = (pop(@_) =~ /\n$/);
123 $newline_last = ($_ =~ /\n$/)
127 # Fold lines into one, quote some characters
139 # Trim whitespace from beginning and end.
146 # Another version of sgml(), for 'inline' @-commands,
147 # and prevent nesting them.
150 my ($gi, $tcmd) = @_;
152 $tcmd =~ s/\\/\\\\/g;
155 sgml($gi, eval("sub { output '${tcmd}\{' unless \$raw_cdata or \$skip_inline++ }"));
158 sgml($gi, eval("sub { output '}' unless \$raw_cdata or --\$skip_inline }"));
163 return "ID" . $id_counter++;
169 ########################################################################
173 ########################################################################
176 if($_[0]->within('BOOKINFO')) {
181 if($_[0]->within('BOOKINFO')) {
182 texi_output('@author{' . fold_string(pop_output()) . "\}\n");
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);
198 sgml('</FIRSTNAME>', ' ');
199 sgml('</SURNAME>', ' ');
200 sgml('</HONORIFIC>', ' ');
201 sgml('</LINEAGE>', ' ');
202 sgml('</OTHERNAME>', ' ');
203 sgml('</AFFILIATION>', ' ');
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 });
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(); });
220 sgml('<TITLEABBREV>', sub { push_output('nul') });
221 sgml('</TITLEABBREV>', sub { pop_output() });
223 texi_sgml('<LEGALNOTICE>', "\n\@page\n\@vskip 0pt plus 1fill\n");
225 sgml('<BOOKINFO>', sub {
226 texi_output("\n\@titlepage\n");
227 texi_output('@title{', $doc_title, "\}\n");
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";
234 # Generate top menu for BOOK.
235 $_[0]->parent->ext->{'output_toc'} = 1;
237 # This is so that elements below can find me.
238 $_[0]->parent->ext->{'id'} = $_[0]->parent->attribute('ID')->value || generate_id();
241 sgml('<TITLE>', \&save_cdata);
242 sgml('</TITLE>', sub {
243 my $title = fold_string(pop_output());
246 if($_[0]->in('BOOKINFO')) {
247 texi_output("\n\@subtitle{", $title, "\}\n");
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;
254 elsif(exists $_[0]->parent->ext->{'nodesection'}) {
255 # Start new node, since we now know its title.
260 my $nodename = fold_string($me->attribute('XREFLABEL')->value) || $title;
263 texi_output("\n\n\@node $nodename\n");
265 # The heading such as @chapter $title.
266 texi_output($me->ext->{'nodesection'}, " $title\n");
268 # This is so that elements below can find me.
269 my $id = $me->attribute('ID')->value || generate_id();
270 $me->ext->{'id'} = $id;
272 # Don't overwrite info from previous parse.
273 if($Refs->get($id) eq '') {
274 $Refs->put($id, $nodename);
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");
282 if($_[0]->in('BOOK')) {
301 ########################################################################
303 # Major sectioning elements
305 ########################################################################
307 sgml('<BOOK>', "\\input texinfo\n\@settitle ");
308 texi_sgml('</BOOK>', "\n\n\@bye\n");
310 # Start a new section with new node.
311 # Most of the handling is at </TITLE>.
314 $_[0]->ext->{'nodesection'} = $_[1];
316 # Flag that the first child node ...
317 $_[0]->ext->{'output_toc'} = 1;
319 # ... need to output a list of nodes.
320 if($_[0]->parent->ext->{'output_toc'}) {
321 $_[0]->parent->ext->{'output_toc'} = 0;
323 my @nodes = split(/,/, $Refs->get($_[0]->parent->ext->{'id'}));
326 texi_output("\n\n\@menu\n");
329 my ($nodename) = split(/,/, $Refs->get($_));
330 output "* ", $nodename, "::\n";
333 texi_output("\n\n\@end menu\n");
337 sgml('<PREFACE>', sub { start_node $_[0], '@chapter'; });
338 sgml('<CHAPTER>', sub { start_node $_[0], '@chapter'; });
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'; });
347 ########################################################################
351 ########################################################################
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';
361 # From Sect2 and after
362 start_node $_[0], '@subsubsection';
366 sgml('<REFENTRYTITLE>', sub {
367 if($_[0]->in('REFMETA')) {
371 sgml('</REFENTRYTITLE>', sub {
372 if($_[0]->in('REFMETA')) {
373 my $title = fold_string(pop_output());
377 my $me = $_[0]->parent->parent;
379 my $nodename = fold_string($me->attribute('XREFLABEL')->value) || $title;
382 texi_output("\n\n\@node $nodename\n");
384 # The heading such as @chapter $title.
385 texi_output($me->ext->{'nodesection'}, " $title\n");
387 # This is so that elements below can find me.
388 my $id = $me->attribute('ID')->value || generate_id();
389 $me->ext->{'id'} = $id;
391 # Don't overwrite info from previous parse.
392 if($Refs->get($id) eq '') {
393 $Refs->put($id, $nodename);
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");
402 sgml('<MANVOLNUM>', sub {
403 if($_[0]->in('REFMETA')) { push_output('nul') }
404 else { texi_output '(' }
406 sgml('</MANVOLNUM>', sub {
407 if($_[0]->in('REFMETA')) { pop_output() }
408 else { texi_output ')' }
411 sgml('<REFMISCINFO>', sub { push_output('nul') });
412 sgml('</REFMISCINFO>', sub { pop_output() });
414 sgml('<REFNAMEDIV>', sub {
415 $_[0]->ext->{'first_refname'} = 1;
417 # FIXME! Add more of these parents!
418 if($_[0]->parent->in('CHAPTER')) {
419 texi_output "\n\n\@unnumberedsubsec Name\n";
421 texi_output "\n\n\@unnumberedsubsubsec Name\n";
425 sgml('<REFNAME>', sub {
426 if($_[0]->parent->ext->{'first_refname'}) {
427 $_[0]->parent->ext->{'first_refname'} = 0;
433 sgml('<REFPURPOSE>', " --- ");
437 sgml('<REFSYNOPSISDIV>', sub {
438 # FIXME! Add more of these parents!
439 if($_[0]->parent->in('CHAPTER')) {
440 texi_output "\n\@unnumberedsubsec Synopsis\n";
442 texi_output "\n\@unnumberedsubsubsec Synopsis\n";
446 sgml('<REFSECT1>', sub {
447 # FIXME! Add more of these parents!
448 if($_[0]->parent->in('CHAPTER')) {
449 texi_output "\n\n\@unnumberedsubsec ";
451 texi_output "\\nn\@unnumberedsubsubsec ";
455 sgml('<REFSECT2>', sub { start_node $_[0], '@unnumberedsubsubsec' });
456 sgml('<REFSECT3>', sub { start_node $_[0], '@unnumberedsubsubsec' });
462 ########################################################################
466 ########################################################################
468 sgml('<FUNCSYNOPSIS>', sub { $skip_inline++ });
469 sgml('</FUNCSYNOPSIS>', sub { $skip_inline-- });
470 sgml('<CMDSYNOPSIS>', sub { $skip_inline++ });
471 sgml('</CMDSYNOPSIS>', sub { $skip_inline-- });
473 sgml('<FUNCPROTOTYPE>', "\n\n");
475 # Arguments to functions. This is C convention.
476 texi_sgml('<PARAMDEF>', '(');
477 texi_sgml('</PARAMDEF>', ');');
478 texi_sgml('<VOID>', '(void);');
480 ## ARG: should be bold, but not needed.
489 ########################################################################
491 # 'Useful highlighting'
493 ########################################################################
496 _inline('<CITETITLE>', '@cite');
497 _inline('<EMAIL>', '@email');
498 _inline('<FIRSTTERM>', '@dfn');
499 _inline('<FILENAME>', '@file');
501 _inline('<ACCEL>', '@key');
502 _inline('<KEYCAP>', '@key');
503 _inline('<KEYCOMBO>', '@key');
504 _inline('<KEYSYM>', '@key');
505 _inline('<USERINPUT>', '@kbd');
507 _inline('<LITERAL>', '@samp');
508 _inline('<MARKUP>', '@samp');
509 _inline('<SGMLTAG>', '@samp');
510 _inline('<TOKEN>', '@samp');
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');
522 _inline('<ACRONYM>', '@sc');
523 _inline('<EMPHASIS>', '@emph');
525 # Only in certain contexts
526 #sgml('<REPLACEABLE>'
528 sgml('<OPTIONAL>', "[");
529 sgml('</OPTIONAL>', "]");
531 sgml('<COMMENT>', "[Comment: ");
532 sgml('</COMMENT>', "]");
561 sgml('<CITEREFENTRY>', sub { $skip_inline++ });
562 sgml('</CITEREFENTRY>', sub { $skip_inline-- });
566 ########################################################################
570 ########################################################################
573 output "\n" unless $newline_last++;
575 if($_[0]->parent->ext->{'nobreak'}) {
576 # Usually this is the FIRST element of
577 # an @item, so we MUST not do a full
579 $_[0]->parent->ext->{'nobreak'} = 0;
585 # Actually applies to a few other block elements as well
587 output "\n" unless $newline_last++;
590 sgml('<PARA>', \¶_start);
591 sgml('<SIMPARA>', \¶_end);
593 texi_sgml('<EXAMPLE>', "\n\@unnumberedsubsubsec ");
594 texi_sgml('</EXAMPLE>', "\n\n");
598 ########################################################################
602 ########################################################################
606 texi_output("\@example\n") unless $no_collapase++;
611 texi_output("\@end example\n") unless --$no_collapase;
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);
625 ########################################################################
627 # Admonitions and other 'outside flow'
629 ########################################################################
631 ## These are supposed to be set off from the text, so
632 ## proper indentation is not so important.
634 #sub admonition_end {
635 # output "\n" unless $newline_last++;
639 #$admonition_end = *admonition_end{CODE};
642 # FIXME! Lotsa things!
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");
655 #sgml('<NOTE>', sub {
656 # output "\n" unless $newline_last++;
658 # output ".B Note: \n";
659 # $listitem_first = 1;
661 #sgml('</NOTE>', $admonition_end);
666 ########################################################################
670 ########################################################################
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");
679 sgml('<VARLISTENTRY>', sub {
680 $_[0]->ext->{'first_term'} = 1;
684 if($_[0]->parent->ext->{'first_term'}) {
685 $_[0]->parent->ext->{'first_term'} = 0;
686 texi_output "\n\n\@item ";
688 texi_output "\n\n\@itemx ";
692 sgml('</TERM>', sub {
693 output fold_string(pop_output()) . "\n";
698 sgml('<LISTITEM>', sub {
699 texi_output "\n\n\@item\n" unless $_[0]->in('VARLISTENTRY');
700 $_[0]->ext->{'nobreak'} = 1;
703 sgml('<SIMPLELIST>', sub {
704 $_[0]->ext->{'first_member'} = 1;
707 sgml('<MEMBER>', sub {
708 my $listtype = $_[0]->parent->attribute(TYPE)->value;
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;
717 } elsif($listtype =~ /Vert/i) {
726 ########################################################################
728 # Stuff we don't know how to handle (yet)
730 ########################################################################
745 # Other document metadata:
747 # Element: RELEASEINFO
760 texi_sgml('<BEGINPAGE>', "\n\@page\n");
768 ########################################################################
770 # Linkage, cross references
772 ########################################################################
775 sgml('<ULINK>', sub {
776 if($skip_inline++) { return; } # hopefully doesn't happen
777 output '@uref{', output $_[0]->attribute('URL'), ', '
779 sgml('</ULINK>', sub {
780 output '}' unless --$skip_inline;
784 my $id = $_[0]->attribute('LINKEND')->value;
785 my ($nodename) = split(/,/, $Refs->get($id));
788 texi_output("\@xref\{$nodename\}");
791 texi_output "[XRef to $id]";
801 ########################################################################
805 ########################################################################
807 sgml('|[lt ]|', "<");
808 sgml('|[gt ]|', ">");
809 sgml('|[amp ]|', "&");
812 # Default handlers (uncomment these if needed). Right now, these are set
813 # up to gag on any unrecognised elements, sdata, processing-instructions,
816 # sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
817 # sgml('end_element','');
832 if($nocollapse_whitespace || !$newline_last) {
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','');