# $Id: tolatex.pl,v 1.1.1.2 1998/03/22 09:39:20 valerio Exp valerio $
$VERSION{__FILE__} = '$Revision: 1.1.1.2 $';
#
# >>Title:: LaTeX Format Driver
#
# >>Copyright::
# Copyright (c) 1997, Ian Clatworthy (ianc@mincom.com).
# You may distribute under the terms specified in the LICENSE file.
#
# >>History::
# -----------------------------------------------------------------------
# Date Who Change
# 30-Oct-98 valerio First Beta release.
# 02-Apr-98 valerio Fixed List closing before Tables.
# 14-Mar-98 valerio Wrote List code.
# 20-Nov-97 valerio Initial rewriting for full use of LaTeX.
# 12-Aug-97 ianc Initial writing for Apache Documentation Project
# 14-May-96 ianc SDF 2.000
# -----------------------------------------------------------------------
#
# >>Purpose::
# This library provides an [[SDF_DRIVER]] which generates
# LaTeX files.
#
# >>Description::
#
# >>Limitations::
#
# >>Resources::
#
# >>Implementation::
#
##### Constants #####
# Default right margin
$_LATEX_DEFAULT_MARGIN = 70;
# Mapping of characters
%_LATEX_CHAR = (
'backslash'. '\\',
'bullet', '$\bullet$',
'c', '\copyright ',
'cent', 'c',
'dagger', '\dagger',
'doubledagger', '\ddagger',
'emdash', '--',
'endash', '---',
'emspace', '\ \ ',
'enspace', '\ ',
'lbrace', '{',
'lbracket', '[',
'nbdash', '-',
'nbspace', ' ',
'nl', "\n",
'pound', '\pounds ',
'r', '(r)',
'rbrace', '}',
'rbracket', ']',
'tab', "\t",
'tm', '$^{TM}$',
'yen', 'y',
# From pod2latex ...
'amp' => '\\&', # ampersand
'lt' => '$<$', # left chevron, less-than
'gt' => '$>$', # right chevron, greater-than
'quot' => '"', # double quote
"Aacute" => "\\'{A}", # capital A, acute accent
"aacute" => "\\'{a}", # small a, acute accent
"Acirc" => "\\^{A}", # capital A, circumflex accent
"acirc" => "\\^{a}", # small a, circumflex accent
"AElig" => '\\AE', # capital AE diphthong (ligature)
"aelig" => '\\ae', # small ae diphthong (ligature)
"Agrave" => "\\`{A}", # capital A, grave accent
"agrave" => "\\`{a}", # small a, grave accent
"Aring" => '\\u{A}', # capital A, ring
"aring" => '\\u{a}', # small a, ring
"Atilde" => '\\~{A}', # capital A, tilde
"atilde" => '\\~{a}', # small a, tilde
"Auml" => '\\"{A}', # capital A, dieresis or umlaut mark
"auml" => '\\"{a}', # small a, dieresis or umlaut mark
"Ccedil" => '\\c{C}', # capital C, cedilla
"ccedil" => '\\c{c}', # small c, cedilla
"Eacute" => "\\'{E}", # capital E, acute accent
"eacute" => "\\'{e}", # small e, acute accent
"Ecirc" => "\\^{E}", # capital E, circumflex accent
"ecirc" => "\\^{e}", # small e, circumflex accent
"Egrave" => "\\`{E}", # capital E, grave accent
"egrave" => "\\`{e}", # small e, grave accent
"ETH" => '\\OE', # capital Eth, Icelandic
"eth" => '\\oe', # small eth, Icelandic
"Euml" => '\\"{E}', # capital E, dieresis or umlaut mark
"euml" => '\\"{e}', # small e, dieresis or umlaut mark
"Iacute" => "\\'{I}", # capital I, acute accent
"iacute" => "\\'{i}", # small i, acute accent
"Icirc" => "\\^{I}", # capital I, circumflex accent
"icirc" => "\\^{i}", # small i, circumflex accent
"Igrave" => "\\`{I}", # capital I, grave accent
"igrave" => "\\`{i}", # small i, grave accent
"Iuml" => '\\"{I}', # capital I, dieresis or umlaut mark
"iuml" => '\\"{i}', # small i, dieresis or umlaut mark
"Ntilde" => '\\~{N}', # capital N, tilde
"ntilde" => '\\~{n}', # small n, tilde
"Oacute" => "\\'{O}", # capital O, acute accent
"oacute" => "\\'{o}", # small o, acute accent
"Ocirc" => "\\^{O}", # capital O, circumflex accent
"ocirc" => "\\^{o}", # small o, circumflex accent
"Ograve" => "\\`{O}", # capital O, grave accent
"ograve" => "\\`{o}", # small o, grave accent
"Oslash" => "\\O", # capital O, slash
"oslash" => "\\o", # small o, slash
"Otilde" => "\\~{O}", # capital O, tilde
"otilde" => "\\~{o}", # small o, tilde
"Ouml" => '\\"{O}', # capital O, dieresis or umlaut mark
"ouml" => '\\"{o}', # small o, dieresis or umlaut mark
"szlig" => '\\ss', # small sharp s, German (sz ligature)
"THORN" => '\\L', # capital THORN, Icelandic
"thorn" => '\\l',, # small thorn, Icelandic
"Uacute" => "\\'{U}", # capital U, acute accent
"uacute" => "\\'{u}", # small u, acute accent
"Ucirc" => "\\^{U}", # capital U, circumflex accent
"ucirc" => "\\^{u}", # small u, circumflex accent
"Ugrave" => "\\`{U}", # capital U, grave accent
"ugrave" => "\\`{u}", # small u, grave accent
"Uuml" => '\\"{U}', # capital U, dieresis or umlaut mark
"uuml" => '\\"{u}', # small u, dieresis or umlaut mark
"Yacute" => "\\'{Y}", # capital Y, acute accent
"yacute" => "\\'{y}", # small y, acute accent
"yuml" => '\\"{y}', # small y, dieresis or umlaut mark
);
# Directive mapping table
%_LATEX_HANDLER = (
'tuning', '_LatexHandlerTuning',
'endtuning', '_LatexHandlerEndTuning',
'table', '_LatexHandlerTable',
'row', '_LatexHandlerRow',
'cell', '_LatexHandlerCell',
'endtable', '_LatexHandlerEndTable',
'import', '_LatexHandlerImport',
'inline', '_LatexHandlerInline',
'output', '_LatexHandlerOutput',
'object', '_LatexHandlerObject',
);
# Phrase directive mapping table
%_LATEX_PHRASE_HANDLER = (
'char', '_LatexPhraseHandlerChar',
'import', '_LatexPhraseHandlerImport',
'inline', '_LatexPhraseHandlerInline',
'variable', '_LatexPhraseHandlerVariable',
);
# List states
$_LATEX_LISTLEVEL = 0;
@_LATEX_LISTTYPES = ();
# Table states
$_LATEX_INTABLE = 1;
$_LATEX_INROW = 2;
$_LATEX_INCELL = 3;
##### Variables #####
# Right margin position
$_latex_margin = $SDF_USER'var{'LATEX_MARGIN'} || $_LATEX_DEFAULT_MARGIN;
# Counters for ordered lists - index is the level
@_latex_list_num = 0;
# Table states and row types
@_latex_tbl_state = ();
@_latex_row_type = ();
# Column number & starting positions for current table
$_latex_col_num = 0;
@_latex_col_posn = ();
# Current column number
$_latex_current_col = 1;
# Number of Table columns
$_latex_tab_cols = 0;
# Table column alignment
@_latex_colaligns = ();
# Location of the first line of the current row
$_latex_first_row = 0;
# The current cell text
$_latex_cell_current = '';
# The current verbatim escape char
$_latex_verbatim_open = '';
$_latex_verbatim_close = '';
# Global in example;
$_latex_in_example = 0;
##### Routines #####
#
# >>Description::
# {{Y:LatexFormat}} is an SDF driver which outputs plain text files.
#
sub LatexFormat {
local(*data) = @_;
local(@result);
local(@contents);
# Initialise defaults
$_latex_margin = $SDF_USER'var{'LATEX_MARGIN'} || $_LATEX_DEFAULT_MARGIN;
# Format the paragraphs
@contents = ();
@result = &_LatexFormatSection(*data, *contents);
# Turn into final form and return
return &_LatexFinalise(*result, *contents);
}
#
# >>_Description::
# {{Y:_LatexFormatSection}} formats a set of SDF paragraphs into text.
# If a parameter is passed to contents, then that array is populated
# with a generated Table of Contents.
#
sub _LatexFormatSection {
local(*data, *contents) = @_;
local(@result);
local($prev_tag, $prev_indent);
local($para_tag, $para_text, %para_attrs);
local($directive);
# Process the paragraphs
@result = ();
$prev_tag = '';
$prev_indent = '';
while (($para_text, $para_tag, %para_attrs) = &SdfNextPara(*data)) {
# handle directives
if ($para_tag =~ /^__(\w+)$/) {
$directive = $_LATEX_HANDLER{$1};
if (defined &$directive) {
&$directive(*result, $para_text, %para_attrs);
}
else {
&AppMsg("warning", "ignoring internal directive '$1' in LATEX driver");
}
next;
}
# Add the paragraph
&_LatexParaAdd(*result, $para_tag, $para_text, *para_attrs, $prev_tag,
$prev_indent, *contents);
}
# Do this stuff before starting next loop iteration
continue {
unless ($para_tag eq 'PB') {
$prev_tag = $para_tag;
$prev_indent = $para_attrs{'in'};
}
}
# Return result
return @result;
}
#
# >>_Description::
# {{Y:_LatexParaAdd}} adds a paragraph.
#
sub _LatexParaAdd {
local(*result, $para_tag, $para_text, *para_attrs, $prev_tag, $prev_indent, *contents) = @_;
# local();
local($in_example);
local($para_fmt);
local($para_override);
local($para);
local($hdg_level);
local($toc_jump);
local($label);
# Set the example flag
$in_example = $SDF_USER'parastyles_category{$para_tag} eq 'example';
if ($in_example) {
if ($_latex_in_example eq 0) {
$_latex_in_example = 1;
$para_text = "\\begin\{verbatim\}\n" . $para_text;
}
}
else {
if ($_latex_in_example eq 1) {
$_latex_in_example = 0;
&_LatexParaAppend(*result, "\n\\end\{verbatim\}\n");
}
}
# Enumerated lists are the same as list paragraphs at the previous level
if ($para_tag =~ /^LI(\d)$/) {
$para_tag = $1 > 1 ? "L" . ($1 - 1) : 'N';
}
# Get the target format name
$para_fmt = $SDF_USER'parastyles_to{$para_tag};
$para_fmt = $para_tag if $para_fmt eq '';
# Map the attributes
&SdfAttrMap(*para_attrs, 'latex', *SDF_USER'paraattrs_to,
*SDF_USER'paraattrs_map, *SDF_USER'paraattrs_attrs,
$SDF_USER'parastyles_attrs{$para_tag});
# Build the Table of Contents as we go
if ($para_tag =~ /^[HAP](\d)$/) {
$para_fmt = $para_tag;
}
# Handle lists (is this needed for text format?)
elsif ($para_tag =~ /^(L[FUN]?)(\d)$/) {
$para_attrs{'in'} = $2;
}
# Prepend the label, if any (replacing tabs with spaces)
$label = $para_attrs{'label'};
$label = 'Note: ' if ($para_tag eq 'Note' || $para_tag eq 'NB') &&
$label eq '';
$label =~ s/\\t/ /g;
$para_text = "{{2:$label}}$para_text" if $label ne '';
# Indent examples, if necessary
if ($in_example) {
# do nothing
}
# Format the paragraph body
if ($para_attrs{'verbatim'} || $in_example) {
$para = $para_text;
delete $para_attrs{'verbatim'};
}
else {
$para = &_LatexParaText($para_text);
}
# If we're in a table, prepend the paragraph onto the current cell
if (@_latex_tbl_state) {
if ($para_fmt eq "Line") {
$_latex_cell_current .= "-" x $_latex_cell_width;
return;
}
$_latex_cell_current .= $para;
return;
}
# Build result
if ($para_tag eq 'PB') {
$para = &_LatexElement($para_fmt, $para, %para_attrs);
&_LatexParaAppend(*result, $para);
}
elsif ($in_example && $para_tag eq $prev_tag && !%para_attrs) {
&_LatexParaAppend(*result, $para);
}
else {
$para = &_LatexElement($para_fmt, $para, %para_attrs);
push(@result, $para);
}
}
#
# >>_Description::
# {{Y:_LatexParaText}} converts SDF paragraph text into LATEX.
#
sub _LatexParaText {
local($para_text) = @_;
local($para);
local($state);
local($sect_type, $char_tag, $text, %sect_attrs);
local($added_anchors);
local(@char_fonts);
local($char_font);
local($directive);
# Process the text
$para = '';
$state = 0;
while (($sect_type, $text, $char_tag, %sect_attrs) =
&SdfNextSection(*para_text, *state)) {
# Build the paragraph
if ($sect_type eq 'special') {
$directive = $_LATEX_PHRASE_HANDLER{$char_tag};
if (defined &$directive) {
&$directive(*para, $text, %sect_attrs);
}
else {
&AppMsg("warning", "ignoring special phrase '$1' in LATEX driver");
}
}
elsif ($sect_type eq 'phrase') {
if ($char_tag eq 'L') {
($text, $url) = &SDF_USER'ExpandLink($text);
$sect_attrs{'jump'} = $url;
}
if ($char_tag ne 'E'
&& $SDF_USER'phrasestyles_to{$char_tag} ne 'SDF_VERBATIM') {
# Escape any special characters
$text = &_LatexEscape($text);
}
if ( $SDF_USER'phrasestyles_to{$char_tag} eq 'SDF_VERBATIM') {
_LatexCheckVerbatim($text);
$text = $_latex_verbatim_open . $text;
}
# Expand non-breaking spaces, if necessary
if ($char_tag eq 'S') {
$text =~ s/ /~/g;
}
# Process formatting attributes
&SdfAttrMap(*sect_attrs, 'latex', *SDF_USER'phraseattrs_to,
*SDF_USER'phraseattrs_map, *SDF_USER'phraseattrs_attrs,
$SDF_USER'phrasestyles_attrs{$char_tag});
# Map the font
$char_font = $SDF_USER'phrasestyles_to{$char_tag};
# Add the text for this phrase
push(@char_fonts, $char_font);
if ($char_font ne '' && $char_font !~ /^SDF/) {
$para .= "$char_font$text";
}
else {
$para .= $text;
}
}
elsif ($sect_type eq 'phrase_end') {
$char_font = pop(@char_fonts);
$para .= "}}" if $char_font ne '' && $char_font !~ /^SDF/;
if ($char_font eq 'SDF_VERBATIM') { $para .= $_latex_verbatim_close; }
}
elsif ($sect_type eq 'string') {
$text = &_LatexEscape($text);
$para .= $text;
}
elsif ($sect_type eq 'phrase') {
}
elsif ($sect_type eq 'phrase_end') {
# do nothing
}
else {
&AppMsg("warning", "unknown section type '$sect_type' in LATEX driver");
}
}
# Return result
return $para;
}
#
# >>_Description::
# {{Y:_LatexElement}} formats a LATEX element from a
# tag, text and set of attributes.
#
sub _LatexElement {
local($tag, $text, %attr) = @_;
local($latex);
local($prefix, $label);
local($list_level, $close_list);
local($cnt);
# Handle page breaks
if ($tag eq 'PB') {
return "\\newpage";
}
# For examples, don't word wrap the lines
if ($tag eq 'E') {
$latex = "$text";
}
# For lines, output a 'line'
elsif ($tag eq 'Line') {
$latex = ("_" x $_latex_margin) . "\n";
}
# For headings, underline the text
elsif ($tag =~ /^[HAP](\d)/) {
while ($_LATEX_LISTLEVEL gt 0) {
$close_list .= "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n";
$_LATEX_LISTLEVEL--;
}
$latex = $close_list . "\n" . "$SDF_USER'parastyles_to{$tag}\{$text\}\n";
# . ($char x length("$SDF_USER'parastyles_to{$tag}\{$text\}\n")) . "\n";
}
# For list items, add the necessary "label"
elsif ($tag =~ /^(L[FUN]?)(\d)$/) {
$ list_level = $2;
#> $prefix = " " x ($2 * 5);
#> $label = " " x (($2 - 1) * 5);
if ($1 eq 'LU') {
if ($_LATEX_LISTLEVEL lt $list_level) {
$label = "\\begin\{itemize\} \% Level $list_level\n";
$_LATEX_LISTLEVEL = $list_level;
@_LATEX_LISTTYPES[$list_level] = "itemize";
}
elsif ($_LATEX_LISTLEVEL gt $list_level) {
$label = "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n";
$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL] = "";
$_LATEX_LISTLEVEL = $list_level;
}
$label .= "\\item ";
}
elsif ($1 eq 'L') {
if ($_LATEX_LISTLEVEL lt $list_level) {
$label = "\\begin\{list\}\{\ \}\{\} \% Level $list_level\n";
$_LATEX_LISTLEVEL = $list_level;
@_LATEX_LISTTYPES[$list_level] = "list";
}
elsif ($_LATEX_LISTLEVEL gt $list_level) {
$label = "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n";
$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL] = "";
$_LATEX_LISTLEVEL = $list_level;
}
$label .= "\\item ";
}
elsif ($1 eq 'LF') {
if ($_LATEX_LISTLEVEL lt $list_level) {
$label = "\\begin\{enumerate\} \% Level $list_level\n";
$_LATEX_LISTLEVEL = $list_level;
@_LATEX_LISTTYPES[$list_level] = "enumerate";
}
elsif ($_LATEX_LISTLEVEL gt $list_level) {
$label = "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n";
$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL] = "";
$_LATEX_LISTLEVEL = $list_level;
}
$label .= "\\item ";
}
else {
if ($_LATEX_LISTLEVEL lt $list_level) {
$label = "\\begin\{enumerate\} \% Level $list_level\n";
$_LATEX_LISTLEVEL = $list_level;
@_LATEX_LISTTYPES[$list_level] = "enumerate";
}
elsif ($_LATEX_LISTLEVEL gt $list_level) {
$label = "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n";
$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL] = "";
$_LATEX_LISTLEVEL = $list_level;
}
$label .= "\\item ";
}
$latex = &MiscTextWrap($label . $text, $_latex_margin, $prefix,
'', 1) . "\n";
}
# Otherwise, format as a plain paragraph
else {
while ($_LATEX_LISTLEVEL gt 0) {
$close_list .= "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n";
$_LATEX_LISTLEVEL--;
}
$latex = &MiscTextWrap($close_list . "\n" . $text, $_latex_margin, '', '', 1) . "\n";
}
# Handle the top attribute
return $para{'top'} ? "\f\n$latex" : $latex;
}
#
# >>_Description::
# {{Y:_LatexParaAppend}} merges {{para}} into the last paragraph
# in {{@result}}. Both paragraphs are assumed to be examples.
#
sub _LatexParaAppend {
local(*result, $para) = @_;
# local();
$result[$#result] .= "$para\n";
}
#
# >>_Description::
# {{Y:_LatexHandlerTuning}} handles the 'tuning' directive.
#
sub _LatexHandlerTuning {
local(*outbuffer, $style, %attr) = @_;
# local();
# do nothing
}
#
# >>_Description::
# {{Y:_LatexHandlerEndTuning}} handles the 'endtuning' directive.
#
sub _LatexHandlerEndTuning {
local(*outbuffer, $style, %attr) = @_;
# local();
# do nothing
}
#
# >>_Description::
# {{Y:_LatexHandlerTable}} handles the 'table' directive.
#
sub _LatexHandlerTable {
local(*outbuffer, $columns, %attr) = @_;
local($tmp, $close_list, $coldim);
local($tbl_title);
$_latex_tab_cols = $columns;
$coldim = (1 / $columns) - 0.02;
# Close all yet open lists
$close_list = "";
while ($_LATEX_LISTLEVEL gt 0) {
$close_list .= "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n";
$_LATEX_LISTLEVEL--;
}
push(@outbuffer, $close_list . "\n\n");
# Update the state
push(@_latex_tbl_state, $_LATEX_INTABLE);
push(@_latex_row_type, '');
# Calculate the column positions (rounded)
@_latex_col_posn = &SdfColPositions($columns, $attr{'format'}, $_latex_margin);
@_latex_colaligns = split(/,/, $attr{'colaligns'});
# Add the title, if any
$tbl_title = $attr{'title'};
if ($tbl_title ne '') {
push(@outbuffer, "\\begin\{table\}\[H\]\n\\caption\[$tbl_title\]\{$tbl_title\}\n");
}
else {
push(@outbuffer, "\\begin\{table\}\[H\]\n");
}
push(@outbuffer, "\\begin\{center\}\n\\begin\{tabular\}");
$outbuffer[$#outbuffer] .= "\{";
if ($attr{'style'} ne 'plain' && $attr{'style'} ne 'rows') {
$outbuffer[$#outbuffer] .= "|";
}
foreach $tmp (1..$_latex_tab_cols) {
$outbuffer[$#outbuffer] .=
"c";
# "\@\{\\hspace\{.01\\linewidth\}\}p\{$coldim\\linewidth\}\@\{\\hspace\{.01\\linewidth\}\}";
if ($attr{'style'} ne 'plain' && $attr{'style'} ne 'rows') {
$outbuffer[$#outbuffer] .= "|";
}
}
$outbuffer[$#outbuffer] .= "\}";
if ($attr{'style'} ne 'plain') {
push(@outbuffer, "\\hline");
}
push(@outbuffer,"%% -> attribute format = $attr{'format'}");
push(@outbuffer,"%% -> attribute colaligns = $attr{'colaligns'}");
}
#
# >>_Description::
# {{Y:_LatexHandlerRow}} handles the 'row' directive.
#
sub _LatexHandlerRow {
local(*outbuffer, $text, %attr) = @_;
# local();
local($current_state);
# Finalise the previous row, if any
$current_state = $_latex_tbl_state[$#_latex_tbl_state];
unless ($current_state eq $_LATEX_INTABLE) {
&_LatexFinalisePrevRow(*outbuffer, $_latex_row_type[$#_latex_row_type]);
}
# Start the new row
push(@outbuffer, "");
$_latex_col_num = 0;
$_latex_first_row = $#outbuffer;
# Update the state
$_latex_tbl_state[$#_latex_tbl_state] = $_LATEX_INROW;
$_latex_row_type[$#_latex_row_type] = $text;
# push(@outbuffer,"%% -> Starting row type $text\n");
}
#
# >>_Description::
# {{Y:_LatexHandlerCell}} handles the 'cell' directive.
#
sub _LatexHandlerCell {
local(*outbuffer, $text, %attr) = @_;
# local();
local($state);
local($padding);
local($tmp);
# Finalise the old cell, if any
$state = $_latex_tbl_state[$#_latex_tbl_state];
if ($state eq $_LATEX_INCELL) {
&_LatexFinishCell(*outbuffer);
# if ($_latex_col_num > 0) {
# foreach $tmp ($_latex_first_row .. $#outbuffer) {
# $padding = $_latex_col_posn[$_latex_col_num - 1] -
# length($outbuffer[$tmp]);
# $padding = 1 if ($padding <= 0);
# $outbuffer[$tmp] .= " " x $padding;
# }
# }
}
# Update the state
$_latex_tbl_state[$#_latex_tbl_state] = $_LATEX_INCELL;
$_latex_cell_margin = ($_latex_col_num>0?$_latex_col_posn[$_latex_col_num-1]:0);
$_latex_col_num+=$attr{cols};
if ($_latex_col_num > $#_latex_col_posn + 1) {
$_latex_cell_width = $_latex_margin - $_latex_cell_margin - 1;
} else {
$_latex_cell_width = $_latex_col_posn[$_latex_col_num-1] -
$_latex_cell_margin - 1;
}
%_latex_cell_attrs = %attr;
$_latex_cell_current = "";
}
#
# >>_Description::
# {{Y:_LatexFinishCell}} adds the cell text to the output
#
sub _LatexFinishCell {
local(*outbuffer) = @_;
$_latex_cell_current =~ s/\s+/ /g;
local @lines = split(/\n/,
&MiscTextWrap($_latex_cell_current, $_latex_cell_width,"",'',1));
local $tmp;
# foreach $tmp ($#outbuffer+1..$_latex_first_row+$#lines) {
# push(@outbuffer, " " x $_latex_cell_margin);
# }
if ($#lines == 0) {
if ($_latex_cell_attrs{'align'} eq "Center") {
$outbuffer[$#outbuffer] .=
"\{\\centering $lines[$#lines]\}";
} elsif ($_latex_cell_attrs{'align'} eq "Right") {
$outbuffer[$#outbuffer] .=
"\{\\raggedright $lines[$#lines]\}";
} else {
$outbuffer[$#outbuffer] .=
"\{\\raggedleft $lines[$#lines]\}";
}
if ($_latex_col_num < $_latex_tab_cols) {
$outbuffer[$#outbuffer] .= " & ";
}
} else {
if ($_latex_cell_attrs{'align'} eq "Center") {
$outbuffer[$#outbuffer] .=
"\{\\centering ";
} elsif ($_latex_cell_attrs{'align'} eq "Right") {
$outbuffer[$#outbuffer] .=
"\{\\raggedright ";
} else {
$outbuffer[$#outbuffer] .=
"\{\\raggedleft ";
}
foreach $tmp (0..$#lines) {
$outbuffer[$#outbuffer] .= " $lines[$tmp] ";
}
$outbuffer[$#outbuffer] .= "\}";
if ( $_latex_col_num < $_latex_tab_cols ) {
$outbuffer[$#outbuffer] .= " \& ";
}
}
$_latex_cell_current = "";
$_latex_current_col++;
}
#
# >>_Description::
# {{Y:_LatexHandlerEndTable}} handles the 'endtable' directive.
#
sub _LatexHandlerEndTable {
local(*outbuffer, $text, %attr) = @_;
# local();
local($state);
local($row_type);
# Finalise the table
$state = pop(@_latex_tbl_state);
$row_type = pop(@_latex_row_type);
if ($state eq $_LATEX_INCELL) {
&_LatexFinalisePrevRow(*outbuffer, $row_type);
$outbuffer[$#outbuffer] .= "\n";
}
elsif ($state eq $_LATEX_INROW) {
&_LatexFinalisePrevRow(*outbuffer, $row_type);
$outbuffer[$#outbuffer] .= "\n";
}
if ($attr{'style'} ne 'plain') {
push(@outbuffer,"\\hline\n");
}
push(@outbuffer, "\\end\{tabular\}\n\\end\{center\}\n\\end\{table\}\n");
}
#
# >>_Description::
# {{Y:_LatexFinalisePrevRow}} finalises the previous row, if any.
#
sub _LatexFinalisePrevRow {
local(*outbuffer, $row_type) = @_;
# local();
local($line_row);
local($prefix);
local($tmp);
local($_);
&_LatexFinishCell(*outbuffer);
foreach $tmp ($_latex_first_row..$#outbuffer) {
$outbuffer[$tmp] =~ s/ *(\n*)$/$1/;
}
# If the last row was a heading, underline it
$outbuffer[$#outbuffer] .= "\\\\";
if ($row_type ne 'Heading') {
# while (< $_latex_col_num) {
# $outbuffer[$#outbuffer] .= " \& \{\}";
# $_latex_col_num++;
# }
} else {
$line_row = "";
if ($attr{'style'} ne 'plain') {
$line_row = "\\hline";
if ($attr{'style'} eq 'grid') {
$line_row .= "\\hline";
}
}
push(@outbuffer, $line_row);
}
}
#
# >>_Description::
# {{Y:_LatexHandlerImport}} handles the import directive.
#
sub _LatexHandlerImport {
local(*outbuffer, $filepath, %attr) = @_;
# local();
local($para);
# Build the result
&_LatexPhraseHandlerImport(*para, $filepath, %attr);
push(@outbuffer, "$para\n");
}
#
# >>_Description::
# {{Y:_LatexHandlerInline}} handles the inline directive.
#
sub _LatexHandlerInline {
local(*outbuffer, $text, %attr) = @_;
# local();
# Check we can handle this format
my $target = $attr{'target'};
return unless $target eq 'latex' || $target eq 'text';
# Build the result
push(@outbuffer, $text);
}
#
# >>_Description::
# {{Y:_LatexHandlerOutput}} handles the 'output' directive.
#
sub _LatexHandlerOutput {
local(*outbuffer, $text, %attrs) = @_;
# local();
# do nothing
}
#
# >>_Description::
# {{Y:_LatexHandlerObject}} handles the 'object' directive.
#
sub _LatexHandlerObject {
local(*outbuffer, $text, %attrs) = @_;
# local();
# Save the margin, if necessary
if ($text eq 'Variable' && $attrs{'Name'} eq 'LATEX_MARGIN') {
$_latex_margin = $attrs{'value'};
}
}
#
# >>_Description::
# {{Y:_LatexPhraseHandlerChar}} handles the 'char' phrase directive.
#
sub _LatexPhraseHandlerChar {
local(*para, $text, %attr) = @_;
# local();
# Map those we know about it
if (defined($_LATEX_CHAR{$text})) {
$para .= $_LATEX_CHAR{$text};
}
else {
$para .= $text;
}
}
#
# >>_Description::
# {{Y:_LatexPhraseHandlerImport}} handles the 'import' phrase directive.
#
sub _LatexPhraseHandlerImport {
local(*para, $filepath, %attr) = @_;
# local();
local($name, $value);
$para .= "** Unable to import figure $filepath **";
}
#
# >>_Description::
# {{Y:_LatexPhraseHandlerInline}} handles the 'inline' phrase directive.
#
sub _LatexPhraseHandlerInline {
local(*para, $text, %attr) = @_;
# local();
# Build the result
$para .= $text;
}
#
# >>_Description::
# {{Y:_LatexPhraseHandlerVariable}} handles the 'variable' phrase directive.
#
sub _LatexPhraseHandlerVariable {
local(*para, $text, %attr) = @_;
# local();
# do nothing
}
#
# >>_Description::
# {{Y:_LatexFinalise}} generates the final LaTeX file.
#
sub _LatexFinalise {
local(*body, *contents) = @_;
# local(@result);
local($title, @sdf_title, @title);
local($version, @head);
local($body);
local($macro, @header, @footer);
local(@dummy);
local($rec, @html_contents, $toc_posn);
# Convert the title
$title = $SDF_USER'var{'DOC_NAME'};
$author = $SDF_USER'var{'DOC_AUTHOR'};
$date = $SDF_USER'var{'DOC_DATE'};
# Build the HEAD element (and append BODY opening)
$version = $SDF_USER'var{'SDF_VERSION'};
@head = (
'%%% This file was generated using SDF $version by',
'%%% Ian Clatworthy (ianc@mincom.com) and the 2latex_ driver',
'%%% $Id: tolatex.pl,v 1.1.1.2 1998/03/22 09:39:20 valerio Exp valerio $',
'%%% written by Valerio Aimale <valerio@svpop.com.dist.unige.it>.',
'%%% SDF is freely available from http://www.mincom.com/mtr/sdf',
''
);
push(@head, '\author{'. $author . '}') if $author;
push(@head, '\date{'. $date . '}') if $date;
push(@head, '\title{'. $title . '}') if $title;
push(@head, '','');
push(@head, '\begin{document}', '');
push(@head, '\maketitle') if $title;
# If requested, provide a Table of Contents
if (@contents) {
push(@head, '\tableofcontents');
}
# Close eventually open lists
while ($_LATEX_LISTLEVEL gt 0) {
push(@body, '', "\\end\{$_LATEX_LISTTYPES[$_LATEX_LISTLEVEL]\}\n");
$_LATEX_LISTLEVEL--;
}
# Return result
push(@body, '', '\end{document}');
return (@head, @body);
}
#
# >>_Description::
# {{Y:_LatexEscape}} escapes special symbols in LaTeX text.
#
sub _LatexEscape {
local($text) = @_;
# local($result);
local($old_match_flag);
# Enable multi-line matching
$old_match_flag = $*;
$* = 1;
# Escape the special symbols. Note that it isn't exactly clear
# from the SGML-Tools and/or QWERTZ DTD documentation as to
# whether all of these are mandatory, but they shouldn't cause
# any harm (I hope!)
$text =~ s/\\/\\verb+\\+/g;
$text =~ s/\&/\\\&/g;
$text =~ s/\</\$<\$/g;
$text =~ s/\>/\$>\$/g;
$text =~ s/\"/"/g;
$text =~ s/\$/\\\$/g;
$text =~ s/\~/\\verb+~+/g;
$text =~ s/\^/\\verb+^+/g;
$text =~ s/\#/\\\#/g;
$text =~ s/\%/\\\%/g;
$text =~ s/_/\\\_/g;
$text =~ s/\|/\|/g;
$text =~ s/\[/\$[\$/g;
$text =~ s/\]/\$]\$/g;
$text =~ s/\{/\\\{/g;
$text =~ s/\}/\\\}/g;
# Reset multi-line matching flag
$* = $old_match_flag;
# Return result
$text;
}
#
# >>_Description::
# {{Y:_LatexCheckVerbatim}} checks for un unsed che in the phrase
#
sub _LatexCheckVerbatim {
local($text) = @_;
local($match);
# local($_i);
for (33..127) {
$match = chr;
if ($text =~ /$match/) {
;
}
else {
$_latex_verbatim_open = '\verb' . $match;
$_latex_verbatim_close = $match;
return;
}
}
$_latex_verbatim_open = '\begin{verbatim}';
$_latex_verbatim_close = '\end{verbatim}';
return;
}
# package return value
1;