#!/usr/bin/perl -w
##
# gphelp originally written by Niels Skoruppa for pariGUIde; forked and
# maintained by Karim Belabas (since v 1.7, 2002)
#
# This script generates html documentation of the gp/pari functions
# on using the tex documentation as given in chapter 3 of the users manual.
# Currently this is a workaround since there seems to exist no reasonable
# plain TeX to html converter. Here we just take the outputs of
# gphelp -raw and translate them into html form. It will be easy to replace,
# in the following code, the use of this function by a more powerful tex2html
# translator.
#
# Usage: gphtml [--dist|--4gui|--base=BASE|--out=OUT|--subsections]
#
# Without any option this will create, in the directory where you
# called, a subdirectory named html, and therein the html documentation.
# --base=BASE: where to find PARI's toplevel (mandatory)
# --out=OUT: where to output our pages
# --dist : add this file and a tar archive of html to html.
# --4gui : creates the reference docs for pariguide.
# The other options are for debugging purposes or consistency checks only.
#
# Adjust the three pathes below (look for AdJuSt).
#########################################################################

#use strict 'vars';

my ($USERSCH3_TEX,
#    $HTML, $DATE, $version,
    $distFlag, $guiFlag, $subsectionsFlag,
    %pics, %basicFrames, %subsections, %sections, %subsectionsByAl, %fill,
    %sublabel, %tr, %html,
    @ou, @shortcuts,
    );

$DATE = localtime();

##############
# AdJuSt these
##############
$base = "/usr/local/src/pari"; # the toplevel PARI/GP sources

#########################
# Parse the argument line
#########################
$distFlag = $guiFlag = $subsectionsFlag = 0;
for (@ARGV) {
  /--dist/        and do { $distFlag = 1; next;};
  /--4gui/        and do { $guiFlag = 1; next;};
  /--subsections/ and do { $subsectionsFlag = 1; next;};
  /--base=(.*)/   and do { $base = $1; next;};
  /--out=(.*)/    and do { $HTML = $1; next;};
  &usage;
}
my ($HTMLdft) = $guiFlag? "./ref": "./html";
if (!$HTML) { $HTML = $HTMLdft; }
$ENV{'GPHELP_DOCDIR'} = "$base/doc";
$USERSCH3_TEX = "$base/doc/usersch3.tex";
$gphelp       = "$base/doc/gphelp";

sub usage {
  print STDERR "Usage: $0 [--base=BASE|--out=OUT|--dist|--4gui|--subsections]\n";
  exit( 0);
}

# We see first what information the system has about pari/gp and collect it
initVersionAndShortcuts();
initSubsections();

# If we only want to list the subsections of usersch3.tex, then this
sub dbgSections {
  for my $k (sort keys %sections) { print "$k $sections{$k}\n"; }
  for my $k (sort keys %subsections) {
    print "\n\n $k\n\n";
    for my $i (@{ $subsections{$k} }) { print "\t$i\n"; }
  }
}
if ($subsectionsFlag) { dbgSections(); exit(0); }

initFixedData();

system( "mkdir -p $HTML");
#######################################################################
# Here we write all *.html files of the pariguide doc
#######################################################################
if ($guiFlag) {
  my ($HEAD) = <<"__UP_TO_HERE__";
<table class="reftop">
<tr>
<td id="top"><b>Pari/GP Reference Documentation</b></td>
<td class="right"><a href="index.html"
  ><img alt="HOME" src="./home.gif" />&nbsp;Contents</a>
 - <a href="function_index.html">Global index</a>
 - <a href="keyboard_shortcuts.html">GP keyboard shortcuts</a></td>
</tr>
</table><br/>

__UP_TO_HERE__

  writeData(*DATA, 1); # icons
  writeToC4Ref($HEAD); #toc
  writeIndex(6, $HEAD); # function index using 6 columns,
  # subsection pages,
  for my $k (sort keys %subsections) { &writeEntries4Ref($k, $HEAD); }
  # and meta commands.
  writeShortcuts($HEAD);
  exit(0);
};

#######################################################################
# Here we write all *.html files, according to the
# frame layout sketched in the data section below (after __DATA__ ).
# Change look and feel by altering the descriptions in the data section.
#######################################################################
# Write basic frames
writeData(*DATA, 0);
writeToC();
# ... and the pages for the frames "item" and "entry"
for my $k (keys %subsections) {
  writeFunctionsByCategory($k);
  &writeEntries($k);
}
writeModRewrite();
writeShortcuts("");
writeOperators();
writeReadline();
for my $l (sort keys %subsectionsByAl) { writeFunctionsByAlphabet($l) }
if ($distFlag)
{ system("cp gphtml $HTML; H=`basename $HTML`; cd $HTML/..; tar cfz \$H.tgz \$H") }

########### The subroutines ##################
sub warning { print STDERR "\t\e[0;31m\e[1mWarning:\e[m ".$_[0]."\n"; }
sub fatal { die "\t\e[0;31m\e[1mError:\e[m ".$_[0]."\n"; }
sub happy { print STDERR "\t".$_[0]." ...... \e[0;32m\e[1m OK\e[m\n"; }
sub unhappy { print STDERR "\t".$_[0]." ...... \e[0;31m\e[1m FAILED\e[m\n"; }

###############################################################################
# Sets ups $version and the list @shortcuts of GP keyboard shortcuts. Calls gp!
# Checks if gphelp is available
###############################################################################
sub initVersionAndShortcuts {
  my ($gp) = "$base/gp";
  my ($v) = `$gp --version-short 2>&1`;
  if ($v eq "") { fatal( "gp --version-short doesn't work"); }
  chomp($v);
  $version = "PARI/GP calculator, version $v";
  happy("gp found ($gp, version $v)");
  @shortcuts = split "\n", `echo '?\\' | $gp -q --test`;
  #
  my ($e) = `$gphelp -raw addprimes`;
  if ($e eq "") { fatal( "gphelp not found"); }
  happy("gphelp found ($gphelp)");
}

###########################################################################
# Sets up hash of lists %subsections. Keys are the sections of usersch3.tex
# Values are the list of corresponding subsections.
###########################################################################
sub initSubsections {
  my($j, $key);

  open IN, "<$USERSCH3_TEX"
    or fatal("Cannot open $USERSCH3_TEX: fix the --base argument");

  $j = 1; $key = "Dummy";
  while (<IN>) {
    next if (/^%/);
    if (s/\\section\{(.*?)\}//) {
      $key = $1;
      $subsections{$key} = [];
      $sections{$j} = $key; $j++;
      $fill{$key} = cleanid($key);
    }
    if (/\\label\{([^}]*)}/) {
      die "duplicate label: $1" if ($sublabel{$1});
      $sublabel{$1} = $fill{$key};
    }
    if( s/\\subseckbd\{(.*?)\}//) {
      $id = $1;
    }
    elsif( s/\\subsecidx\{(.*?)\}//) {
      $id = $1;
    }
    elsif( s/\\subsec\{(.*?)\}//) {
      $id = $1;
      $id =~ s/\$\(.*//; # remove arguments
      $id =~ s/\\//g;
    }
    else { next; }
    push @{ $subsections{$key} }, $id;
    next if ($id =~ / /); # keep only keywords for index, not all subsections
    next if ($id !~ /^([a-zA-Z])/); # remove operators
    my ($letter) = uc($1);
    push @{ $subsectionsByAl{$letter} }, "[$id]__($key)__\n";
  }
  close IN;
}

sub GPatEnd {
  my ($A) = cleankey($a); $A = "ZZZ$A" if ($A =~ /GP/);
  my ($B) = cleankey($b); $B = "ZZZ$B" if ($B =~ /GP/);
  $A cmp $B;
}

# Writes index.html, the entry page for the reference documentation.
# Relies on the hash %subsection.
sub writeToC4Ref {
  my ($HEAD) = $_[0];
  my ($toc1, $toc2);

  $toc1 = $toc2 =''; $z = 0;
  for my $key (sort GPatEnd keys %subsections) {
    0 == $z and $toc1 .= "<tr>\n";
    $toc1 .= "<td><a href=\"./$fill{$key}.html\">". cleankey($key) . '</a></td>' . "\n";
    1 == $z and $toc1 .= "</tr>\n";
    $z = 1 - $z;
  }
  1 == $z and $toc1 .= "<td>&nbsp;</td>\n</tr>";

  for my $l (sort keys %subsectionsByAl) {
    $toc2 .= "<a href = \"./function_index.html#$l\">$l</a>\n";
  }

  my ($txt) = <<"__UP_TO_HERE__";
$HEAD
<h3>Functions by Category</h3>
<table class="toc">
$toc1
</table>

<h4><a href="./keyboard_shortcuts.html">GP Keyboard Shortcuts</a></h4><br/>

<h3>Functions in Alphabetical Order</h3>
$toc2
<br><hr><br>
<small>
Catalogue of Functions for the $version.
<br>
(generated by gphtml on $DATE.)</small>
__UP_TO_HERE__

  printHTML("index.html", "Table of Contents", '', $txt);
}

# Writes toc.html. Relies on the hash %subsection.
sub writeToC {
  my($txt, $toc1, $toc2);

  $toc1 = $toc2 ='';
  for my $key (sort GPatEnd keys %subsections) {
    die "Unknown subsection: $key" if (!defined($fill{$key}) );
    $toc1 .= "<A href=\"./cont_$fill{$key}.html\" target=\"itemFrame\" "
      . "onClick=\"parent.entryFrame.location='$fill{$key}'\">"
      . cleankey($key) . "</A>\n<HR>\n";
  }
  for my $l (sort keys %subsectionsByAl) {
    $toc2 .= "&nbsp;<A href=\"./cont_$l.html\" target=\"itemFrame\">$l</A>\n";
  }

  $txt = <<"__UP_TO_HERE__";
<div class="center">
<A href="https://pari.math.u-bordeaux.fr/" target="_top">
<img alt="Pari/GP Home Page" src="https://pari.math.u-bordeaux.fr/site_icons/Logo_PARI-GP_Couleurs_L150px.png"></A>
</div>

<div class="left">
<H4>Functions by Category</H4>
<small>
$toc1
<A href="./operators.html" target="entryFrame">GP operators</A>
<hr>
<A href="./readline.html" target="entryFrame">GP line editor: readline</A>
<hr>
<A href="./keyboard_shortcuts.html" target="entryFrame">GP keyboard shortcuts</A>
</small>
<hr>

<H4>Functions in Alphabetical Order</H4>
<div style="font-size: 80%; text-align: justify;">
$toc2
</div>
</div>
__UP_TO_HERE__

  printHTML("toc.html", "Table of Contents", 'style="background-image:url(toc.jpg)"', $txt);
}

sub cleankey { my ($k) = $_[0];
  $k =~ s/\$//g;
  $k =~ s/\\bs/\\/g;
  $k =~ s/\\%/%/g;
  $k =~ s/\\pow/\^/g;
  $k;
}
sub cleanid  { my ($k) = $_[0];
  $k =~s/\+/plus/g;
  $k =~s/\-/minus/g;
  $k =~s/\\/backslash/g;
  $k =~s/\//slash/g;
  $k =~s/\%/percent/g;
  $k =~s/\*/star/g;
  $k =~ s/[^a-zA-Z0-9]/_/g;
  $k;
}

#############################################################################
# Writes, for each list of subsection titles pointed to by $key, an html file
# cont_$key.html. This is a collection of links to the respective entries in
# $key.html. Uses the hash %subsection.
# Call in the form writeFunctionsByCategory($key)
#############################################################################
sub writeFunctionsByCategory {
  my($key, $txt, @A);
  $key = $_[0];

  for my $item (@{$subsections{$key}}) {
    my ($a, $b) = (cleanid($item), cleankey($item));
    push(@A, "<A href=\"$fill{$key}.html#$a\" target=\"entryFrame\">$b</A>");
  }
  my ($cleankey) = cleankey($key);
  $txt = "\n<h3 class=\"center\">Index: $cleankey</h3>\n"
       . '<div style="font-size: 80%; text-align: justify;">'
       . join(",\n", @A)
       . "\n</div>";
  printHTML("cont_$fill{$key}.html", "$cleankey", '', $txt);
}

############################################################################
# Writes function_index.html. This is a collection of links to the respective
# entries in the entry pages. Uses the hash %subsectionsByAl.
# Call in the form writeIndex(number_of_columns)
############################################################################
sub writeIndex {
  my ($nCols, $HEAD) = @_;
  my ($txt);
  $txt = $HEAD . "<h3 class=\"left\">Index</h3>\n"
               .'<table class="index">'."\n";
  for my $letter (sort keys %subsectionsByAl) {
    $txt .= "<tr>\n<td id=\"$letter\"><b>$letter</b></td>\n";
    my ($z) = 1;
    for my $item (sort @{$subsectionsByAl{$letter}}) {
      $item =~ /^\[(.*?)\]__\((.*?)\)__$/;
      if ($z == $nCols) { $z = 1; $txt .= "</tr>\n<tr>\n<td>&nbsp;</td>\n"; }
      $txt .= "<td><A href=\"./$fill{$2}.html#$1\">$1</A></td>\n";
      $z++;
    }
    for(; $z < $nCols; $z++) { $txt .= "<td>&nbsp;</td>\n"; }
    $txt .= '</tr>'."\n";
  }
  $txt .= "</table>";
  printHTML('function_index.html', 'Index', '', $txt);
}

sub writeModRewrite {
  my ($f) = "ModRewrite-table";
  my ($txt);
  for my $letter (sort keys %subsectionsByAl) {
    for my $item (sort @{$subsectionsByAl{$letter}}) {
      $item =~ /^\[(.*?)\]__\((.*?)\)__$/;
      $txt .= "$1 $fill{$2}.html#$1\n";
    }
  }
  open OUT, ">$HTML/$f" or fatal("Cannot create the file $HTML/$f\n");
  print OUT $txt;
  close(OUT);
}

############################################################################
# Writes, for each letter the file cont_$letter.html. This is a collection of
# links to the respective entries in the entry pages.
# Uses the hash %subsectionsByAl.
# Call in the form  writeFunctionsByAlphabet( $letter)
############################################################################
sub writeFunctionsByAlphabet {
  my ($letter) = $_[0];
  my ($txt) = "\n<h3 class=\"center\">Index: $letter</h3></div>\n";;
  for my $item (sort @{ $subsectionsByAl{$letter} }) {
    $item =~ /^\[(.*?)\]__\((.*?)\)__$/;
    $txt .=
      "&nbsp;&nbsp;<A href=\"./$fill{$2}.html#$1\" target=\"entryFrame\">$1</A>\n";
  }
  printHTML("cont_$letter.html", "$letter", '', $txt);
}

sub refexpand { my ($c) = $_[0];
  my ($p) = $sublabel{$c};
  if (!$p)
  {
#    warning("missing label $c");
    return $c;
  }
  "<a href=\"$p.html\#$c\"
    onClick=\"parent.itemFrame.location='cont_$p.html'\">$c<\/a>";
}
sub keyrefexpand { my ($c) = $_[0];
  my ($p) = $sublabel{'se:' . $c};
  if (!$p) { return $c; }
  "<a href=\"$p.html\#se:$c\"
    onClick=\"parent.itemFrame.location='cont_$p.html'\">$c<\/a>";
}

sub get_entry {
  my ($item) = @_;
  my ($l, $r, $d, @names);
  my (%trans0) = (
#    '&' => '&amp;',
    '<' => '&lt;',
    '>' => '&gt;',
    '~{O}' => '&Otilde;',
    '\oplus' =>  '&bigoplus; ',
    '\bigoplus' => ' &bigoplus; ',
    '\bigsqcup' => ' &bigsqcup; ',
    '\subset' => ' &subset; ',
    '\otimes' => ' &bigotimes; ',
    '\in' => ' &in; ',
    '\bigotimes' => ' &bigotimes; ',
    '\to' => ' &rightarrow; ',
    '\triangleleft' => ' &triangleleft; ',
    '\geq' => ' &geq; ',
    '\leq' => ' &leq; ',
    ':---@[gt]' => ' &longmapsto; ',
    '---' => ' &mdash; ',
  );
  my (%trans) = (
    '\{'         => '{',
    '\}'         => '}',
    '\langle'    => '&langle;',
    '\rangle'    => '&rangle;',
    '@0'         => '  ',
    '@1'         => '',
    '@2'         => '',
    '@3'         => '',
  );

  my ($e, $title);
  $e = `$gphelp -raw -noskip '$item'`;
  ($e =~ /^'.*' not\ found !$/) and unhappy("\t$item");
  # first kill TeX leftovers
  $e =~ s/\\not *\\in\b/ \&notin; /gs;
  for my $key (keys %trans0) {
    $l = quotemeta($key); $r = $trans0{$key};
    $e =~ s/$l/$r/gs;
  }
  $e =~ s/\_\{([^}]*)}/<sub>$1<\/sub>/g;
  $e =~ s/\^\{([^}]*)}/<sup>$1<\/sup>/g;
  # one letter subscripts, otherwise 't_MAT' & co gets mangled
  $e =~ s/\_([a-zA-Z0-9])\b/<sub>$1<\/sub>/g;
#  Too many mistakes: polynomials in verbatim code :-(
#  $e =~ s/\^([a-zA-Z0-9])\b/<sup>$1<\/sup>/g;
  $e =~ s/\^\*/<sup>*<\/sup>/g;  # this one is OK
  my ($a, $b);
  # symbols
  $a = quotemeta('@[startword]');
  $b = quotemeta('@[endword]');
  $e =~ s/$a([a-zA-Z]*)$b/\&$1;/xg;
  # calligraphic letters
  $a = quotemeta('@[startbc]');
  $b = quotemeta('@[endbc]');
  $e =~ s/$a([A-Z])$b/\&$1scr;/g;
  # blackboard bold letters
  $a = quotemeta('@[startbi]');
  $b = quotemeta('@[endbi]');
  $e =~ s/$a([A-Z])$b/\&$1opf;/g;
  # Fraktur
  $a = quotemeta('@[startbg]');
  $b = quotemeta('@[endbg]');
  $e =~ s/$a([A-Za-z])$b/\&$1fr;/g;
  #overline
  $e =~ s/\\(overline|bar)\{([^}]*)\}/<span style="text-decoration:overline">$2<\/span>/g;
  # <=, >=
  $a = quotemeta('@[startcode]');
  $b = quotemeta('@[endcode]');
  $e =~ s/$a\@\[lt\]=$b/&leq;/g;
  $e =~ s/$a\@\[gt\]=$b/&geq;/g;
  $e =~ s/$a(\w+)$b/'@[startcode]' . keyrefexpand($1) . '@[endcode]'/gse;

  $e =~ s/\@\[startref\]([^\@]*)\@\[endref\]/refexpand($1)/gse;
  while ($e =~ s/\@\[label ([^\]]*)\]//) { push(@names,$1); }
# TODO: Fix the dirty hack from here
  # handle \bprog @com
  $e =~ s/(\@1 *\@\[startcode\][^\@]*)\@\[endcode\]([^\n]*)\@\[startcode\]/$1 $2/gs;
  # handle @com
  $e =~ s/(\@0[^\@]*)\@\[endcode\]([^\n]*)\@\[startcode\]/$1 $2/gs;
  $l = '\@1 *\@\[startcode\]'; $r = '</p><pre class="code">  ';
  $e =~ s/$l/$r/gs;
  $l = '\@[23] *\@\[endcode\]'; $r = '</pre><p>';
  $e =~ s/$l/$r/gs;
# to here.

  for my $key (keys %trans) {
    $l = quotemeta($key); $r = $trans{$key};
    $e =~ s/$l/$r/gs;
  }

  # warn about leftovers
  if ($e =~ /(\\[a-zA-Z]{3,})/)
  { my ($w) = "$item: $1";
    # silence false positive
    if ($w ne 'se:def,TeXstyle: \right' &&
        $w ne 'se:def,TeXstyle: \def' &&
        $w ne 'ecppexport: \nFormat' &&
        $w ne 'strtex: \pmatrix' &&
        $w ne 'mspolygon: \usepackage' &&
        $w ne 'msfarey: \documentclass'
    ) { warning $w; }
  }

  # then make a nice header
  $e =~ s/^\@\[startbold](.*?)\:\@\[endbold]\n\n/<p>/;
  warning("no title: $item") if (!$1);
  $title = "<h4>$1<\/h4>";
  $title =~ s/, */, /g;

  # now care for the @[] markers
  for my $key (@ou) {
    $l = quotemeta($tr{$key}); $r = $html{$key};
    $e =~ s/$l/$r/gs;
    $title =~ s/$l/$r/gs;
  }

  # finally break into paragraphs
  $e =~ s/\n\n/\<\/p\>\n\<p\>/gs;

  my ($names) = "";
  for (@names) { $names .= "<div id=\"$_\"><\/div>\n"; }
  return ($e, $names, $title);
}

sub writeEntries4Ref() {
  my ($key, $HEAD) = @_;
  my ($cleankey) = cleankey($key);
  print STDERR "\twriting: $cleankey\n";
  # desambiguate between keywords belonging to 2 sections, e.g. 'log'
  my ($pre) = ($cleankey eq "GP defaults")? "se:def,": "";
  my ($toc) = '';
  for my $item (sort @{ $subsections{$key} }) {
    my ($a, $b) = (cleanid($item), cleankey($item));
    $toc .= "<a href=\"./$fill{$key}.html#$a\">$b</a>&nbsp;&nbsp;\n";
  }

  my ($txt) = <<"__UP_TO_HERE__";
$HEAD
<h2 class="left">$cleankey</h2><br/>

<table class="ref">
<tr><td colspan=2>
$toc
</td></tr>
<tr><td colspan=2>&nbsp;</td></tr>
__UP_TO_HERE__
  my ($e, $names) = get_entry($key);
  $txt .= "<tr><td colspan=2>$e</td></tr>";

  for my $item (@{ $subsections{$key} }) {
    my ($a, $b) = (cleanid($item), cleankey($item));
    my ($e, $names) = get_entry("$pre$item");

    $txt .= <<"__UP_TO_HERE__";
<tr>
<td class="refh" id="$a"><b>$b</b></td>
<td class="refh right">
<a href="./index.html"><img alt="HOME" src="./home.gif" /></a>&nbsp;&nbsp;
<a href="#top"><img alt="TOP" src="./top.gif" /></a></td></tr>
<tr><td class="ref" colspan=2>$e</td></tr>
<tr class="spacer"><td class="ref" colspan=2></td></tr>
__UP_TO_HERE__
  }
  $txt .= '</table>';

  printHTML("$fill{$key}.html", "$key", '', $txt);
}

# write GP keyboard shortcuts
sub writeShortcuts { my ($header) = @_;
  my ($t,$t2) = ('','');
  for (@shortcuts)
  {
    if (/^ *([^:].*) *: *(.*) *$/)
    { $t .= "<tr><td class=\"shortcuts\">$1</td>" .
                "<td class=\"shortcuts\">$2</td></tr>\n"; }
    else
    { $t2 .= $_; }
  }
  $t =<<"__UP_TO_HERE__";
$header
<h3>GP Keyboard Shortcuts</h3>
$t2
<table class="shortcuts">
$t
</table>
__UP_TO_HERE__
  printHTML('keyboard_shortcuts.html', 'GP Keyboard Shortcuts', '', $t);
}
# write GP readline introduction
sub writeReadline {
  my ($t) = "<h3>GP Line Editor: Readline</h3>\n";
  my ($e) = get_entry("readline");
  $t .= $e;
  printHTML('readline.html', 'GP Keyboard Shortcuts', '', $t);
}
# write GP operators section
sub writeOperators {
  my ($t) = "<h3>GP Operators and their Priorities</h3>\n";
  my ($e) = get_entry("operator");
  $t .= $e;
  printHTML('operators.html', 'GP Operators', '', $t);
}

###########################################################################
# Writes, for each list pointed to by $key, a file $key.html containing the
# subsections of the corresponding section in usersch3.tex. Needs %subsections
# and uses "gphelp -raw to convert subsections of usersch3.tex into html.
# Use in the form writeEntries($key)
###########################################################################
sub writeEntries() {
  my ($key) = $_[0];

  my ($cleankey) = cleankey($key);
  print STDERR "\twriting: $cleankey\n";
  # desambiguate between keywords belonging to 2 sections, e.g. 'log'
  my ($pre) = ($cleankey eq "GP defaults")? "se:def,": "";
  my ($e, $names) = get_entry("$key");
  my ($txt) = "\n$names<h2 class=\"center\">$cleankey</h2>\n\n";
  $txt .= $e; # initial text
  if ($e) { $txt .= "<hr>\n" }
  for my $item (@{ $subsections{$key} }) {
    my ($a) = cleanid($item);
    my ($e,$names,$title) = get_entry("$pre$item");
    $txt .= "$names<div id=\"$a\"></div>\n$title\n$e\n<hr>\n";
  }
  printHTML( "$fill{$key}.html", "$cleankey", '', $txt);
}

# auxilliary for writeData
sub printFile { my($skin, $Mode, $data, $parm) = @_;
  # all skins
  return if (!$Mode);
  if ($Mode eq 'TXT') { printTXT(@{$parm}, $data); return; }
  # no html in ref mode
  if ($Mode eq 'HTML') { printHTML(@{$parm}, $data) if (!$skin); return; }
  # PIC: filter out unneeded icons according to skin
  my ($f) = @{$parm}; # filename
  return if ($skin && ($f eq 'empty.jpg' || $f eq 'toc.jpg'));
  return if (!$skin && ($f eq 'home.gif' || $f eq 'top.gif'));
  $data =~ s/\s//g; printPIC(@{$parm}, $data);
}

################################################################
# Writes html pages and images described in file FILE. See below
# __DATA__ for the description syntax.
# Call in the form writeData (*FILEHANDLE, $skin) 1 for ref/0 else
################################################################
sub writeData {
  my ($IN, $skin) = @_;
  my($Mode, @parm, $data);

  $Mode = '';
  while (<$IN>) {
    if (/^\s*\@PIC\{\s*(.*?)\s*\}/) {
      @parm = ($1);
      $data = ''; $Mode = 'PIC'; next;
    }
    if (/^\s*\@HTML\{\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*\}/) {
      @parm = ($1, $2, $3);
      $data = ''; $Mode = 'HTML'; next;
    }
    if (/^\s*\@TXT\{\s*(.*?)\}/)
    {
      @parm = ($1);
      $data = ''; $Mode = 'TXT'; next;
    }
    if (/\@DONE/) {
#      print "writing $parm[0]\n";
      printFile($skin, $Mode, $data, \@parm);
      $Mode = ''; next;
    }
    next if (!$Mode);

    # eval. variables in DATA section
    if ($Mode eq 'HTML') { s/\$(\w+)/${$1}/g; };
    $data .= $_; next;
  }
}

##################################################################
# Writes an html page to file $HTML/$f. Call in the form
# printHTML($name_of_file, $title_of_page, $background, $contents)
# with properly initialized scalar arguments.
# If $content starts by <FRAMESET> then no <BODY> tag is printed
##################################################################
sub printHTML { my ($f, $title, $bgd, $con) = @_;
  my ($DTD);
  if ($con =~ /^<FRAMESET/i)
  { $DTD = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">'; }
  else
  {
    $DTD = '<!DOCTYPE html>';
    $con = "<body $bgd>$con</body>";
  }
  my ($meta) = '';
  $meta = '<meta name="robots" content="noindex">' if ($f =~ /^cont_/);

  open OUT, ">$HTML/$f" or fatal("Cannot create the file $HTML/$f\n");
  print OUT <<"__UP_TO_HERE__";
$DTD
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Catalogue of GP/PARI Functions: $title</title>

  <meta name="author"       content="Karim Belabas">
  <meta name="created"      content="$DATE">
  <meta name="author-email" content="pari\@math.u-bordeaux.fr">
  <meta name="keywords"     content="PARI, GP, DOC">
  $meta
  <link rel="stylesheet" href="/pari.css">
  <link rel="stylesheet" href="./gphtml.css">
</head>
$con
__UP_TO_HERE__
  close OUT;
}

########################################################
# Writes a stream of 2 digit hex values as chars to file
# Call in the form printPIC( $file, $stream)
########################################################
sub printPIC { my ($f, $data) = @_;
  open OUT, ">${HTML}/$f" or fatal( "Cannot create the file ${HTML}/$f\n");	
  $data =~ s/(..)/chr(hex($1))/ge;
  print OUT $data;
  close OUT;
}
sub printTXT { my ($f, $data) = @_;
  open OUT, ">${HTML}/$f" or fatal( "Cannot create the file ${HTML}/$f\n");	
  print OUT $data;
  close OUT;
}

################DO NOT ALTER BELOW THIS LINE #############################
sub initFixedData
{
  @ou = qw(
    nbrk
    dollar
    startbold endbold
    startcode endcode
    startpodcode endpodcode
    startbi endbi
    startit endit
    startword endword
    startlword endlword
    pm
    obr cbr
    lt gt
    agrave eacute uuml ouml
  );
#         dollar                                             => ignore
#         nbrk                                               => ignore
#         startbold endbold        -gp/pari functions        => boldface
#         startcode endcode        -???                      => color
#         startpodcode endpodcode  -???                      => go
#startlink endlink                 -nix da in raw
#startbcode endbcode               -nix da in raw
#         startbi endbi            -blackboard boldface      => boldface
#         startit endit            -optional argments        => underline
#         startword endword        -greek letters            => color
#         startlword endlword      -math.abbrev. like $\log$ => ignore
#         pm                       -+-                       =>
#empty gt lt podleader             -nix da in raw            => ignore
#
# Neu in parigp.2.1.1:
#         obr cbr                                            => { }
#         lt gt                                              => < >
#	  agrave eacute uuml ouml                            => &agrave; ...

  @tr{@ou} = map "\@[$_]", @ou;

  %html = (
    nbrk         => '&nbsp;',
    startbold    => '<b>',
    endbold      => '</b>',
    startcode    => '<code>',
    endcode      => '</code>',
    startpodcode => '',
    endpodcode   => '',
    startbi      => '<b>',
    endbi        => '</b>',
    startit      => '<em>',
    endit        => '</em>',
    startword    => '<font color=#FF0000>',
    endword      => '</font>',
    dollar       => '',
    startlword   => '',
    endlword     => '',
    pm           => '&#177;',
    obr          => '{',
    cbr          => '}',
    lt           => '&lt;',
    gt           => '&gt;',
    agrave       => '&agrave;',
    eacute       => '&eacute;',
    uuml         => '&uuml;',
    ouml         => '&uml;',
  );
}

__DATA__

Layout of frames:
=================

         / empty empty empty empty
        /              item
 index <   empty toc   ----- empty
        \              entry
         \ empty empty title empty

@HTML{index.html, Main Page,}
<FRAMESET COLS="1%,280,*,1%" ROWS="1%,91%,8%" BORDER=0 FRAMEBORDER="no" FRAMESPACING=0>
<FRAME src="empty.html" scrolling="no" style="border:none">
<FRAME src="empty.html" scrolling="no" style="border:none">
<FRAME src="empty.html" scrolling="no" style="border:none">
<FRAME src="empty.html" scrolling="no" style="border:none">

<FRAME src="empty.html" scrolling="no" style="border:none">
<FRAME src="toc.html" style="border:none">
<FRAMESET rows="140,*" border=0 frameborder="yes" framespacing=0>
<FRAME name="itemFrame"   src="item.html">
<FRAME name="entryFrame"  src="entry.html">
</FRAMESET>
<FRAME src="empty.html" scrolling="no">

<FRAME src="empty.html" scrolling="no">
<FRAME src="empty.html" scrolling="no">
<FRAME src="title.html" scrolling="no">
<FRAME src="empty.html" scrolling="no">
</FRAMESET>
@DONE

@HTML{empty.html, Empty Page :-), style="background-image:url(empty.jpg)"}
@DONE

@HTML{title.html, Title Page, style="background-image:url(empty.jpg)"}
Catalogue of Functions for the $version.
<br>
<small>(generated by gphtml on $DATE.)</small>
@DONE

@HTML{item.html, Items Page, style="background-color:#FFFFFF;"}
@DONE

@HTML{entry.html, Welcome Page, style="background-color:#FFFFFF;"}
<br><br>
<center>
<h2>This is an html documentation of<br>
functions available under the $version.</h2>
</center>
<br>
Comments and proposals for improvement
<a href="mailto:pari@math.u-bordeaux.fr">
are welcome</a>.
<br>
<br>
You can <a href="../$HTML.tgz">download these html files</a> (as gzipped tar
file) or generate them by yourself using the perl script
<a href="../gphtml">gphtml</a> (provided perl, gp, gphelp and the gp/pari tex
documentation file usersch3.tex are installed on your system).
@DONE

@PIC{empty.jpg}
ffd8ffe000104a46494600010101004800480000fffe0017437265617465642077697468205468652047494d50ffdb004300080606070605080707070909080a0c140d0c0b0b0c1912130f141d1a1f1e1d1a1c1c20242e2720222c231c1c2837292c30313434341f27393d38323c2e333432ffdb0043010909090c0b0c180d0d1832211c213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232ffc0001108000a000a03012200021101031101ffc4001500010100000000000000000000000000000006ffc40014100100000000000000000000000000000000ffc4001501010100000000000000000000000000000506ffc40014110100000000000000000000000000000000ffda000c03010002110311003f00b800c261ffd9
@DONE

@PIC{toc.jpg}
ffd8ffe000104a46494600010101004800480000fffe0017437265617465642077697468205468652047494d50ffdb004300080606070605080707070909080a0c140d0c0b0b0c1912130f141d1a1f1e1d1a1c1c20242e2720222c231c1c2837292c30313434341f27393d38323c2e333432ffdb0043010909090c0b0c180d0d1832211c213232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232ffc00011080014011803012200021101031101ffc40017000101010100000000000000000000000002000106ffc4001510010100000000000000000000000000000001ffc40017010101010100000000000000000000000002010506ffc4001511010100000000000000000000000000000001ffda000c03010002110311003f00ee0a0946c399850861094694128850a10c242850a0c28250a3632362142282510a142830a2146c3810e2146c2184250a1418510a146c646c42850a0c282508a09442850a0c28851b0a0c28850a10c24285128909c01449aae76142484a34a24850a124850a14484a146c490a114490a142892146c3892146c2484a1428921428d8921428512128451242850a24851b0a24850a124850a24909ffd9
@DONE

@PIC{home.gif}
47494638396110000d00b30000000000664433995522444444bb6644bb8866aa8888ccbb88bbccddddddddddbb99ffddbbffffddddeeffc0c0c0ffffff21f9040100000c002c0000000010000d0040042c90c949ab7429eb9d9cbf5cd84d5e699614b6391673bedee88a2b4b9a2d18be3a9db12a5acc1614a17a464604003b
@DONE

@PIC{top.gif}
4749463839610f000b00f10300000000c0c0c0ddddddffffff21f90401000003002c000000000f000b0000025edcb871e3c28d1b376edcb871a1c28d1b376edcb850a2c28d1b376e5c2851a2c28d1b372e942851a2c28d1b17268c283161c28d1b372e94a870e3c68d1b3746949871e3c68d1b174a54b871e3c68d1b234accb871e3c68d0b1326dcb87105003b
@DONE

@TXT{gphtml.css}
table { width: 100%; }
img { border: 0px; }

table.ref { padding: 0px; border-spacing: 0px; background-color: #FFFFEE;
            border: 0px;}
td.refh { padding: 4px; background-color: #EEEEAA; }
tr.spacer { background-color:#FFFFFF; height: 6px; }
table.reftop { padding: 2px; border-spacing: 0px; background-color: #83a2ef;
            border: 0px; }
table.toc { padding: 0px; border-spacing: 0px; border: 0px }
table.index { padding: 4px; border-spacing: 0px; border: 0px }

.shortcuts { padding: 5px; border-spacing: 0; background-color: #83a2ef;
             border: 1px solid black;}
table.shortcuts { border-collapse: collapse; width: 80%; }

.right { text-align:right; }
.center { text-align:center; }
.left { text-align:left; }
@DONE
