#! /usr/bin/perl
#
# ${R_HOME}/bin/Sd2Rd for converting S documentation to Rd format

# Copyright (C) 1997-2001 The R Core Development Team
#
# This document is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# A copy of the GNU General Public License is available via WWW at
# http://www.gnu.org/copyleft/gpl.html.  You can also obtain it by
# writing to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA  02111-1307  USA.

use Getopt::Long;
use R::Utils;

my $revision = ' $Revision: 1.21 $ ';
my $version;
my $name;

$revision =~ / ([\d\.]*) /;
$version = $1;
($name = $0) =~ s|.*/||;

sub usage {
  print STDERR <<END;
Usage: R CMD Sd2Rd [options] FILE

Convert S documentation in FILE to R documentation format.

Options:
  -h, --help		print short help message and exit
  -v, --version		print Sd2Rd version info and exit
  -n			render examples non-executable by wrapping them
			into a \\dontrun{} environment
  -x			(S3 docs) interpret all single-quoted names 
                        as code names

Email bug reports to <r-bugs\@r-project.org>.
END
  exit 0; 
}

@knownoptions = ("v|version", "h|help", "n", "x");
GetOptions(@knownoptions) || &usage();
&R_version($name, $version) if $opt_v;
&usage() if $opt_h;

@lines = <>;
## peek at the first line of the file, then dispatch to
## S3-style (nroff) or S4-style (SGML spec).
if(@lines[0] =~ /^<!doctype/) { doS4(); } else { doS3(); }
exit 0;
 
sub doS3 {
  $braceLevel = 0;
  $inReferences = 0;
  $inVerbatim = 0;
  $inSeeAlso = 0;
  $inCode = 0;
  $isDataSet = 0;
  $doprint = 1;
  $needArg = 1;
  $needVal = 0;
  $underlineNext = 0;
  $output = "";

  foreach $_ (@lines) {
    chop;
    &substitute unless /^\./;
    my @word = split;

    if (/^\s*$/) { &output("\n"); }
    if (/^[^.]/) { 
      if ($underlineNext) {
	$_ = "\\emph{" . $_ ."}";
	$underlineNext = 0;
      }
      &output($_);
    }

    ## Added by BDR 1998-08-27
    if (/^\.\\\"/o) {
      s/^\.\\\"/%/;
      &output($_);
    }
    ## End

    if (/^\.BG D/) {
      $isDataSet = 1;
    }
    if (/^\.AG/) {
      if ($isDataSet) {
	if ($needArg) {
	  &section(1, "\\describe\{");
	  $needArg = 0;
	}
	$arg = $_;
	$arg =~ s/^\.AG\s//;
	&section(2, "\\item\{\\code\{$arg\}\}\{");
      } else {
	if ($needArg) {
	  &section(0, "\\arguments\{");
	  $needArg = 0;
	}
	$arg = $_;
	$arg =~ s/^\.AG\s//;
	&section(1, "\\item\{$arg\}\{");
      }
    }
    if (/^\.CS/) {
      &section(0, "\\usage\{");
      $inVerbatim = 1;
    }
    if (/^\.DN/) { &section(0, "\\description\{"); }
    if (/^\.DT/) { &section(0, "\\details\{"); }
    if (/^\.EX/) {
      if ($opt_n) {
	&section(1, "\\examples\{\\dontrun\{");
      } else {
	&section(0, "\\examples\{");
      }
      $inVerbatim = 1;
    }
    if (/^\.FN/) {
      unless($fun) { $fun = $word[1]; }
      push(@aliases, $word[1]);
    }
    if (/^\.(IP|PP)/) { &output("\n"); }
    if (/^\.KW/) { 
      if ($braceLevel > 0) {
	&section(0, "");
	$braceLevel = 0;
      }
      if ($word[1] =~ /sysdata/) {
	&output("\\keyword\{datasets\}");
      } else {
	&output("\\keyword\{$word[1]\}");
      }
    }
    if (/^\.RC/) {
      if ($needVal) {
	$needVal = 0;	    
	&section(0, "\\value\{\n$output\n");
	$doprint = 1;
      }
      &section(1, "\\item\{" . join(" ", @word[1..$#word]) . "\}\{");
    }
    if (/^\.RT/) {
      $needVal = 1;
      $doprint = 0;
      $output = "";
    }
    if (/^\.SA/) {
      &section(0, "\\seealso\{");
      $inSeeAlso = 1;
    }
    if (/^\.SE/) { &section(0, "\\section\{Side Effects\}\{"); }
    if (/^\.SH/) {
      if ($word[1] =~ /REFERENCE/) {
	&section(0, "\\references\{");
	$inReferences = 1;
      } elsif ($word[1] =~ /AUTHOR/) {
	&section(0, "\\author\{");
      } elsif ($word[1] =~ /NOTE/) {
	&section(0, "\\note\{");
      } elsif ($word[1] =~ /SOURCE/) {
	&section(0, "\\source\{");
	$inReferences = 1;
      } elsif ($word[1] =~ /SUMMARY/) {
	&section(0, "\\description\{");
      } elsif ($word[1] =~ /WARNINGS/) {
	&section(0, "\\section{Warnings}\{");
      } elsif ($word[1] =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      print("\\name\{$fun\}\n");
      =~ /WARNING/) {
	&section(0, "\\section{Warning}\{");
      } elsif (join(" ", @word[1..2]) =~ /DATA DESCRIPTION/) {
	&section(0, "\\usage\{\ndata($fun)");
	&section(0, "\\format\{");
      } else {
	# This line may be of the form .SH "A B C"
	($tmp = join(" ", @word[1..$#word])) =~ s/\"(.*)\"/$1/;
	&section(0, "\\section\{$tmp\}\{");
      }
    }
    if (/^\.sp/) {
      if($word[1] == 0) {
	output("\\cr")
      } else {
	output("\n")
      }
    }
    if (/^\.TL/) {
      