GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
#!/usr/bin/perl -w1#2# Script to convert GAP manual TeX files to HTML3# Usage:4# convert.pl [-csti] [-f <frontpage>] [-n <sharepkg>] <doc-dir> [<html-dir>]5#6# Requirements: Perl (might need to edit the first line of this file)7# TtH is not strictlty necessary but very desirable to treat8# formulas.9#10# Caveats:11#12# 1. This script assumes that the .toc, .lab and .bbl files are up-to-date13# with the .tex files and will almost certainly fail horribly if they14# are not.15#16# 2. The output files are CxxxSxxx.htm, (not .html) plus chapters.htm,17# theindex.htm and biblio.htm, except when called with the -c option18# (in which case, there are CHAPxxx.htm files instead of CxxxSxxx.htm).19# A (front page) file index.htm is assumed, but not created.20# Not all servers will serve .htm files as HTML without adjustments.21#22# 3. The script assumes that the .tex files comply with GAP conventions,23# including unwritten ones. It tries to follow the behaviour of TeX24# assuming those conventions. The on-line browser attempts to provide25# an ASCII equivalent. See BUGS.26#27# 4. The hierarchy of the HTML manuals assumed is of the following form:28#29# <GAPDIR>/30# doc/31# htm/32# <main>33# pkg/34# <pkg>/35# htm36#37# for each main manual <main> (in: ref, ext, tut, prg, new) and each38# share package <pkg>. To make inter-linking between manuals work,39# one should generally use the -c option for everything, (or not use40# it for everything). Linking to share package manuals from the main41# manual can only be expected to work if the share package manuals42# are created using this converter.43#44# 5. Only the manual.lab files for books that are referenced via the45# \UseReferences and \UseGapDocReferences commands in the manual.tex46# file of the book being converted (and the book's own manual.lab47# file, of course) are read. Make sure all the \UseReferences and48# \UseGapDocReferences commands needed are present! (The TeX-produced49# manuals will be missing lots of cross-references also, if some are50# missing.) You will get `Bad link' messages if you have some missing.51#52# Options:53#54# -c file-per-chapter mode: Generates one HTML file CHAPxxx.htm55# for each chapter; sections are level 2 headings and anchors56# CHAPxxx.htm#SECTxxx.57# This is intended for local browsing, especially under MS-DOS.58# It may be used with the -n (share package) option.59#60# -f <frontpage>61# Adds a "Top" link to link <frontpage> to each manual page,62# only available if -n option is also used.63#64# -s silent running: Conversational messages are suppressed.65#66# -n <sharepkg>67# We are not building the main manual but the one for the share68# package <sharepkg>. To get cross references to the main library69# right, it assumes that the share package is in the right place.70# The -c option may be used with this option.71#72# -i index: Only one index file is produced.73#74# -t tex-math: Runs `tth' (which must be installed on the local system)75# to produce better HTML code for formulae. (It would be possible to76# replace tth by another conversion, for example TeXexplorer, but77# (at least) the line calling `tth' would need to be modified.)7879# -u Like -t, but uses `tth -u1' to produce unicode.80#81# <doc-dir> The directory where all the needed .tex, .toc, .lab and .bbl82# files are located.83#84# <html-dir> The directory (which should already exist) in which to put85# the generated .htm files. Defaults to the current directory,86# if omitted.87#88# Example usage:89# convert.pl -n mypkg doc htm # in directory .../pkg/mypkg90# convert.pl -t -n mypkg doc htm # ditto previous + use tth for maths91# convert.pl -t -n mypkg -c doc htm # ditto previous + 1 file per chapter92# convert.pl -t -c ../ref ref # (for Ref manual) in dir .../doc/htm93#94# FEATURES (and intended departures from the TeX behaviour)95# . Now interprets 2nd argument of an \atindex command if it is96# of form @... and ignores the first argument, or otherwise it97# interprets the first argument. Interprets ! as a comma and98# indices output have no sub-headers.99# . The @... component of \> commands is ignored. The assumption100# is that for: \>`...'{...}@{...} the @{...} component is just101# the {...} with font changes.102# . In a \beginitems ... \enditems environment everything is indented103# except for the item headers, rather than just the paragraph104# following the item header.105# . By default, the \beginlist ... \endlist environment is interpreted106# as a compact description list. By adding %unordered or %ordered...107# markup it will be interpreted as either an unordered or ordered108# list respectively (see the ext manual for details).109# . There are spacing differences e.g. \begintt ... \endtt etc.110# environments are not indented.111# . Supports all accents of TeX, in probably the best way currently112# possible with HTML.113# . Treats PseudoInput chapters in the `same' way as Input chapters.114# . With -t switch announces the version of TtH used.115# . Now supports %display{nontex}, %display{nontext} and116# %display{nonhtml} variants of %display environment.117# . References to subsections are now interpreted as one would expect.118#119# BUGS (and known departures from the TeX behaviour)120# . $a.b$ is only interpreted correctly in -t mode.121# . The citation keys that appear are the .bib file keys rather122# than the keys BibTeX constructs with the `alpha' bib-style.123#124# TODO125# . Refine macro_replace subroutine so it can also be used to purge126# 2nd arg of \atindex macros.127# . For -t mode, scan for \def commands in manual.tex and write128# to TTHIN (tthmacros.tex). Should we only look for a block129# demarcated by %mathsmacros ... %endmathsmacros ?130# These \def commands are only intended for such font131# changing commands as: \def\B{{\cal B}} (`tth' provides a132# script-type font).133# . Provide a table environment, if/when a \begintable ...134# \endtable environment is added to gapmacro.tex.135#136#############################################################################137138# Check PERL version139#140$] > 5 or die "Needs perl 5";141142use Getopt::Std;143144145#146# Global variables147#148# $dir -- the full pathname of the input directory, including a trailing /149# $odir -- the full pathname of the output directory, including a trailing /150# $opt_c and $opt_s set by getopts()151# @chapters -- the chapters data structure152# IN -- the current input file (outputfiles are handled by select)153# $footer -- the trailer put on every page154# $indexcount -- used within chapters to number the index anchors155# $lastnumchap -- number of last numerically numbered chapter156#157158159# These match chapter and section lines in a .toc file160#161162$chapexp = '\\\\chapcontents\s+\{((?:\d+|[A-Z]))\}\s*\{(.+)\}\s*\{\d+\}';163$secexp = '\\\\seccontents\s+\{((?:\d+|[A-Z]))\.(\d+)\}\s*\{(.+)\}\s*\{\d+\}';164#$ignoreexp = '\\\\tocstrut|\\\\appno|\\\\seccontents\s+\{\d+\}';165$lastnumchap = 0;166167# Variable that is set to 2 inside a nest of \itemitem s of a168# \beginlist ... \endlist environment169#170171$listdepth = 0;172173# This is augmented each time a line: \Package{...} is read in a manual.tex174# file, so that macro_replace knows to set a {\...} macro in sans-serif.175#176177$sharepkg = "";178179# The books converted to HTML with this converter180# The values set are: 0 or 1 according to whether or not -c was used.181#182183%convertbooks = ();184185# This is added to when scanning for \UseGapDocReferences.186#187188%gapdocbooks = ();189190# Types of href label are:191# 0 (non -c books) : C<MMM>S<NNN>.htm192# 1 (-c books) : CHAP<MMM>.htm#SECT<NNN>193# 2 (== $gapdoc) : chap<M>.html#s<N>ss0194#195# It would be nice to support subsections properly like GapDoc,196# but this involves creating a subsection data-structure modelled197# on section, which is a mite non-trivial (maybe ... if I find time).198# For now in-text references go to the beginning of the chapter.199#200201$gapdoc = 2;202203# sansserif:204#205# Used mainly to set GAP in sans serif font. Inside <title> ... </title>206# there should *not* be any tags, since they are not translated there by207# web browsers, and hence sansserif should *not* be applied to anything208# that ends up in the <title> ... </title> field, but *is* quite appropriate209# for the header in the <h1> ... </h1> field at the top of the body of an210# HTML file and anywhere else within the body of an HTML file.211#212sub sansserif {213my ($name) = @_;214return "<font face=\"Gill Sans,Helvetica,Arial\">$name</font>";215}216217# booktitle_body:218#219# This is for generating the title of a document that goes in the220# <h1> ... </h1> field at the top of the body, as opposed to the title221# that goes in the <title> ... </title> field which should be unembellished.222#223sub booktitle_body {224my ($bktitle, @prog_or_pkg) = @_;225foreach $prog_or_pkg (@prog_or_pkg) {226$newstring = sansserif $prog_or_pkg;227$bktitle =~ s/$prog_or_pkg/$newstring/;228}229return $bktitle;230}231232#233# used to standardize section names for use as hash indices.234#235236sub canonize {237my ($key) = @_;238$key =~ tr/A-Z/a-z/;239$key =~ s/\s//g;240$key =~ s/\\//g;241$key;242}243sub kanonize {244my ($key) = @_;245$key =~ s/\\ / /g;246$key =~ s/!/ /g;247$key;248}249250sub def_section_by_name {251my ($sec, $chapno, $secno, $ssecno) = @_;252my $secname = canonize $1;253if (defined $sections_by_name{$secname}) {254if (($sections_by_name{$secname}->{chapnum} ne $chapno) ||255($sections_by_name{$secname}->{secnum} ne $secno) ||256($sections_by_name{$secname}->{ssecnum} ne $ssecno)) {257print STDERR "Section: \"$secname\" already defined as: ",258"$sections_by_name{$secname}->{chapnum}.",259"$sections_by_name{$secname}->{secnum}.",260"$sections_by_name{$secname}->{ssecnum}\n";261print STDERR "Now being redefined as: $chapno.$secno.$ssecno\n";262$redefined_secname{$secname} = 1;263} else {264return;265}266}267$sections_by_name{$secname}268= {chapnum => $chapno,269secnum => $secno,270ssecnum => $ssecno};271# print STDERR "Defined section \"$secname\": $chapno.$secno.$ssecno\n";272}273274sub tonum { # Needed since chanu may be A,B,... for appendices275my ($chanu) = @_;276return $chanu =~ /\d+/ ? $chanu : $lastnumchap + ord($chanu) - ord('A') + 1;277}278279# getchaps:280#281# Scan the .tex and .toc files to get chapter names and numbers,282# section names and numbers and associated filenames.283# Loads up chapters and sections_by_name.284#285286sub getchaps {287open( TOC, "<${dir}manual.toc" )288|| die "Can't open ${dir}manual.toc.\n You can " .289"create the .toc file by doing: tex manual (at least once).\n";290my ($chap,$sec,$chapno,$chap_as_sec,$chapnam,$chanu);291while (<TOC>) {292if ( /$chapexp/o ) {293$chapnam = $2;294$chanu = $1;295$lastnumchap = $chanu if ( $chanu =~ /\d+/ );296297# remove `(preliminary)' part that messes everything up298$chapnam =~ s/ \(preliminary\)//g;299300$chap = {name => $chapnam,301number => $chanu};302$chap_as_sec = {name => $chapnam,303chapnum => $chanu,304secnum => 0,305chapter => $chap};306$chap->{sections}[0] = $chap_as_sec;307defined ($chapters[tonum $chanu]) && die "chapter number repeated";308$chapters[tonum $chanu] = $chap;309} elsif ( /$secexp/o ) {310defined ($chapters[tonum $1])311|| die "section $2:$3 in unknown chapter $1";312defined ($chapters[tonum $1]{sections}[$2])313&& die "section number repeated";314$sec = {name => $3,315secnum => $2,316chapnum => $1,317chapter => $chapters[tonum $1]};318$chapters[tonum $1]{sections}[$2] = $sec;319# this would produce warnings from empty chapters. Thus ignore.320# } elsif ( $_ !~ /$ignoreexp/o ) {321# print STDERR "Bad line: $_";322}323}324close TOC;325open (TEX, "<${dir}manual.tex") || die "Can't open ${dir}manual.tex";326$chapno = 0;327while (<TEX>) {328if ( /^[^%]*\\(|Pseudo)Input\{([^}]+)\}(\{([^}]+)\}\{([^}]+)\})?/ ) {329if (not -f "$dir$2.tex" or not -r "$dir$2.tex") {330print STDERR "Chapter file $2.tex does not exist in $dir\n";331}332if ($1 eq "") {333$chapters[++$chapno]{file} = $2;334} else {335$chapnam = $5;336$chanu = ++$chapno;337$lastnumchap = $chanu;338339$chap = {name => $chapnam,340number => $chanu};341$chap_as_sec = {name => $chapnam,342chapnum => $chanu,343secnum => 0,344ssecnum => 0,345chapter => $chap};346if ($4 ne $5) {347def_section_by_name("$book:$chapnam", $chanu, 0, 0);348add_to_index(htm_fname($opt_c,$chanu,0),349$4, $chap_as_sec, 0);350}351352$chap->{sections}[0] = $chap_as_sec;353defined($chapters[$chanu]) && die "chapter number repeated";354$chapters[$chanu] = $chap;355$chapters[$chanu]{file} = $2;356}357}358}359close TEX;360}361362sub getlabs {363my ($bkdir) = @_;364open (LAB, "<${bkdir}manual.lab") || print "Can't open ${bkdir}manual.lab";365while (<LAB>) {366if ( /\\setcitlab/ ) {367next; # We don't get the bibliography labels from here368} elsif (/\\makelabel\s*\{([^}]+)\}\s*\{(\w+)(\.(\d+))?(\.(\d+))?\}/) {369def_section_by_name($1, $2, (defined($3) ? $4 : 0),370(defined($5) ? $6 : 0));371} else {372chomp;373print STDERR "Ignored line: $_\n... in ${bkdir}manual.lab\n";374}375}376close LAB;377}378379#380# Mainly diagnostic, prints the chapters data structure. Also381# checks that each section has the correct back reference to its382# chapter383#384385sub printchaps {386my @chapters = @_;387CHAP: foreach $chapter (@chapters) {388next CHAP unless (defined ($chapter));389print "Chapter $chapter->{number} $chapter->{name} $chapter->{file}\n";390SECT: foreach $section (@{$chapter->{sections}}) {391next SECT unless defined ($section);392print " Section $section->{chapnum}.$section->{secnum} $section->{name}\n";393if ($section->{chapter} ne $chapter ) {394print " loop problem\n";395}396}397398}399}400401# Printed at the bottom of every page.402$footer = "<P>\n" . sansserif( "GAP 4 manual<br>" . `date +"%B %Y"` ) .403"</body></html>";404405# Section label ... this is the bit that goes after a # in an HREF link406# or is assigned to the value of NAME in an anchor.407#408sub sec_label {409my ($c_s_gapdoc,$cnum,$snum,$ssnum) = @_;410411if ($c_s_gapdoc == $gapdoc) {412return "s${snum}ss${ssnum}";413}414415$snum = "0" x (3 - length $snum) . $snum;416if ($c_s_gapdoc) {417if ($snum eq "000") {418return "";419} elsif ($ssnum) {420return "SSEC${snum}.$ssnum";421} else {422return "SECT${snum}";423}424} else {425return ($ssnum) ? "SSEC$ssnum" : "";426}427}428429# The HREFs of subsections, sections and chapter files are determined by430# this routine directly if the chapter, section, subsection numbers are known.431sub htm_fname {432my ($c_s_gapdoc,$cnum,$snum,$ssnum) = @_;433434my $seclabel = sec_label($c_s_gapdoc,$cnum,$snum,$ssnum);435$seclabel = "#$seclabel" if ($seclabel ne "");436437if ($c_s_gapdoc == $gapdoc) {438return "chap${cnum}.html$seclabel";439}440441$cnum = "0" x (3 - length $cnum) . $cnum;442$snum = "0" x (3 - length $snum) . $snum;443return ($c_s_gapdoc) ? "CHAP${cnum}.htm$seclabel"444: "C${cnum}S$snum.htm$seclabel";445}446447# Returns the value that $opt_c must have had when the book $book448# was compiled with this converter.449sub hreftype {450my ($book, $bdir) = @_;451if ( !(exists $convertbooks{$book}) ) {452my @ls = `ls ${odir}$bdir`;453$convertbooks{$book}454= (grep { m/^CHAP...[.]htm$/ } @ls) ?4551 : # .htm files have shape CHAP<MMM>.htm456(grep { m/^CHAP...[.]htm$/ } @ls) ?4570 : # .htm files have shape C<MMM>S<NNN>.htm458$opt_c; # can't determine the shape ... don't exist459# yet ... we assume the shape of the current460# manual being compiled.461}462return $convertbooks{$book};463}464465# The names of the section and chapter files are determined by this routine466# when one has to determine the chapter and section number indirectly.467sub name2fn {468my ($name,$ischap) = @_;469my $bdir = "";470my $c_s_gapdoc = $opt_c;471472# : indicates a cross-volume reference473my $canon_name = canonize $name;474#print STDERR "canon_name = $canon_name\n";475if ( $canon_name =~ /^(ref|tut|ext|prg|new):/ ) {476if ($mainman==1) {477$bdir = "../$1/";478} else {479$bdir = "../../../doc/htm/$1/";480}481$c_s_gapdoc = hreftype($1, $bdir);482} elsif ($canon_name =~ /^([a-zA-Z_0-9]*):/ ) {483# presumably a package name484#print STDERR "package name = $1\n";485if ($mainman==1) {486if (exists $gapdocbooks{$1}) { # a main manual referring487$bdir = "../../../pkg/$1/doc/"; # to a GapDoc-produced manual488$c_s_gapdoc = $gapdoc;489} else {490$bdir = "../../../pkg/$1/htm/";491$c_s_gapdoc = hreftype($1, $bdir);492}493} elsif (exists $gapdocbooks{$1}) { # a package manual referring494$bdir = "../../$1/doc/"; # to a GapDoc-produced manual495$c_s_gapdoc = $gapdoc;496} else {497$bdir = "../../$1/htm/";498$c_s_gapdoc = hreftype($1, $bdir);499}500} elsif ($canon_name !~ /^($book):/) {501$name = "$book:$name";502$canon_name = canonize $name;503}504$name =~ s/\s+/ /g;505506if (exists $redefined_secname{$canon_name}) {507print STDERR "Ref to multiply defined label: ",508"\"$name\" at line $. of $chap->{file}.tex\n";509}510my $sec = $sections_by_name{$canon_name};511512unless (defined ( $sec)) {513print STDERR "Bad link: \"$name\" at line $. of $chap->{file}.tex\n";514return "badlink:$name";515}516return $bdir . htm_fname($c_s_gapdoc,517$sec->{chapnum},518($ischap == 1) ? 0 : $sec->{secnum},519($ischap == 1) ? 0 : $sec->{ssecnum});520}521522523# strip out the tag from cross book references for the body of links524sub name2linktext {525my $name;526($name) = @_;527$name =~ s/^(ref|tut|ext|prg|new)://;528return $name;529}530531#532# Add an index entry to the index.533# ($hname = $fname or $fname#..., where $fname is a filename)534sub add_to_index {535my ($hname, $key, $sec) = @_;536my $secno = "$sec->{chapnum}.$sec->{secnum}";537if (defined $sec->{ssecnum} and $sec->{ssecnum}) {538$secno .= ".$sec->{ssecnum}";539}540push @{$index{$key}}, [ $hname, $secno ];541# print STDERR "hname = $hname, key = $key, ";542# print STDERR "sec = $secno\n";543}544545#546# Create a label for an index entry, add it to the index if new,547# and return the label (which is an empty string if not new).548sub inxentry {549my ($fname,$key,$sec) = @_;550my $curs="$sec->{chapnum}.$sec->{secnum}";551# print STDERR "curs = $curs\n";552# print STDERR "fname = $fname, key = $key, ";553# print STDERR "sec = $sec->{chapnum}.$sec->{secnum}\n";554my $label = "<a name = \"I$indexcount\"></a>\n";555if (defined $index{$key}) {556my $ar;557foreach $ar (@{$index{$key}}) {558if ( ($ar->[1]) eq $curs ) {559$label=""; # index entry is not new560last;561}562}563} else {564$index{$key} = [];565}566if ($label ne "") {567add_to_index("$fname#I$indexcount", $key, $sec);568# print STDERR "$fname#I$indexcount\n";569$indexcount++;570}571return $label;572}573574#575# Return a NAME anchor for a subsection576#577sub subsec_name {578my ($fname,$key,$sec) = @_;579# print STDERR "curs = $curs\n";580# print STDERR "sec = $sec->{chapnum}.$sec->{secnum}.$sec->{ssecnum}\n";581$key =~ s/!\{(.*)\}$/!$1/;582$key =~ s/\s+/ /g;583my $canon_name = canonize "$book:$key";584my $sec_of_key = $sections_by_name{$canon_name};585if (exists $redefined_secname{$key}) {586print STDERR "Multiply defined label: ",587"\"$key\" at line $. of $chap->{file}.tex\n",588"... subsection will be unreachable\n";589return "";590} elsif ($sec_of_key->{chapnum} ne $sec->{chapnum} ||591$sec_of_key->{secnum} ne $sec->{secnum}) {592print STDERR "Section of \"$key\" (",593"$sec_of_key->{chapnum}.$sec_of_key->{secnum}) ",594"doesn't agree with the current section (",595"$sec->{chapnum}.$sec->{secnum}) ",596"at line $. of $chap->{file}.tex\n",597"... subsection will be unreachable\n";598return "";599} else {600my $curs = "$sec_of_key->{chapnum}.$sec_of_key->{secnum}" .601".$sec_of_key->{ssecnum}";602my $label = sec_label($opt_c, $sec_of_key->{chapnum},603$sec_of_key->{secnum},604$sec_of_key->{ssecnum});605if (defined $index{$key}) {606my $ar;607foreach $ar (@{$index{$key}}) {608if ( ($ar->[1]) eq $curs ) {609return ""; # index entry is not new610}611}612} else {613$index{$key} = [];614}615# print STDERR "Subsection key: \"$key\"\n";616add_to_index("$fname#$label", $key, $sec_of_key);617return "<a name = \"$label\"></a>\n";618}619}620621622# Some characters must be represented differently in HTML.623sub html_literal {624my ($lit) = @_;625if ($lit eq "<") { return "<"; }626elsif ($lit eq ">") { return ">"; }627elsif ($lit eq "&") { return "&"; }628else { return $lit; }629}630631632# Gather lines ending in % together.633sub gather {634my ($line, $nontex) = @_;635my $nextline;636while ($line =~ s/%+\s*$// and defined($nextline = <IN>)) {637$nextline =~ s/^%// if $nontex;638unless ($nextline =~ /^%/) {639$nextline =~ s/^\s*//;640$line .= $nextline;641chomp $line;642}643}644return $line;645}646647648# This routine is called to process the text of the section649# the output file is assumed to be pre-selected. The input filehandle650# is simply IN651#652# As we process, we can be in "normal" mode (text), "maths" mode653# inside $ ... $, or "verbatim" mode inside a multi-line example654#655# We separately track whether we are in bold or tt,656# whether we are in a xxx: .... paragraph and whether we are reading657# a cross-reference that is split across multiple lines658#659# Finally, we track whether we have already660# emitted a <P> for this group of blank lines661#662663664$boldcommands = 'CAS|[A-Z]|danger|exercise';665$TeXbinops = "in|wedge|vee|cup|cap|otimes|oplus|le|ge|rightarrow";666$EndTeXMacro = "(?![A-Za-z])";667$TeXaccents = "\'`~=^"; # ^ must come last, this is also used as regexp668# From these and the argument following the HTML symbol is built669# e.g. `a -> à670%accents = ( "\'" => "acute", "19" => "acute",671"`" => "grave", "18" => "grave",672"~" => "tilde", "126" => "tilde",673"^" => "circ", "94" => "circ",674"c" => "cedil", "48" => "cedil",675"H" => "uml", "125" => "uml", "127" => "uml" );676# These are the replacements for accents that have an empty argument677# or for which there is no single HTML symbol (so that the accent must678# precede the argument)679%acc_0arg = ( "\'" => "\'", "19" => "\'",680"`" => "`", "18" => "`",681"~" => "~", "126" => "~",682"=" => "macr", "22" => "macr",683"^" => "^", "94" => "^",684"c" => "", "48" => "", # too hard ... just omit685"d" => "", # too hard ... just omit686"b" => "", # too hard ... just omit687"t" => "", # too hard ... just omit688"u" => "\\u", "21" => "\\u", # too hard ... put back689"v" => "\\v", "20" => "\\v", # too hard ... put back690"H" => "uml", "125" => "uml", "127" => "uml" );691692# Calls tth to find out its version number693sub tth_version {694`tth -H >tthout 2> tthout`;695open (TTHOUT, "<tthout") || die "Can't read tthout\n";696while (<TTHOUT>) {697if (s/.*(Version [^ ]*).*/$1/) {698close TTHOUT;699system("rm tthout");700chomp;701return $_;702}703}704}705706707# We use this routine when using -t option to do any maths translation708sub tth_math_replace {709my ($tth) = @_;710open (TTHIN, ">tthin") || die "Can't create tthin";711#print STDERR "in: ${tth}\n";712my $tthorig = $tth;713# replace <...> by proper TeX714while ($tth =~ /(.*[^\\])<(.*[^\\])>(.*)/) {715$tth= $1."{\\it ".$2."\\/}".$3;716}717# replace `...' by proper TeX718while ($tth =~ /(.*[^\\])`(.*[^\\])\'(.*)/) {719$tth= $1."{\\tt ".$2."}".$3;720}721# replace \< by proper TeX722while ($tth =~ /(.*[^\\])\\<(.*)/) {723$tth= $1."<".$2;724}725#while ($tth =~ /(.*[^\\])\\>(.*)/) {726# $tth= $1.">".$2;727#}728729$tth =~ s/([^\\]|^)([.])/$1\\cdot /g; # . not preceded by \ becomes \cdot730$tth =~ s/\\[.]/./g; # \. becomes .731$tth =~ s/(\\right)\\cdot/$1./g; # ... except for \right. (leave as is)732$tth =~ s/(\\not)\s*/$1/g;733$tth =~ s/\\\*/*/g;734if ($opt_t < 2.52) {735$tth =~ s/\\not\\in(?![a-zA-Z])/\\notin/g;736$tth =~ s/\\not\\subset/ not subset/g;737}738# Ensure display mode used for \buildrel and \choose constructions739$tth =~ s/\$/\$\$/g if ($tth =~ /\\buildrel|\\choose/ and $tth !~ /\$\$/);740if ($tth =~ /\\[A-Za-z]/) {741# there might be macros: Load our macros742#print STDERR "tth: ${tth}\n";743print TTHIN "\\input tthmacros.tex\n";744}745# we put in TTHBEGIN .. TTHEND746# so we can strip out the superfluous <p>s747# tth 2.78+ puts in, later.748print TTHIN "TTHBEGIN${tth}TTHEND\n";749close TTHIN;750`$tthbin -r -i <tthin >tthout 2>/dev/null`;751open (TTHOUT, "<tthout") || die "Can't read tthout";752$tth="";753while ( $tthin = <TTHOUT> ) {754chomp($tthin);755$tth .= $tthin;756}757close TTHOUT;758#print STDERR "out: ${tth}\n";759# only the stuff between TTHBEGIN and TTHEND760# actually belongs to the formula translated761$tth =~ s/.*TTHBEGIN(.*)TTHEND.*/$1/762|| do {print STDERR "!tth failed with input:\n $tthorig\n",763"!Null formula written to HTML file\n";764$tth = "";};765# tth leaves \mathbin etc. in ... get rid of them if present766$tth =~ s/\\math(bin|rel|op)//g;767# TtH up to version 2.86 doesn't know the following768$tth =~ s/\\wr(?![a-zA-Z])/ wr /g;769$tth =~ s/\\vdash(?![a-zA-Z])/ |- /g;770$tth =~ s/\\tilde(?![a-zA-Z])/~/g; # needed for in-line maths771#print STDERR "stripped: ${tth}\n";772773# replace italic typewriter (happens because we force774# italic letters) by roman typewriter style775while ($tth =~ /(.*)<tt><i>(.*)<\/i><\/tt>(.*)/) {776$tth= $1."<tt>".$2."</tt>".$3;777}778779# increasing the font size doesn't affect maths displays780# ... and `...' markup doesn't get increased in font size781# So let's get rid of it.782#$tth = "<font size=\"+1\">$tth</font>";783#print STDERR "enlarged: ${tth}\n";784return $tth;785}786787#788# Takes a line of form: "<head><spaces>{<arg>}<rest>"789# and returns an array with: <rest>, <arg>, <head>790# i.e. it finds the matching } for {.791sub get_arg {792my ($line) = @_;793if ($line =~ /\s*\{([^{}]*)/) {794$line = $`;795my $arg = $1;796my $rest = $';797my $nbraces = 1;798while ($nbraces) {799if ($rest =~ s/^(\{[^{}]*)//) {800$arg .= $1;801$nbraces++;802} elsif ($nbraces == 1 and $rest =~ s/^\}//) {803$nbraces--;804} elsif ($rest =~ s/^(\}[^{}]*)//) {805$arg .= $1;806$nbraces--;807} else { # abort ... but make sure braces match808$rest = "{" x $nbraces . $rest;809$arg .= "}" x ($nbraces - 1);810$nbraces = 0;811}812}813return ($rest, $arg, $line);814} else {815print STDERR "line:$line\n";816die "Expected argument: at line $. of file";817}818}819820#821# Given an accent macro with the \ or \accent stripped and the rest822# of a line with the macro's argument at it beginning return the823# HTML version of the accented argument and rest after the macro's824# argument has been stripped from it.825sub do_accent {826my ($rest, $macro) = @_;827$rest =~ /^(\w)|\{(\w?)\}/;828$rest = $';829my $arg = (defined $1) ? $1 : $2;830$macro = ($arg eq "") ? $acc_0arg{$macro} : "&$arg$accents{$macro};";831return ($rest, $macro);832}833834#835# Takes rest which has a TeX macro without its \ at its beginning and836# returns the HTML version of the TeX macro and rest with the TeX macro837# stripped from it.838sub macro_replace {839my ($rest) = @_;840if ($rest =~ /^([$TeXaccents])\s*/) {841return do_accent($', $1);842}843if ($rest =~ /^([a-zA-Z]+)\s*/) {844$rest = $';845my $macro = $1;846if ($macro eq "accent") {847$rest =~ /^(\d+)\s*/;848$rest = $';849$macro = $1;850$macro = "" unless (defined $acc_0arg{$macro});851}852if (defined $accents{$macro}) { return do_accent($rest, $macro); }853elsif (defined $acc_0arg{$macro}) { return ($rest, $acc_0arg{$macro}); }854elsif ($macro eq "copyright") { return ($rest, "©"); }855elsif ($macro eq "aa") { return ($rest, "å"); }856elsif ($macro eq "AA") { return ($rest, "Å"); }857elsif ($macro eq "lq") { return ($rest, "`"); }858elsif ($macro =~ /^(rq|pif)$/) { return ($rest, "'"); }859elsif ($macro =~ /^($boldcommands)$/)860{ return ($rest,"<font face=\"helvetica,arial\">".uc($&)."</font>"); }861elsif ($macro =~ /^(GAP|ATLAS|MOC$sharepkg)$/)862{ return ($rest, sansserif $macro); }863elsif ($macro eq "package")864{ my ($last, $arg, $first) = get_arg("$rest"); # $first = ""865return ($last, sansserif $arg);}866elsif ($macro eq "sf")867{ my ($last, $arg, $first) = get_arg("{$rest"); # $first = ""868return ($last, sansserif $arg);}869elsif ($macro =~ /^([hv]box|rm|kernttindent|math(bin|rel|op))$/)870{ return ($rest, "");}871elsif ($macro =~ /^(obeylines|(begin|end)group)$/)872{ return ($rest, "");}873elsif ($macro =~ /^hfil(|l)$/) { return ($rest, " ");}874elsif ($macro =~ /^break$/) { return ($rest, "<br>");}875elsif ($macro =~ /^(it|sl)$/)876{ my ($last, $arg, $first) = get_arg("{$rest"); # $first = ""877return ("$arg}\\emphend $last", "<em>");}878# pseudo ``emph'' end token879elsif ($macro eq "emphend") { return ($rest, "</em>"); }880elsif ($macro eq "hrule") { return ($rest, "<hr>"); }881elsif ($macro eq "enspace") { return ($rest, " "); }882elsif ($macro eq "quad") { return ($rest, " "); }883elsif ($macro eq "qquad") { return ($rest, " "); }884elsif ($macro eq "ss") { return ($rest, "ß"); }885elsif ($macro eq "o") { return ($rest, "ø"); }886elsif ($macro eq "O") { return ($rest, "Ø"); }887elsif ($macro =~ /^l?dots$/) { return ($rest, "..."); }888elsif ($macro =~ /^bs?f|stars$/) { return ($rest, "<hr>"); }889elsif ($macro eq "cr") { return ($rest, "<br>"); }890# <li> in the next line would be invalid HTML891elsif ($macro eq "fmark") { return ($rest, " "); }892elsif ($macro eq "item")893{ ($rest, $itemarg, $first) = get_arg("$rest"); # $first = ""894if ($listdepth == 2) {895$listdepth = 1;896if ($listtype eq "d") {897return ("$itemarg\\itmnd $rest", "\n</dl>\n<dt>");898} else { #ignore bit in braces (ordered and unordered lists)899return ($rest, "\n</${listtype}l>\n<li>");900}901} else {902if ($listtype eq "d") {903return ("$itemarg\\itmnd $rest", "<dt>");904} else { #ignore bit in braces (ordered and unordered lists)905return ($rest, "<li>");906}907}908}909elsif ($macro eq "itemitem")910{ ($rest, $itemarg, $first) = get_arg("$rest"); # $first = ""911$rest =~ /^(%(un|)ordered)? #defines $sublisttype912(\{([1aAiI])\})? #defines TYPE of ordered sublist913(\{(\d+)\})? #defines START of ordered sublist914/x;915if ($listdepth == 1) {916$sublisttype = list_type($1, $2);917$sublistentry = begin_list($sublisttype, $3, $4, $5, $6) . "\n";918$listdepth = 2;919} else {920$sublistentry = "";921}922if ($sublisttype eq "d") {923return ("$itemarg\\itmnd $rest", "$sublistentry<dt>");924} else { #ignore bit in braces (ordered and unordered lists)925return ($rest, "$sublistentry<li>");926}927}928# pseudo ``itemend'' character929elsif ($macro eq "itmnd") { return ($rest, "<dd>"); }930elsif ($macro eq "cite" and $rest =~ /^\{\s*(\w+)\s*\}/)931{ return ($', "<a href=\"biblio.htm#$1\"><cite>$1</cite></a>"); }932elsif ($macro eq "URL" and $rest =~ /^\{([^\}]*)\}/)933{ return ($', "<a href=\"$1\">$1</a>"); }934elsif ($macro eq "Mailto" and $rest =~ /^\{([^\}]*)\}/)935{ return ($', "<a href=\"mailto:$1\">$1</a>"); }936else { return ($rest, $macro); }937} elsif ($rest =~ /^-/) {938return ($', ""); # hyphenation help -- ignore939} elsif ($rest =~ /^</) {940return ($', "<");941} elsif ($rest =~ /^\&/) {942return ($', "&");943} else {944$rest =~ /^./;945return ($', $&);946}947}948949# Returns the type of a list950951sub list_type {952my ($type, $un) = @_;953return ( !(defined $type) ) ? "d" #descriptive954: ($un eq "un")955? "u" #unordered956: "o"; #ordered957}958959# Returns a string for starting a list of the appropriate type960961sub begin_list {962my ($listtype, $otypedef, $otype, $ostartdef, $ostart) = @_;963my $beginlist = "<${listtype}l";964if ($listtype eq "d") {965$beginlist .= " compact";966} elsif ($listtype eq "o") {967if ( (defined $otypedef) && (defined $otype) ) {968$beginlist .= " type=$otype";969if ( (defined $ostartdef) && (defined $ostart) ) {970$beginlist .= " start=$ostart";971}972}973}974$beginlist .= ">";975return $beginlist;976}977978#979# This could probably be done more cleverly -- this routine is too long980#981982sub convert_text {983my $fname = $_[0];984my $refchars = '[\-\\w\\s`\',./:!()?$]'; # these make up cross references985my $ref = "";986my $endline = ""; # used for </code> at the end of line987my $mode = "normal"; # $mode can be:988# "normal" : TeX macros need to be interpreted989# "verbatim" : No interpretation done, except that990# || is converted to |.991# "html" : No interpretation done, except that992# initial % is removed.993# "maths" : A variant of "normal" where inside994# $...$ or $$...$$ (TeX's math mode)995my $ttenv = 0; # $ttenv is set to 1 in \begintt .. \endtt "verbatim" mode996my $nontex = 0; # $nontex is set to 1 in %display{nontex} and997# %display{nontext} env'ts, for which $mode is "normal"998# but initial % of each line is removed.999my $skip_lines = 0; # $skip_lines is set non-zero in %display{tex},1000# %display{text}, %display{jpeg}, %display{nonhtml}1001# and \answer env'ts1002my ($bold,$tt,$it,$sub,$sup,$inlist,$inref,$donepar) = (0,0,0,0,0,0,0);1003my ($indexarg,$indexarg2,$zwei,$drei,$vier,$macro,$endmath,$endmathstring);10041005#1006# Now we loop over lines. a line with 16 initial % signs marks1007# end of section1008#10091010LINE: while (defined($_ = <IN>) and not /^\%{16,}/) {1011chomp; # drop the trailing newline1012my $rest = $_; # rest of the line to scan1013my $outline = ""; # build the output in here10141015# First we deal with various special whole lines.1016# \beginexample, \begintt, %display (this may end a $skip_lines)1017if ($mode eq "normal" and /^\\begin(example|tt)/) {1018if ($_ =~ /^\\begintt/) { # This is to catch a \begintt .. \endtt1019$ttenv = 1; # environment enclosing \beginexample ..1020} # \endexample1021$mode = "verbatim";1022$skip_lines = 0;1023print "<pre>\n";1024next LINE;1025} elsif ($mode eq "normal" and /^%display\{nontex(|t)\}/) {1026$nontex = 1;1027$skip_lines = 0;1028next LINE;1029} elsif ($mode eq "normal" and /^%display\{(text?|jpeg|nonhtml)\}/) {1030# Paragraphs to be skipped by HTML.1031$mode = "normal";1032$nontex = 0;1033$skip_lines = 2;1034next LINE;1035} elsif ($mode eq "normal" and /^%display\{html\}/) {1036$mode = "html";1037$skip_lines = 0;1038} elsif ($mode eq "html" and /^%display\{text\}/) {1039$mode = "normal";1040$nontex = 0;1041$skip_lines = 2;1042next LINE;1043} elsif (/^%enddisplay/ and !$ttenv) {1044if ($mode eq "verbatim") {1045print "</pre>\n";1046}1047$mode = "normal";1048$nontex = 0;1049$skip_lines = 0;1050next LINE;1051} elsif ($mode eq "verbatim") {1052# \endexample, \endtt1053if (/^\\endtt/ or (/^\\endexample/ and !$ttenv)) {1054$mode = "normal";1055$ttenv = 0;1056print "</pre>\n";1057next LINE;1058}1059# |_1060if (/^\|_/) {1061next LINE;1062}1063} elsif ($mode eq "html") {1064if (/^%/) {1065print "$'\n";1066} else {1067print STDERR "Line $. ignored in \%display{html} mode, " .1068"because it didn't start with \%\n";1069}1070next LINE;1071} elsif ((!$nontex and /^%/) ||1072(!/\\(at|)index/ and /^([{}]|\s*\{?\\[a-zA-Z].*)%$/)) {1073# Ignore lines starting with a % except if in html or verbatim1074# modes (dealt with above) or if in nontex mode which we deal1075# with below.1076# Also ignore specific lines ending in a % (we have to be careful1077# here -- % also indicates a continuation). The lines we ignore are1078# those that match: "{%", "}%", "{\\X..%", "\\X..%" where X denotes1079# any letter and .. any sequence of chars. This is meant to exclude1080# lines like "{\obeylines ... %", "\begingroup ... %". If this proves1081# problematic the .tex files will need to use the %display{tex} env't1082# to exclude such lines.1083next LINE;10841085# All that's left are whole lines that occur in "normal" mode1086} else {10871088# Line skipping.1089if ($skip_lines) {1090if ($skip_lines == 1 and $_ =~ /^\s*$/) {1091$skip_lines = 0;1092}1093next LINE;1094}10951096# Remove initial % if there is one when in %display{nontex} or1097# %display{nontext} environment1098if ($nontex) {1099s/^%//;1100$rest = $_;1101}1102# a '%' at end-of-line indicates a continuation1103$_ = gather($_, $nontex);11041105# Paragraphs are ended by blank lines.1106if (/^\s*$/) {1107unless ($donepar) {1108$outline .= "<p>\n";1109$donepar = 1;1110}11111112# If we get to the end of a paragraph we assume that we have1113# lost track of what is going on, warn and try to resume.1114if ($mode eq "maths" or $inref) {1115print STDERR "Paragraph ended in $mode mode at $.\n" .1116"reverting to normal\n";1117$outline .= "</I>" if ($mode eq "maths");1118$mode = "normal";1119}11201121print $outline;1122next LINE;1123}1124# Vertical skips.1125if (/^\\(med|big)skip/) {1126$outline .= "<p>";1127print "$outline\n";1128next LINE;1129}1130# Index entries -- emit an anchor and remember the index1131# keys for later there may be several on one line and1132# several references to one key1133if (/^\\(at|)index/) {1134# $_ = gather($_, $nontex); # already done above1135while (/\\((at|)index(tt|))\{/g) {1136($rest, $indexarg) = (get_arg("{".$'))[0,1];1137if ($1 eq "atindex") {1138($indexarg2) = (get_arg($rest))[1];1139if ($indexarg2 =~ /^@/) {1140$indexarg = $';1141$indexarg =~ s/\\noexpand\s*`([^']*)'/$1/g;1142$indexarg =~ s/\\noexpand\s*<([^>]*)>/$1/g;1143$indexarg =~ s/\\noexpand//g;1144$indexarg =~ s/\|.*//; # remove "|indexit" if present1145# $indexarg might still have macros ...1146# we should do something about these too1147}1148}1149# Just the crudest form of macro removal - probably enough1150$indexarg =~ s/\\(.)/$1/g;1151$indexarg =~ s/\$//g; #assume $s match in pairs!!1152$bla = inxentry($fname,$indexarg,$sec);1153$outline .= $bla;1154print "$outline\n";1155}1156next LINE;1157}1158# \> and \) lines (joined with next line if ending in %)1159if (/^\\[>)]/) {1160# $_ = gather($_, $nontex); # already done above1161# if \> with ` or ( without a matching ' or ) gather lines1162if ( /^\\> *\`/ ) { # line should have ended in a %1163while ( !/\'/ ) { $_ = gather("$_%", $nontex); }1164} elsif ( /^\\>.*\(/ ) { # line should have ended in a %1165while ( !/\)/ ) { $_ = gather("$_%", $nontex); }1166}1167# get rid of @{...} or @`...' if present.1168if (/@/) {1169# print STDERR "before:$_\n";1170if (s/@\s*(\{[^{}]*\}|\`[^\']*\')\s*/ /) { # easy1171} elsif (/@\s*/) {1172# nested braces ... need to find matching brace1173$_ = $`;1174($rest) = get_arg($');1175$_ .= " $rest";1176$rest ="";1177}1178# print STDERR "after:$_\n";1179print STDERR "@ still present at $_" if (/@/);1180}1181}1182# if there is a comment in square brackets we extract it now1183# ... this way if this feature is undesirable we can easily get1184# rid of it1185my $comment = "";1186# These cases [<something>] is not a comment:1187# \><anything>; # [<arg>] here is treated as an optional arg1188# \>`<func-with-args>'{<func>![gdfile]} # possibility from1189# # buildman.pe \Declaration1190if (/^\\>(.*;|`[^\']+\'{[^}!]*!\[[^\]]*\]})/) {1191;1192} elsif (/^\\>.*\(/) {1193if (s/^(\\>[^(]*\([^)]*\)[^\[]*)(\[[^\]]*\])/$1/) {1194$comment = " $2";1195}1196} elsif (s/^(\\>[^\[]*)(\[[^\]]*\])/$1/) {1197$comment = " $2";1198}1199# \>`<variable>' V1200if (/^\\> *`([^\']+)\'\s*(\[[^\]]*\])?\s*V?\s*$/) {1201$endline = "</code>";1202$outline .= subsec_name($fname,$1,$sec); # $1 = <variable>1203$outline .= "<dt>" if $inlist;1204$outline .= "<li><code>";1205$tt = 1;1206$rest = $1.$comment." V";1207}1208# \>`<non-func>'{<label>}[!<sub-entry>][ <capital>]1209# <capital> is usually one of A-Z (but any non-space will be matched)1210elsif (/^\\> *`([^\']+)\'\s*\{([^}]+)\}(!\{.*\})?\s*([^\s]+)?\s*$/) {1211# $1 = <non-func> $2 = <label> [$3 = !<sub-entry>][$4 = <capital>]1212$endline = "</code>";1213$drei = defined($3) ? $3 : "";1214$vier = defined($4) ? " $4" : "";1215# $2$drei = <label><sub-entry>1216$outline .= subsec_name($fname,"$2$drei",$sec);1217#print STDERR "non-func:$1 - $2 - $drei - $vier |$2$drei|\n";1218$outline .= "<dt>" if $inlist;1219$outline .= "<li><code>";1220$tt = 1;1221$rest = $1.$comment.$vier;1222}1223# \><func>[(<args>)][!{<sub-entry>}][ <capital>]1224# <capital> is usually one of A-Z (but any non-space will be matched)1225elsif (/^\\> *([^(]+)(\([^)]*\))?(!\{.*\})?\s*([^\s]+)?\s*$/) {1226# $1 = <func> $2 = (<args>) [$3 = !<sub-entry>][$4 = <capital>]1227$endline = "</code>";1228$zwei = defined($2) ? $2 : "";1229$drei = defined($3) ? $3 : "";1230$vier = defined($4) ? " $4" : "";1231$outline .= subsec_name($fname,"$1$drei",$sec);1232# $1$drei = <func><sub-entry>1233#print STDERR "func:$1 - $zwei - $drei - $vier |$1$drei|\n";1234$outline .= "<dt>" if $inlist;1235$outline .= "<li><code>";1236$tt = 1;1237$rest = $1.$zwei.$comment.$vier;12381239}1240elsif (/^\\\>/) {1241die "Didn't find an appropriate \\> match for $_ ... syntax?";1242}1243elsif (/^\\\) *(.*)$/) {1244$endline = "</code>";1245$outline .= "<dt>" if $inlist;1246if ($donepar) {1247$outline .= "<code>";1248} else {1249$outline .= "<br><code>";1250}1251$tt = 1;1252$rest = $1;1253# Skip all other lines starting or ending in % or containing1254# `align'.1255} elsif ($mode ne "verbatim" and1256$_ =~ /^\s*%|%\s*$|\\[a-z]+align/) {1257next LINE;1258}1259}12601261# Here we have a "non-special" line to process We scan it for1262# special characters and deal with them individually $rest1263# contains the text that we have yet to look at We accumulate1264# the output in $outline, rather than printing it because a &1265# requires us to back up to start of line1266$donepar = 0;12671268# The (rare) situation that we are processing a multi-line cross1269# reference is handled specially.1270if ($inref) {1271# if it finishes on this line emit the link1272# otherwise keep accumulating it1273if ($rest =~ /^$refchars+\"/o) {1274$rest = $';1275chop($ref .= $&);1276$ref1 = name2fn($ref,0);1277$ref2 = name2linktext($ref);1278$outline .= "<a href=\"$ref1\">$ref2</a>";1279$inref = "0";1280} elsif ($rest =~ /^$refchars*$/o) {1281$ref .= "$rest ";1282next LINE;1283} else {1284die "Bad reference. So far $ref, now got $rest";1285}1286}12871288# || really means | in verbatim mode1289$rest =~ s/\|\|/\|/g if ($mode eq "verbatim");12901291# The main case, scan for special characters.1292SPECIAL: while ( $rest =~ /[\\{}\$<>`\'*\"&%~_^]/ ) {1293$outline .= $`; # the part that we scanned past1294$rest = $'; # the remainder1295my $matched = $&; # the character matched12961297# In verbatim mode, everything is passed to HTML.1298if ($mode eq "verbatim") {1299# if ($matched ne "%") {1300$outline .= html_literal $matched;1301# }1302next SPECIAL;1303}13041305# backslash1306if ($matched eq "\\") {1307# commands that begin a new output line1308NEWLINE: {1309if ($rest =~ /^beginitems/ and not $inlist) {1310$outline .= "<p>\n<dl compact>";1311$inlist = 1;1312} elsif ($rest =~ /^enditems/ and $inlist) {1313$outline .= "</dl>";1314$inlist = 0;1315} elsif ($rest =~ /^beginlist1316(%(un|)ordered)? #defines $listtype1317(\{([1aAiI])\})? #defines TYPE of ordered list1318(\{(\d+)\})? #defines START of ordered list1319/x ) {1320$listtype = list_type($1, $2);1321$outline .= begin_list($listtype, $3, $4, $5, $6);1322$listdepth = 1;1323} elsif ($rest =~ /^endlist/) {1324$outline .= ("</${listtype}l>") x $listdepth;1325$listdepth = 0;1326} elsif ($rest =~ /^answer/) {1327$outline = "";1328$skip_lines = 1;1329} else {1330last NEWLINE;1331}1332print "$outline\n";1333next LINE;1334}1335# commands that are replaced by HTML text1336REPLACE: {1337($rest, $macro) = macro_replace($rest);1338$outline .= $macro;1339next SPECIAL;1340}1341# Try to get nice spacing around certain maths constructs that1342# are used a lot.1343if ($mode eq "maths") {1344MATHREPLACE: {1345if ($rest =~/^($TeXbinops)$EndTeXMacro/o) {1346$outline .= " $1 "; }1347elsif ($rest =~/^backslash$EndTeXMacro/o) {1348$outline .= " \\ "; }1349elsif ($rest =~/^split$EndTeXMacro/o) {1350$outline .= ":"; }1351elsif ($rest =~/^langle$EndTeXMacro/o) {1352$outline .= " <"; }1353elsif ($rest =~ /^rangle$EndTeXMacro/o) {1354$outline .= "> "; }1355else { last MATHREPLACE; }1356$rest = $';1357next SPECIAL;1358}1359}1360# Take the next character literally.1361if ($rest ne "") {1362$outline .= html_literal substr($rest,0,1);1363$rest = substr($rest,1);1364}1365next SPECIAL;1366}13671368# Subscripts and superscripts in math mode.1369if ($mode eq "maths" and !$sub and !$sup) {1370SUBSUPER: {1371if ($matched eq "_" and $rest =~ /^\{/) {1372$outline .= "<sub>";1373$sub = 1; if ($tt) { $tt++; } }1374elsif ($matched eq "^" and $rest =~ /^\{/) {1375$outline .= "<sup>";1376$sup = 1; if ($tt) { $tt++; } }1377elsif ($matched eq "_" and $rest =~ /^[^\\]/) {1378$outline .= "<sub>$&</sub>"; }1379elsif ($matched eq "^" and $rest =~ /^[^\\]/) {1380$outline .= "<sup>$&</sup>"; }1381else { last SUBSUPER; }1382$rest = $';1383next SPECIAL;1384}1385}1386if ($matched =~ /[_^]/) {1387$outline .= $matched;1388next SPECIAL;1389}13901391# Braces are ignored, but must must be balanced inside `...'.1392if ($matched eq "{") {1393if ($tt) { $tt++; }1394if ($sub) { $sub++; }1395elsif ($sup) { $sup++; }1396next SPECIAL;1397}1398if ($matched eq "}") {1399if ($tt == 1) {1400# print STDERR "o:$outline,m:$matched,r:$rest\n";1401die "Unbalanced braces in `...' ($outline$matched$rest)";1402}1403if ($tt) { $tt--; }1404if ($sub and !--$sub) { $outline .= "</sub>"; }1405if ($sup and !--$sup) { $outline .= "</sup>"; }1406next SPECIAL;1407}14081409# A tilde is a non-break space.1410if ($matched eq "~") {1411$outline .= " ";1412next SPECIAL;1413}14141415# $ toggles maths mode.1416if ($matched eq "\$") {1417if ($rest =~ /^\$/) {1418$rest = $';1419$endmath = "[\$][\$]";1420$endmathstring = "\$\$";1421} else {1422$endmath = "[\$]";1423$endmathstring = "\$";1424}1425if ($opt_t) {1426if ($mode eq "normal") {1427$tth= "";1428$mode = "tth";14291430while ($mode eq "tth") {1431if ( $rest =~ /$endmath/ ) {1432$tth .= $`; # the part scanned past1433$rest = $';14341435# make a math mode string1436$tth = "$endmathstring$tth$endmathstring";14371438# pass $tth to tth to convert to HTML1439# and append the result1440$outline .= tth_math_replace($tth);1441$mode = "normal";1442}1443else {1444# we are in tth mode but the line has no terminating1445# $ or $$: continue into next line1446if ($rest =~ s/%$//) { # Mirror TeX behaviour when1447$tth .= $rest; # line ends in a % ...1448$rest = <IN>; # swallow whitespace at1449$rest =~ s/^\s*//; # beginning of next line1450} else {1451$tth .= $rest." ";1452$rest = <IN>;1453}1454chomp($rest);1455}1456}14571458next SPECIAL;1459} else {1460die "math mode messup";1461}1462} else {1463$outline .= "<p>" if ($endmathstring eq "\$\$");1464if ($mode eq "maths") {1465if ($sub) { die "Math mode ended during subscript ".1466"($outline$matched$rest)"; }1467elsif ($sup) { die "Math mode ended during superscript ".1468"($outline$matched$rest)"; }1469$mode = "normal";1470$outline .= "</var>";1471if ($tt) { $outline .= "<code>"; }1472next SPECIAL;1473}1474$mode = "maths";1475if ($tt) { $outline .= "</code>"; }1476$outline .= "<var>";1477next SPECIAL;1478}1479}14801481# < > open and close italics.1482if ($matched eq "<") {1483if (not $it) {1484if ($tt) { $outline .= "</code>"; }1485$outline .= "<var>";1486$it = 1;1487} else {1488$outline .= "<";1489}1490next SPECIAL;1491}1492if ($matched eq ">") {1493if ($it) {1494$outline .= "</var>";1495if ($tt) { $outline .= "<code>"; }1496$it = 0;1497} else {1498$outline .= ">";1499}1500next SPECIAL;1501}15021503# * in normal mode toggles bold-face.1504if ($matched eq "*") {1505if ($mode eq "normal" and not $tt) {1506if ($bold) {1507$outline .= "</strong>";1508$bold = 0;1509} else {1510$outline .= "<strong>";1511$bold = 1;1512}1513} else {1514$outline .= "*";1515}1516next SPECIAL;1517}15181519# ` and ' in normal mode control typewriter.1520if ($matched eq "`") {1521if ($tt) {1522$outline .= "`";1523} elsif ( $rest =~ /^`/ ) {1524$rest = $';1525$outline .= "``";1526} else {1527$tt = 1;1528$outline .= "<code>";1529}1530next SPECIAL;1531}1532if ($matched eq "\'") {1533if ($tt == 1) {1534$outline .= "</code>";1535$tt = 0;1536} else {1537$outline .= "\'";1538}1539next SPECIAL;1540}15411542# & signals a definition. We go back to start of line for the1543# tag, and on to end of para for the definition. We do not1544# merge adjacent definitions into the same list.1545if ($matched eq "&") {1546if ($inlist) {1547$outline = "<dt>$outline<dd>"; # Sometimes we get an extra1548} # <dt> we don't need ...1549next SPECIAL; # but it has no effect :)1550}15511552# " starts a cross-reference. If it ends on the same input1553# line then we can deal with it at once otherwise we set1554# $inref.1555if ($matched eq "\"") {1556if ($tt) {1557$outline .= "\"";1558next SPECIAL;1559}1560if ($rest =~ /^$refchars+\"/o) {1561$rest = $';1562chop($ref = $&);1563$ref1 = name2fn($ref,0);1564$ref2 = name2linktext($ref,0);1565$outline .= "<a href=\"$ref1\">$ref2</a>";1566next SPECIAL;1567}1568if ($rest =~ /^$refchars*$/o) {1569$ref = "$rest ";1570$inref = 1;1571print $outline;1572next LINE;1573}1574die "Bad reference $rest at $_";1575}15761577# Ignore from % to end of line, on-line browser does not do this.1578if ($matched eq "%") {1579print $outline."\n";1580next LINE;1581}15821583} # SPECIAL1584print $outline.$rest.$endline."\n";1585if ($endline =~ /<\/code>/) {1586$tt = 0;1587}1588$endline ="";1589} # LINE1590}159115921593sub metaquote {1594my $name = quotemeta $_[0];1595$name =~ s/\\ /\\s+/g;1596return $name;1597}15981599sub startfile {1600my $sec = $_[0];1601my ($num, $name, $re, $fname, $name1, $name2);1602if ($sec->{secnum} == 0) {1603$sec->{chapnum} = $chap->{number};1604$num = $chap->{number};1605$name = $chap->{name};1606$name1 = metaquote $name;1607$re = "^\\\\(Chapter|PreliminaryChapter)\\{$name1\\}";1608} else {1609$num = $sec->{chapnum} . "." .$sec->{secnum};1610$name = $sec->{name};1611$name1 = metaquote $name;1612$re = "^\\\\Section\\{$name1\\}";1613}1614$name2 = kanonize $name;1615$fname = htm_fname($opt_c,1616$sec->{chapnum}, $sec->{secnum}, $sec->{ssecnum});16171618open ( OUT, ">${odir}${fname}" ) || die "Can't write to ${odir}${fname}";1619select OUT;16201621print "<html><head><title>[$book] $num $name2</title></head>\n";1622print "<body text=\"\#000000\" bgcolor=\"\#ffffff\">\n";1623add_to_index($fname, $name, $sec);1624navigation( ($opt_c) ? $chap->{sections}[0] : $sec );1625print "<h1>$num $name2</h1><p>\n";16261627return ($fname, $re);1628}16291630sub startsec {1631my $sec = $_[0];1632my $snum = $sec->{secnum};1633my $name = $sec->{name};1634add_to_index(htm_fname($opt_c, $sec->{chapnum}, $snum, 0), $name, $sec);1635my $num = $sec->{chapnum} . "." .$snum;1636$snum = "0" x (3 - length $snum) . $snum;1637my $name1 = metaquote $name;1638my $name2 = kanonize $name;1639print "<h2><a name=\"SECT$snum\">$num $name2</a></h2>\n<p>";1640return "^\\\\Section\\{$name1\\}";1641}16421643sub sectionlist {1644my $chap = $_[0];1645my $sec;1646print "<P>\n<H3>Sections</H3>\n<oL>\n";1647SUBSEC: for $sec (@{$chap->{sections}}) {1648next SUBSEC if ($sec->{secnum} == 0);1649my $link = htm_fname($opt_c, $sec->{chapnum}, $sec->{secnum}, 0);1650my $name2 = kanonize $sec->{name};1651print "<li> <A HREF=\"$link\">$name2</a>\n";1652}1653print "</ol><p>\n";1654}16551656#1657# Basically the chapter file is read in one pass, using information previously1658# read from the .toc file to fill in next and previous pointers and the like1659#16601661sub navigation {1662my $sec = $_[0];1663my $chap = $sec->{chapter};1664my $cfname = htm_fname($opt_c, $sec->{chapnum}, 0, 0);1665if ($mainman == 1) {1666print "[<a href=\"../index.htm\">Top</a>] "1667} else {1668if ($opt_f) {1669print "[<a href=\"$opt_f\">Top</a>] "1670}1671};1672if ($sec->{secnum} == 0) {1673print "[<a href = \"chapters.htm\">Up</a>] ";1674if (tonum($chap->{number}) != 1) {1675my $prev = htm_fname($opt_c,1676$chapters[tonum($chap->{number}) - 1]{number},16770, 0);1678print "[<a href =\"$prev\">Previous</a>] ";1679}1680if (tonum($chap->{number}) != $#chapters) {1681my $next = htm_fname($opt_c,1682$chapters[tonum($chap->{number}) + 1]{number},16830, 0);1684print "[<a href =\"$next\">Next</a>] ";1685}1686} else {1687print "[<a href = \"$cfname\">Up</a>] ";1688if ($sec->{secnum} != 1) {1689my $prev = htm_fname($opt_c, $chap->{number}, $sec->{secnum} - 1,16900);1691print "[<a href =\"$prev\">Previous</a>] ";1692}1693if ($sec->{secnum} != $#{$chap->{sections}}) {1694my $next = htm_fname($opt_c, $chap->{number}, $sec->{secnum} + 1,16950);1696print "[<a href =\"$next\">Next</a>] ";1697} elsif (tonum($chap->{number}) != $#chapters) {1698my $next = htm_fname($opt_c,1699$chapters[tonum($chap->{number}) + 1]{number},17000, 0);1701print "[<a href =\"$next\">Next</a>] ";1702}1703}1704print "[<a href = \"theindex.htm\">Index</a>]\n";1705}170617071708sub convert_chap {1709my ($chap) = @_;1710my ($re, $startre, $fname, $secline);1711$indexcount = 0;1712open (IN, "<$dir$chap->{file}.tex")1713|| die "Can't read $dir$chap->{file}.tex";1714$_ = <IN>;17151716# loop, controlled by the list of sections that we expect1717# will fail, possibly messily if this does not match reality17181719# The call to startfile produces navigation + a chapter heading1720if ($opt_c) { # each chapter in a single file1721($fname,$re) = startfile $chap->{sections}[0];1722}17231724# note we *need* $sec to act globally in what follows!1725SECT: for $sec (@{$chap->{sections}}) {17261727# sort out what we are processing (chapter or section)1728# produce the header of the Web page17291730if ($opt_c) {1731$re = startsec $sec unless ($sec->{secnum} == 0);1732} else {1733# The call to startfile produces navigation + a section heading1734($fname, $re) = startfile $sec;1735# print STDERR "fname: $fname, re: $re\n";1736}1737($startre = $re) =~ s/(^[^\{]*\{).*/$1/;17381739#1740# Look for the \Chapter or \Section line1741#17421743while ( !/$startre/ ) {1744unless (defined($_ = <IN>)) {1745die "Missing chapter or section line matching $startre" };1746};17471748chomp;1749$secline = $_;1750while ( $secline !~ /\}/ ) {1751unless (defined($_ = <IN>)) {1752die "Missing chapter or section line matching $re" };1753chomp;1754s/\%.*//;1755$secline .= " $_";1756};17571758unless ($secline =~ /$re/) {1759die "Missing chapter or section line matching $re"1760};17611762# If this is the beginning of a chapter, we list its sections1763if ($sec->{secnum} == 0) {1764if (defined($chap->{sections}[1])) {1765sectionlist $chap;1766} else {1767print STDERR "Warning: Chapter has no sections\n";1768}1769}17701771# Now we print the section body1772convert_text($fname);1773print "<p>\n";17741775# If it's one file per section ... add navigation etc. at end of file1776unless ($opt_c) {1777navigation $sec;1778print $footer;1779close OUT;1780select STDOUT;1781}1782}17831784# If it's one file per chapter ... add navigation etc. at end of file1785if ($opt_c) {1786navigation $chap->{sections}[0];1787print $footer;1788close OUT;1789select STDOUT;1790}1791close IN;1792}1793179417951796sub chapters_page {1797open (OUT, ">${odir}chapters.htm")1798|| die "Can't write to ${odir}chapters.htm";1799select OUT;18001801print <<END1802<html><head><title>$booktitle - Chapters</title></head>1803<body text=\"\#000000\" bgcolor=\"\#ffffff\">1804<h1>$booktitle_body - Chapters</h1>1805<ul>1806<li><a href=\"theindex.htm\">Index</a>1807</ul>1808<ol>1809END1810;18111812CHAP: foreach $chap (@chapters) {1813unless (defined $chap) { next CHAP};1814my $link = htm_fname($opt_c, $chap->{number}, 0, 0);1815my $name2 = kanonize $chap->{name};1816print "</ol><ol type=\"A\">\n" if ( $chap->{number} eq "A" );1817print "<li><a href=\"$link\">$name2</a>\n";1818}18191820print <<END1821</ol>1822<ul>1823<li><a href=\"biblio.htm\">References</a>1824<li><a href=\"theindex.htm\">Index</a>1825</ul><p>1826END1827;1828if ($mainman == 1) {1829print "[<a href=\"../index.htm\">Top</a>]<p>"1830} else {1831if ($opt_f) {1832print "[<a href=\"$opt_f\">Top</a>] "1833}1834};1835print $footer;1836close OUT;1837select STDOUT;18381839# Touch the chapters file so that `make' recognizes the conversion1840# has been done.1841system "touch ${odir}chapters.htm";1842}18431844sub caseless { lc($a) cmp lc ($b) or $a cmp $b }18451846sub index_head {1847my ($letter, @letters) = @_;1848my ($bstb);1849print <<END1850<html><head><title>$booktitle - Index ${letter}</title></head>1851<body text=\"\#000000\" bgcolor=\"\#ffffff\">1852<h1>$booktitle_body - Index ${letter}</h1>1853<p>1854END1855;1856# print STDERR $letter, @letters, "\n";1857foreach $bstb (@letters) {1858if ($opt_i) {1859print "<a href=\"\#idx${bstb}\">$bstb</A>\n";1860}1861elsif ($bstb eq "_") {1862print "<a href=\"theindex.htm\">$bstb</A>\n";1863}1864else {1865print "<a href=\"indx${bstb}.htm\">$bstb</A>\n";1866}1867}1868}18691870sub index_end {1871print "</dl><p>\n";1872if ($mainman == 1) {1873print "[<a href=\"../index.htm\">Top</a>] "1874} else {1875if ($opt_f) {1876print "[<a href=\"$opt_f\">Top</a>] "1877}1878};1879print "[<a href=\"chapters.htm\">Up</a>]";1880print "<p>\n$footer";1881}18821883sub index_page {1884my ($ent, $ref, $letter, $bstb, $thisletter, @entries, %letters, @letters);1885%letters = $opt_i ? ()1886: ("_" => ""); # With multiple indices, the "_"1887# index is theindex.htm1888foreach $ent (keys %index) {1889$bstb = uc(substr($ent,0,1));1890if ($bstb lt "A" or $bstb gt "Z") {$bstb = "_";}1891$letters{$bstb} = "";1892}1893@letters = sort caseless keys %letters;18941895$letter = $opt_i ? "" : "_";1896open (OUT, ">${odir}theindex.htm")1897|| die "Can't write to ${odir}theindex.htm";1898select OUT;1899index_head($letter, @letters);19001901ENTRY: foreach $ent (sort caseless keys %index) {1902$thisletter = uc(substr($ent,0,1));1903if ($thisletter lt "A" or $thisletter gt "Z") {$thisletter = "_";}1904if ($letter eq "") { # Only happens first time round for $opt_i1905$letter = $thisletter;1906print "<H2><A NAME=\"idx${letter}\">$letter</A></H2>\n<dl>\n";1907}1908elsif ($letter ne $thisletter) {1909$letter = $thisletter;1910if ($opt_i) {1911print "</dl><p>\n";1912print "<H2><A NAME=\"idx${letter}\">$letter</A></H2>\n<dl>\n";1913}1914else {1915index_end;1916close OUT;1917select STDOUT;1918open (OUT, ">${odir}indx${letter}.htm")1919|| die "Can't write to ${odir}indx${letter}.htm";1920select OUT;1921index_head($letter, @letters);1922}1923}1924$ent1 = $ent;1925$ent1 =~ s/!/, /g;1926$ent1 =~ s/[{}]//g;1927print "<dt>".kanonize $ent1." ";1928for $ref (@{$index{$ent}}) {1929print "<a href=\"$ref->[0]\">$ref->[1]</a> ";1930}1931print "\n";1932}1933index_end;1934close OUT;1935select STDOUT;1936}19371938sub biblio_page {1939my $infile = "${dir}manual.bbl";1940my $outfile = "${odir}biblio.htm";1941my $macro;1942open (OUT, ">${outfile}") || die "Can't write to ${outfile}";1943select OUT;19441945print <<END1946<html><head><title>$booktitle - References</title></head>1947<body text=\"\#000000\" bgcolor=\"\#ffffff\">1948<h1>$booktitle_body - References</h1><dl>1949END1950;19511952if (-f $infile and -r $infile) {1953open IN, "<$infile";1954my ($brace,$embrace) = (0,-1);1955while (<IN>) {1956chomp;1957my $outline = "";1958if (/newcommand/ || /thebibliography/) { }1959elsif (/^\\bibitem\[[^\]]+\]\{([^\}]+)\}/) {1960print "<dt><a name=\"$1\"><b>[$1]</b></a><dd>\n";1961} else {1962my $line = $_;1963if ($line =~ /^\s*\\newblock/) { $outline .= "<br>";1964$line = $'; }1965while ($line =~ /[\${}<>~&\\]/) {1966$outline .= $`;1967$matched = $&;1968$line = $';1969if ($opt_t and $matched eq "\$" and $line =~ /([^\$]*\$)/) {1970# if we are using the -t option and we have1971# detected a *simple* maths formula $...$ pass it1972# off directly to tth_math_replace. Bibliographies1973# should only have very simple maths formulae. If1974# it's broken over a line, we won't detect it.1975$matched .= $&;1976$outline .= tth_math_replace($matched);1977$line = $';1978} elsif ($matched eq "\{") {1979if ($line =~ /^\\(em|it)\s*/) { $embrace = $brace;1980$outline .= "<em>";1981$line = $'; }1982$brace++;1983} elsif ($matched eq "\}") {1984$brace--;1985if ($brace == -1 ) {1986die "Unbalanced braces in bbl file ".1987"($outline$matched$line";1988} elsif ($brace == $embrace) { $outline .= "</em>";1989$embrace = -1; }1990} elsif ($matched eq "\\") {1991if ($line =~ /^cite\{([^\}]*)\}/) {1992$outline .= "<a href=\"#$1\"><cite>$1</cite></a>";1993$line = $';1994} else {1995($line, $macro) = macro_replace($line);1996$outline .= $macro;1997}1998} elsif ($matched eq "~" ) {1999$outline .= " ";2000} elsif ($matched ne "\$") {2001$outline .= html_literal $matched;2002}2003}2004print "$outline$line\n";2005}2006}2007} else {2008print STDERR "Warning: did not find a .bbl file ... ok?\n";2009}2010print "</dl><p>\n";2011if ($mainman == 1) {2012print "[<a href=\"../index.htm\">Top</a>] "2013} else {2014if ($opt_f) {2015print "[<a href=\"$opt_f\">Top</a>] "2016}2017};2018print "[<a href=\"chapters.htm\">Up</a>]";2019print "<p>\n$footer\n";2020close OUT;2021select STDOUT;2022}20232024#2025# Main program starts here2026#2027# Process option and sort out input and output directories2028#20292030getopts('csitun:f:');20312032if (!$opt_c) {$opt_c = 0;} # just to ensure it is not empty20332034chomp($dir = shift @ARGV);2035if (substr($dir,0,1) ne "/") {2036$dir = `pwd` . "/" . $dir;2037$dir =~ s/\n//;2038}2039if (substr($dir,-1) ne "/") {2040$dir .= "/";2041}2042unless (-d $dir and -r $dir) {2043die "Can't use input directory $dir";2044}20452046if ($opt_t) {2047my ($whichtth) = `which tth`;2048chomp($whichtth);2049if ($whichtth !~ m+/tth$+) {2050print STDERR "!! tth: not in path.\n$whichtth\n",2051"... Maths formulae will vanish!",2052" Install tth or avoid -t option.\n";2053}2054$tthbin="tth";2055}20562057if ($opt_u) {2058my ($whichtth) = `which tth`;2059chomp($whichtth);2060if ($whichtth !~ m+/tth$+) {2061print STDERR "!! tth: not in path.\n$whichtth\n",2062"... Maths formulae will vanish!",2063" Install tth or avoid -t option.\n";2064}2065$tthbin="tth -u1";2066}20672068if ($opt_n) {2069# get book title2070$book=$opt_n;2071#$booktitle = "$opt_n : a GAP example";2072$booktitle = "$opt_n : a GAP 4 package";2073$booktitle_body = booktitle_body($booktitle, ("GAP", $opt_n));2074$mainman=0;2075$footer = "<P>\n<address>$opt_n manual<br>" .2076`date +"%B %Y"` . "</address></body></html>";2077#print "c: $opt_c \n";2078} else {2079if ($opt_f) {2080die "option -f can only be used together with -n ";2081}2082if ($dir =~ /\/([^\/]+)\/$/) {2083$book = $1;2084} else {2085die "Can't find basename of $dir";2086}2087if ($book eq "tut") {2088$booktitle = "The GAP 4 Tutorial";2089} elsif ($book eq "ref") {2090$booktitle = "The GAP 4 Reference Manual";2091} elsif ($book eq "prg") {2092$booktitle = "The GAP 4 Programming Tutorial";2093} elsif ($book eq "ext") {2094$booktitle = "The GAP 4 Programming Reference Manual";2095} elsif ($book eq "new") {2096$booktitle = "GAP 4: New Features for Developers";2097} else {2098die "Invalid book, must be tut, ref, prg, new or ext";2099}2100$booktitle_body = booktitle_body($booktitle, "GAP");2101$mainman=1;2102}21032104if ($#ARGV != -1) {2105chomp($odir=shift @ARGV);2106} else {2107$odir = "";2108}2109if (substr($odir,0,1) ne "/") {2110$odir = `pwd` . "/" . $odir;2111$odir =~ s/\n//;2112}2113if (substr($odir,-1) ne "/") {2114$odir .= "/";2115}2116unless (-d $odir and -w $odir) {2117die "Can't use output directory $odir";2118}2119print "Reading input from $dir\n" unless ($opt_s);2120print "Creating output in $odir\n" unless ($opt_s);21212122if ($opt_t || $opt_u) {2123# create macro file for our expressions and macros not known to tth in TeX2124# mode.2125$opt_t = tth_version;2126print STDERR "Using TtH $opt_t to translate maths formulae.\n";2127$opt_t =~ s/Version //;2128open (TTHIN, ">tthmacros.tex") || die "Can't create tthmacros.tex";2129print TTHIN "\\def\\Q{{\\bf Q}}\\def\\Z{{\\bf Z}}\\def\\N{{\\bf N}}\n",2130"\\def\\R{{\\bf R}}\\def\\F{{\\bf F}}\n";2131# \R and \I are used in the last chapter of ext2132print TTHIN "\\def\\calR{{\\cal R}}\\def\\I{{\\cal I}}\n",2133"\\def\\frac#1#2{{{#1}\\over{#2}}}\\def\\colon{:}\n",2134"\\def\\longmapsto{\\mapsto}\\def\\lneqq{<}\n",2135"\\def\\hookrightarrow{\\rightarrow}\n";2136if ($opt_t < 2.52) {2137# We work-around most of the deficiencies of versions of TtH2138# prior to Version 2.52 ... but can't easily fix the lack of2139# proper treatment of \not.2140print STDERR2141"Your version of TtH does not know many TeX commands.\n",2142"It is recommended that you upgrade to the latest version from\n",2143" http://hutchinson.belmont.ma.us/tth/tth-noncom/download.html\n";2144print TTHIN "\\def\\mid{ | }\\def\\lbrack{[}\\def\\rbrack{]}\n",2145"\\def\\gets{\\leftarrow}\\def\\land{\\wedge}\n";2146}2147close TTHIN;2148}21492150getchaps;2151print "Processed TOC files\n" unless ($opt_s);21522153open (TEX, "<${dir}manual.tex") || die "Can't open ${dir}manual.tex";2154getlabs $dir;2155while (<TEX>) {2156if (/\\UseReferences{([^}]*)}/) {2157getlabs "$dir$1/";2158} elsif (/\\UseGapDocReferences{([^}]*)}/) {2159getlabs "$dir$1/";2160($gapdocbook = $1) =~ s?.*/([^/]*)/doc?$1?;2161$gapdocbooks{$gapdocbook} = 1;2162print STDERR "GapDoc books: ", keys(%gapdocbooks), "\n";2163} elsif (/\\Package{([^}]*)}/) {2164$sharepkg .= "|$1";2165}2166}2167print "Processed LAB files\n" unless ($opt_s);21682169#2170# OK go to work2171#21722173CHAP: foreach $chap (@chapters) {2174unless (defined $chap) {2175next CHAP;2176}2177print "$chap->{number}. $chap->{name} ... $chap->{file}.tex\n"2178unless ($opt_s);2179convert_chap $chap;2180}21812182print "and the chapters page\n" unless ($opt_s);2183chapters_page;2184print "and the index pages\n" unless ($opt_s);2185index_page;2186print "and the references\n" unless ($opt_s);2187biblio_page;21882189if ($opt_t || $opt_u ) {2190# remove the tth stuff2191unlink 'tthin','tthout','tthmacros.tex';2192}21932194print "done\n" unless ($opt_s);2195#############################################################################219621972198