#!/usr/bin/perl
# File: api2man.pl
# Description: Convert the PLplot API chapter (file api.xml of the DocBook
#              manual) into a series of man pages.
# Author: Rafael Laboissière <rafael@icp.inpg.fr>
#
# Copyright (C) 2000, 2003 Rafael Laboissiere
# Copyright (C) 2010-2017 Alan W. Irwin
#
# This script relies on the present structure of the API chapter (file
# ../src/api.xml), where each API function is documented in its own
# section.  Here is the typical structure of a section:
#
#   <sect1 id="NAME">
#     <title><function>NAME</function>: DESCRIPTION</title>
#
#     <para>
#       <funcsynopsis>
#       <funcprototype>
# 	<funcdef>
# 	  <function>NAME</function>
# 	</funcdef>
#         <paramdef><parameter>ARG1</parameter></paramdef>
#         <paramdef><parameter>ARG2</parameter></paramdef>
#          ...
#       </funcprototype>
#       </funcsynopsis>
#     </para>
#
#     <para>
#       DESCRIPTION
#     </para>
#
#     <variablelist>
#       <varlistentry>
# 	<term>
# 	  <parameter>ARG1</parameter>
# 	  TYPE
# 	</term>
# 	<listitem>
# 	  <para>
# 	    ARG1 DESCRIPTION
# 	  </para>
# 	</listitem>
#       </varlistentry>
#       ...
#     </variablelist>
#
#   </sect1>

#  Call this script by giving the master file (typically
#  plplotdoc.xml) as the first argument, the API chapter file
#  (typically api.xml) as second argument, and the man volume
#  (typically 3plplot) as third.

use XML::Parser;
use XML::DOM;

$api = "";
open (MASTER, "< $ARGV[0]");
while (<MASTER>) {
  if (/^(<!DOCTYPE.*)\[/) {
    $api .= "$1 [\n";
  }
  elsif (/^<\?xml/) {
    $api .= '<?xml version="1.0" standalone="yes"?>
';
  }
# Use entities from MASTER starting with "pl"
  elsif (/^<!ENTITY pl/) {
    $api .= $_;
  }
# Use entities from MASTER starting with "PL"
  elsif (/^<!ENTITY PL/) {
    $api .= $_;
  }
}
# Add a few additional entities that are needed.
$api .= "<!ENTITY amp '#38;#38;'>
<!ENTITY deg ' degrees'>
<!ENTITY gt '&#x003E;'>
<!ENTITY leq '&#38;#60;='>
<!ENTITY le '&#38;#60;='>
<!ENTITY lt '&#38;#60;'>
<!ENTITY ndash '--'>
]>\n";
close MASTER;

open (API, "< $ARGV[1]");
$/ = undef;
$api .= <API>;
close API;

$manvol = $ARGV[2];
$date = `date +"%B, %Y"`;
$date =~ s/\n.*//;
$opening = ".\\\" This page was automatically generated.  Do not edit!\n.\\\"\n";
$closing = "
.SH AUTHORS
Many developers (who are credited at @PLPLOT_WEBSITE@/credits.php)
have contributed to PLplot over its long history.
.SH SEE ALSO
PLplot documentation at @PLPLOT_WEBSITE@/documentation.php.
";
$manifest = "";

sub process_node {
  my $ret = "";
  my $t = shift;
  my $c = $t->getChildNodes;
  my $m = $c->getLength;
  for (my $j = 0; $j < $m; $j++) {
    my $e = $c->item($j);
    my $nt = $e->getNodeType;
    if ($nt == TEXT_NODE) {
      my $a = $e->getData;
      $a =~ s/^\s+/ /;
      $a =~ s/^\s+$//;
      $a =~ s/\n\s+/ /g;
      $ret .= $a;
    }
    elsif ($nt == ELEMENT_NODE) {
      my $tag = $e->getTagName;
    if ($tag eq "parameter") {
        $ret .= "\\fI" . process_node ($e) . "\\fP";
      }
      elsif  ($tag eq "function") {
        $ret .= "\\fB" . process_node ($e) . "\\fP";
      }
      elsif  ($tag eq "link") {
        $ret .= process_node ($e) . "($manvol)";
      }
      elsif  ($tag eq "funcprototype") {
        $startproto = 1;
	my $p = process_node ($e);
	$p =~ s/ +$//;
        $ret .= $p . ")";
      }
      elsif  ($tag eq "paramdef") {
	my $p = process_node ($e);
	$p =~ s/ +$//;
        $ret .= ($startproto ? "(" : ", ") . $p;
        $startproto = 0;
      }
      elsif  ($tag eq "term") {
        $ret .= ".TP\n" . process_node ($e) . "\n";
      }
      elsif  ($tag eq "listitem") {
        $ret .= process_node ($e) . "\n";
      }
      elsif  ($tag eq "xref") {
        $ret .= "the PLplot documentation";
      }
      elsif ($tag eq "simplelist") {
        my $ncols = $e->getAttributeNode ("columns")->getValue;
        my $children = $e->getElementsByTagName ("member");
        my $nc = $children->getLength;
        $ret .= "\n.RS\n.P\n.PD 0"
          . join ("", map {
            ($_ % $ncols ? "\n" : "\n.P\n")
              . process_node ($children->item ($_))
                . " ";
           } (0 .. ($nc - 1)))
            . "\n.PD\n.P\n";
      }
      else {
        $ret .= process_node ($e);
      }
    }
    else {
      $ret .= process_node ($e);
    }
  }
  $ret =~ s/^\s+//;
  return $ret;
}

$p = new XML::DOM::Parser(ErrorContext => 2);
$sects = $p->parse ($api)->getElementsByTagName ("sect1");
my $ns = $sects->getLength;
$titles = "";

for ($i = 0; $i < $ns; $i++) {
  $fun = $sects->item ($i);
  $name = $fun->getAttribute ("id");
  $c = $fun->getChildNodes;
  $nc = $c->getLength;
  $desc = "";
  $varlist = "";
  $got_synopsis = 0;
  for ($j = 0; $j < $nc; $j++) {
    $part = $c->item($j);
    if ($part->getNodeType == ELEMENT_NODE) {
      $contents = process_node ($part);
      $node = $part->getTagName;
      if ($node eq "title") {
        $title = $contents;
      }
      elsif ($node eq "para") {
        if ($got_synopsis) {
          $desc .= "\n.P\n" . $contents;
        }
        else {
          $synopsis = $contents;
          $got_synopsis = 1;
        }
      }
      elsif ($node eq "variablelist") {
        $varlist = $contents;
      }
    }
  }

  open (MAN, "> $name.$manvol");
  # Suppress warnings about UTF-8 in MAN.
  binmode MAN, ':utf8';

  print MAN $opening;
  print MAN ".TH " . uc ($name) . ' 3plplot  "' . $date . '" "" "PLplot API"' . "\n";
  $titles .= "\n.TP\n$title";
  # Get rid of extra spaces which might be after ":" in title
  # and replace ":" by "-"
  $title =~ s/: */ - /;
  # Perl processing leaves some trailing blanks.  Get rid of those.
  $title =~ s/ *\n/\n/g;
  $desc =~ s/ *\n/\n/g;
  $synopsis =~ s/ *\n/\n/g;
  $varlist =~ s/ *\n/\n/g;
  $title =~ s/ *$//;
  $desc =~ s/ *$//;
  $synopsis =~ s/ *$//;
  $varlist =~ s/ *$//;
  print MAN ".SH NAME\n$title";
  print MAN "\n.SH SYNOPSIS\n$synopsis";
  print MAN "\n.SH DESCRIPTION\n$desc";
  if (not $varlist eq "") {
    print MAN "\n.SH ARGUMENTS\n$varlist";
  }
  print MAN $closing;
  close MAN;
  $manifest .= "$name.3plplot\n";
}

$main = "plplot.$manvol";
open (MAN, "> $main");
print MAN $opening;
print MAN ".TH plplot 3plplot  \"" . $date . '" "" "PLplot API"' . "\n";
# Perl processing leaves some trailing blanks.  Get rid of those.
$titles =~ s/ *\n/\n/g;
$titles =~ s/ *$//;
print MAN ".SH NAME
PLplot - Advanced 2D and 3D scientific plotting library
.SH DESCRIPTION
Available API man pages:
.nr PD 0
$titles
.nr PD 10
$closing
";
close MAN;
$manifest .= "$main\n";
print $manifest;
