# $Id: am2dvi.pl,v 1.2 2000/08/21 18:45:01 tomek Exp $
####################################
# Konwersja DocBook ARTICLE -> PostScript/PDF
# Autor skryptu: Tomasz Przechlewski
# Data 17/07/2000 ***Ostatnie poprawki: 18/08/2000 ***
####################################

use SGMLS;
use SGMLS::Output;
use SGMLS::Refs; # Tylko na potrzeby bibliografii

my $DocColor = 'color'; # Domyślna wartość opcji
my $PageSize = 'A4page'; # Domyślna wielkość strony
my $TeXOutput = ''; # Domyślnie DVI, może być PDF

#  Sprawdzamy parametry z linii poleceń: /////////////////////
#
while ($_ = shift) { 
  if (/^--nocolor/) { $DocColor='nocolor' } 
  if (/^--B5/) { $PageSize='B5page' } 
  if (/^--A4/) { $PageSize='A4page' } 
  if (/^--makepdf/) { $TeXOutput=',makepdf' } 
}

my $Options = "$DocColor,$PageSize$TeXOutput"; #

my $latex_verb_seps='+|@?!'; # potencjalne znaki separujące polecenia `\verb'
my $strangechars = "[\\_#\$%^&{}~]"; # TeX strange chars ---
my $GawkExSym = "{\\GawkEx}"; # oznaczenie rozszerzeń gawk-a
my $UserDfSym = "{\\UserDf}"; # oznaczenie funkcji użytkownika

#  Document Handlers. ////////////////////////////////////////
#
sgml('start',sub { $Refs = new SGMLS::Refs('awk-man.refs'); });
sgml('end', sub { $Refs->warn; });

# Element Handlers. //////////////////////////////////////////
#
sgml('<ARTICLE>', sub {
  my $paper = 'A4page'; # Domyślnie
  $paper = 'b5paper' if ($PageSize eq 'B5page');

  output ( "\\documentclass[$paper,twoside,titlepage]{article}\n" );
  output ( "\\usepackage[$Options]{awk-man}\n\\makeindex\n" );
  output ( "%\\catcode`\\%\\active\\def%{\\%}\n\\begin{document}\n" );

});

sgml('</ARTICLE>', "\\end{document}");

sgml('<ARTHEADER>', "");

sgml('</ARTHEADER>', sub {

  #  if (defined $bibliomisc) { output ("\n\\title{$articletitle\\thanks{$bibliomisc}}\n") }
  #  else { output ("\n\\title{$articletitle}\n") }
  output ("\n\\title{$articletitle}\n");

  # Drukowanie imion/nazwisk autorów:
  output ("\\author{");  my $i;

  for ( $i=0; $i <= $#authors; $i++ ) { 
     my $a = ${$authors[$i]}{'firstname'}  . ' ' . ${$authors[$i]}{'surname'};
     my $e = ${$authors[$i]}{'email'};
     if ( $i < $#authors ) { output ("$a\\and\n");  $signature .= "$a, "; }
     else { output ("$a}\n");  $signature .= "$a"; }     
  }

  # *** Tytuł i spis treści: ***
  output ("\\maketitle\n");
  output ("\\begin{legalnotice}\n");
  output ("$bibliomisc\\par\\vfill\n")  if ($bibliomisc) ;
  output ("Copyright (C) $copyright\n\\bigskip\n");
  output ("$legalnotice\n\\end{legalnotice}\n\\newpage");
  output ("\\tableofcontents\n\\newpage"); 

  @authors=(); # zawartość tablicy już niepotrzebna
  undef $articletitle; # ditto, tytuł artykułu...
  undef $bibliomisc; 

});  # ditto, podziękowania itp...

# Element `TITLE'. //////////////////////////////////////////
#
sgml('<TITLE>',\&push ); 

sgml('</TITLE>', sub {
    my $element=shift;
    my $t;

    $t=pop_output;
    $_=$element->parent->name;

    # Pobranie warto/sci atrybutu id elementu, kt/ory zawiera `title'
    my $label=$element->parent->attribute(ID)->value;

  TITLE: {
      /ARTHEADER/ and do { $articletitle = $t; last TITLE };
      /SECT1/ and do { 
             if ($label ne '') {
               $t="\n\\section{$t\\label\{$label\}}\n";
             } 
             else { 
               $t="\n\\section{$t}\n";
             }
             output $t;
             last TITLE 
      };
      /SECT2/ and do { 
             if ($label ne '') {
                $t="\n\\subsection{$t\\label\{$label\}}\n"; 
	     }
	     else {
                $t="\n\\subsection{$t}\n"; 
             }
             output $t;
             last TITLE 
       };

      /EXAMPLE/ and do { 
           $t="\n\\ExampleTitle ";   output $t; # 
           last TITLE };

      /VARIABLELIST/ and do { 
           $t="\\centerline{\\bf $t}\\par\\nobreak\\smallskip\\hrule\\par\\nobreak\\smallskip\n";
           output $t;
           last TITLE };

      /FIGURE/ and do { my $num = &counter($_);
                           $t="\\caption\{$t\}\n";
                           $figcap=$t; 
                           undef $t;
			   output $t;
                           last TITLE };
      /TABLE/ and do { 
               $t = "\\centerline{\\bf $t}\\par\\nobreak\n\\smallskip\\hrule \\par\\nobreak\\smallskip\n";
               output $t;
               last TITLE };
      /BIBLIOENTRY/ and do { 
          # Tytuł jest drukowany po napotkaniu `/BIBLIOENTRY'
          # Tutaj go tylko zapamiętujemy
          $booktitle =$t; 
          last TITLE };
      /BIBLIOSET/ and do { 
          my $what = $element->parent->attribute(RELATION)->value;
      
          $articletitle = $t if ($what eq 'article');
          $journaltitle = $t if ($what eq 'journal');
          last TITLE 
      };

  }

});


# Bibliografia i odsyłacze bibliograficzne /////////////////
#
sgml('<CITATION>', \&push);

sgml('</CITATION>', sub{ &getcontents;
    output("\\cite{$citation}");
});

sgml('<BIBLIOGRAPHY>', sub {
    # Liczbę pozycji w spisie literatury znajdujemy w drugim przebiegu. 
    #W pierwszym przyjmujemy `9', co na jedno wychodzi:-)
    my $b = $Refs-> get('BibNum') || 9 ;
    output ("\n\\begin{thebibliography}{$b}\n");
    output ("\\addcontentsline{toc}{section}{Bibliografia}\n"); });

sgml('</BIBLIOGRAPHY>', sub { 
    output ( "\\end{thebibliography}\n");
    $Refs-> put("BibNum", $bib_ent_total); });

sgml('<BIBLIOENTRY>', sub {
    my $element = shift;
    my $label = $element ->attribute('XREFLABEL')->value;
    output ("\\bibitem{$label}\n");
    $bib_ent_total++; # Liczba pozycji w spisie
 });

sgml('</BIBLIOENTRY>', sub {
    my $i;
    # Autorzy
    for ( $i=0; $i <= $#authors; $i++ ) { 
      my $a = ${$authors[$i]}{'surname'}  . ' ' . ${$authors[$i]}{'firstname'};
      my $e = ${$authors[$i]}{'email'};
      if ( $i < $#authors ) { output ("$a,\n"); }
      else { output ("$a:\n"); }
    }
    # Formatowanie pozycji typu: książka
    if ($booktitle) {
      output("\\textit{$booktitle}");
      output(",\n$publishername") if $publishername;
  
      if ($pubdate && $publishername) { output("\n$pubdate")  }
      else { if ($pubdate ) {output(",\n$pubdate") } }

      output(".\n$bibliomisc") if $bibliomisc;
      output(".\n");
    }
    # Formatowanie pozycji typu: artykuł
    if ($articletitle ) {
      output("\\textrm{$articletitle}, \\textit{$journaltitle}");
  
    if ($volumenum && $pubdate) { output("\n$volumenum/$pubdate")  }
    else { if ($pubdate ) {output(",\n$pubdate") } }

    output(",\ns.~$pagenums") if $pagenums;
    output(",\n$bibliomisc") if $bibliomisc;
    output(".\n");

  }
  
  @authors=(); # tablica jest już niepotrzebna

  undef $booktitle;
  undef $publishername;
  undef $pubdate;
  undef $bibliomisc;

  undef $articletitle;
  undef $journaltitle;

  undef $pagenums;
  undef $volumenum;

});

sgml('<AUTHOR>', "");

sgml('</AUTHOR>', sub {
  push(@authors, {'surname'  => $surname,
                  'firstname' => $firstname,
                  'email'     => $email} );
});

sgml('<AUTHORGROUP>', \&push);
sgml('</AUTHORGROUP>', \&getcontents);

sgml('<FIRSTNAME>', \&push);
sgml('</FIRSTNAME>', \&getcontents);

sgml('<CORPAUTHOR>', \&push);
sgml('</CORPAUTHOR>', \&getcontents);

sgml('<EDITION>', \&push);
sgml('</EDITION>', \&getcontents);

sgml('<ISSN>', \&push);
sgml('</ISSN>', \&getcontents);

sgml('<PUBLISHERNAME>', \&push);
sgml('</PUBLISHERNAME>', \&getcontents);

sgml('<OTHERNAME>', \&push);
sgml('</OTHERNAME>', \&getcontents);

sgml('<SURNAME>', \&push);
sgml('</SURNAME>', \&getcontents);

sgml('<PUBDATE>', \&push);
sgml('</PUBDATE>', \&getcontents);

sgml('<VOLUMENUM>', \&push);
sgml('</VOLUMENUM>', \&getcontents);

sgml('<PAGENUMS>', \&push);
sgml('</PAGENUMS>', \&getcontents);

sgml('<DATE>', \&push);
sgml('</DATE>', \&getcontents);

sgml('<ADDRESS>', \&push);
sgml('</ADDRESS>', \&getcontents);

sgml('<ABSTRACT>', "\n\\begin{abstract}\n");
sgml('</ABSTRACT>', "\\end{abstract}\n");

sgml('<CITY>', \&push);
sgml('</CITY>', \&getcontents);

sgml('<EMAIL>', \&push);
sgml('</EMAIL>', \&getcontents);

sgml('<LEGALNOTICE>', \&push);
sgml('</LEGALNOTICE>', \&getcontents);

sgml('<COPYRIGHT>', \&push);
sgml('</COPYRIGHT>', \&getcontents);

sgml('<HOLDER>', \&push);
sgml('</HOLDER>', sub { 
   my $element=shift;
   my $holder =pop_output;
   if ($element->within(COPYRIGHT) ) { output "\\CopHolder{$holder}\n"; } });

sgml('<YEAR>', \&push);
sgml('</YEAR>', sub { 
    my $element=shift;
    my $y =pop_output;
    if ($element->within(COPYRIGHT) ) { output "\\CopYear{$y}\n"; } });

sgml('<BIBLIOMISC>', sub { my $element=shift;
    my $parent=$element->parent->name;  push_output 'string';} );

sgml('</BIBLIOMISC>', sub { my $element=shift; 
    $bibliomisc = pop_output;});

# Różne elementy typu: `inline' /////////////////////////////////
#
sgml('<PARA>', sub {
    my $element=shift;
    $para_num++;
    if (($element->within(FOOTNOTE) || $element->within(NOTE)) )
      { if ( $para_num != 1 ) { output "\n\n"; }}
    else { output "\n"; }
});

sgml('</PARA>', sub {
    my $element=shift;
    if ($element->within(FOOTNOTE) || $element->within(NOTE)) { ; }
    else { output "\n"; }
});

sgml('<NOTE>', sub { undef $para_num; output "\\begin{Notes}\n" } );
sgml('</NOTE>', sub { output "\n\\end{Notes}\n" } );

sgml('<FOREIGNPHRASE>', "ang. {\\it ");
sgml('</FOREIGNPHRASE>', "}");

sgml('<EMPHASIS>', "\\emph{");
sgml('</EMPHASIS>', "}");

# Różne elementy typu: `block' ////////////////////////////////////
#

    # \end{verbatim} bez końca wiersza na końcu!
sgml('<PROGRAMLISTING>', sub { output("\\begin{verbatim}\n") }); 
sgml('</PROGRAMLISTING>', sub { output ("\n\\end{verbatim}") });

sgml('<LITERALLAYOUT>', sub { output("\\begin{verbatim}\n") }); 
sgml('</LITERALLAYOUT>', sub { output ("\n\\end{verbatim}") });

sgml('<EXAMPLE>', sub {
    my $element=shift;
    my $label=$element->attribute(ID)->value;
    output ("\n\\begin\{example\}\n\\ExampleId{$label}");
 });

sgml('</EXAMPLE>', sub { output ("\\end\{example\}\n"); });


# Skorowidz ////////////////////////////////////////////////////
#
sgml('<INDEX>',"\n\\begin{IndexPre}");

sgml('</INDEX>',sub {
   output ("\\end{IndexPre}\n");
   output ("\\def\\indexspace{\\par \\vskip 6pt plus 3pt minus 1.5pt\\relax}\n");
   output ("\\printindex\n\\clearpage\n");
});

sgml('<INDEXTERM>', \&push);

sgml('</INDEXTERM>', sub{
    my $element=shift;
    my $indexterm = pop_output;
    #
    $indexterm =~ s/[ \t]*$//g; # usuń spacje na końcu napisu
    $indexterm =~ s/^[ \t]*//g; # oraz na początku napisu!

    $indexterm =~ s/\\verb([$latex_verb_seps])([^\1]+)\1/$2\@$&/;
    $indexterm =~ s/\\texttt\{([^{}]+)\}/$1\@$&/;

    output ("\\index{$indexterm}");
});

sgml('<PRIMARY>', "");
sgml('</PRIMARY>', "");

sgml('<SECONDARY>', "!");
sgml('</SECONDARY>', "");


# Wyliczanki //////////////////////////////////////////////
#
sgml('<ITEMIZEDLIST>', "\\begin{itemize}\n");
sgml('</ITEMIZEDLIST>', "\\end{itemize}\n");

sgml('<ORDEREDLIST>', "\\begin{enumerate}\n");
sgml('</ORDEREDLIST>', "\\end{enumerate}\n");

sgml('<LISTITEM>', sub {
    my $element=shift;
    my $parent=$element->parent->name;
    if ($parent ne 'VARLISTENTRY') { output "\\item "; }
});

sgml('</LISTITEM>', "");

sgml('<VARIABLELIST>', "\\summary\n");
sgml('</VARIABLELIST>', "\\endsummary\n");

sgml('<TERM>', "\\itm ");
sgml('</TERM>', "\\desc");

# Elementy składane imitacją pisma maszynowego  ///////////////
#
sgml('<OPTION>', \&push);
sgml('</OPTION>', \&print_verbatim);

sgml('<COMMAND>', \&push);
sgml('</COMMAND>', \&print_verbatim);

sgml('<LITERAL>', \&push ); 
sgml('</LITERAL>', \&print_verbatim); 

sgml('<VARNAME>', \&push ); 
sgml('</VARNAME>', \&print_verbatim); 

sgml('<FUNCTION>', \&push );
sgml('</FUNCTION>', \&print_verbatim); 

sgml('<FILENAME>', \&push );
sgml('</FILENAME>', \&print_verbatim); 

sgml('<APPLICATION>', \&push );
sgml('</APPLICATION>', \&print_verbatim );

    # USERINPUT jest zawsze wewnątrz LITERAL albo PROGRAMLISTING
    # nie wymaga zatem żadnego dodatkowego formatowania
sgml('<USERINPUT>', "");
sgml('</USERINPUT>', "");

sgml('<PARAMETER>', "<");
sgml('</PARAMETER>', ">");

    # Zakładamy, że `REPLACEABLE' i `OPTIONAL' występują zawsze
    # wewnątrz elementów składanych ,,verbatim''
sgml('<REPLACEABLE>', sub { output ("\177"); });
sgml('</REPLACEABLE>', sub { output ("\177"); });

sgml('<OPTIONAL>', sub { output ("\177["); });
sgml('</OPTIONAL>', sub {  output ("]\177"); });

# Przypisy i odsyłacze /////////////////////////////////////
#
sgml('<FOOTNOTE>', sub{ undef $para_num; output("\\footnote{"); });
sgml('</FOOTNOTE>', "}");

sgml('<XREF>', sub {
     my $element=shift;
     my $linkend=$element->attribute(LINKEND)->value;
     my $role= lc($element->attribute(ROLE)->value);
     if ($role eq 'ex') { output("\\ref{$linkend} (s.~\\pageref{$linkend})"); }
     else { output("\\ref{$linkend}"); }
});
sgml('</XREF>', "");

# Element: ULINK
sgml('<ULINK>', sub {
   my $element = shift;
   #my $uri = $element ->attribute('URL')->value;
   #output ("\\url{$uri}") if $uri;
   $uri = $element ->attribute('URL')->value;
   &push;
});
#sgml('</ULINK>', "")
sgml('</ULINK>', sub {
   my $uritext =pop_output;
   $uritext =~ s/^[ \t\n]$//gs; # usuń wszystkie odstępy

   if ($uritext eq '') { output "\\url{$uri}" }
   else { output "$uritext" if ( $TeXOutput eq '' ); # normalny TeX
      output "\\href{$uri}{$uritext}" if ( $TeXOutput eq ',makepdf' ) } # PDF

});

# Tabele /////////////////////////////////////////////////////
#
sgml('<ROW>', sub { $entry=0; output "\n"; });
sgml('</ROW>', sub { output "\\cr"; });

sgml('<ENTRY>', sub {
       my $element=shift;
       my $align=$element->attribute('ALIGN')->value;
       output "&" if $entry;
       output lc("\\$align\{") if $align;
       $entry++;
     });

sgml('</ENTRY>', sub {
       my $element=shift;
       my $align=$element->attribute('ALIGN')->value;
       output "\}" if $align;
     });

sgml('<TBODY>', "");
sgml('</TBODY>', "");

sgml('<THEAD>', "");
sgml('</THEAD>', "\\noalign{\\vskip2pt\\hrule\\vskip2pt}");

sgml('<INFORMALTABLE>', "\\hbox to \\hsize{\\hfill");
sgml('</INFORMALTABLE>', "\\hfill}");

sgml('<TABLE>', "\\summary\n");
sgml('</TABLE>', "\\endsummary\n");

sgml('<TGROUP>', sub {
       my $element=shift;
       my $cols=$element->attribute('COLS')->value; # liczba kolumn
       output ("\\halign to\\hsize{\\tabskip0em plus9em#\\hss&&\\quad#\\hss\\cr");
     });
sgml('</TGROUP>', sub { output "}"; });

# Podział logiczny dokumentu

sgml('<SECT1>', "");
sgml('</SECT1>', "");

sgml('<SECT2>', "");
sgml('</SECT2>', "");

sgml('<SECT3>', "");
sgml('</SECT3>', "");

# SDATA Handlers //////////////////////////////////////////////////
#
sgml('|[deg   ]|', "\$^\\circ\$");
sgml('|[minus ]|', "\$-\$");
sgml('|[percen]|', "\\%");
sgml('|[hellip]|', "\\ldots");
sgml('|[tilde ]|', "\\(\\tilde{}\\)");
sgml('|[bsol  ]|', "\\(\\backslash\\)");
sgml('|[num   ]|', "#");
sgml('|[rcub  ]|', "\\}");
sgml('|[lcub  ]|', "\\{");
sgml('|[mdash ]|', "--");
sgml('|[ndash ]|', "--");
sgml('|[amp   ]|', "&");
sgml('|[lt    ]|', "<");
sgml('|[gt    ]|', ">");
sgml('|[nbsp  ]|','~');
sgml('|[vspace]|','~'); # visible space// rozwiązanie tymczasowe //
sgml('|[gawkex]|',"$GawkExSym"); # visible space
sgml('|[userex]|',"$UserDfSym"); # visible space


# Procedury pomocnicze //////////////////////////////////////////
#
sub push{ my $element=shift; push_output 'string'; }

sub getcontents{ my $element=shift; my $name = lc($element->name);
    $$name = pop_output; } # symbolic reference, powstaje zmienna 
          # o nazwie określonej przez wartość zmiennej $name 

sub stepcounter{ my $name=shift; ++$count{$name}; }

sub counter{ my $name=shift; $count{$name}; }

    # Procedura wyszukiwania `dobrego' znaku separującego w LaTeX-owym
    # poleceniu `\verb', tj. takiego ze znaków zadeklarowanych 
    # jako wartość $latex_verb_seps, który nie występuje jak wartość
    # argumentu tego polecenia:  

sub set_verbatim_sep {
    my $s = shift; # napis -- argument polecenia `\verb'
    my $goodseps = $latex_verb_seps;

    my $tmp = $s;

    $tmp =~ s/[^$latex_verb_seps]//g;
    if ($tmp eq '') { $goodseps = $latex_verb_seps } # wymaga poprawki
    else { $goodseps =~ s/[$tmp]//g; }

    $goodseps ne '' || die "Nie ma dobrego separatora polecenia verb";
    # procedura zwraca pierwszy znak -- poprawny separator:
    return ( substr($goodseps,0,1) );

}

    # Procedura drukowania element/ow, które są formatowane ,verbatim':

sub print_verbatim { 
    my $element=shift; 
    my $name = $element->name;
    my $content = pop_output; 
    $content =~ s/\n/ /gs; # zamień końce linii na spacje

    #my $fragile = $element->within(TITLE) || $element->within(FOOTNOTE); 
    my $infragile = $element->within(TITLE) || $element->within(FOOTNOTE); 
    # $element->within(TERM); # *** to, na razie, nie jest potrzebne ***

    # Funkcje, zmienne wbudowane i inne elementy będące rozszerzeniem
    # języka AWK, oznaczono za pomocą atrybutu `ROLE', który w takim
    # przypadku przyjmuje wartość `gawk'
    my $role = $element->attribute('ROLE')->value;

    if ($role eq 'gawk') { $role="$GawkExSym" } else { 
       if ($role eq 'userdefined' && $element->within(INDEXTERM ))
          {  $role="$UserDfSym" } else { $role="" }
    };

    my $sep = '+'; # nazwa funcji nie zawiera `+' 
    if ($name eq 'LITERAL') { $sep = set_verbatim_sep( $content ) }

    if ( $infragile || ( $content !~ m/[\\\_\#\$%^&{}~]/ )) { output "\\texttt{$content}$role"; }
    else { output "\\verb$sep$content$sep$role"; }
} 

1;

