#
#  fmt_txt.pl
#
#  $Id$
#
#  TXT-specific driver stuff
#
#  © Copyright 1996, Cees de Groot
#
package LinuxDocTools::fmt_txt;
use strict;

use File::Copy;
use Text::EntityMap;
use LinuxDocTools::CharEnts;
use LinuxDocTools::Lang;
use LinuxDocTools::Vars;
use LinuxDocTools::Utils qw(create_temp);

my $txt = {};
$txt->{NAME} = "txt";
$txt->{HELP} = "";
$txt->{OPTIONS} = [
   { option => "manpage", type => "f", short => "m" },
   { option => "filter",  type => "f", short => "f" },
   { option => "blanks",  type => "i", short => "b" }
];
$txt->{manpage} = 0;
$txt->{filter}  = 0;
$txt->{blanks}  = 3;

$Formats{$txt->{NAME}} = $txt;

#
#  Set correct NsgmlsOpts
#
$txt->{preNSGMLS} = sub
{
  if ($txt->{manpage})
    {
      $global->{NsgmlsOpts} .= " -iman ";
      $global->{charset} = "man";
    }
  else
    {
      $global->{NsgmlsOpts} .= " -ifmttxt ";
      $global->{charset} = "latin1" if $global->{charset} eq "latin";
    }


  #
  #  Is there a cleaner solution than this? Can't do it earlier,
  #  would show up in the help messages...
  #
  #  the language support ja.
  #  the charset  support nippon.
  #
  $global->{format} = $global->{charset};
  $global->{charset} = "nippon" if $global->{language} eq "ja";
  $global->{format} = "groff" if $global->{format} eq "ascii";
  $global->{format} = "groff" if $global->{format} eq "nippon";
  $global->{format} = "groff" if $global->{format} eq "euc-kr";
  $ENV{SGML_SEARCH_PATH} =~ s/txt/$global->{format}/;

  $Formats{"groff"} = $txt;
  $Formats{"latin1"} = $txt;
  $Formats{"man"} = $txt;

  $global->{NsgmlsPrePipe} = "cat $global->{file} " ;
};


# Ascii escape sub.  this is called-back by `parse_data' below in
# `txt_preASP' to properly escape `\' characters coming from the SGML
# source.
my $txt_escape = sub {
    my ($data) = @_;

    $data =~ s|"|\\\&\"|g;	# Insert zero-width space in front of "
    $data =~ s|^\.|\\&.|;	# ditto in front of . at start of line
    $data =~ s|\\|\\\\|g;	# Escape backslashes

    return ($data);
};

#
#  Run the file through the genertoc utility before sgmlsasp. Not necessary
#  when producing a manpage. A lot of code from FJM, untested by me.
#
$txt->{preASP} = sub
{
  my ($infile, $outfile) = @_;
  my (@toc, @lines);
  my $char_maps = load_char_maps ('.2tr', [ Text::EntityMap::sdata_dirs() ]);
  if ( $global->{charset} eq "latin1" )
   {
    $char_maps = load_char_maps ('.2l1tr', [ Text::EntityMap::sdata_dirs() ]);
   }

   if ($txt->{manpage})
    {
     while (<$infile>)
      {
       if (/^-/)
        {
         my ($str) = $';
         chop ($str);
         print $outfile "-" . 
                 parse_data ($str, $char_maps, $txt_escape) . "\n";
         next;
        }
       elsif (/^A/)
        {
         /^A(\S+) (IMPLIED|CDATA|NOTATION|ENTITY|TOKEN)( (.*))?$/
             || die "bad attribute data: $_\n";
         my ($name,$type,$value) = ($1,$2,$4);
         if ($type eq "CDATA")
          {
            # CDATA attributes get translated also
            $value = parse_data ($value, $char_maps, $txt_escape);
          }
         print $outfile "A$name $type $value\n";
         next;
        }
        #
        #  Default action if not skipped over with next: copy in to out.
        #
        print $outfile $_;
      }

      return;
    }

  # note the conversion of `sdata_dirs' list to an anonymous array to
  # make a single argument

  #
  #  Build TOC. The file is read into @lines in the meantime, we need to
  #  traverse it twice.
  #
  push (@toc, "(HLINE\n");
  push (@toc, ")HLINE\n");
  push (@toc, "(P\n");
  push (@toc, "-" . Xlat ("Table of Contents") . "\n");
  push (@toc, ")P\n");
  push (@toc, "(VERB\n");
  my (@prevheader, @header);
  my $appendix = 0;
  my $nonprint = 0;
  while (<$infile>)
    {
      push (@lines, $_);

      if (/^\(SECT(.*)/) 
        {
	  @prevheader = @header;
	  @header = @header[0..$1];
	  if ($appendix == 1) 
            {
	      $header[$1] = "A";
	      $appendix = 0;
            } else 
            {
	      $header[$1]++;
	    }
        }
      if (/^\(APPEND(.*)/) 
        {
	  $appendix = 1;
        }
      if (/^\(HEADING/) 
        {
	  $_ = <$infile>;
	  s/\\n/ /g;
	  push (@lines, $_);
	  chop;
	  s/^-//;
	  $_ = join(".",@header) . " " . $_;
	  s/\(\\[0-9][0-9][0-9]\)/\\\1/g;

	  if (!$#header) 
	    {
	      # put a newline before top-level sections unless previous was also
	      # a top level section
	      $_ = "\\n" . $_ unless (!$#prevheader);
	      # put a . and a space after top level sections
	      s/ /. /;
#####	      $_ = "-" . $_ . "\\n";
	      $_ = "-" . $_;
	    } 
	  else 
	    {
	      # subsections get indentation matching hierarchy
	      $_ = "-" . "   " x $#header . $_;
	    }

#	remove tags from a toc
	  s/\)TT//g;
	  s/\(TT//g;
	  s/\)IT//g;
	  s/\(IT//g;
	  s/\)EM//g;
	  s/\(EM//g;
	  s/\)BF//g;
	  s/\(BF//g;
	  s/AID * CDATA.*$//g;
	  s/\)LABEL//g;
	  s/\(LABEL//g;

	  push(@toc, parse_data ($_, $char_maps, $txt_escape));

	  $_ = <$infile>;
	  while (!/^\)HEADING/) {
	    s/\\n/ /g; ####
	    push(@lines, $_);
	    chop;
	    s/^-//;

#	remove tags from a toc
	    s/\)TT//g;
	    s/\(TT//g;
	    s/\)IT//g;
	    s/\(IT//g;
	    s/\)EM//g;
	    s/\(EM//g;
	    s/\)BF//g;
	    s/\(BF//g;
	    s/AID * CDATA.*$//g;
	    s/\)LABEL//g;
	    s/\(LABEL//g;

#	remove NIDX, NCDX from a toc entry
	    if (/^\(NIDX$/ || /^\(NCDX$/) { $nonprint = 1; }
	    if (/^\)NIDX$/ || /^\)NCDX$/) { $nonprint = 1; }

#	  $_ = "-" . $_ . "\\n";
	    push(@toc, parse_data ($_, $char_maps, $txt_escape))
	      if (! $nonprint);
	    $_ = <$infile>;
	  }
	  s/\\n/ /g; ###
	  push(@lines, $_);
	  push(@toc, "\\n\n");
      }
    }
  push (@toc, ")VERB\n");
  push (@toc, "(HLINE\n");
  push (@toc, ")HLINE\n");

  my $inheading = 0;
  my $tipo = '';
  for (@lines)
    {
      if ($inheading)
        {
	  next if (/^\)TT/ || /^\(TT/ || /^\)IT/ || /^\(IT/ ||
                   /^\)EM/ || /^\(EM/ || /^\)BF/ || /^\(BF/);
	  if (/^-/) 
            {
	      $tipo .=  $' ;
	      chop ($tipo);
	      $tipo .= " " unless $tipo =~ / $/;
	    }
	  else 
	    {
	      $tipo =~ s/ $//;
	      if ($tipo)
		{
		  print $outfile "-"
		      . parse_data ($tipo, $char_maps, $txt_escape)
		      . "\n";
		}
	      print $outfile $_;
	      $tipo = '';
	    }
	  if (/^\)HEADING/)
	    {
	      $inheading = 0;
            }
	  next;
	}
      if (/^\(HEADING/) 
        {
	  #
	  #  Go into heading processing mode.
	  #
	  $tipo = '';
	  $inheading = 1;
	}
      if (/^\(TOC/)
        {
	  print $outfile @toc;
	  next;
	}
      if (/^-/)
        {
	  my ($str) = $';
	  chop ($str);
	  print $outfile "-" . parse_data ($str, $char_maps, $txt_escape) . "\n";
	  next;
        }
      elsif (/^A/)
        {
	  /^A(\S+) (IMPLIED|CDATA|NOTATION|ENTITY|TOKEN)( (.*))?$/
	      || die "bad attribute data: $_\n";
	  my ($name,$type,$value) = ($1,$2,$4);
	  if ($type eq "CDATA")
	    {
	      # CDATA attributes get translated also
	      $value = parse_data ($value, $char_maps, $txt_escape);
	    }
	  print $outfile "A$name $type $value\n";
	  next;
        }

      #
      #  Default action if not skipped over with next: copy in to out.
      #
      print $outfile $_;
    }
};


#
#  Take the sgmlsasp output, and make something
#  useful from it.
#
$txt->{postASP} = sub
{
  my $infile = shift;
  my ($outfile, $groffout);

  if ($txt->{manpage})
    {
      $outfile = new FileHandle ">$global->{filename}.man";
    }
  else
    {
      create_temp("$global->{tmpbase}.txt.1");
      $outfile = new FileHandle 
	  "|$main::progs->{GROFF} $global->{pass} -T $global->{charset} -t $main::progs->{GROFFMACRO} >\"$global->{tmpbase}.txt.1\"";
    }

  #
  #  Feed $outfile with roff input.
  #
  while (<$infile>)
    {
      unless (/^\.DS/.../^\.DE/) 
        {
	  s/^[ \t]{1,}(.*)/$1/g;
        }
      s/^\.[ \t].*/\\\&$&/g;
      s/\\fC/\\fR/g;
      s/^.ft C/.ft R/g; 
      print $outfile $_;
    }  
  $outfile->close;

  #
  #  If we were making a manpage, we're done. Otherwise, a little bit
  #  of work is left.
  #
  if ($txt->{manpage})
    {
      return 0;
    }
  else
    {
      $outfile->open (">$global->{filename}.txt");
      $groffout = new FileHandle "<$global->{tmpbase}.txt.1";
      my $count = 0;
      if ($txt->{filter})
        {
	  while (<$groffout>)
	    {
	      s/[^\cH][^\cH]\cH\cH//g;
	      s/.//g;
              if ($txt->{blanks})
                {
                  $count = &{$txt->{cutblank}}($count, $outfile, $_);
                }
              else
                {
                  print $outfile $_;
                }
	    }
	}
      else
        {
          if ($txt->{blanks})
            {
              while (<$groffout>)
                {
                  $count = &{$txt->{cutblank}}($count, $outfile, $_);
                }
            }
          else
            {
	      copy ($groffout, $outfile);
            }
	}
    }
  $groffout->close;
  $outfile->close;

  return 0;
};

$txt->{cutblank} = sub
{
  my ($num, $out, $in) = @_;
  if ( $in =~ /^$/ )
    {
      $num++;
    }
  else
    {
      $num = 0;
    }
  if ( $num <= $txt->{blanks} )
    {
      print $out $in;
    }

  return ($num);
};

1;
