#! /usr/bin/perl # Copyright (c) 1996, 1997 Russell Quong. # # In the following, the "author" refers to "Russell Quong." # # Permission to use, copy, modify, distribute, and sell this software and # its documentation for any purpose is hereby granted without fee, provided # that the following conditions are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Russell Quong. # 3. All HTML generated by ltoh must retain a visible notice that it # was generated by ltoh and contain a link to the ltoh web page # # Any or all of these provisions can be waived if you have specific, # prior permission from the author. # # THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, # EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY # WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. # # IN NO EVENT SHALL RUSSELL QUONG BE LIABLE FOR ANY SPECIAL, # INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, # WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY # THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. # ltoh.pl = a LaTeX to HTML converter # Russell Quong 1996, 1997 # Version 97e. # enable readable "English names" for variables, like $MATCH or $PERL_VERSION # instead of " punctuation names" for variables, like $& or $] use English; $false = 0; $true = 1; $author = "Russell W. Quong"; $version = "Version 97e."; $reldate = "Mar 1997"; $status = "Experimental"; $dirsep = "/"; # directory separator character $qval{"today"} = strip_hms_and_day( scalar(localtime()) ); $qval{"title"} = ""; $qval{"author"} = "Unknown document author"; $qval{"email"} = "Unknown email"; $qval{"url"} = "Unknown Web URL"; $qval{"keep_comments"} = 0; $warnlevel = 3; sub bad_command { my($err_msg, $descrip) = @_; return " $err_msg $descrip "; } # lookup(varname) ==> get the value of variable VARNAME. sub lookup { my($idx) = @_; if ( ! defined $qval{$idx} ) { return "$idx undefined"; } else { return $qval{$idx}; } } sub print_html_header { my($filename) = @_; print '', "\n"; print "\n"; if ($qval{"title"} eq "") { $qval{"title"} = "$filename : [LaTeX --> HTML]"; } print "\n\n", $qval{title} , "\n\n\n"; print "\n"; } sub print_html_trailer { my($filename) = @_; # need to declare ctime separately from next line, ugh. (scalar vs. array) print "
\n"; print "[Converted LaTeX --> HTML by"; print ' ltoh]'; print "
\n"; print "
\n"; if ($qval{"url"} =~ /Unknown/) { if (! ($qval{"author"} =~ /Unknown/)) { print "$qval{author}\n" ; } } else { print "$qval{author}\n"; } if (! ($qval{"email"} =~ /Unknown/)) { print "($qval{email}"; print ")\n"; } my($ctime); $ctime = localtime; $ctime = strip_hms_and_day($ctime); print "Last modified: $ctime\n"; my($mtime) = get_file_mtime($filename); if ($mtime ne $ctime) { print "(LaTeX doc modified: "; print $mtime; print ")
\n"; } print "
\n"; print "\n\n"; } sub strip_hms_and_day { my($str_time) = @_; # The next two lines strip off # the hours:min:secs and the leading day of the week, giving # Jul 29 1996 $str_time =~ s/^[A-Z][a-z][a-z][ \t]*//; $str_time =~ s/\d+:\d+:\d+[ \t]*([A-Z][A-Z]T[ \t]*)?//; return $str_time; } # # return the time (as a string) that the file XXX was last modified. # called via: # $string = get_file_mtime (XXX); # sub get_file_mtime { my($filename) = @_; my($str_time) = ''; # default value my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename); if ($dev != null) { $str_time = localtime($mtime); # We now have string like: # Mon Jul 29 19:53:49 PDT 1996 $str_time = strip_hms_and_day($str_time); warning(9, "File $filename last modified on $str_time"); } return $str_time; } sub logmessage { my($prefix, @params) = @_; my($level) = 0; if (@params > 1) { if ($params[0] =~ /\d/) { $level = shift(@params); } else { print ("No level given: @_"); } } if ($level <= $warnlevel) { print "$prefix :: @params\n"; } else { # print "level $level > warnlevel $warnleve\n"; } } sub errmsg { logmessage(" * Error: ", @_); } sub warning { logmessage(" + Warning: ", @_); } sub fyi { logmessage(" - fyi: ", @_); } # # Try to figure out where the perl script is actually located. # (1) We can follow symbolic links to ABSOLUTE PATHS correctly, # (2) But we can't handle relative symbolic links to another directory, # as we need to keep track of where the link is relative to. # Case (1) handles the common case of a link: xyz --> /whereever/bin/ltoh # Also, we can handle the last link referring to a file in the same dir. sub get_scriptdir { fyi("PROGRAM_NAME = $PROGRAM_NAME"); my($scriptfile) = $PROGRAM_NAME; # maybe a link. We trace it down. my($scriptdir, $fulldir) = ("." , ""); while (-l $scriptfile) { fyi(9, "$scriptfile is link to -->"); if ($scriptfile =~ /(.*) $dirsep ( [^$dirsep]+ )/x ) { $scriptdir = $1; # if ($scriptdir =~ /^$dirsep/) { # $fulldir = $scriptdir; # } else { # $fulldir .= $scriptdir; # } # fyi(9, "scriptdir = $scriptdir"); # fyi(9, "fulldir = $fulldir"); } $scriptfile = readlink $scriptfile; fyi(9, " $scriptfile."); fyi(7, "scriptdir = $scriptdir"); } return $scriptdir; } # # handle all the arguments, in the @ARGV array. # sub main { fyi("PROGRAM_VERSION = $version"); fyi(" by $author. 1996, 1997."); my($nextline, $f); my($nspecfiles) = 0; my($scriptdir) = get_scriptdir(); # attempt to trace down a sym link. # list of spec files my(@specfiles) = ( "$scriptdir$dirsep" . "ltoh.specs" , "~$dirsep.ltoh.specs" , ".$dirsep.ltoh.specs" ); foreach $f (@specfiles) { $nspecfiles += read_specfile($f); } if ($nspecfiles == 0) { $nspecfiles += read_specfile("/usr/local/bin/ltoh.specs"); } if ($nspecfiles == 0) { $nspecfiles += read_specfile("/usr/bin/ltoh.specs"); } if ($nspecfiles == 0) { warning("Tried to read spec files: @specfiles"); errmsg("No specification files found. Bye-bye."); exit(1); } if (@ARGV == 0) { handle_file('-'); } foreach $i (@ARGV) { my($texfile) = $i; if ($i =~ /^(.+)\.([ltex]+)$/ ) { warning(7, "filebase = $1, suffix = $2, $input file = $texfile"); } else { $texfile = $i . ".tex"; } if (! -r $texfile) { print "Cannot read file: $texfile\n"; return -1; } handle_file($texfile); } } # # process a specific file. Called via: handle_file($filename); # sub handle_file { my($texfilename) = @_; my($INFILE) = $texfilename; if ($texfilename eq '-') { $INFILE = STDIN; } else { open($INFILE, $texfilename); } $qval{"title"} = "Unnamed Web page"; fyi(5, "+ Reading LaTeX input ... handle_file($texfilename)"); @orig = <$INFILE>; print_arr('Orig $lineno:', \@orig) if ($warnlevel >= 8); do_comment_verbatim(\@orig); print_arr('Verb $lineno:', \@orig) if ($warnlevel >= 8); do_tables(\@orig); print_arr('Tabl $lineno:', \@orig) if ($warnlevel >= 8); do_begin_end(\@orig); print_arr('BegE $lineno:', \@orig) if ($warnlevel >= 8); do_tex_comms(\@orig); print_arr('Comm $lineno:', \@orig) if ($warnlevel >= 8); mark_delims(\@orig); print_arr('Mark $lineno:\n', \@delim_lines) if ($warnlevel >= 8); do_simple_latex_defs(\@delim_lines); print_arr('{} $lineno:\n', \@delim_lines) if ($warnlevel >= 8); do_complicated_latex_defs(\@delim_lines); print_arr('{N} $lineno:\n', \@delim_lines) if ($warnlevel >= 8); my($i); final_cleanup(\@delim_lines); print_arr('[<$lineno>]', \@delim_lines) if ($warnlevel >= 8); print_arr("", \@delim_lines) if ($warnlevel >= 8); print_html_file($texfilename); } # generate the HTML file. Pass in the name of the .tex file # print_html_file( "filename.tex" ); # sub print_html_file { my($texfile) = @_; my($base, $suffix) = ($texfile, ""); my($outfile) = $qval{"htmlfile_spec"}; fyi(8,"texfile = $texfile, outfile = $outfile"); if ($texfile =~ /^(.+)\.([^.]*)$/ ) { $base = $1; $suffix = $2; } fyi(8, "base = $base, suffix = $suffix, $input file = $texfile"); $outfile =~ s/\$BASE/$base/e; $outfile =~ s/\$SUFFIX/$suffix/e; fyi(3, "+ texbase = $base ; HTML output file => $outfile ."); if (-e $outfile) { # # comment out the following warning if desired. # # print "Warn, file $outfile already exists\n"; } open(OUTF , ">"."$outfile"); # # print to OUTF by default, by selecting it. # select OUTF; print_html_header($texfile); # # print the generated HTML. # @delim_lines is the final HTML after processing # print_arr("", \@delim_lines); print_html_trailer($texfile); select STDOUT; } $re_fields = 4; # # DO NOT EDIT THEM MANUALLY. # associative arrays indexed by the LaTeX command # containing the corresponding the HTML # E.g, we might have something like: # %html_start{'textbf'} = ''; # %html_end{'textbf'} = ''; # The values are read in from a specification file. # DO NOT EDIT THEM MANUALLY. sub do_spec_pseudo_op { my($line) = @_; if ($line =~ /^=\*\*\*=[ \t]+([^ \t\n]*)/ ) { chomp($line); my($op) = $1; fyi(7, "Psuedo-op $op: ($line)"); if ($line =~ /endfile/) { return $op; } if ($line =~ /=[ \t]*echo./) { print "$POSTMATCH\n"; } if ($line =~ /=[ \t]*exit/) { fyi(6, "Exit request, line $INPUT_LINE_NUMBER, $spec_fname\n"); exit(1); } if ($line =~ /=[ \t]*warnlevel\s*:=\s*(\d+)/i) { $warnlevel = $1; } return "pseudo-op"; } elsif ($line =~ /^([a-zA-Z_][\w]*)\s*:=(.*)$/ ) { my($name, $val, $oldval) = ($1, $2, ""); $val =~ s/^[\s]*["]?//; $val =~ s/["]?[\s]*$//; $oldval = $qval{$name}; $qval{$name} = $val; fyi(6, "set var: $name := ($val), oldval = $oldval"); return "set-var"; } else { return ""; } } # Example # For the specification # ':b/e :\begin{rqitemize}(\{[^\}]*\})*: