From cb23eeb534a85547c427b695b6838e5792e31ddb Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 26 Sep 2004 21:06:17 +0000 Subject: [PATCH] Update docs. Integrate texi2html into source tree. --- doc/Makefile | 2 +- doc/filesys.texi | 88 +- doc/standards.texi | 4 +- doc/texi2html | 6332 ++++++++++++++++++++++++++++++++++++++++++++ doc/threads.texi | 23 +- doc/userprog.texi | 16 +- doc/vm.texi | 233 +- 7 files changed, 6523 insertions(+), 175 deletions(-) create mode 100755 doc/texi2html diff --git a/doc/Makefile b/doc/Makefile index 69ea110..6b4ce8f 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -4,7 +4,7 @@ filesys.texi vm.texi standards.texi doc.texi devel.texi debug.texi all: projects.html projects.info projects.html: $(TEXIS) mlfqs1.png mlfqs2.png - texi2html -toc_file=$@ -split=chapter -no-sec_nav -no-menu -init_file pintos-t2h.init $< + ./texi2html -toc_file=$@ -split=chapter -no-sec_nav -no-menu -init_file pintos-t2h.init -no-number $< projects.info: $(TEXIS) makeinfo $< diff --git a/doc/filesys.texi b/doc/filesys.texi index b496de7..c854ff3 100644 --- a/doc/filesys.texi +++ b/doc/filesys.texi @@ -31,7 +31,7 @@ Your submission should define @code{THREAD_JOIN_IMPLEMENTED} in * Problem 4-3 Subdirectories:: * Problem 4-4 Buffer Cache:: * File System Design Document Requirements:: -* File System FAQs:: +* File System FAQ:: @end menu @node File System New Code @@ -51,11 +51,11 @@ Top-level interface to the file system. @item directory.h @itemx directory.c -Translates file names to disk file headers; the -directory data structure is stored as a file. +Translates file names to inodes. The directory data structure is +stored as a file. -@item filehdr.h -@itemx filehdr.c +@item inode.h +@itemx inode.c Manages the data structure representing the layout of a file's data on disk. @@ -64,11 +64,6 @@ file's data on disk. Translates file reads and writes to disk sector reads and writes. -@item devices/disk.h -@itemx devices/disk.c -Provides access to the physical disk, abstracting away the rather -awful IDE interface. - @item lib/kernel/bitmap.h @itemx lib/kernel/bitmap.c A bitmap data structure along with routines for reading and writing @@ -95,25 +90,26 @@ prepared for interactions with all previous parts (as usual). Modify the file system to allow the maximum size of a file to be as large as the disk. You can assume that the disk will not be larger than 8 MB. In the basic file system, each file is limited to a file -size of just under 64 kB. Each file has a header (@code{struct -filehdr}) that is a table of direct pointers to the disk blocks for -that file. Since the header is stored in one disk sector, the maximum -size of a file is limited by the number of pointers that will fit in -one disk sector. Increasing the limit to 8 MB will require you to -implement doubly-indirect blocks. +size of just under 64 kB. Each file has a header called an index node +or @dfn{inode} (represented by @code{struct inode}) that is a table of +direct pointers to the disk blocks for that file. Since the inode is +stored in one disk sector, the maximum size of a file is limited by +the number of pointers that will fit in one disk sector. Increasing +the limit to 8 MB will require you to implement doubly-indirect +blocks. @node Problem 4-2 File Growth @section Problem 4-2: File Growth Implement extensible files. In the basic file system, the file size is specified when the file is created. One advantage of this is that -the FileHeader data structure, once created, never changes. In UNIX -and most other file systems, a file is initially created with size 0 -and is then expanded every time a write is made off the end of the -file. Modify the file system to allow this. As one test case, allow -the root directory file to expand beyond its current limit of ten -files. Make sure that concurrent accesses to the file header remain -properly synchronized. +the inode data structure, once created, never changes. In UNIX and +most other file systems, a file is initially created with size 0 and +is then expanded every time a write is made off the end of the file. +Modify the file system to allow this. As one test case, allow the +root directory file to expand beyond its current limit of ten files. +Make sure that concurrent accesses to the inode remain properly +synchronized. @node Problem 4-3 Subdirectories @section Problem 4-3: Subdirectories @@ -167,7 +163,7 @@ cache, and if so, fetch it immediately from the cache without going to disk. (Otherwise, fetch the block from disk into cache, evicting an older entry if necessary.) You are limited to a cache no greater than 64 sectors in size. Be sure to choose an intelligent cache -replacement algorithm. Experiment to see what combination of use, +replacement algorithm. Experiment to see what combination of accessed, dirty, and other information results in the best performance, as measured by the number of disk accesses. (For example, metadata is generally more valuable to cache than data.) Document your @@ -232,7 +228,7 @@ in the cache? How did you choose elements to evict from the cache? How and when did you flush the cache? @end itemize -@node File System FAQs +@node File System FAQ @section FAQ @enumerate 1 @@ -296,14 +292,21 @@ be implemented properly in @file{threads/init.c} and No, @code{DISK_SECTOR_SIZE} will not change. @item -@b{Will the @code{struct filehdr} take up space on the disk too?} +@b{Will the @code{struct inode} take up space on the disk too?} -Yes. Anything stored in @code{struct filehdr} takes up space on disk, +Yes. Anything stored in @code{struct inode} takes up space on disk, so you must include this in your calculation of how many entires will fit in a single disk sector. +@end enumerate -@item -File Growth FAQs +@menu +* Problem 4-2 File Growth FAQ:: +* Problem 4-3 Subdirectory FAQ:: +* Problem 4-4 Buffer Cache FAQ:: +@end menu + +@node Problem 4-2 File Growth FAQ +@subsection Problem 4-2: File Growth FAQ @enumerate 1 @item @@ -311,12 +314,12 @@ File Growth FAQs The disk we create will be 8 MB or smaller. However, individual files will have to be smaller than the disk to accommodate the metadata. -You'll need to consider this when deciding your @code{struct filehdr} -(inode) organization. +You'll need to consider this when deciding your @code{struct inode} +organization. @end enumerate -@item -Subdirectory FAQs +@node Problem 4-3 Subdirectory FAQ +@subsection Problem 4-3: Subdirectory FAQ @enumerate 1 @item @@ -375,19 +378,19 @@ regular files and directories. You may assume that directories can only be deleted if they are empty, as in Unix. @end enumerate -@item -Buffer Cache FAQs +@node Problem 4-4 Buffer Cache FAQ +@subsection Problem 4-4: Buffer Cache FAQ @enumerate 1 @item @b{We're limited to a 64-block cache, but can we also keep a copy of -each @code{struct filehdr} for an open file inside @code{struct file}, +each @code{struct inode} for an open file inside @code{struct file}, the way the stub code does?} No, you shouldn't keep any disk sectors stored anywhere outside the cache. That means you'll have to change the way the file implementation accesses its corresponding inode right now, since it -currently just creates a new @code{struct filehdr} in its constructor +currently just creates a new @code{struct inode} in its constructor and reads the corresponding sector in from disk when it's created. There are two reasons for not storing inodes in @code{struct file}. @@ -407,16 +410,15 @@ amount of metadata for each of your 64 cache entries, that's fine. @b{But why can't we store copies of inodes in @code{struct file}? We don't understand the answer to the previous question.} -The issue regarding storing @code{struct filehdr}s has to do with +The issue regarding storing @code{struct inode}s has to do with implementation of the buffer cache. Basically, you can't store a -@code{struct filehdr *} in @code{struct filehdr}. Each time you need -to read a @code{struct filehdr}, you'll have to get it either from the +@code{struct inode *} in @code{struct inode}. Each time you need +to read a @code{struct inode}, you'll have to get it either from the buffer cache or from disk. -If you look at @code{file_read_at()}, it uses @code{hdr} directly +If you look at @code{file_read_at()}, it uses the inode directly without having first read in that sector from wherever it was in the storage hierarchy. You are no longer allowed to do this. You will need to change @code{file_read_at} (and similar functions) so that it -reads @code{hdr} from the storage hierarchy before using it. -@end enumerate +reads the inode from the storage hierarchy before using it. @end enumerate diff --git a/doc/standards.texi b/doc/standards.texi index 60aa21a..e7ed568 100644 --- a/doc/standards.texi +++ b/doc/standards.texi @@ -71,7 +71,7 @@ this function. @item Problem 1-4, the advanced scheduler. We must be able to turn this on -and off with a compile time directive. You must use the macro name we +and off with a compile-time directive. You must use the macro name we specify for that part. @xref{Problem 1-4 Advanced Scheduler}, for details. @@ -140,7 +140,7 @@ the C compiler concatenates adjacent string literals: #include @dots{} int32_t value = @dots{}; -printf ("value=%08"PRId32"\n"); +printf ("value=%08"PRId32"\n", value); @end example @noindent The @samp{%} is not supplied by the @code{PRI} macros. As shown diff --git a/doc/texi2html b/doc/texi2html new file mode 100755 index 0000000..dd122ed --- /dev/null +++ b/doc/texi2html @@ -0,0 +1,6332 @@ +#! /usr/bin/env perl +'di '; +'ig 00 '; +#+############################################################################## +# +# texi2html: Program to transform Texinfo documents to HTML +# +# Copyright (C) 1999, 2000 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +#-############################################################################## + +# This requires perl version 5 or higher +require 5.0; + +# Perl pragma to restrict unsafe constructs +use strict; +# +# According to +# larry.jones@sdrc.com (Larry Jones) +# this pragma is not present in perl5.004_02: +# +# Perl pragma to control optional warnings +# use warnings; + +# Declarations +use vars qw( + $ADDRESS + $ANTI_ALIAS + $ANTI_ALIAS_TEXT + $ASCII_MODE + $AUTO_LINK + $AUTO_PREFIX + $BIBRE + $CHAPTEREND + $CHILDLINE + $Configure_failed + $DEBUG + $DEBUG_BIB + $DEBUG_DEF + $DEBUG_GLOSS + $DEBUG_HTML + $DEBUG_INDEX + $DEBUG_L2H + $DEBUG_TOC + $DEBUG_USER + $DESTDIR + $ERROR + $EXTERNAL_FILE + $EXTERNAL_IMAGES + $EXTERNAL_UP_LINK + $EXTERNAL_UP_TITLE + $FH + $FIGURE_SCALE_FACTOR + $FILERE + $HTML_VERSION + $IMAGES_ONLY + $INFO + $LINE_WIDTH + $LOCAL_ICONS + $LONG_TITLES + $MATH_SCALE_FACTOR + $MAX_LINK_DEPTH + $MAX_SPLIT_DEPTH + $NETSCAPE_HTML + $NODERE + $NODESRE + $NOLATEX + $NO_FOOTNODE + $NO_IMAGES + $NO_NAVIGATION + $NO_SIMPLE_MATH + $NO_SUBDIR + $PAPERSIZE + $PREFIX + $PROTECTTAG + $PS_IMAGES + $REUSE + $SCALABLE_FONTS + $SECTIONEND + $SHORTEXTN + $SHORT_INDEX + $SHOW_SECTION_NUMBERS + $SPLIT + $T2H_ADDRESS + $T2H_AFTER_ABOUT + $T2H_AFTER_BODY_OPEN + $T2H_AUTHORS + $T2H_BODYTEXT + $T2H_BUTTONS + $T2H_EXTRA_HEAD + $T2H_FAILURE_TEXT + $T2H_HAS_TOP_HEADING + $T2H_HOMEPAGE + $T2H_ICONS + $T2H_OBSOLETE_OPTIONS + $T2H_OVERVIEW + $T2H_PRE_BODY_CLOSE + $T2H_THIS_SECTION + $T2H_TOC + $T2H_TODAY + $T2H_TOP + $T2H_USAGE_TEXT + $T2H_USER + $TEXDEFS + $THISPROG + $THISVERSION + $TITLE + $TITLES_LANGUAGE + $TMP + $TOPEND + $VARRE + $VERBOSE + $WARN + $WORDS_IN_NAVIGATION_PANEL_TITLES + $WORDS_IN_PAGE + $about_body + $addr + $after + $before + $bib_num + $button + $call + $changed + $complex_format_map + $contents + $count + $counter + $curlevel + $d + $default_language + $deferred_ref + $doc_num + $docid + $docu + $docu_about + $docu_about_file + $docu_dir + $docu_doc + $docu_doc_file + $docu_ext + $docu_foot + $docu_foot_file + $docu_frame_file + $docu_name + $docu_rdir + $docu_stoc + $docu_stoc_file + $docu_toc + $docu_toc_file + $docu_toc_frame_file + $docu_top + $docu_top_file + $done + $dont_html + $dotbug + $elt + $end_of_para + $end_tag + $entry + $ext + $extensions + $failed + $fh_name + $file + $first_index_chapter + $first_line + $foot + $foot_num + $footid + $ftype + $full + $gloss_num + $h_content + $h_line + $has_top + $has_top_command + $hcontent + $html_element + $html_num + $i + $id + $idx_num + $in + $in_bibliography + $in_glossary + $in_html + $in_list + $in_pre + $in_table + $in_titlepage + $in_top + $index + $index_properties + $init_file + $int_file + $is_extra + $key + $keys + $l + $l2h_cache_file + $l2h_cached_count + $l2h_extract_error + $l2h_html_count + $l2h_html_file + $l2h_latex_closing + $l2h_latex_count + $l2h_latex_file + $l2h_latex_preample + $l2h_name + $l2h_prefix + $l2h_range_error + $l2h_to_latex_count + $l_l2h + $latex_file + $len + $letter + $level + $macros + $man + $match + $maximage + $next + $nn + $node + $node_next + $node_prev + $node_up + $nodes + $num + $old + $only_text + $options + $post + $pre + $prev_node + $previous + $progdir + $re + $reused + $root + $sec_num + $section + $string + $style + $sub + $subst_code + $table_type + $tag + $texi_style + $to_do + $toc_indent + $tocid + $toplevel + $type + $url + $use_acc + $use_bibliography + $what + %T2H_ACTIVE_ICONS + %T2H_BUTTONS_EXAMPLE + %T2H_BUTTONS_GOTO + %T2H_HREF + %T2H_NAME + %T2H_NAVIGATION_TEXT + %T2H_NODE + %T2H_PASSIVE_ICONS + %T2H_THISDOC + %accent_map + %bib2href + %context + %def_map + %format_map + %gloss2href + %idx2node + %l2h_cache + %l2h_img + %l2h_to_latex + %macros + %node2href + %node2next + %node2prev + %node2sec + %node2up + %number2sec + %predefined_index + %sec2level + %sec2node + %sec2seccount + %seccount2sec + %sec2number + %seen + %simple_map + %style_map + %tag2pro + %things_map + %to_skip + %user_sub + %valid_index + %value + @T2H_CHAPTER_BUTTONS + @T2H_MISC_BUTTONS + @T2H_SECTION_BUTTONS + @appendix_sec_num + @args + @doc_lines + @fhs + @foot_lines + @html_stack + @input_spool + @l2h_from_html + @l2h_to_latex + @lines + @lines2 + @lines3 + @normal_sec_num + @sections + @stoc_lines + @tables + @toc_lines + ); + +#++############################################################################## +# +# NOTE FOR DEBUGGING THIS SCRIPT: +# You can run 'perl texi2html.pl' directly, provided you have +# the environment variable T2H_HOME set to the directory containing +# the texi2html.init file +# +#--############################################################################## + +# CVS version: +# $Id: texi2html,v 1.1 2004-09-26 21:06:17 blp Exp $ + +# Homepage: +$T2H_HOMEPAGE = "http://texi2html.cvshome.org"; + +# Authors: +$T2H_AUTHORS = < (original author) + Karl Berry + Olaf Bachmann + and many others. +Maintained by: Many creative people +Send bugs and suggestions to +EOT + +# Version: set in configure.in +$THISVERSION = '1.66'; +$THISPROG = "texi2html $THISVERSION"; # program name and version + +# The man page for this program is included at the end of this file and can be +# viewed using the command 'nroff -man texi2html'. + +#+++############################################################################ +# # +# Initialization # +# Pasted content of File $(srcdir)/texi2html.init: Default initializations # +# # +#---############################################################################ + +# leave this within comments, and keep the require statement +# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/texi2html.init +# exists. + +# +# -*-perl-*- +###################################################################### +# File: texi2html.init +# +# Sets default values for command-line arguments and for various customizable +# procedures +# +# A copy of this file is pasted into the beginning of texi2html by +# 'make texi2html' +# +# Copy this file and make changes to it, if you like. +# Afterwards, either, load it with command-line option -init_file +# +# $Id: texi2html,v 1.1 2004-09-26 21:06:17 blp Exp $ + +###################################################################### +# stuff which can also be set by command-line options +# +# +# Note: values set here, overwrite values set by the command-line +# options before -init_file and might still be overwritten by +# command-line arguments following the -init_file option +# + +# T2H_OPTIONS is a hash whose keys are the (long) names of valid +# command-line options and whose values are a hash with the following keys: +# type ==> one of !|=i|:i|=s|:s (see GetOpt::Long for more info) +# linkage ==> ref to scalar, array, or subroutine (see GetOpt::Long for more info) +# verbose ==> short description of option (displayed by -h) +# noHelp ==> if 1 -> for "not so important options": only print description on -h 1 +# 2 -> for obsolete options: only print description on -h 2 + +my $T2H_DEBUG = 0; +my $T2H_OPTIONS; +$T2H_OPTIONS -> {debug} = +{ + type => '=i', + linkage => \$T2H_DEBUG, + verbose => 'output HTML with debuging information', +}; + +# APA: Add SystemLiteral to identify the canonical DTD. +# [Definition:] The SystemLiteral is called the entity's system +# identifier. It is a URI, which may be used to retrieve the entity. +# See http://www.xml.com/axml/target.html#NT-ExternalID +my $T2H_DOCTYPE = ''; +$T2H_OPTIONS -> {doctype} = +{ + type => '=s', + linkage => \$T2H_DOCTYPE, + verbose => 'document type which is output in header of HTML files', + noHelp => 1 +}; + +my $T2H_CHECK = 0; +$T2H_OPTIONS -> {check} = +{ + type => '!', + linkage => \$T2H_CHECK, + verbose => 'if set, only check files and output all things that may be Texinfo commands', + noHelp => 1 +}; + +# -expand +# if set to "tex" (or, "info") expand @iftex and @tex (or, @ifinfo) sections +# else, neither expand @iftex, @tex, nor @ifinfo sections +my $T2H_EXPAND = "info"; +$T2H_OPTIONS -> {expand} = +{ + type => '=s', + linkage => \$T2H_EXPAND, + verbose => 'Expand info|tex|none section of texinfo source', +}; + +# - glossary +# If set, uses section named `Footnotes' for glossary. +my $T2H_USE_GLOSSARY = 0; +$T2H_OPTIONS -> {glossary} = +{ + type => '!', + linkage => \$T2H_USE_GLOSSARY, + verbose => "if set, uses section named `Footnotes' for glossary", + noHelp => 1, +}; + + +# -invisible +# $T2H_INVISIBLE_MARK is the text used to create invisible destination +# anchors for index links (you can for instance use the invisible.xbm +# file shipped with this program). This is a workaround for a known +# bug of many WWW browsers, including netscape. +# For me, it works fine without it -- on the contrary: if there, it +# inserts space between headers and start of text (obachman 3/99) +my $T2H_INVISIBLE_MARK = ''; +# $T2H_INVISIBLE_MARK = ' '; +$T2H_OPTIONS -> {invisible} = +{ + type => '=s', + linkage => \$T2H_INVISIBLE_MARK, + verbose => 'use text in invisble anchot', + noHelp => 1, +}; + +# -iso +# if set, ISO8859 characters are used for special symbols (like copyright, etc) +my $T2H_USE_ISO = 0; +$T2H_OPTIONS -> {iso} = +{ + type => 'iso', + linkage => \$T2H_USE_ISO, + verbose => 'if set, ISO8859 characters are used for special symbols (like copyright, etc)', + noHelp => 1, +}; + +# -I +# list directories where @include files are searched for (besides the +# directory of the doc file) additional '-I' args add to this list +# APA: Don't implicitely search ., to conform with the docs! +# my @T2H_INCLUDE_DIRS = ("."); +my @T2H_INCLUDE_DIRS = (); +$T2H_OPTIONS -> {I} = +{ + type => '=s', + linkage => \@T2H_INCLUDE_DIRS, + verbose => 'append $s to the @include search path', +}; + +# -top_file +# uses file of this name for top-level file +# extension is manipulated appropriately, if necessary. +# If empty, .html is used. +# Typically, you would set this to "index.html". +my $T2H_TOP_FILE = ''; +$T2H_OPTIONS -> {top_file} = +{ + type => '=s', + linkage => \$T2H_TOP_FILE, + verbose => 'use $s as top file, instead of .html', +}; + + +# -toc_file +# uses file of this name for table of contents. File +# extension is manipulated appropriately, if necessary. +# If empty, _toc.html is used. +my $T2H_TOC_FILE = ''; +$T2H_OPTIONS -> {toc_file} = +{ + type => '=s', + linkage => \$T2H_TOC_FILE, + verbose => 'use $s as ToC file, instead of _toc.html', +}; + +# -frames +# if set, output two additional files which use HTML 4.0 "frames". +my $T2H_FRAMES = 0; +$T2H_OPTIONS -> {frames} = +{ + type => '!', + linkage => \$T2H_FRAMES, + verbose => 'output files which use HTML 4.0 frames (experimental)', + noHelp => 1, +}; + + +# -menu | -nomenu +# if set, show the Texinfo menus +my $T2H_SHOW_MENU = 1; +$T2H_OPTIONS -> {menu} = +{ + type => '!', + linkage => \$T2H_SHOW_MENU, + verbose => 'ouput Texinfo menus', +}; + +# -number | -nonumber +# if set, number sections and show section names and numbers in references +# and menus +my $T2H_NUMBER_SECTIONS = 1; +$T2H_OPTIONS -> {number} = +{ + type => '!', + linkage => \$T2H_NUMBER_SECTIONS, + verbose => 'use numbered sections' +}; + +# if set, and T2H_NUMBER_SECTIONS is set, then use node names in menu +# entries, instead of section names +my $T2H_NODE_NAME_IN_MENU = 0; + +# if set and menu entry equals menu descr, then do not print menu descr. +# Likewise, if node name equals entry name, do not print entry name. +my $T2H_AVOID_MENU_REDUNDANCY = 1; + +# -split section|chapter|none +# if set to 'section' (resp. 'chapter') create one html file per (sub)section +# (resp. chapter) and separate pages for Top, ToC, Overview, Index, +# Glossary, About. +# Otherwise, create a monolithic html file that contains the whole document. +#$T2H_SPLIT = 'section'; +my $T2H_SPLIT = ''; +$T2H_OPTIONS -> {split} = +{ + type => '=s', + linkage => \$T2H_SPLIT, + verbose => 'split document on section|chapter else no splitting', +}; + +# -section_navigation|-no-section_navigation +# if set, then navigation panels are printed at the beginning of each section +# and, possibly at the end (depending on whether or not there were more than +# $T2H_WORDS_IN_PAGE words on page +# This is most useful if you do not want to have section navigation +# on -split chapter +my $T2H_SECTION_NAVIGATION = 1; +$T2H_OPTIONS -> {sec_nav} = +{ + type => '!', + linkage => \$T2H_SECTION_NAVIGATION, + verbose => 'output navigation panels for each section', +}; + +# -subdir +# If set, then put result files into the specified directory. +# If not set, then result files are put into the current directory. +#$T2H_SUBDIR = 'html'; +my $T2H_SUBDIR = ''; +$T2H_OPTIONS -> {subdir} = +{ + type => '=s', + linkage => \$T2H_SUBDIR, + verbose => 'put HTML files in directory $s, instead of $cwd', +}; + +# -short_extn +# If this is set, then all HTML files will have extension ".htm" instead of +# ".html". This is helpful when shipping the document to DOS-based systems. +my $T2H_SHORTEXTN = 0; +$T2H_OPTIONS -> {short_ext} = +{ + type => '!', + linkage => \$T2H_SHORTEXTN, + verbose => 'use "htm" extension for output HTML files', +}; + + +# -prefix +# Set the output file prefix, prepended to all .html, .gif and .pl files. +# By default, this is the basename of the document +my $T2H_PREFIX = ''; +$T2H_OPTIONS -> {prefix} = +{ + type => '=s', + linkage => \$T2H_PREFIX, + verbose => 'use as prefix for output files, instead of ', +}; + +# -o filename +# If set, generate monolithic document output html into $filename +my $T2H_OUT = ''; +$T2H_OPTIONS -> {out_file} = +{ + type => '=s', + linkage => sub {$T2H_OUT = $_[1]; $T2H_SPLIT = '';}, + verbose => 'if set, all HTML output goes into file $s', +}; + +# -short_ref +#if set cross-references are given without section numbers +my $T2H_SHORT_REF = ''; +$T2H_OPTIONS -> {short_ref} = +{ + type => '!', + linkage => \$T2H_SHORT_REF, + verbose => 'if set, references are without section numbers', +}; + +# -idx_sum +# if value is set, then for each @prinindex $what +# $docu_name_$what.idx is created which contains lines of the form +# $key\t$ref sorted alphabetically (case matters) +my $T2H_IDX_SUMMARY = 0; +$T2H_OPTIONS -> {idx_sum} = +{ + type => '!', + linkage => \$T2H_IDX_SUMMARY, + verbose => 'if set, also output index summary', + noHelp => 1, +}; + +# -def_table +# Use a table construction for @def .... stuff instead +# New Option: 27.07.2000 Karl Heinz Marbaise +my $T2H_DEF_TABLE = 0; +$T2H_OPTIONS -> {def_table} = +{ + type => '!', + linkage => \$T2H_DEF_TABLE, + verbose => 'if set, \@def.. are converted using tables.', + noHelp => 1, +}; + +# -verbose +# if set, chatter about what we are doing +my $T2H_VERBOSE = ''; +$T2H_OPTIONS -> {Verbose} = +{ + type => '!', + linkage => \$T2H_VERBOSE, + verbose => 'print progress info to stdout', +}; + +# -lang +# For page titles use $T2H_WORDS->{$T2H_LANG}->{...} as title. +# To add a new language, supply list of titles (see $T2H_WORDS below). +# and use ISO 639 language codes (see e.g. perl module Locale-Codes-1.02 +# for definitions) +# Default's to 'en' if not set or no @documentlanguage is specified +my $T2H_LANG = ''; +$T2H_OPTIONS -> {lang} = +{ + type => '=s', + linkage => sub {SetDocumentLanguage($_[1])}, + verbose => 'use $s as document language (ISO 639 encoding)', +}; + +# -l2h +# if set, uses latex2html for generation of math content +my $T2H_L2H = ''; +$T2H_OPTIONS -> {l2h} = +{ + type => '!', + linkage => \$T2H_L2H, + verbose => 'if set, uses latex2html for @math and @tex', +}; + +###################### +# The following options are only relevant if $T2H_L2H is set +# +# -l2h_l2h +# name/location of latex2html program +my $T2H_L2H_L2H = "latex2html"; +$T2H_OPTIONS -> {l2h_l2h} = +{ + type => '=s', + linkage => \$T2H_L2H_L2H, + verbose => 'program to use for latex2html translation', + noHelp => 1, +}; + +# -l2h_skip +# If set, skips actual call to latex2html: tries to reuse previously generated +# content, instead. +my $T2H_L2H_SKIP = ''; +$T2H_OPTIONS -> {l2h_skip} = +{ + type => '!', + linkage => \$T2H_L2H_SKIP, + verbose => 'if set, tries to reuse previously latex2html output', + noHelp => 1, +}; + +# -l2h_tmp +# If set, l2h uses the specified directory for temporary files. The path +# leading to this directory may not contain a dot (i.e., a "."); +# otherwise, l2h will fail. +my $T2H_L2H_TMP = ''; +$T2H_OPTIONS -> {l2h_tmp} = +{ + type => '=s', + linkage => \$T2H_L2H_TMP, + verbose => 'if set, uses $s as temporary latex2html directory', + noHelp => 1, +}; + +# if set, cleans intermediate files (they all have the prefix $doc_l2h_) +# of l2h +my $T2H_L2H_CLEAN = 1; +$T2H_OPTIONS -> {l2h_clean} = +{ + type => '!', + linkage => \$T2H_L2H_CLEAN, + verbose => 'if set, do not keep intermediate latex2html files for later reuse', + noHelp => 1, +}; + +$T2H_OPTIONS -> {D} = +{ + type => '=s', + linkage => sub {$main::value{$_[1]} = 1;}, + verbose => 'equivalent to Texinfo "@set $s 1"', + noHelp => 1, +}; + +$T2H_OPTIONS -> {init_file} = +{ + type => '=s', + linkage => \&LoadInitFile, + verbose => 'load init file $s' +}; + + +############################################################################## +# +# The following can only be set in the init file +# +############################################################################## + +# if set, center @image by default +# otherwise, do not center by default +my $T2H_CENTER_IMAGE = 1; + +# used as identation for block enclosing command @example, etc +# If not empty, must be enclosed in +my $T2H_EXAMPLE_INDENT_CELL = ' '; +# same as above, only for @small +my $T2H_SMALL_EXAMPLE_INDENT_CELL = ' '; +# font size for @small +my $T2H_SMALL_FONT_SIZE = '-1'; + +# if non-empty, and no @..heading appeared in Top node, then +# use this as header for top node/section, otherwise use value of +# @settitle or @shorttitle (in that order) +my $T2H_TOP_HEADING = ''; + +# if set, use this chapter for 'Index' button, else +# use first chapter whose name matches 'index' (case insensitive) +my $T2H_INDEX_CHAPTER = ''; + +# if set and $T2H_SPLIT is set, then split index pages at the next letter +# after they have more than that many entries +my $T2H_SPLIT_INDEX = 100; + +# if set (e.g., to index.html) replace hrefs to this file +# (i.e., to index.html) by ./ +my $T2H_HREF_DIR_INSTEAD_FILE = ''; + +######################################################################## +# Language dependencies: +# To add a new language extend T2H_WORDS hash and create $T2H_<...>_WORDS hash +# To redefine one word, simply do: +# $T2H_WORDS->{}->{} = 'whatever' in your personal init file. +# +my $T2H_WORDS_EN = +{ + # titles of pages + 'ToC_Title' => 'Table of Contents', + 'Overview_Title' => 'Short Table of Contents', + 'Index_Title' => 'Index', + 'About_Title' => 'About this document', + 'Footnotes_Title' => 'Footnotes', + 'See' => 'See', + 'see' => 'see', + 'section' => 'section', + # If necessary, we could extend this as follows: + # # text for buttons + # 'Top_Button' => 'Top', + # 'ToC_Button' => 'Contents', + # 'Overview_Button' => 'Overview', + # 'Index_button' => 'Index', + # 'Back_Button' => 'Back', + # 'FastBack_Button' => 'FastBack', + # 'Prev_Button' => 'Prev', + # 'Up_Button' => 'Up', + # 'Next_Button' => 'Next', + # 'Forward_Button' =>'Forward', + # 'FastWorward_Button' => 'FastForward', + # 'First_Button' => 'First', + # 'Last_Button' => 'Last', + # 'About_Button' => 'About' +}; + +my $T2H_WORDS_DE = +{ + 'ToC_Title' => 'Inhaltsverzeichniss', + 'Overview_Title' => 'Kurzes Inhaltsverzeichniss', + 'Index_Title' => 'Index', + 'About_Title' => 'Über dieses Dokument', + 'Footnotes_Title' => 'Fußnoten', + 'See' => 'Siehe', + 'see' => 'siehe', + 'section' => 'Abschnitt', +}; + +my $T2H_WORDS_NL = +{ + 'ToC_Title' => 'Inhoudsopgave', + 'Overview_Title' => 'Korte inhoudsopgave', + 'Index_Title' => 'Index', #Not sure ;-) + 'About_Title' => 'No translation available!', #No translation available! + 'Footnotes_Title' => 'No translation available!', #No translation available! + 'See' => 'Zie', + 'see' => 'zie', + 'section' => 'sectie', +}; + +my $T2H_WORDS_ES = +{ + 'ToC_Title' => 'índice General', + 'Overview_Title' => 'Resumen del Contenido', + 'Index_Title' => 'Index', #Not sure ;-) + 'About_Title' => 'No translation available!', #No translation available! + 'Footnotes_Title' => 'Fußnoten', + 'See' => 'Véase', + 'see' => 'véase', + 'section' => 'sección', +}; + +my $T2H_WORDS_NO = +{ + 'ToC_Title' => 'Innholdsfortegnelse', + 'Overview_Title' => 'Kort innholdsfortegnelse', + 'Index_Title' => 'Indeks', #Not sure ;-) + 'About_Title' => 'No translation available!', #No translation available! + 'Footnotes_Title' => 'No translation available!', + 'See' => 'Se', + 'see' => 'se', + 'section' => 'avsnitt', +}; + +my $T2H_WORDS_PT = +{ + 'ToC_Title' => 'Sumário', + 'Overview_Title' => 'Breve Sumário', + 'Index_Title' => 'Índice', #Not sure ;-) + 'About_Title' => 'No translation available!', #No translation available! + 'Footnotes_Title' => 'No translation available!', + 'See' => 'Veja', + 'see' => 'veja', + 'section' => 'Seção', +}; + +my $T2H_WORDS_FR = +{ + 'ToC_Title' => 'Table des mati&egrav;res', + 'Overview_Title' => 'Résumée du contenu', + 'Index_Title' => 'Index', + 'About_Title' => 'A propos de ce document', + 'Footnotes_Title' => 'Notes de bas de page', + 'See' => 'Voir', + 'see' => 'voir', + 'section' => 'section', +}; + +my $T2H_WORDS = +{ + 'en' => $T2H_WORDS_EN, + 'de' => $T2H_WORDS_DE, + 'nl' => $T2H_WORDS_NL, + 'es' => $T2H_WORDS_ES, + 'no' => $T2H_WORDS_NO, + 'pt' => $T2H_WORDS_PT, + 'fr' => $T2H_WORDS_FR +}; + +my @MONTH_NAMES_EN = + ( + 'January', 'February', 'March', 'April', 'May', + 'June', 'July', 'August', 'September', 'October', + 'November', 'December' + ); + +my @MONTH_NAMES_DE = + ( + 'Januar', 'Februar', 'März', 'April', 'Mai', + 'Juni', 'Juli', 'August', 'September', 'Oktober', + 'November', 'Dezember' + ); + +my @MONTH_NAMES_NL = + ( + 'Januari', 'Februari', 'Maart', 'April', 'Mei', + 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', + 'November', 'December' + ); + +my @MONTH_NAMES_ES = + ( + 'enero', 'febrero', 'marzo', 'abril', 'mayo', + 'junio', 'julio', 'agosto', 'septiembre', 'octubre', + 'noviembre', 'diciembre' + ); + +my @MONTH_NAMES_NO = + ( + + 'januar', 'februar', 'mars', 'april', 'mai', + 'juni', 'juli', 'august', 'september', 'oktober', + 'november', 'desember' + ); + +my @MONTH_NAMES_PT = + ( + 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', + 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', + 'Novembro', 'Dezembro' + ); + +my @MONTH_NAMES_FR = +( + 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', + 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', + 'Novembre', 'Décembre' +); + + + +my $MONTH_NAMES = +{ + 'en' => \@MONTH_NAMES_EN, + 'de' => \@MONTH_NAMES_DE, + 'es' => \@MONTH_NAMES_ES, + 'nl' => \@MONTH_NAMES_NL, + 'no' => \@MONTH_NAMES_NO, + 'pt' => \@MONTH_NAMES_PT, + 'fr' => \@MONTH_NAMES_FR +}; + +######################################################################## +# Control of Page layout: +# You can make changes of the Page layout at two levels: +# 1.) For small changes, it is often enough to change the value of +# some global string/hash/array variables +# 2.) For larger changes, reimplement one of the T2H_DEFAULT_* routines, +# give them another name, and assign them to the respective +# $T2H_ variable. + +# As a general interface, the hashes T2H_HREF, T2H_NAME, T2H_NODE hold +# href, html-name, node-name of +# This -- current section (resp. html page) +# Top -- top page ($T2H_TOP_FILE) +# Contents -- Table of contents +# Overview -- Short table of contents +# Index -- Index page +# About -- page which explain "navigation buttons" +# First -- first node +# Last -- last node +# +# Whether or not the following hash values are set, depends on the context +# (all values are w.r.t. 'This' section) +# Next -- next node of texinfo +# Prev -- previous node of texinfo +# Up -- up node of texinfo +# Forward -- next node in reading order +# Back -- previous node in reading order +# FastForward -- if leave node, up and next, else next node +# FastBackward-- if leave node, up and prev, else prev node +# +# Furthermore, the following global variabels are set: +# $T2H_THISDOC{title} -- title as set by @setttile +# $T2H_THISDOC{fulltitle} -- full title as set by @title... +# $T2H_THISDOC{subtitle} -- subtitle as set by @subtitle +# $T2H_THISDOC{author} -- author as set by @author +# +# and pointer to arrays of lines which need to be printed by t2h_print_lines +# $T2H_OVERVIEW -- lines of short table of contents +# $T2H_TOC -- lines of table of contents +# $T2H_TOP -- lines of Top texinfo node +# $T2H_THIS_SECTION -- lines of 'This' section + +# +# There are the following subs which control the layout: +# +my $T2H_print_section = \&T2H_DEFAULT_print_section; +my $T2H_print_Top_header = \&T2H_DEFAULT_print_Top_header; +my $T2H_print_Top_footer = \&T2H_DEFAULT_print_Top_footer; +my $T2H_print_Top = \&T2H_DEFAULT_print_Top; +my $T2H_print_Toc = \&T2H_DEFAULT_print_Toc; +my $T2H_print_Overview = \&T2H_DEFAULT_print_Overview; +my $T2H_print_Footnotes = \&T2H_DEFAULT_print_Footnotes; +my $T2H_print_About = \&T2H_DEFAULT_print_About; +my $T2H_print_misc_header = \&T2H_DEFAULT_print_misc_header; +my $T2H_print_misc_footer = \&T2H_DEFAULT_print_misc_footer; +my $T2H_print_misc = \&T2H_DEFAULT_print_misc; +my $T2H_print_chapter_header = \&T2H_DEFAULT_print_chapter_header; +my $T2H_print_chapter_footer = \&T2H_DEFAULT_print_chapter_footer; +my $T2H_print_page_head = \&T2H_DEFAULT_print_page_head; +my $T2H_print_page_foot = \&T2H_DEFAULT_print_page_foot; +my $T2H_print_head_navigation = \&T2H_DEFAULT_print_head_navigation; +my $T2H_print_foot_navigation = \&T2H_DEFAULT_print_foot_navigation; +my $T2H_button_icon_img = \&T2H_DEFAULT_button_icon_img; +my $T2H_print_navigation = \&T2H_DEFAULT_print_navigation; +my $T2H_about_body = \&T2H_DEFAULT_about_body; +my $T2H_print_frame = \&T2H_DEFAULT_print_frame; +my $T2H_print_toc_frame = \&T2H_DEFAULT_print_toc_frame; + +######################################################################## +# Layout for html for every sections +# +sub T2H_DEFAULT_print_section +{ + my $fh = shift; + local $T2H_BUTTONS = \@T2H_SECTION_BUTTONS; + &$T2H_print_head_navigation($fh) if $T2H_SECTION_NAVIGATION; + my $nw = t2h_print_lines($fh); + if (defined $T2H_SPLIT + and ($T2H_SPLIT eq 'section' && $T2H_SECTION_NAVIGATION)) + { + &$T2H_print_foot_navigation($fh, $nw); + } + else + { + print $fh '
' . "\n"; + } +} + +################################################################### +# Layout of top-page I recommend that you use @ifnothtml, @ifhtml, +# @html within the Top texinfo node to specify content of top-level +# page. +# +# If you enclose everything in @ifnothtml, then title, subtitle, +# author and overview is printed +# T2H_HREF of Next, Prev, Up, Forward, Back are not defined +# if $T2H_SPLIT then Top page is in its own html file +sub T2H_DEFAULT_print_Top_header +{ + &$T2H_print_page_head(@_) if $T2H_SPLIT; + t2h_print_label(@_); # this needs to be called, otherwise no label set + &$T2H_print_head_navigation(@_); +} +sub T2H_DEFAULT_print_Top_footer +{ + &$T2H_print_foot_navigation(@_); + &$T2H_print_page_foot(@_) if $T2H_SPLIT; +} +sub T2H_DEFAULT_print_Top +{ + my $fh = shift; + + # for redefining navigation buttons use: + # local $T2H_BUTTONS = [...]; + # as it is, 'Top', 'Contents', 'Index', 'About' are printed + local $T2H_BUTTONS = \@T2H_MISC_BUTTONS; + &$T2H_print_Top_header($fh); + if ($T2H_THIS_SECTION) + { + # if top-level node has content, then print it with extra header + print $fh "

$T2H_NAME{Top}

\n" + unless ($T2H_HAS_TOP_HEADING); + t2h_print_lines($fh, $T2H_THIS_SECTION) + } + else + { + # top-level node is fully enclosed in @ifnothtml + # print fulltitle, subtitle, author, Overview + print $fh + "
\n

" . + join("

\n

", split(/\n/, $T2H_THISDOC{fulltitle})) . + "

\n"; + print $fh "

$T2H_THISDOC{subtitle}

\n" if $T2H_THISDOC{subtitle}; + print $fh "$T2H_THISDOC{author}\n" if $T2H_THISDOC{author}; + print $fh < +
+

+

Overview:

+
+EOT + t2h_print_lines($fh, $T2H_OVERVIEW); + print $fh "
\n"; + } + &$T2H_print_Top_footer($fh); +} + +################################################################### +# Layout of Toc, Overview, and Footnotes pages +# By default, we use "normal" layout +# T2H_HREF of Next, Prev, Up, Forward, Back, etc are not defined +# use: local $T2H_BUTTONS = [...] to redefine navigation buttons +sub T2H_DEFAULT_print_Toc +{ + return &$T2H_print_misc(@_); +} +sub T2H_DEFAULT_print_Overview +{ + return &$T2H_print_misc(@_); +} +sub T2H_DEFAULT_print_Footnotes +{ + return &$T2H_print_misc(@_); +} +sub T2H_DEFAULT_print_About +{ + return &$T2H_print_misc(@_); +} + +sub T2H_DEFAULT_print_misc_header +{ + &$T2H_print_page_head(@_) if $T2H_SPLIT; + # this needs to be called, otherwise, no labels are set + t2h_print_label(@_); + &$T2H_print_head_navigation(@_); +} +sub T2H_DEFAULT_print_misc_footer +{ + &$T2H_print_foot_navigation(@_); + &$T2H_print_page_foot(@_) if $T2H_SPLIT; +} +sub T2H_DEFAULT_print_misc +{ + my $fh = shift; + local $T2H_BUTTONS = \@T2H_MISC_BUTTONS; + &$T2H_print_misc_header($fh); + print $fh "

$T2H_NAME{This}

\n"; + t2h_print_lines($fh); + &$T2H_print_misc_footer($fh); +} + +################################################################### +# chapter_header and chapter_footer are only called if +# T2H_SPLIT eq 'chapter' +# chapter_header: after print_page_head, before print_section +# chapter_footer: after print_section of last section, before print_page_foot +# +# If you want to get rid of navigation stuff after each section, +# redefine print_section such that it does not call print_navigation, +# and put print_navigation into print_chapter_header +@T2H_CHAPTER_BUTTONS = + ( + 'FastBack', 'FastForward', ' ', + ' ', ' ', ' ', ' ', + 'Top', 'Contents', 'Index', 'About', + ); + +sub T2H_DEFAULT_print_chapter_header +{ + # nothing to do there, by default + if (! $T2H_SECTION_NAVIGATION) + { + my $fh = shift; + local $T2H_BUTTONS = \@T2H_CHAPTER_BUTTONS; + &$T2H_print_navigation($fh); + print $fh "\n
\n"; + } +} + +sub T2H_DEFAULT_print_chapter_footer +{ + local $T2H_BUTTONS = \@T2H_CHAPTER_BUTTONS; + &$T2H_print_navigation(@_); +} +################################################################### + +sub pretty_date { + my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst); + + ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + $year += ($year < 70) ? 2000 : 1900; + # obachman: Let's do it as the Americans do + return($MONTH_NAMES->{$T2H_LANG}[$mon] . ", " . $mday . " " . $year); +} + + +################################################################### +# Layout of standard header and footer +# + +# This init routine is called at the beginning of pass5 before first +# output is generated. +sub T2H_InitGlobals +{ + # Set the default body text, inserted between + $T2H_BODYTEXT = 'LANG="' . $T2H_LANG . '" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#800080" ALINK="#FF0000"'; + # text inserted after + $T2H_AFTER_BODY_OPEN = ''; + #text inserted before + $T2H_PRE_BODY_CLOSE = ''; + # this is used in footer + $T2H_ADDRESS = "$T2H_USER " if $T2H_USER; + $T2H_ADDRESS .= "on $T2H_TODAY"; + # this is added inside after and some META NAME stuff + # can be used for <style> <script>, <meta> tags + $T2H_EXTRA_HEAD = ''; +} + +sub T2H_DEFAULT_print_page_head +{ + my $fh = shift; + my $longtitle = "$T2H_THISDOC{title}"; + $longtitle .= ": $T2H_NAME{This}" if exists $T2H_NAME{This}; + print $fh <<EOT; +$T2H_DOCTYPE +<HTML> +<!-- Created on $T2H_TODAY by $THISPROG --> +<!-- +$T2H_AUTHORS +--> +<HEAD> +<TITLE>$longtitle + + + + + + +$T2H_EXTRA_HEAD + + + +$T2H_AFTER_BODY_OPEN +EOT +} + +sub T2H_DEFAULT_print_page_foot +{ + my $fh = shift; + print $fh < + +This document was generated +by $T2H_ADDRESS +using texi2html + +$T2H_PRE_BODY_CLOSE + + +EOT +} + +################################################################### +# Layout of navigation panel + +# if this is set, then a vertical navigation panel is used +my $T2H_VERTICAL_HEAD_NAVIGATION = 0; +sub T2H_DEFAULT_print_head_navigation +{ + my $fh = shift; + if ($T2H_VERTICAL_HEAD_NAVIGATION) + { + print $fh < + + +EOT + } + &$T2H_print_navigation($fh, $T2H_VERTICAL_HEAD_NAVIGATION); + if ($T2H_VERTICAL_HEAD_NAVIGATION) + { + print $fh < + +EOT + } + elsif (defined $T2H_SPLIT + and ($T2H_SPLIT eq 'section')) + { + print $fh "
\n"; + } +} + +# Specifies the minimum page length required before a navigation panel +# is placed at the bottom of a page (the default is that of latex2html) +# T2H_THIS_WORDS_IN_PAGE holds number of words of current page +my $T2H_WORDS_IN_PAGE = 300; +sub T2H_DEFAULT_print_foot_navigation +{ + my $fh = shift; + my $nwords = shift; + if ($T2H_VERTICAL_HEAD_NAVIGATION) + { + print $fh < + + +EOT + } + print $fh "
\n"; + &$T2H_print_navigation($fh) if (defined $nwords + and $nwords >= $T2H_WORDS_IN_PAGE) +} + +###################################################################### +# navigation panel +# +# specify in this array which "buttons" should appear in which order +# in the navigation panel for sections; use ' ' for empty buttons (space) +@T2H_SECTION_BUTTONS = + ( + 'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward', + ' ', ' ', ' ', ' ', + 'Top', 'Contents', 'Index', 'About', + ); + +# buttons for misc stuff +@T2H_MISC_BUTTONS = ('Top', 'Contents', 'Index', 'About'); + +# insert here name of icon images for buttons +# Icons are used, if $T2H_ICONS and resp. value are set +%T2H_ACTIVE_ICONS = + ( + 'Top', '', + 'Contents', '', + 'Overview', '', + 'Index', '', + 'Back', '', + 'FastBack', '', + 'Prev', '', + 'Up', '', + 'Next', '', + 'Forward', '', + 'FastForward', '', + 'About' , '', + 'First', '', + 'Last', '', + ' ', '' + ); + +# insert here name of icon images for these, if button is inactive +%T2H_PASSIVE_ICONS = + ( + 'Top', '', + 'Contents', '', + 'Overview', '', + 'Index', '', + 'Back', '', + 'FastBack', '', + 'Prev', '', + 'Up', '', + 'Next', '', + 'Forward', '', + 'FastForward', '', + 'About', '', + 'First', '', + 'Last', '', + ); + +# how to create IMG tag +sub T2H_DEFAULT_button_icon_img +{ + my $button = shift; + my $icon = shift; + my $name = shift; + return qq{$button: $name}; +} + +# Names of text as alternative for icons +%T2H_NAVIGATION_TEXT = + ( + 'Top', 'Top', + 'Contents', 'Contents', + 'Overview', 'Overview', + 'Index', 'Index', + ' ', '   ', + 'Back', ' < ', + 'FastBack', ' << ', + 'Prev', 'Prev', + 'Up', ' Up ', + 'Next', 'Next', + 'Forward', ' > ', + 'FastForward', ' >> ', + 'About', ' ? ', + 'First', ' |< ', + 'Last', ' >| ' + ); + +sub T2H_DEFAULT_print_navigation +{ + my $fh = shift; + my $vertical = shift; + my $spacing = 1; + print $fh "\n"; + + print $fh "" unless $vertical; + for $button (@$T2H_BUTTONS) + { + print $fh qq{\n} if $vertical; + print $fh qq{\n"; + print $fh "\n" if $vertical; + } + print $fh "" unless $vertical; + print $fh "
}; + + if (ref($button) eq 'CODE') + { + &$button($fh, $vertical); + } + elsif ($button eq ' ') + { # handle space button + print $fh + $T2H_ICONS && $T2H_ACTIVE_ICONS{' '} ? + &$T2H_button_icon_img($button, $T2H_ACTIVE_ICONS{' '}) : + $T2H_NAVIGATION_TEXT{' '}; + next; + } + elsif ($T2H_HREF{$button}) + { # button is active + print $fh + $T2H_ICONS && $T2H_ACTIVE_ICONS{$button} ? # use icon ? + t2h_anchor('', $T2H_HREF{$button}, # yes + &$T2H_button_icon_img($button, + $T2H_ACTIVE_ICONS{$button}, + $T2H_NAME{$button})) + : # use text + "[" . + t2h_anchor('', $T2H_HREF{$button}, $T2H_NAVIGATION_TEXT{$button}) . + "]"; + } + else + { # button is passive + print $fh + $T2H_ICONS && $T2H_PASSIVE_ICONS{$button} ? + &$T2H_button_icon_img($button, + $T2H_PASSIVE_ICONS{$button}, + $T2H_NAME{$button}) : + + "[" . $T2H_NAVIGATION_TEXT{$button} . "]"; + } + print $fh "
\n"; +} + +###################################################################### +# Frames: this is from "Richard Y. Kim" +# Should be improved to be more conforming to other _print* functions + +sub T2H_DEFAULT_print_frame +{ + my $fh = shift; + print $fh < +$T2H_THISDOC{title} + + + + + +EOT +} + +sub T2H_DEFAULT_print_toc_frame +{ + my $fh = shift; + &$T2H_print_page_head($fh); + print $fh <Content +EOT + print $fh map {s/HREF=/target=\"main\" HREF=/; $_;} @stoc_lines; + print $fh "\n"; +} + +###################################################################### +# About page +# + +# T2H_PRE_ABOUT might be a function +my $T2H_PRE_ABOUT = <texi2html +

+EOT +my $T2H_AFTER_ABOUT = ''; + +sub T2H_DEFAULT_about_body +{ + my $about; + if (ref($T2H_PRE_ABOUT) eq 'CODE') + { + $about = &$T2H_PRE_ABOUT(); + } + else + { + $about = $T2H_PRE_ABOUT; + } + $about .= <

+ + + + + + + +EOT + + for $button (@T2H_SECTION_BUTTONS) + { + next if $button eq ' ' || ref($button) eq 'CODE'; + $about .= < + + + + +EOT + } + + $about .= < +

+ where the Example assumes that the current position + is at Subsubsection One-Two-Three of a document of + the following structure:

+
    +
  • 1. Section One +
      +
    • 1.1 Subsection One-One +
        +
      • ...
      • +
      +
    • 1.2 Subsection One-Two +
        +
      • 1.2.1 Subsubsection One-Two-One
      • +
      • 1.2.2 Subsubsection One-Two-Two
      • +
      • 1.2.3 Subsubsection One-Two-Three     + <== Current Position
      • +
      • 1.2.4 Subsubsection One-Two-Four
      • +
      +
    • +
    • 1.3 Subsection One-Three +
        +
      • ...
      • +
      +
    • +
    • 1.4 Subsection One-Four
    • +
    +
  • +
+$T2H_AFTER_ABOUT +EOT + return $about; +} + + +%T2H_BUTTONS_GOTO = + ( + 'Top', 'cover (top) of document', + 'Contents', 'table of contents', + 'Overview', 'short table of contents', + 'Index', 'concept index', + 'Back', 'previous section in reading order', + 'FastBack', 'beginning of this chapter or previous chapter', + 'Prev', 'previous section same level', + 'Up', 'up section', + 'Next', 'next section same level', + 'Forward', 'next section in reading order', + 'FastForward', 'next chapter', + 'About' , 'this page', + 'First', 'first section in reading order', + 'Last', 'last section in reading order', + ); + +%T2H_BUTTONS_EXAMPLE = + ( + 'Top', '   ', + 'Contents', '   ', + 'Overview', '   ', + 'Index', '   ', + 'Back', '1.2.2', + 'FastBack', '1', + 'Prev', '1.2.2', + 'Up', '1.2', + 'Next', '1.2.4', + 'Forward', '1.2.4', + 'FastForward', '2', + 'About', '   ', + 'First', '1.', + 'Last', '1.2.4', + ); + + +###################################################################### +# from here on, its l2h init stuff +# + +## initialization for latex2html as for Singular manual generation +## obachman 3/99 + +# +# Options controlling Titles, File-Names, Tracing and Sectioning +# +$TITLE = ''; + +$SHORTEXTN = 0; + +$LONG_TITLES = 0; + +$DESTDIR = ''; # should be overwritten by cmd-line argument + +$NO_SUBDIR = 0; # should be overwritten by cmd-line argument + +$PREFIX = ''; # should be overwritten by cmd-line argument + +$AUTO_PREFIX = 0; # this is needed, so that prefix settings are used + +$AUTO_LINK = 0; + +$SPLIT = 0; + +$MAX_LINK_DEPTH = 0; + +$TMP = ''; # should be overwritten by cmd-line argument + +$DEBUG = 0; + +$VERBOSE = 1; + +# +# Options controlling Extensions and Special Features +# +$HTML_VERSION = "3.2"; + +$TEXDEFS = 1; # we absolutely need that + +$EXTERNAL_FILE = ''; + +$SCALABLE_FONTS = 1; + +$NO_SIMPLE_MATH = 1; + +$LOCAL_ICONS = 1; + +$SHORT_INDEX = 0; + +$NO_FOOTNODE = 1; + +$ADDRESS = ''; + +$INFO = ''; + +# +# Switches controlling Image Generation +# +$ASCII_MODE = 0; + +$NOLATEX = 0; + +$EXTERNAL_IMAGES = 0; + +$PS_IMAGES = 0; + +$NO_IMAGES = 0; + +$IMAGES_ONLY = 0; + +$REUSE = 2; + +$ANTI_ALIAS = 1; + +$ANTI_ALIAS_TEXT = 1; + +# +#Switches controlling Navigation Panels +# +$NO_NAVIGATION = 1; +$ADDRESS = ''; +$INFO = 0; # 0 = do not make a "About this document..." section + +# +#Switches for Linking to other documents +# +# currently -- we don't care + +$MAX_SPLIT_DEPTH = 0; # Stop making separate files at this depth + +$MAX_LINK_DEPTH = 0; # Stop showing child nodes at this depth + +$NOLATEX = 0; # 1 = do not pass unknown environments to Latex + +$EXTERNAL_IMAGES = 0; # 1 = leave the images outside the document + +$ASCII_MODE = 0; # 1 = do not use any icons or internal images + +# 1 = use links to external postscript images rather than inlined bitmap +# images. +$PS_IMAGES = 0; +$SHOW_SECTION_NUMBERS = 0; + +### Other global variables ############################################### +$CHILDLINE = ""; + +# This is the line width measured in pixels and it is used to right justify +# equations and equation arrays; +$LINE_WIDTH = 500; + +# Used in conjunction with AUTO_NAVIGATION +$WORDS_IN_PAGE = 300; + +# Affects ONLY the way accents are processed +$default_language = 'english'; + +# The value of this variable determines how many words to use in each +# title that is added to the navigation panel (see below) +# +$WORDS_IN_NAVIGATION_PANEL_TITLES = 0; + +# This number will determine the size of the equations, special characters, +# and anything which will be converted into an inlined image +# *except* "image generating environments" such as "figure", "table" +# or "minipage". +# Effective values are those greater than 0. +# Sensible values are between 0.1 - 4. +$MATH_SCALE_FACTOR = 1.5; + +# This number will determine the size of +# image generating environments such as "figure", "table" or "minipage". +# Effective values are those greater than 0. +# Sensible values are between 0.1 - 4. +$FIGURE_SCALE_FACTOR = 1.6; + + +# If both of the following two variables are set then the "Up" button +# of the navigation panel in the first node/page of a converted document +# will point to $EXTERNAL_UP_LINK. $EXTERNAL_UP_TITLE should be set +# to some text which describes this external link. +$EXTERNAL_UP_LINK = ""; +$EXTERNAL_UP_TITLE = ""; + +# If this is set then the resulting HTML will look marginally better if viewed +# with Netscape. +$NETSCAPE_HTML = 1; + +# Valid paper sizes are "letter", "legal", "a4","a3","a2" and "a0" +# Paper sizes has no effect other than in the time it takes to create inlined +# images and in whether large images can be created at all ie +# - larger paper sizes *MAY* help with large image problems +# - smaller paper sizes are quicker to handle +$PAPERSIZE = "a4"; + +# Replace "english" with another language in order to tell LaTeX2HTML that you +# want some generated section titles (eg "Table of Contents" or "References") +# to appear in a different language. Currently only "english" and "french" +# is supported but it is very easy to add your own. See the example in the +# file "latex2html.config" +$TITLES_LANGUAGE = "english"; + +1; # This must be the last non-comment line + +# End File texi2html.init +###################################################################### + + +require "$ENV{T2H_HOME}/texi2html.init" + if ($0 =~ /\.pl$/ && + -e "$ENV{T2H_HOME}/texi2html.init" && -r "$ENV{T2H_HOME}/texi2html.init"); + +#+++############################################################################ +# # +# Initialization # +# Pasted content of File $(srcdir)/MySimple.pm: Command-line processing # +# # +#---############################################################################ + +# leave this within comments, and keep the require statement +# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/texi2html.init +# exists. + +# +package Getopt::MySimple; + +# Name: +# Getopt::MySimple. +# +# Documentation: +# POD-style (incomplete) documentation is in file MySimple.pod +# +# Tabs: +# 4 spaces || die. +# +# Author: +# Ron Savage rpsavage@ozemail.com.au. +# 1.00 19-Aug-97 Initial version. +# 1.10 13-Oct-97 Add arrays of switches (eg '=s@'). +# 1.20 3-Dec-97 Add 'Help' on a per-switch basis. +# 1.30 11-Dec-97 Change 'Help' to 'verbose'. Make all hash keys lowercase. +# 1.40 10-Nov-98 Change width of help report. Restructure tests. +# 1-Jul-00 Modifications for Texi2html + +# -------------------------------------------------------------------------- +# Locally modified by obachman (Display type instead of env, order by cmp) +# $Id: texi2html,v 1.1 2004-09-26 21:06:17 blp Exp $ + +# use strict; +# no strict 'refs'; + +use vars qw(@EXPORT @EXPORT_OK @ISA); +use vars qw($fieldWidth $opt $VERSION); + +use Exporter(); +use Getopt::Long; + +@ISA = qw(Exporter); +@EXPORT = qw(); +@EXPORT_OK = qw($opt); # An alias for $self -> {'opt'}. + +# -------------------------------------------------------------------------- + +$fieldWidth = 20; +$VERSION = '1.41'; + +# -------------------------------------------------------------------------- + +sub byOrder +{ + my($self) = @_; + + return uc($a) cmp (uc($b)); +} + +# -------------------------------------------------------------------------- + +sub dumpOptions +{ + my($self) = @_; + + print 'Option', ' ' x ($fieldWidth - length('Option') ), "Value\n"; + + for (sort byOrder keys(%{$self -> {'opt'} }) ) + { + print "-$_", ' ' x ($fieldWidth - (1 + length) ), "${$self->{'opt'} }{$_}\n"; + } + + print "\n"; + +} # End of dumpOptions. + +# -------------------------------------------------------------------------- +# Return: +# 0 -> Error. +# 1 -> Ok. + +sub getOptions +{ + push(@_, 0) if ($#_ == 2); # Default for $ignoreCase is 0. + push(@_, 1) if ($#_ == 3); # Default for $helpThenExit is 1. + + my($self, $default, $helpText, $versionText, + $helpThenExit, $versionThenExit, $ignoreCase) = @_; + + $helpThenExit = 1 unless (defined($helpThenExit)); + $versionThenExit = 1 unless (defined($versionThenExit)); + $ignoreCase = 0 unless (defined($ignoreCase)); + + $self -> {'default'} = $default; + $self -> {'helpText'} = $helpText; + $self -> {'versionText'} = $versionText; + $Getopt::Long::ignorecase = $ignoreCase; + + unless (defined($self -> {'default'}{'help'})) + { + $self -> {'default'}{'help'} = + { + type => ':i', + default => '', + linkage => sub {$self->helpOptions($_[1]); exit (0) if $helpThenExit;}, + verbose => "print help and exit" + }; + } + + unless (defined($self -> {'default'}{'version'})) + { + $self -> {'default'}{'version'} = + { + type => '', + default => '', + linkage => sub {print $self->{'versionText'}; exit (0) if $versionThenExit;}, + verbose => "print version and exit" + }; + } + + for (keys(%{$self -> {'default'} }) ) + { + my $type = ${$self -> {'default'} }{$_}{'type'}; + push(@{$self -> {'type'} }, "$_$type"); + $self->{'opt'}->{$_} = ${$self -> {'default'} }{$_}{'linkage'} + if ${$self -> {'default'} }{$_}{'linkage'}; + } + + my($result) = &GetOptions($self -> {'opt'}, @{$self -> {'type'} }); + + return $result unless $result; + + for (keys(%{$self -> {'default'} }) ) + { + if (! defined(${$self -> {'opt'} }{$_})) #{ + { + ${$self -> {'opt'} }{$_} = ${$self -> {'default'} }{$_}{'default'}; + } + } + + $result; +} # End of getOptions. + +# -------------------------------------------------------------------------- + +sub helpOptions +{ + my($self) = shift; + my($noHelp) = shift; + $noHelp = 0 unless $noHelp; + my($optwidth, $typewidth, $defaultwidth, $maxlinewidth, $valind, $valwidth) + = (10, 5, 9, 78, 4, 11); + + print "$self->{'helpText'}" if ($self -> {'helpText'}); + + print ' Option', ' ' x ($optwidth - length('Option') -1 ), + 'Type', ' ' x ($typewidth - length('Type') + 1), + 'Default', ' ' x ($defaultwidth - length('Default') ), + "Description\n"; + + for (sort byOrder keys(%{$self -> {'default'} }) ) + { + my($line, $help, $option, $val); + $option = $_; + next if ${$self->{'default'} }{$_}{'noHelp'} && ${$self->{'default'} }{$_}{'noHelp'} > $noHelp; + #$line = " -$_" . ' ' x ($optwidth - (2 + length) ) . + # "${$self->{'default'} }{$_}{'type'} ". + # ' ' x ($typewidth - (1+length(${$self -> {'default'} }{$_}{'type'}) )); + $line = " -$_" . "${$self->{'default'} }{$_}{'type'}". + ' ' x ($typewidth - (1+length(${$self -> {'default'} }{$_}{'type'}) )); + + $val = ${$self->{'default'} }{$_}{'linkage'}; + if ($val) + { + if (ref($val) eq 'SCALAR') + { + $val = $$val; + } + else + { + $val = ''; + } + } + else + { + $val = ${$self->{'default'} }{$_}{'default'}; + } + $line .= "$val "; + $line .= ' ' x ($optwidth + $typewidth + $defaultwidth + 1 - length($line)); + + if (defined(${$self -> {'default'} }{$_}{'verbose'}) && + ${$self -> {'default'} }{$_}{'verbose'} ne '') + { + $help = "${$self->{'default'} }{$_}{'verbose'}"; + } + else + { + $help = ' '; + } + if ((length("$line") + length($help)) < $maxlinewidth) + { + print $line , $help, "\n"; + } + else + { + print $line, "\n", ' ' x $valind, $help, "\n"; + } + for $val (sort byOrder keys(%{${$self->{'default'}}{$option}{'values'}})) + { + print ' ' x ($valind + 2); + print $val, ' ', ' ' x ($valwidth - length($val) - 2); + print ${$self->{'default'}}{$option}{'values'}{$val}, "\n"; + } + } + + print <| ! no argument: variable is set to 1 on -foo (or, to 0 on -nofoo) + =s | :s mandatory (or, optional) string argument + =i | :i mandatory (or, optional) integer argument +EOT +} # End of helpOptions. + +#------------------------------------------------------------------- + +sub new +{ + my($class) = @_; + my($self) = {}; + $self -> {'default'} = {}; + $self -> {'helpText'} = ''; + $self -> {'opt'} = {}; + $opt = $self -> {'opt'}; # An alias for $self -> {'opt'}. + $self -> {'type'} = (); + + return bless $self, $class; + +} # End of new. + +# -------------------------------------------------------------------------- + +1; + +# End MySimple.pm + +require "$ENV{T2H_HOME}/MySimple.pm" + if ($0 =~ /\.pl$/ && + -e "$ENV{T2H_HOME}/MySimple.pm" && -r "$ENV{T2H_HOME}/MySimple.pm"); + +package main; + +#+++############################################################################ +# # +# Constants # +# # +#---############################################################################ + +$DEBUG_TOC = 1; +$DEBUG_INDEX = 2; +$DEBUG_BIB = 4; +$DEBUG_GLOSS = 8; +$DEBUG_DEF = 16; +$DEBUG_HTML = 32; +$DEBUG_USER = 64; +$DEBUG_L2H = 128; + + +$BIBRE = '\[[\w\/-]+\]'; # RE for a bibliography reference +$FILERE = '[\/\w.+-]+'; # RE for a file name +$VARRE = '[^\s\{\}]+'; # RE for a variable name +$NODERE = '[^,:]+'; # RE for a node name +$NODESRE = '[^:]+'; # RE for a list of node names + +$ERROR = "***"; # prefix for errors +$WARN = "**"; # prefix for warnings + + # program home page +$PROTECTTAG = "_ThisIsProtected_"; # tag to recognize protected sections + +$CHAPTEREND = "\n"; # to know where a chpater ends +$SECTIONEND = "\n"; # to know where section ends +$TOPEND = "\n"; # to know where top ends + + + +# +# pre-defined indices +# +$index_properties = +{ + 'c' => { name => 'cp'}, + 'f' => { name => 'fn', code => 1}, + 'v' => { name => 'vr', code => 1}, + 'k' => { name => 'ky', code => 1}, + 'p' => { name => 'pg', code => 1}, + 't' => { name => 'tp', code => 1} +}; + + +%predefined_index = ( + 'cp', 'c', + 'fn', 'f', + 'vr', 'v', + 'ky', 'k', + 'pg', 'p', + 'tp', 't', + ); + +# +# valid indices +# +%valid_index = ( + 'c', 1, + 'f', 1, + 'v', 1, + 'k', 1, + 'p', 1, + 't', 1, + ); + +# +# texinfo section names to level +# +%sec2level = ( + 'top', 0, + 'chapter', 1, + 'unnumbered', 1, + 'majorheading', 1, + 'chapheading', 1, + 'appendix', 1, + 'section', 2, + 'unnumberedsec', 2, + 'heading', 2, + 'appendixsec', 2, + 'appendixsection', 2, + 'subsection', 3, + 'unnumberedsubsec', 3, + 'subheading', 3, + 'appendixsubsec', 3, + 'subsubsection', 4, + 'unnumberedsubsubsec', 4, + 'subsubheading', 4, + 'appendixsubsubsec', 4, + ); + +# +# accent map, TeX command to ISO name +# +%accent_map = ( + '"', 'uml', + '~', 'tilde', + '^', 'circ', + '`', 'grave', + '\'', 'acute', + ); + +# +# texinfo "simple things" (@foo) to HTML ones +# +%simple_map = ( + # cf. makeinfo.c + "*", "
", # HTML+ + " ", " ", + "\t", " ", + "-", "­", # soft hyphen + "\n", " ", + "|", "", + 'tab', '<\/TD>
Button Name Go to From 1.2.3 go to
+EOT + $about .= + ($T2H_ICONS && $T2H_ACTIVE_ICONS{$button} ? + &$T2H_button_icon_img($button, $T2H_ACTIVE_ICONS{$button}) : + " [" . $T2H_NAVIGATION_TEXT{$button} . "] "); + $about .= < + +$button + +$T2H_BUTTONS_GOTO{$button} + +$T2H_BUTTONS_EXAMPLE{$button} +
', + # spacing commands + ":", "", + "!", "!", + "?", "?", + ".", ".", + "-", "", + ); + +# +# texinfo "things" (@foo{}) to HTML ones +# +%things_map = ( + 'TeX', 'TeX', + 'br', '

', # paragraph break + 'bullet', '*', + #'copyright', '(C)', + 'copyright', '©', + 'dots', '...<\/small>', + 'enddots', '....<\/small>', + 'equiv', '==', + 'error', 'error-->', + 'expansion', '==>', + 'minus', '-', + 'point', '-!-', + 'print', '-|', + 'result', '=>', + # APA: &pretty_date requires $MONTH_NAMES and $T2H_LANG + # to be initialized. The latter gets initialized by + # &SetDocumentLanguage in &main. + # We set following hash entry in &main afterwards. + # 'today', &pretty_date, + 'aa', 'å', + 'AA', 'Å', + 'ae', 'æ', + 'oe', 'œ', + 'AE', 'Æ', + 'OE', 'Œ', + 'o', 'ø', + 'O', 'Ø', + 'ss', 'ß', + 'l', '\/l', + 'L', '\/L', + 'exclamdown', '¡', + 'questiondown', '¿', + 'pounds', '£' + ); + +# +# texinfo styles (@foo{bar}) to HTML ones +# +%style_map = ( + 'acronym', '&do_acronym', + 'asis', '', + 'b', 'B', + 'cite', 'CITE', + 'code', 'CODE', + 'command', 'CODE', + 'ctrl', '&do_ctrl', # special case + 'dfn', 'EM', # DFN tag is illegal in the standard + 'dmn', '', # useless + 'email', '&do_email', # insert a clickable email address + 'emph', 'EM', + 'env', 'CODE', + 'file', '"TT', # will put quotes, cf. &apply_style + 'i', 'I', + 'kbd', 'KBD', + 'key', 'KBD', + 'math', '&do_math', + 'option', '"SAMP', # will put quotes, cf. &apply_style + 'r', '', # unsupported + 'samp', '"SAMP', # will put quotes, cf. &apply_style + 'sc', '&do_sc', # special case + 'strong', 'STRONG', + 't', 'TT', + 'titlefont', '', # useless + 'uref', '&do_uref', # insert a clickable URL + 'url', '&do_url', # insert a clickable URL + 'var', 'VAR', + 'w', '', # unsupported + 'H', '&do_accent', + 'dotaccent', '&do_accent', + 'ringaccent','&do_accent', + 'tieaccent', '&do_accent', + 'u','&do_accent', + 'ubaraccent','&do_accent', + 'udotaccent','&do_accent', + 'v', '&do_accent', + ',', '&do_accent', + 'dotless', '&do_accent' + ); + +# +# texinfo format (@foo/@end foo) to HTML ones +# +%format_map = ( + 'quotation', 'BLOCKQUOTE', + # lists + 'itemize', 'UL', + 'enumerate', 'OL', + # poorly supported + 'flushleft', 'PRE', + 'flushright', 'PRE', + ); + +# +# an eval of these $complex_format_map->{what}->[0] yields beginning +# an eval of these $complex_format_map->{what}->[1] yieleds end +$complex_format_map = +{ + example => + [ + q{"$T2H_EXAMPLE_INDENT_CELL
"},
+  q{'
'} + ], + smallexample => + [ + q{"$T2H_SMALL_EXAMPLE_INDENT_CELL
"},
+  q{'
'} + ], + display => + [ + q{"$T2H_EXAMPLE_INDENT_CELL
'},
+  q{'
'} + ], + smalldisplay => + [ + q{"$T2H_SMALL_EXAMPLE_INDENT_CELL
'},
+  q{'
'} + ] +}; + +$complex_format_map->{lisp} = $complex_format_map->{example}; +$complex_format_map->{smalllisp} = $complex_format_map->{smallexample}; +$complex_format_map->{format} = $complex_format_map->{display}; +$complex_format_map->{smallformat} = $complex_format_map->{smalldisplay}; + +# +# texinfo definition shortcuts to real ones +# +%def_map = ( + # basic commands + 'deffn', 0, + 'defvr', 0, + 'deftypefn', 0, + 'deftypeop', 0, + 'deftypevr', 0, + 'defcv', 0, + 'defop', 0, + 'deftp', 0, + # basic x commands + 'deffnx', 0, + 'defvrx', 0, + 'deftypefnx', 0, + 'deftypeopx', 0, + 'deftypevrx', 0, + 'defcvx', 0, + 'defopx', 0, + 'deftpx', 0, + # shortcuts + 'defun', 'deffn Function', + 'defmac', 'deffn Macro', + 'defspec', 'deffn {Special Form}', + 'defvar', 'defvr Variable', + 'defopt', 'defvr {User Option}', + 'deftypefun', 'deftypefn Function', + 'deftypevar', 'deftypevr Variable', + 'defivar', 'defcv {Instance Variable}', + 'deftypeivar', 'defcv {Instance Variable}', # NEW: FIXME + 'defmethod', 'defop Method', + 'deftypemethod', 'defop Method', # NEW:FIXME + # x shortcuts + 'defunx', 'deffnx Function', + 'defmacx', 'deffnx Macro', + 'defspecx', 'deffnx {Special Form}', + 'defvarx', 'defvrx Variable', + 'defoptx', 'defvrx {User Option}', + 'deftypefunx', 'deftypefnx Function', + 'deftypevarx', 'deftypevrx Variable', + 'defivarx', 'defcvx {Instance Variable}', + 'defmethodx', 'defopx Method', + ); + +# +# things to skip +# +%to_skip = ( + # comments + 'c', 1, + 'comment', 1, + 'ifnotinfo', 1, + 'ifnottex', 1, + 'ifhtml', 1, + 'end ifhtml', 1, + 'end ifnotinfo', 1, + 'end ifnottex', 1, + # useless + 'detailmenu', 1, + 'direntry', 1, + 'contents', 1, + 'shortcontents', 1, + 'summarycontents', 1, + 'footnotestyle', 1, + 'end ifclear', 1, + 'end ifset', 1, + 'titlepage', 1, + 'end titlepage', 1, + # unsupported commands (formatting) + 'afourpaper', 1, + 'cropmarks', 1, + 'finalout', 1, + 'headings', 1, + 'sp', 1, + 'need', 1, + 'page', 1, + 'setchapternewpage', 1, + 'everyheading', 1, + 'everyfooting', 1, + 'evenheading', 1, + 'evenfooting', 1, + 'oddheading', 1, + 'oddfooting', 1, + 'smallbook', 1, + 'vskip', 1, + 'filbreak', 1, + 'paragraphindent', 1, + # unsupported formats + 'cartouche', 1, + 'end cartouche', 1, + 'group', 1, + 'end group', 1, + ); + +#+++############################################################################ +# # +# Argument parsing, initialisation # +# # +#---############################################################################ + +# +# flush stdout and stderr after every write +# +select(STDERR); +$| = 1; +select(STDOUT); +$| = 1; + + +%value = (); # hold texinfo variables, see also -D +$use_bibliography = 1; +$use_acc = 1; + +# +# called on -init-file +sub LoadInitFile +{ + my $init_file = shift; + # second argument is value of options + $init_file = shift; + if (-f $init_file) + { + print "# reading initialization file from $init_file\n" + if ($T2H_VERBOSE); + require($init_file); + } + else + { + print "$ERROR Error: can't read init file $int_file\n"; + $init_file = ''; + } +} + +# +# called on -lang +sub SetDocumentLanguage +{ + my $lang = shift; + if (! exists($T2H_WORDS->{$lang})) + { + warn "$ERROR: Language specs for '$lang' do not exists. Reverting to '" . + ($T2H_LANG ? $T2H_LANG : "en") . "'\n"; + } + else + { + print "# using '$lang' as document language\n" if ($T2H_VERBOSE); + $T2H_LANG = $lang; + } +} + +## +## obsolete cmd line options +## +$T2H_OBSOLETE_OPTIONS -> {'no-section_navigation'} = +{ + type => '!', + linkage => sub {$T2H_SECTION_NAVIGATION = 0;}, + verbose => 'obsolete, use -nosec_nav', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {use_acc} = +{ + type => '!', + linkage => \$use_acc, + verbose => 'obsolete', + noHelp => 2 +}; +$T2H_OBSOLETE_OPTIONS -> {expandinfo} = +{ + type => '!', + linkage => sub {$T2H_EXPAND = 'info';}, + verbose => 'obsolete, use "-expand info" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {expandtex} = +{ + type => '!', + linkage => sub {$T2H_EXPAND = 'tex';}, + verbose => 'obsolete, use "-expand tex" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {monolithic} = +{ + type => '!', + linkage => sub {$T2H_SPLIT = '';}, + verbose => 'obsolete, use "-split no" instead', + noHelp => 2 +}; +$T2H_OBSOLETE_OPTIONS -> {split_node} = +{ + type => '!', + linkage => sub{$T2H_SPLIT = 'section';}, + verbose => 'obsolete, use "-split section" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {split_chapter} = +{ + type => '!', + linkage => sub{$T2H_SPLIT = 'chapter';}, + verbose => 'obsolete, use "-split chapter" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {no_verbose} = +{ + type => '!', + linkage => sub {$T2H_VERBOSE = 0;}, + verbose => 'obsolete, use -noverbose instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {output_file} = +{ + type => '=s', + linkage => sub {$T2H_OUT = $_[1]; $T2H_SPLIT = '';}, + verbose => 'obsolete, use -out_file instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {section_navigation} = +{ + type => '!', + linkage => \$T2H_SECTION_NAVIGATION, + verbose => 'obsolete, use -sec_nav instead', + noHelp => 2, +}; + +$T2H_OBSOLETE_OPTIONS -> {verbose} = +{ + type => '!', + linkage => \$T2H_VERBOSE, + verbose => 'obsolete, use -Verbose instead', + noHelp => 2 +}; + +# read initialzation from $sysconfdir/texi2htmlrc or $HOME/.texi2htmlrc +my $home = $ENV{HOME}; +defined($home) or $home = ''; +foreach $i ('/etc/texi2htmlrc', "$home/.texi2htmlrc") +{ + if (-f $i) + { + print "# reading initialization file from $i\n" + if ($T2H_VERBOSE); + require($i); + } +} + + +#+++############################################################################ +# # +# parse command-line options +# # +#---############################################################################ +$T2H_USAGE_TEXT = <getOptions($T2H_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n")) +{ + print $Configure_failed if $Configure_failed; + die $T2H_FAILURE_TEXT; +} + +if (@ARGV > 1) +{ + eval {Getopt::Long::Configure("no_pass_through");}; + if (! $options->getOptions($T2H_OBSOLETE_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n")) + { + print $Configure_failed if $Configure_failed; + die $T2H_FAILURE_TEXT; + } +} + +if ($T2H_CHECK) +{ + die "Need file to check\n$T2H_FAILURE_TEXT" unless @ARGV > 0; + ✓ + exit; +} + +#+++############################################################################ +# # +# evaluation of cmd line options +# # +#---############################################################################ + +if ($T2H_EXPAND eq 'info') +{ + $to_skip{'ifinfo'} = 1; + $to_skip{'end ifinfo'} = 1; +} +elsif ($T2H_EXPAND eq 'tex') +{ + $to_skip{'iftex'} = 1; + $to_skip{'end iftex'} = 1; + +} + +$T2H_INVISIBLE_MARK = '' if $T2H_INVISIBLE_MARK eq 'xbm'; + +# +# file name buisness +# +die "Need exactly one file to translate\n$T2H_FAILURE_TEXT" unless @ARGV == 1; +$docu = shift(@ARGV); +if ($docu =~ /.*\//) +{ + chop($docu_dir = $&); + $docu_name = $'; +} +else +{ + $docu_dir = '.'; + $docu_name = $docu; +} +unshift(@T2H_INCLUDE_DIRS, $docu_dir); +$docu_name =~ s/\.te?x(i|info)?$//; # basename of the document +$docu_name = $T2H_PREFIX if ($T2H_PREFIX); + +# subdir +if ($T2H_SUBDIR && ! $T2H_OUT) +{ + $T2H_SUBDIR =~ s|/*$||; + unless (-d "$T2H_SUBDIR" && -w "$T2H_SUBDIR") + { + if ( mkdir($T2H_SUBDIR, oct(755))) + { + print "# created directory $T2H_SUBDIR\n" if ($T2H_VERBOSE); + } + else + { + warn "$ERROR can't create directory $T2H_SUBDIR. Put results into current directory\n"; + $T2H_SUBDIR = ''; + } + } +} + +if ($T2H_SUBDIR && ! $T2H_OUT) +{ + $docu_rdir = "$T2H_SUBDIR/"; + print "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE); +} +else +{ + if ($T2H_OUT && $T2H_OUT =~ m|(.*)/|) + { + $docu_rdir = "$1/"; + print "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE); + } + else + { + print "# putting result files into current directory \n" if ($T2H_VERBOSE); + $docu_rdir = ''; + } +} + +# extension +if ($T2H_SHORTEXTN) +{ + $docu_ext = "htm"; +} +else +{ + $docu_ext = "html"; +} +if ($T2H_TOP_FILE =~ /\..*$/) +{ + $T2H_TOP_FILE = $`.".$docu_ext"; +} + +# result files +if (! $T2H_OUT && ($T2H_SPLIT =~ /section/i || $T2H_SPLIT =~ /node/i)) +{ + $T2H_SPLIT = 'section'; +} +elsif (! $T2H_OUT && $T2H_SPLIT =~ /chapter/i) +{ + $T2H_SPLIT = 'chapter' +} +else +{ + undef $T2H_SPLIT; +} + +$docu_doc = "$docu_name.$docu_ext"; # document's contents +$docu_doc_file = "$docu_rdir$docu_doc"; +if ($T2H_SPLIT) +{ + $docu_toc = $T2H_TOC_FILE || "${docu_name}_toc.$docu_ext"; # document's table of contents + $docu_stoc = "${docu_name}_ovr.$docu_ext"; # document's short toc + $docu_foot = "${docu_name}_fot.$docu_ext"; # document's footnotes + $docu_about = "${docu_name}_abt.$docu_ext"; # about this document + $docu_top = $T2H_TOP_FILE || $docu_doc; +} +else +{ + if ($T2H_OUT) + { + $docu_doc = $T2H_OUT; + $docu_doc =~ s|.*/||; + } + $docu_toc = $docu_foot = $docu_stoc = $docu_about = $docu_top = $docu_doc; +} + +$docu_toc_file = "$docu_rdir$docu_toc"; +$docu_stoc_file = "$docu_rdir$docu_stoc"; +$docu_foot_file = "$docu_rdir$docu_foot"; +$docu_about_file = "$docu_rdir$docu_about"; +$docu_top_file = "$docu_rdir$docu_top"; + +$docu_frame_file = "$docu_rdir${docu_name}_frame.$docu_ext"; +$docu_toc_frame_file = "$docu_rdir${docu_name}_toc_frame.$docu_ext"; + +# +# variables +# +$value{'html'} = 1; # predefine html (the output format) +$value{'texi2html'} = $THISVERSION; # predefine texi2html (the translator) +# _foo: internal to track @foo +foreach ('_author', '_title', '_subtitle', + '_settitle', '_setfilename', '_shorttitle') +{ + $value{$_} = ''; # prevent -w warnings +} +%node2sec = (); # node to section name +%sec2node = (); # section to node name +%sec2seccount = (); # section to section count +%seccount2sec = (); # section count to section +%sec2number = (); # section to number + # $number =~ ^[\dA-Z]+\.(\d+(\.\d+)*)?$ +%number2sec = (); # number to section +%idx2node = (); # index keys to node +%node2href = (); # node to HREF +%node2next = (); # node to next +%node2prev = (); # node to prev +%node2up = (); # node to up +%bib2href = (); # bibliography reference to HREF +%gloss2href = (); # glossary term to HREF +@sections = (); # list of sections +%tag2pro = (); # protected sections + +# +# initial indexes +# +$bib_num = 0; +$foot_num = 0; +$gloss_num = 0; +$idx_num = 0; +$sec_num = 0; +$doc_num = 0; +$html_num = 0; + +# +# can I use ISO8859 characters? (HTML+) +# +if ($T2H_USE_ISO) +{ + $things_map{'bullet'} = "•"; + $things_map{'copyright'} = "©"; + $things_map{'dots'} = "…"; + $things_map{'equiv'} = "≡"; + $things_map{'expansion'} = "→"; + $things_map{'point'} = "∗"; + $things_map{'result'} = "⇒"; +} + +# +# read texi2html extensions (if any) +# +$extensions = 'texi2html.ext'; # extensions in working directory +if (-f $extensions) +{ + print "# reading extensions from $extensions\n" if $T2H_VERBOSE; + require($extensions); +} +($progdir = $0) =~ s/[^\/]+$//; +if ($progdir && ($progdir ne './')) +{ + $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory + if (-f $extensions) + { + print "# reading extensions from $extensions\n" if $T2H_VERBOSE; + require($extensions); + } +} + + +print "# reading from $docu\n" if $T2H_VERBOSE; + +######################################################################### +# +# latex2html stuff +# +# latex2html conversions consist of three stages: +# 1) ToLatex: Put "latex" code into a latex file +# 2) ToHtml: Use latex2html to generate corresponding html code and images +# 3) FromHtml: Extract generated code and images from latex2html run +# + +########################## +# default settings +# + +# defaults for files and names + +sub l2h_Init +{ + local($root) = @_; + return 0 unless ($root); + $l2h_name = "${root}_l2h"; + $l2h_latex_file = "$docu_rdir${l2h_name}.tex"; + $l2h_cache_file = "${docu_rdir}l2h_cache.pm"; + $T2H_L2H_L2H = "latex2html" unless ($T2H_L2H_L2H); + # destination dir -- generated images are put there, should be the same + # as dir of enclosing html document -- + $l2h_html_file = "$docu_rdir${l2h_name}.html"; + $l2h_prefix = "${l2h_name}_"; + return 1; +} + + +########################## +# +# First stage: Generation of Latex file +# Initialize with: l2h_InitToLatex +# Add content with: l2h_ToLatex($text) --> HTML placeholder comment +# Finish with: l2h_FinishToLatex +# + +$l2h_latex_preample = <$l2h_latex_file")) + { + warn "$ERROR Error l2h: Can't open latex file '$latex_file' for writing\n"; + return 0; + } + print "# l2h: use ${l2h_latex_file} as latex file\n" if ($T2H_VERBOSE); + print L2H_LATEX $l2h_latex_preample; + } + # open database for caching + l2h_InitCache(); + $l2h_latex_count = 0; + $l2h_to_latex_count = 0; + $l2h_cached_count = 0; + return 1; +} + +# print text (1st arg) into latex file (if not already there), return +# HTML commentary which can be later on replaced by the latex2html +# generated text +sub l2h_ToLatex +{ + my($text) = @_; + my($count); + $l2h_to_latex_count++; + $text =~ s/(\s*)$//; + # try whether we can cache it + my $cached_text = l2h_FromCache($text); + if ($cached_text) + { + $l2h_cached_count++; + return $cached_text; + } + # try whether we have text already on things to do + unless ($count = $l2h_to_latex{$text}) + { + $count = $l2h_latex_count; + $l2h_latex_count++; + $l2h_to_latex{$text} = $count; + $l2h_to_latex[$count] = $text; + unless ($T2H_L2H_SKIP) + { + print L2H_LATEX "\\begin{rawhtml}\n"; + print L2H_LATEX "\n"; + print L2H_LATEX "\\end{rawhtml}\n"; + + print L2H_LATEX "$text\n"; + + print L2H_LATEX "\\begin{rawhtml}\n"; + print L2H_LATEX "\n"; + print L2H_LATEX "\\end{rawhtml}\n"; + } + } + return ""; +} + +# print closing into latex file and close it +sub l2h_FinishToLatex +{ + local ($reused); + $reused = $l2h_to_latex_count - $l2h_latex_count - $l2h_cached_count; + unless ($T2H_L2H_SKIP) + { + print L2H_LATEX $l2h_latex_closing; + close(L2H_LATEX); + } + print "# l2h: finished to latex ($l2h_cached_count cached, $reused reused, $l2h_latex_count contents)\n" if ($T2H_VERBOSE); + unless ($l2h_latex_count) + { + l2h_Finish(); + return 0; + } + return 1; +} + +################################### +# Second stage: Use latex2html to generate corresponding html code and images +# +# l2h_ToHtml([$l2h_latex_file, [$l2h_html_dir]]): +# Call latex2html on $l2h_latex_file +# Put images (prefixed with $l2h_name."_") and html file(s) in $l2h_html_dir +# Return 1, on success +# 0, otherwise +# +sub l2h_ToHtml +{ + local($call, $ext, $root, $dotbug); + if ($T2H_L2H_SKIP) + { + print "# l2h: skipping latex2html run\n" if ($T2H_VERBOSE); + return 1; + } + # Check for dot in directory where dvips will work + if ($T2H_L2H_TMP) + { + if ($T2H_L2H_TMP =~ /\./) + { + warn "$ERROR Warning l2h: l2h_tmp dir contains a dot. Use /tmp, instead\n"; + $dotbug = 1; + } + } + else + { + if (&getcwd =~ /\./) + { + warn "$ERROR Warning l2h: current dir contains a dot. Use /tmp as l2h_tmp dir \n"; + $dotbug = 1; + } + } + # fix it, if necessary and hope that it works + $T2H_L2H_TMP = "/tmp" if ($dotbug); + + $call = $T2H_L2H_L2H; + # use init file, if specified + $call = $call . " -init_file " . $init_file if ($init_file && -f $init_file); + # set output dir + $call .= ($docu_rdir ? " -dir $docu_rdir" : " -no_subdir"); + # use l2h_tmp, if specified + $call = $call . " -tmp $T2H_L2H_TMP" if ($T2H_L2H_TMP); + # options we want to be sure of + $call = $call ." -address 0 -info 0 -split 0 -no_navigation -no_auto_link"; + $call = $call ." -prefix ${l2h_prefix} $l2h_latex_file"; + + print "# l2h: executing '$call'\n" if ($T2H_VERBOSE); + if (system($call)) + { + warn "l2h ***Error: '${call}' did not succeed\n"; + return 0; + } + else + { + print "# l2h: latex2html finished successfully\n" if ($T2H_VERBOSE); + return 1; + } +} + +# this is directly pasted over from latex2html +sub getcwd +{ + local($_) = `pwd`; + + die "'pwd' failed (out of memory?)\n" + unless length; + chop; + $_; +} + + +########################## +# Third stage: Extract generated contents from latex2html run +# Initialize with: l2h_InitFromHtml +# open $l2h_html_file for reading +# reads in contents into array indexed by numbers +# return 1, on success -- 0, otherwise +# Extract Html code with: l2h_FromHtml($text) +# replaces in $text all previosuly inserted comments by generated html code +# returns (possibly changed) $text +# Finish with: l2h_FinishFromHtml +# closes $l2h_html_dir/$l2h_name.".$docu_ext" + +sub l2h_InitFromHtml +{ + local($h_line, $h_content, $count, %l2h_img); + + if (! open(L2H_HTML, "<${l2h_html_file}")) + { + print "$ERROR Error l2h: Can't open ${l2h_html_file} for reading\n"; + return 0; + } + print "# l2h: use ${l2h_html_file} as html file\n" if ($T2H_VERBOSE); + + $l2h_html_count = 0; + while ($h_line = ) + { + if ($h_line =~ /^/) + { + $count = $1; + $h_content = ""; + while ($h_line = ) + { + if ($h_line =~ /^/) + { + chomp $h_content; + chomp $h_content; + $l2h_html_count++; + $h_content = l2h_ToCache($count, $h_content); + $l2h_from_html[$count] = $h_content; + $h_content = ''; + last; + } + $h_content = $h_content.$h_line; + } + if ($hcontent) + { + print "$ERROR Warning l2h: l2h_end $l2h_name $count not found\n" + if ($T2H_VERBOSE); + close(L2H_HTML); + return 0; + } + } + } + print "# l2h: Got $l2h_html_count of $l2h_latex_count html contents\n" + if ($T2H_VERBOSE); + + close(L2H_HTML); + return 1; +} + +sub l2h_FromHtml +{ + my($text) = @_; + my($done, $to_do, $count); + $to_do = $text; + while ($to_do =~ /([^\000]*)([^\000]*)/) + { + $to_do = $1; + $count = $2; + $done = $3.$done; + $done = "".$done + if ($T2H_DEBUG & $DEBUG_L2H); + + $done = &l2h_ExtractFromHtml($count) . $done; + + $done = "".$done + if ($T2H_DEBUG & $DEBUG_L2H); + } + return $to_do.$done; +} + + +sub l2h_ExtractFromHtml +{ + local($count) = @_; + return $l2h_from_html[$count] if ($l2h_from_html[$count]); + if ($count >= 0 && $count < $l2h_latex_count) + { + # now we are in trouble + local($l_l2h, $_); + + $l2h_extract_error++; + print "$ERROR l2h: can't extract content $count from html\n" + if ($T2H_VERBOSE); + # try simple (ordinary) substition (without l2h) + $l_l2h = $T2H_L2H; + $T2H_L2H = 0; + $_ = $l2h_to_latex{$count}; + $_ = &substitute_style($_); + &unprotect_texi; + $_ = "" . $_ + if ($T2H_DEBUG & $DEBUG_L2H); + $T2H_L2H = $l_l2h; + return $_; + } + else + { + # now we have been incorrectly called + $l2h_range_error++; + print "$ERROR l2h: Request of $count content which is out of valide range [0,$l2h_latex_count)\n"; + return "" + if ($T2H_DEBUG & $DEBUG_L2H); + return ""; + } +} + +sub l2h_FinishFromHtml +{ + if ($T2H_VERBOSE) + { + if ($l2h_extract_error + $l2h_range_error) + { + print "# l2h: finished from html ($l2h_extract_error extract and $l2h_range_error errors)\n"; + } + else + { + print "# l2h: finished from html (no errors)\n"; + } + } +} + +sub l2h_Finish +{ + l2h_StoreCache(); + if ($T2H_L2H_CLEAN) + { + print "# l2h: removing temporary files generated by l2h extension\n" + if $T2H_VERBOSE; + while (<"$docu_rdir$l2h_name"*>) + { + unlink $_; + } + } + print "# l2h: Finished\n" if $T2H_VERBOSE; + return 1; +} + +############################## +# stuff for l2h caching +# + +# I tried doing this with a dbm data base, but it did not store all +# keys/values. Hence, I did as latex2html does it +sub l2h_InitCache +{ + if (-r "$l2h_cache_file") + { + my $rdo = do "$l2h_cache_file"; + warn("$ERROR l2h Error: could not load $docu_rdir$l2h_cache_file: $@\n") + unless ($rdo); + } +} + +sub l2h_StoreCache +{ + return unless $l2h_latex_count; + my ($key, $value); + open(FH, ">$l2h_cache_file") || return warn"$ERROR l2h Error: could not open $docu_rdir$l2h_cache_file for writing: $!\n"; + while (($key, $value) = each %l2h_cache) + { + # escape stuff + $key =~ s|/|\\/|g; + $key =~ s|\\\\/|\\/|g; + # weird, a \ at the end of the key results in an error + # maybe this also broke the dbm database stuff + $key =~ s|\\$|\\\\|; + $value =~ s/\|/\\\|/go; + $value =~ s/\\\\\|/\\\|/go; + $value =~ s|\\\\|\\\\\\\\|g; + print FH "\n\$l2h_cache_key = q/$key/;\n"; + print FH "\$l2h_cache{\$l2h_cache_key} = q|$value|;\n"; + } + print FH "1;"; + close(FH); +} + +# return cached html, if it exists for text, and if all pictures +# are there, as well +sub l2h_FromCache +{ + my $text = shift; + my $cached = $l2h_cache{$text}; + if ($cached) + { + while ($cached =~ m/SRC="(.*?)"/g) + { + unless (-e "$docu_rdir$1") + { + return undef; + } + } + return $cached; + } + return undef; +} + +# insert generated html into cache, move away images, +# return transformed html +$maximage = 1; +sub l2h_ToCache +{ + my $count = shift; + my $content = shift; + my @images = ($content =~ /SRC="(.*?)"/g); + my ($src, $dest); + + for $src (@images) + { + $dest = $l2h_img{$src}; + unless ($dest) + { + my $ext; + if ($src =~ /.*\.(.*)$/ && $1 ne $docu_ext) + { + $ext = $1; + } + else + { + warn "$ERROR: L2h image $src has invalid extension\n"; + next; + } + while (-e "$docu_rdir${docu_name}_$maximage.$ext") + { + $maximage++; + } + $dest = "${docu_name}_$maximage.$ext"; + system("cp -f $docu_rdir$src $docu_rdir$dest"); + $l2h_img{$src} = $dest; + unlink "$docu_rdir$src" unless ($DEBUG & $DEBUG_L2H); + } + $content =~ s/$src/$dest/g; + } + $l2h_cache{$l2h_to_latex[$count]} = $content; + return $content; +} + + +#+++############################################################################ +# # +# Pass 1: read source, handle command, variable, simple substitution # +# # +#---############################################################################ +sub pass1 +{ + my $name; + my $line; + @lines = (); # whole document + @toc_lines = (); # table of contents + @stoc_lines = (); # table of contents + $curlevel = 0; # current level in TOC + $node = ''; # current node name + $node_next = ''; # current node next name + $node_prev = ''; # current node prev name + $node_up = ''; # current node up name + $in_table = 0; # am I inside a table + $table_type = ''; # type of table ('', 'f', 'v', 'multi') + @tables = (); # nested table support + $in_bibliography = 0; # am I inside a bibliography + $in_glossary = 0; # am I inside a glossary + $in_top = 0; # am I inside the top node + $has_top = 0; # did I see a top node? + $has_top_command = 0; # did I see @top for automatic pointers? + $in_pre = 0; # am I inside a preformatted section + $in_list = 0; # am I inside a list + $in_html = 0; # am I inside an HTML section + $first_line = 1; # is it the first line + $dont_html = 0; # don't protect HTML on this line + $deferred_ref = ''; # deferred reference for indexes + @html_stack = (); # HTML elements stack + $html_element = ''; # current HTML element + &html_reset; + %macros = (); # macros + $toc_indent = # used for identation in TOC's + ($T2H_NUMBER_SECTIONS ? 'BLOCKQUOTE' : 'UL'); + + # init l2h + $T2H_L2H = &l2h_Init($docu_name) if ($T2H_L2H); + $T2H_L2H = &l2h_InitToLatex if ($T2H_L2H); + + # build code for simple substitutions + # the maps used (%simple_map and %things_map) MUST be aware of this + # watch out for regexps, / and escaped characters! + $subst_code = ''; + foreach (keys(%simple_map)) + { + ($re = $_) =~ s/(\W)/\\$1/g; # protect regexp chars + $subst_code .= "s/\\\@$re/$simple_map{$_}/g;\n"; + } + foreach (keys(%things_map)) + { + $subst_code .= "s/\\\@$_\\{\\}/$things_map{$_}/g;\n"; + } + if ($use_acc) + { + # accentuated characters + foreach (keys(%accent_map)) + { + if ($_ eq "`") + { + $subst_code .= "s/$;3"; + } + elsif ($_ eq "'") + { + $subst_code .= "s/$;4"; + } + else + { + $subst_code .= "s/\\\@\\$_"; + } + $subst_code .= "([a-z])/&\${1}$accent_map{$_};/gi;\n"; + } + } + eval("sub simple_substitutions { $subst_code }"); + + &init_input; + INPUT_LINE: while ($_ = &next_line) + { + # + # remove \input on the first lines only + # + if ($first_line) + { + next if /^\\input/; + $first_line = 0; + } + # non-@ substitutions cf. texinfmt.el + # + # parse texinfo tags + # + $tag = ''; + $end_tag = ''; + if (/^\s*\@end\s+(\w+)\b/) + { + $end_tag = $1; + } + elsif (/^\s*\@(\w+)\b/) + { + $tag = $1; + } + # + # handle @html / @end html + # + if ($in_html) + { + if ($end_tag eq 'html') + { + $in_html = 0; + } + else + { + $tag2pro{$in_html} .= $_; + } + next; + } + elsif ($tag eq 'html') + { + $in_html = $PROTECTTAG . ++$html_num; + push(@lines, $in_html); + next; + } + + # + # try to remove inlined comments + # syntax from tex-mode.el comment-start-skip + # + s/((^|[^\@])(\@\@)*)\@(c( |\{)|comment ).*$/$1/; + + # Sometimes I use @c right at the end of a line ( to suppress the line feed ) + # s/((^|[^\@])(\@\@)*)\@c(omment)?$/$1/; + # s/((^|[^\@])(\@\@)*)\@c(omment)? .*/$1/; + # s/(.*)\@c{.*?}(.*)/$1$2/; + # s/(.*)\@comment{.*?}(.*)/$1$2/; + # s/^(.*)\@c /$1/; + # s/^(.*)\@comment /$1/; + + ############################################################# + # value substitution before macro expansion, so that + # it works in macro arguments + s/\@value{($VARRE)}/$value{$1}/eg; + + ############################################################# + # macro substitution + while (/\@(\w+)/g) + { + if (exists($macros->{$1})) + { + my $before = $`; + $name = $1; + my $after = $'; + my @args; + my $args; + ##################################################### + # Support for multi-line macro invocations and nested + # '{' and '}' within macro invocations added by + # Eric Sunshine 2000/09/10. + ##################################################### + if ($after =~ /^\s*\{/) # Macro arguments delimited by '{' and '}'? + { + my ($protect, $start, $end, $depth, $c) = (0, 0, 0, 0, 0); + foreach $c (unpack('C*', $after)) + { + if ($protect) + { # Character protected by '\' or '@'; pass through unmolested. + $protect = 0; + } + elsif ($c == ord('\\') || $c == ord('@')) + { # '\' and '@' remove special meaning of next character. + $protect = 1; + } + elsif ($c == ord('{')) # Allow '{' and '}' to nest. + { + $depth++; + } + elsif ($c == ord('}')) + { + $depth--; + last if $depth == 0; + } + $start++ if !$depth; # Position of opening brace. + $end++; # Position of closing brace. + } + + # '{' & '}' did not completely unnest; append next line; try again. + if ($depth > 0) + { + my $paste = &next_line; + die "$ERROR Missing closing brace '}' for invocation of macro " . + "\"\@$name\" on line:\n", substr($_,0,70), "...\n" unless $paste; + s/\n$/ /; + unshift @input_spool, $_ . $paste; + next INPUT_LINE; + } + + # Extract macro arguments from within '{' and '}'. + $len = $end - $start - 1; + $args = ($len > 0) ? substr($after, $start + 1, $len) : ''; + $after = substr($after, $end + 1); + } + ############ End Sunshine Modifications ############# + elsif (@{$macros->{$name}->{Args}} == 1) # Macro arg extends to EOL. + { + $args = $after; + $args =~ s/^\s*//; + $args =~ s/\s*$//; + $after = ''; + } + $args =~ s|\\\\|\\|g; + $args =~ s|\\{|{|g; + $args =~ s|\\}|}|g; + if (@{$macros->{$name}->{Args}} > 1) + { + $args =~ s/(^|[^\\]),/$1$;/g ; + $args =~ s|\\,|,|g; + @args = split(/$;\s*/, $args) if (@{$macros->{$name}->{Args}} > 1); + } + else + { + $args =~ s|\\,|,|g; + @args = ($args); + } + my $macrobody = $macros->{$name}->{Body}; + for ($i=0; $i<=$#args; $i++) + { + $macrobody =~ s|\\$macros->{$name}->{Args}->[$i]\\|$args[$i]|g; + } + $macrobody =~ s|\\\\|\\|g; + $_ = $before . $macrobody . $after; + unshift @input_spool, map {$_ = $_."\n"} split(/\n/, $_); + next INPUT_LINE; + } + } + # + # try to skip the line + # + if ($end_tag) + { + $in_titlepage = 0 if $end_tag eq 'titlepage'; + next if $to_skip{"end $end_tag"}; + } + elsif ($tag) + { + $in_titlepage = 1 if $tag eq 'titlepage'; + next if $to_skip{$tag}; + last if $tag eq 'bye'; + } + if ($in_top) + { + # parsing the top node + if ($tag eq 'node' || + ($sec2level{$tag} && $tag !~ /unnumbered/ && $tag !~ /heading/)) + { + # no more in top + $in_top = 0; + push(@lines, $TOPEND); + } + } + unless ($in_pre) + { + s/``/\"/go; + s/''/\"/go; + s/([\w ])---([\w ])/$1--$2/g; + } + # + # analyze the tag + # + if ($tag) + { + # skip lines + &skip_until($tag), next if $tag eq 'ignore'; + &skip_until($tag), next if $tag eq 'ifnothtml'; + if ($tag eq 'ifinfo') + { + &skip_until($tag), next unless $T2H_EXPAND eq 'info'; + } + if ($tag eq 'iftex') + { + &skip_until($tag), next unless $T2H_EXPAND eq 'tex'; + } + if ($tag eq 'tex') + { + # add to latex2html file + if ($T2H_EXPAND eq 'tex' && $T2H_L2H && ! $in_pre) + { + # add space to the end -- tex(i2dvi) does this, as well + push(@lines, &l2h_ToLatex(&string_until($tag) . " ")); + } + else + { + &skip_until($tag); + } + next; + } + if ($tag eq 'titlepage') + { + next; + } + # handle special tables + if ($tag =~ /^(|f|v|multi)table$/) + { + $table_type = $1; + $tag = 'table'; + } + # special cases + # APA: Fixed regexp to ONLY match the top node, not any + # node starting with the word top. + if ($tag eq 'top' || ($tag eq 'node' && /^\@node\s+top\s*(,.*)?$/i)) + { + $in_top = 1; + $has_top = 1; + $has_top_command = 1 if $tag eq 'top'; + @lines = (); # ignore all lines before top (title page garbage) + next; + } + elsif ($tag eq 'node') + { + if ($in_top) + { + $in_top = 0; + push(@lines, $TOPEND); + } + warn "$ERROR Bad node line: $_" unless $_ =~ /^\@node\s$NODESRE$/o; + # request of "Richard Y. Kim" + s/^\@node\s+//; + $_ = &protect_html($_); # if node contains '&' for instance + ($node, $node_next, $node_prev, $node_up) = split(/,/); + if ($node) + { + &normalise_node($node); + } + else + { + warn "$ERROR Node is undefined: $_ (eg. \@node NODE-NAME, NEXT, PREVIOUS, UP)"; + } + if ($node_next) + { + &normalise_node($node_next); + } + if ($node_prev) + { + &normalise_node($node_prev); + } + if ($node_up) + { + &normalise_node($node_up); + } + $node =~ /\"/ ? + push @lines, &html_debug("\n", __LINE__) : + push @lines, &html_debug("\n", __LINE__); + next; + } + elsif ($tag eq 'include') + { + if (/^\@include\s+($FILERE)\s*$/o) + { + $file = LocateIncludeFile($1); + if ($file && -e $file) + { + &open($file); + print "# including $file\n" if $T2H_VERBOSE; + } + else + { + warn "$ERROR Can't find $1, skipping"; + } + } + else + { + warn "$ERROR Bad include line: $_"; + } + next; + } + elsif ($tag eq 'ifclear') + { + if (/^\@ifclear\s+($VARRE)\s*$/o) + { + next unless defined($value{$1}); + &skip_until($tag); + } + else + { + warn "$ERROR Bad ifclear line: $_"; + } + next; + } + elsif ($tag eq 'ifset') + { + if (/^\@ifset\s+($VARRE)\s*$/o) + { + next if defined($value{$1}); + &skip_until($tag); + } + else + { + warn "$ERROR Bad ifset line: $_"; + } + next; + } + elsif ($tag eq 'menu') + { + unless ($T2H_SHOW_MENU) + { + &skip_until($tag); + next; + } + &html_push_if($tag); + push(@lines, &html_debug('', __LINE__)); + } + elsif ($format_map{$tag}) + { + $in_pre = 1 if $format_map{$tag} eq 'PRE'; + &html_push_if($format_map{$tag}); + push(@lines, &html_debug('', __LINE__)); + $in_list++ if $format_map{$tag} eq 'UL' || $format_map{$tag} eq 'OL' ; + # push(@lines, &debug("

\n", __LINE__)) + # if $tag =~ /example/i; + # Eric Sunshine :
blah
looks + # better than
\nblah
on OmniWeb2 NextStep browser. + push(@lines, &debug("<$format_map{$tag}>" . + ($in_pre ? '' : "\n"), __LINE__)); + next; + } + elsif (exists $complex_format_map->{$tag}) + { + my $start = eval $complex_format_map->{$tag}->[0]; + # APA: implicitly ends paragraph, so let's do it + # explicitly to keep our HTML stack in sync. + if ($start =~ /\A\s*
/i) + { + if ($html_element eq 'P') + { + push (@lines2, &debug("

\n", __LINE__)); + &html_pop(); + } + } + if ($@) + { + print "$ERROR: eval of complex_format_map->{$tag}->[0] $complex_format_map->{$tag}->[0]: $@"; + $start = '
'
+                }
+                $in_pre = 1 if $start =~ /
 implicitly ends paragraph, so let's
+                        # do it explicitly to keep our HTML stack in sync.
+                        if ($html_element eq 'P')
+                        {
+                            push (@lines, &debug("

\n", __LINE__)); + &html_pop(); + } + # don't use borders -- gets confused by empty cells + push(@lines, &debug("
\n", __LINE__)); + &html_push_if('TABLE'); + } + else + { + # APA:
implicitly ends paragraph, so let's + # do it explicitly to keep our HTML stack in sync. + if ($html_element eq 'P') + { + push (@lines, &debug("

\n", __LINE__)); + &html_pop(); + } + push(@lines, &debug("
\n", __LINE__)); + &html_push_if('DL'); + } + push(@lines, &html_debug('', __LINE__)); + } + else + { + warn "$ERROR Bad table line: $_"; + } + next; + } + elsif ($tag eq 'synindex' || $tag eq 'syncodeindex') + { + if (/^\@$tag\s+(\w+)\s+(\w+)\s*$/) + { + my $from = $1; + my $to = $2; + my $prefix_from = IndexName2Prefix($from); + my $prefix_to = IndexName2Prefix($to); + + warn("$ERROR unknown from index name $from ind syn*index line: $_"), next + unless $prefix_from; + warn("$ERROR unknown to index name $to ind syn*index line: $_"), next + unless $prefix_to; + + if ($tag eq 'syncodeindex') + { + $index_properties->{$prefix_to}->{'from_code'}->{$prefix_from} = 1; + } + else + { + $index_properties->{$prefix_to}->{'from'}->{$prefix_from} = 1; + } + } + else + { + warn "$ERROR Bad syn*index line: $_"; + } + next; + } + elsif ($tag eq 'defindex' || $tag eq 'defcodeindex') + { + if (/^\@$tag\s+(\w+)\s*$/) + { + $name = $1; + $index_properties->{$name}->{name} = $name; + $index_properties->{$name}->{code} = 1 if $tag eq 'defcodeindex'; + } + else + { + warn "$ERROR Bad defindex line: $_"; + } + next; + } + elsif (/^\@printindex/) + { + # APA: HTML generated for @printindex contains
+ # which implicitly ends paragraph, so let's do it + # explicitly to keep our HTML stack in sync. + if ($html_element eq 'P') + { + push(@lines, &debug("

\n", __LINE__)); + &html_pop(); + } + push (@lines, "$_"); + next; + } + elsif ($tag eq 'sp') + { + push(@lines, &debug("

\n", __LINE__)); + next; + } + elsif ($tag eq 'center') + { + push(@lines, &debug("
\n", __LINE__)); + s/\@center//; + } + elsif ($tag eq 'setref') + { + my ($setref); + &protect_html; # if setref contains '&' for instance + if (/^\@$tag\s*{($NODERE)}\s*$/) + { + $setref = $1; + $setref =~ s/\s+/ /go; # normalize + $setref =~ s/ $//; + $node2sec{$setref} = $name; + $sec2node{$name} = $setref; + $node2href{$setref} = "$docu_doc#$docid"; + } + else + { + warn "$ERROR Bad setref line: $_"; + } + next; + } + elsif ($tag eq 'lowersections') + { + my ($sec, $level); + while (($sec, $level) = each %sec2level) + { + $sec2level{$sec} = $level + 1; + } + next; + } + elsif ($tag eq 'raisesections') + { + my ($sec, $level); + while (($sec, $level) = each %sec2level) + { + $sec2level{$sec} = $level - 1; + } + next; + } + elsif ($tag eq 'macro' || $tag eq 'rmacro') + { + if (/^\@$tag\s*(\w+)\s*(.*)/) + { + $name = $1; + my @args; + @args = split(/\s*,\s*/ , $1) + if ($2 =~ /^\s*{(.*)}\s*/); + + $macros->{$name}->{Args} = \@args; + $macros->{$name}->{Body} = ''; + while (($_ = &next_line) && $_ !~ /\@end $tag/) + { + $macros->{$name}->{Body} .= $_; + } + die "ERROR: No closing '\@end $tag' found for macro definition of '$name'\n" + unless (/\@end $tag/); + chomp $macros->{$name}->{Body}; + } + else + { + warn "$ERROR: Bad macro defintion $_" + } + next; + } + elsif ($tag eq 'unmacro') + { + delete $macros->{$1} if (/^\@unmacro\s*(\w+)/); + next; + } + elsif ($tag eq 'documentlanguage') + { + SetDocumentLanguage($1) if (!$T2H_LANG && /documentlanguage\s*(\w+)/); + } + elsif (defined($def_map{$tag})) + { + if ($def_map{$tag}) + { + s/^\@$tag\s+//; + $tag = $def_map{$tag}; + $_ = "\@$tag $_"; + $tag =~ s/\s.*//; + } + } + elsif (defined($user_sub{$tag})) + { + s/^\@$tag\s+//; + $sub = $user_sub{$tag}; + print "# user $tag = $sub, arg: $_" if $T2H_DEBUG & $DEBUG_USER; + if (defined(&$sub)) + { + chop($_); + &$sub($_); + } + else + { + warn "$ERROR Bad user sub for $tag: $sub\n"; + } + next; + } + if (defined($def_map{$tag})) + { + s/^\@$tag\s+//; + if ($tag =~ /x$/) + { + # extra definition line + $tag = $`; + $is_extra = 1; + } + else + { + $is_extra = 0; + } + while (/\{([^\{\}]*)\}/) + { + # this is a {} construct + ($before, $contents, $after) = ($`, $1, $'); + # protect spaces + $contents =~ s/\s+/$;9/g; + # restore $_ protecting {} + $_ = "$before$;7$contents$;8$after"; + } + @args = split(/\s+/, &protect_html($_)); + foreach (@args) + { + s/$;9/ /g; # unprotect spaces + s/$;7/\{/g; # ... { + s/$;8/\}/g; # ... } + } + $type = shift(@args); + $type =~ s/^\{(.*)\}$/$1/; + print "# def ($tag): {$type} ", join(', ', @args), "\n" + if $T2H_DEBUG & $DEBUG_DEF; + $type .= ':' if (!$T2H_DEF_TABLE); # it's nicer like this + $name = shift(@args); + $name =~ s/^\{(.*)\}$/$1/; + if ($is_extra) + { + $_ = &debug("
", __LINE__) if (!$T2H_DEF_TABLE); + $_ = &debug("", __LINE__) if ($T2H_DEF_TABLE); + #$_ = &debug("
\n", __LINE__) if ($T2H_DEF_TABLE); + } + else + { + # APA:
implicitly ends paragraph, so let's + # do it explicitly to keep our HTML stack in sync. + if ($html_element eq 'P') + { + $_ = &debug("

\n", __LINE__); + &html_pop(); + } + else + { + $_ = ''; + } + $_ .= &debug("
\n
", __LINE__) if (!$T2H_DEF_TABLE); + $_ .= &debug("
\n", __LINE__) if ($T2H_DEF_TABLE); + } + if ($tag eq 'deffn' || $tag eq 'defvr' || $tag eq 'deftp') + { + if ($T2H_DEF_TABLE) + { + $_ .= "\n\n"; + $_ .= "\n\n"; + } + else + { + $_ .= "$type$name"; + $_ .= " @args" if @args; + } + } + elsif ($tag eq 'deftypefn' || $tag eq 'deftypevr' + || $tag eq 'deftypeop' || $tag eq 'defcv' + || $tag eq 'defop') + { + $ftype = $name; + $name = shift(@args); + $name =~ s/^\{(.*)\}$/$1/; + if ($T2H_DEF_TABLE) + { + $_ .= "\n\n"; + $_ .= "\n\n"; + } + else + { + $_ .= "$type $ftype $name"; + $_ .= " @args" if @args; + } + } + else + { + warn "$ERROR Unknown definition type: $tag\n"; + $_ .= "$type$name"; + $_ .= " @args" if @args; + } + $_ .= &debug("\n
", __LINE__) if (!$T2H_DEF_TABLE); + ########$_ .= &debug("\n
$name\n"; + $_ .= " @args" if @args; + $_ .= ""; + $_ .= "$type
$name"; + $_ .= " @args" if @args; + $_ .= ""; + $_ .= "$type of $ftype
\n\n", __LINE__) if ($T2H_DEF_TABLE); + $name = &unprotect_html($name); + if ($tag eq 'deffn' || $tag eq 'deftypefn') + { + EnterIndexEntry('f', $name, $docu_doc, $section, \@lines); + # unshift(@input_spool, "\@findex $name\n"); + } + elsif ($tag eq 'defop') + { + EnterIndexEntry('f', "$name on $ftype", $docu_doc, $section, \@lines); + # unshift(@input_spool, "\@findex $name on $ftype\n"); + } + elsif ($tag eq 'defvr' || $tag eq 'deftypevr' || $tag eq 'defcv') + { + EnterIndexEntry('v', $name, $docu_doc, $section, \@lines); + # unshift(@input_spool, "\@vindex $name\n"); + } + else + { + EnterIndexEntry('t', $name, $docu_doc, $section, \@lines); + # unshift(@input_spool, "\@tindex $name\n"); + } + $dont_html = 1; + } + } + elsif ($end_tag) + { + if ($format_map{$end_tag}) + { + $in_pre = 0 if $format_map{$end_tag} eq 'PRE'; + $in_list-- if $format_map{$end_tag} eq 'UL' || $format_map{$end_tag} eq 'OL' ; + &html_pop_if('P'); + &html_pop_if('LI'); + &html_pop_if(); + push(@lines, &debug("\n", __LINE__)); + push(@lines, &html_debug('', __LINE__)); + } + elsif (exists $complex_format_map->{$end_tag}) + { + my $end = eval $complex_format_map->{$end_tag}->[1]; + if ($@) + { + print "$ERROR: eval of complex_format_map->{$end_tag}->[1] $complex_format_map->{$end_tag}->[0]: $@"; + $end = '' + } + $in_pre = 0 if $end =~ m||; + push(@lines, html_debug($end, __LINE__)); + } + elsif ($end_tag =~ /^(|f|v|multi)table$/) + { + unless (@tables) + { + warn "$ERROR \@end $end_tag without \@*table\n"; + next; + } + &html_pop_if('P'); + ($table_type, $in_table) = split($;, shift(@tables)); + unless ($1 eq $table_type) + { + warn "$ERROR \@end $end_tag without matching \@$end_tag\n"; + next; + } + if ($table_type eq "multi") + { + push(@lines, "
\n"); + &html_pop_if('TR'); + } + else + { + # APA: implicitly ends paragraph, so let's + # do it explicitly to keep our HTML stack in sync. + if ($html_element eq 'P') + { + push(@lines, &debug("

\n", __LINE__)); + &html_pop(); + } + push(@lines, "\n"); + &html_pop_if('DD'); + } + &html_pop_if(); + if (@tables) + { + ($table_type, $in_table) = split($;, $tables[0]); + } + else + { + $in_table = 0; + } + } + elsif (defined($def_map{$end_tag})) + { + # APA: and
implicitly ends paragraph, + # so let's do it explicitly to keep our HTML stack in + # sync. + if ($html_element eq 'P') + { + push(@lines, &debug("

\n", __LINE__)); + &html_pop(); + } + push(@lines, &debug("\n", __LINE__)) if (!$T2H_DEF_TABLE); + push(@lines, &debug("\n", __LINE__)) if ($T2H_DEF_TABLE); + } + elsif ($end_tag eq 'menu') + { + &html_pop_if(); + push(@lines, $_); # must keep it for pass 2 + } + next; + } + ############################################################# + # anchor insertion + while (/\@anchor\s*\{(.*?)\}/) + { + $_ = $`.$'; + my $anchor = $1; + $anchor = &normalise_node($anchor); + push @lines, &html_debug("\n"); + $node2href{$anchor} = "$docu_doc#$anchor"; + next INPUT_LINE if $_ =~ /^\s*$/; + } + ############################################################# + # index entry generation, after value substitutions + if (/^\@(\w+?)index\s+/) + { + EnterIndexEntry($1, $', $docu_doc, $section, \@lines); + next; + } + # + # protect texi and HTML things + &protect_texi; + $_ = &protect_html($_) unless $dont_html; + $dont_html = 0; + # substitution (unsupported things) + s/^\@exdent\s+//go; + s/\@noindent\s+//go; + s/\@refill\s+//go; + # other substitutions + &simple_substitutions; + s/\@footnote\{/\@footnote$docu_doc\{/g; # mark footnotes, cf. pass 4 + # + # analyze the tag again + # + if ($tag) + { + if (defined($sec2level{$tag}) && $sec2level{$tag} > 0) + { + if (/^\@$tag\s+(.+)$/) + { + $name = $1; + $name = &normalise_node($name); + $level = $sec2level{$tag}; + # check for index + $first_index_chapter = $name + if ($level == 1 && !$first_index_chapter && + $name =~ /index/i); + if ($in_top && /heading/) + { + $T2H_HAS_TOP_HEADING = 1; + $_ = &debug("$name\n", __LINE__); + &html_push_if('body'); + print "# top heading, section $name, level $level\n" + if $T2H_DEBUG & $DEBUG_TOC; + } + else + { + unless (/^\@\w*heading/) + { + unless (/^\@unnumbered/) + { + my $number = &update_sec_num($tag, $level); + $name = $number . ' ' . $name if $T2H_NUMBER_SECTIONS; + $sec2number{$name} = $number; + $number2sec{$number} = $name; + } + if (defined($toplevel)) + { + push @lines, ($level==$toplevel ? $CHAPTEREND : $SECTIONEND); + } + else + { + # first time we see a "section" + unless ($level == 1) + { + warn "$WARN The first section found is not of level 1: $_"; + } + $toplevel = $level; + } + push(@sections, $name); + next_doc() if (defined $T2H_SPLIT + and + ($T2H_SPLIT eq 'section' + || + $T2H_SPLIT && $level == $toplevel)); + } + $sec_num++; + $docid = "SEC$sec_num"; + $tocid = (/^\@\w*heading/ ? undef : "TOC$sec_num"); + # check biblio and glossary + $in_bibliography = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*bibliography$/i); + $in_glossary = ($name =~ /^([A-Z]|\d+)?(\.\d+)*\s*glossary$/i); + # check node + if ($node) + { + warn "$ERROR Duplicate node found: $node\n" + if ($node2sec{$node}); + } + else + { + $name .= ' ' while ($node2sec{$name}); + $node = $name; + } + $name .= ' ' while ($sec2node{$name}); + $section = $name; + $node2sec{$node} = $name; + $sec2node{$name} = $node; + $sec2seccount{$name} = $sec_num; + $seccount2sec{$sec_num} = $name; + $node2href{$node} = "$docu_doc#$docid"; + $node2next{$node} = $node_next; + $node2prev{$node} = $node_prev; + $node2up{$node} = $node_up; + print "# node $node, section $name, level $level\n" + if $T2H_DEBUG & $DEBUG_TOC; + + $node = ''; + $node_next = ''; + $node_prev = ''; + $node_next = ''; + if ($tocid) + { + # update TOC + while ($level > $curlevel) + { + $curlevel++; + push(@toc_lines, "<$toc_indent>\n"); + } + while ($level < $curlevel) + { + $curlevel--; + push(@toc_lines, "\n"); + } + $_ = &t2h_anchor($tocid, "$docu_doc#$docid", $name, 1); + $_ = &substitute_style($_); + push(@stoc_lines, "$_
\n") if ($level == 1); + if ($T2H_NUMBER_SECTIONS) + { + push(@toc_lines, $_ . "
\n") + } + else + { + push(@toc_lines, "
  • " . $_ ."
  • "); + } + } + else + { + push(@lines, &html_debug("\n", + __LINE__)); + } + # update DOC + push(@lines, &html_debug('', __LINE__)); + &html_reset; + $_ = " $name \n\n"; + $_ = &debug($_, __LINE__); + push(@lines, &html_debug('', __LINE__)); + } + # update DOC + foreach $line (split(/\n+/, $_)) + { + push(@lines, "$line\n"); + } + next; + } + else + { + warn "$ERROR Bad section line: $_"; + } + } + else + { + # track variables + $value{$1} = Unprotect_texi($2), next if /^\@set\s+($VARRE)\s+(.*)$/o; + delete $value{$1}, next if /^\@clear\s+($VARRE)\s*$/o; + # store things + $value{'_shorttitle'} = Unprotect_texi($1), next if /^\@shorttitle\s+(.*)$/; + $value{'_setfilename'} = Unprotect_texi($1), next if /^\@setfilename\s+(.*)$/; + $value{'_settitle'} = Unprotect_texi($1), next if /^\@settitle\s+(.*)$/; + $value{'_author'} .= Unprotect_texi($1)."\n", next if /^\@author\s+(.*)$/; + $value{'_subtitle'} .= Unprotect_texi($1)."\n", next if /^\@subtitle\s+(.*)$/; + $value{'_title'} .= Unprotect_texi($1)."\n", next if /^\@title\s+(.*)$/; + + # list item + if (/^\s*\@itemx?\s+/) + { + $what = $'; + $what =~ s/\s+$//; + if ($in_bibliography && $use_bibliography) + { + if ($what =~ /^$BIBRE$/o) + { + $id = 'BIB' . ++$bib_num; + $bib2href{$what} = "$docu_doc#$id"; + print "# found bibliography for '$what' id $id\n" + if $T2H_DEBUG & $DEBUG_BIB; + $what = &t2h_anchor($id, '', $what); + } + } + elsif ($in_glossary && $T2H_USE_GLOSSARY) + { + $id = 'GLOSS' . ++$gloss_num; + $entry = $what; + $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/; + $gloss2href{$entry} = "$docu_doc#$id"; + print "# found glossary for '$entry' id $id\n" + if $T2H_DEBUG & $DEBUG_GLOSS; + $what = &t2h_anchor($id, '', $what); + } + elsif ($in_table && ($table_type eq 'f' || $table_type eq 'v')) + { + # APA: Insert
    before index anchor, if + # necessary to produce valid HTML. Close open + # paragraph first. + if ($html_element ne 'DT') + { + # APA: End paragraph, if any. + if ($html_element eq 'P') + { + push(@lines, &debug("

    \n", __LINE__)); + &html_pop(); + } + push(@lines, &debug("
    ", __LINE__)); + &html_push('DT'); + } + EnterIndexEntry($table_type, $what, $docu_doc, $section, \@lines); + } + # APA: End paragraph, if any. + if ($html_element eq 'P') + { + push(@lines, &debug("

    \n", __LINE__)); + &html_pop(); + } + if ($html_element =~ m|^D[DLT]$|) + { + unless ($html_element eq 'DT') + { + push(@lines, &debug("
    ", __LINE__)); + } + if ($things_map{$in_table} && !$what) + { + # special case to allow @table @bullet for instance + push(@lines, &debug("$things_map{$in_table}\n", __LINE__)); + } + else + { + push(@lines, &debug("\@$in_table\{$what\}\n", __LINE__)); + } + push(@lines, "
    "); + &html_push('DD') unless $html_element eq 'DD'; + if ($table_type) + { # add also an index + unshift(@input_spool, "\@${table_type}index $what\n"); + } + } + elsif ($html_element eq 'TABLE') + { + push(@lines, &debug("$what\n", __LINE__)); + &html_push('TR'); + } + elsif ($html_element eq 'TR') + { + push(@lines, &debug("\n", __LINE__)); + push(@lines, &debug("$what\n", __LINE__)); + } + else + { + push(@lines, &debug("
  • $what\n", __LINE__)); + &html_push('LI') unless $html_element eq 'LI'; + } + push(@lines, &html_debug('', __LINE__)); + if ($deferred_ref) + { + push(@lines, &debug("$deferred_ref\n", __LINE__)); + $deferred_ref = ''; + } + next; + } + elsif (/^\@tab\s+(.*)$/) + { + push(@lines, "$1\n"); + next; + } + } + } + # paragraph separator + if ($_ eq "\n" && ! $in_pre) + { + next if $#lines >= 0 && $lines[$#lines] eq "\n"; + if ($html_element eq 'P') + { + push (@lines, &debug("

    \n

    \n", __LINE__)); + } + # else + # { + # push(@lines, "

    \n"); + # $_ = &debug("

    \n", __LINE__); + # } + elsif ($html_element eq 'body' || $html_element eq 'BLOCKQUOTE' || $html_element eq 'DD' || $html_element eq 'LI') + { + &html_push('P'); + push(@lines, &debug("

    \n", __LINE__)); + } + } + # otherwise + push(@lines, $_) unless $in_titlepage; + push(@lines, &debug("

  • \n", __LINE__)) if ($tag eq 'center'); + } + # finish TOC + $level = 0; + while ($level < $curlevel) + { + $curlevel--; + push(@toc_lines, "\n"); + } + print "# end of pass 1\n" if $T2H_VERBOSE; +} + +#+++############################################################################ +# # +# Stuff related to Index generation # +# # +#---############################################################################ + +sub EnterIndexEntry +{ + my $prefix = shift; + my $key = shift; + my $docu_doc = shift; + my $section = shift; + my $lines = shift; + local $_; + + warn "$ERROR Undefined index command: $_", next + unless (exists ($index_properties->{$prefix})); + $key =~ s/\s+$//; + $_ = $key; + &protect_texi; + $key = $_; + $_ = &protect_html($_); + my $html_key = substitute_style($_); + my $id; + $key = remove_style($key); + $key = remove_things($key); + $_ = $key; + &unprotect_texi; + $key = $_; + while (exists $index->{$prefix}->{$key}) + { + $key .= ' '; + } + ; + if ($lines->[$#lines] =~ /^$/) + { + $id = $1; + } + else + { + $id = 'IDX' . ++$idx_num; + push(@$lines, &t2h_anchor($id, '', $T2H_INVISIBLE_MARK, !$in_pre)); + } + $index->{$prefix}->{$key}->{html_key} = $html_key; + $index->{$prefix}->{$key}->{section} = $section; + $index->{$prefix}->{$key}->{href} = "$docu_doc#$id"; + print "# found ${prefix}index for '$key' with id $id\n" + if $T2H_DEBUG & $DEBUG_INDEX; +} + +sub IndexName2Prefix +{ + my $name = shift; + my $prefix; + + for $prefix (keys %$index_properties) + { + return $prefix if ($index_properties->{$prefix}->{name} eq $name); + } + return undef; +} + +sub GetIndexEntries +{ + my $normal = shift; + my $code = shift; + my ($entries, $prefix, $key) = ({}); + for $prefix (keys %$normal) + { + for $key (keys %{$index->{$prefix}}) + { + $entries->{$key} = {%{$index->{$prefix}->{$key}}}; + } + } + + if (defined($code)) + { + for $prefix (keys %$code) + { + unless (exists $normal->{$prefix}) + { + for $key (keys %{$index->{$prefix}}) + { + $entries->{$key} = {%{$index->{$prefix}->{$key}}}; + $entries->{$key}->{html_key} = "$entries->{$key}->{html_key}"; + } + } + } + } + return $entries; +} + +sub byAlpha +{ + if ($a =~ /^[A-Za-z]/) + { + if ($b =~ /^[A-Za-z]/) + { + return lc($a) cmp lc($b); + } + else + { + return 1; + } + } + elsif ($b =~ /^[A-Za-z]/) + { + return -1; + } + else + { + return lc($a) cmp lc($b); + } +} + +sub GetIndexPages +{ + my $entries = shift; + my (@Letters, $key); + my ($EntriesByLetter, $Pages, $page) = ({}, [], {}); + my @keys = sort byAlpha keys %$entries; + + for $key (@keys) + { + push @{$EntriesByLetter->{uc(substr($key,0, 1))}} , $entries->{$key}; + } + @Letters = sort byAlpha keys %$EntriesByLetter; + $T2H_SPLIT_INDEX = 0 unless $T2H_SPLIT; + + unless ($T2H_SPLIT_INDEX) + { + $page->{First} = $Letters[0]; + $page->{Last} = $Letters[$#Letters]; + $page->{Letters} = \@Letters; + $page->{EntriesByLetter} = $EntriesByLetter; + push @$Pages, $page; + return $Pages; + } + + if ($T2H_SPLIT_INDEX =~ /^\d+$/) + { + my $i = 0; + my ($prev_letter, $letter); + for $letter (@Letters) + { + if ($i > $T2H_SPLIT_INDEX) + { + $page->{Last} = $prev_letter; + push @$Pages, $page; + $i=0; + } + if ($i == 0) + { + $page = {}; + $page->{Letters} = []; + $page->{EntriesByLetter} = {}; + $page->{First} = $letter; + } + push @{$page->{Letters}}, $letter; + $page->{EntriesByLetter}->{$letter} = [@{$EntriesByLetter->{$letter}}]; + $i += scalar(@{$EntriesByLetter->{$letter}}); + $prev_letter = $letter; + } + $page->{Last} = $Letters[$#Letters]; + push @$Pages, $page; + } + return $Pages; +} + +sub GetIndexSummary +{ + my $first_page = shift; + my $Pages = shift; + my $name = shift; + my ($page, $letter, $summary, $i, $l1, $l2, $l); + + $i = 0; + $summary = '
    Jump to:   '; + for $page ($first_page, @$Pages) + { + for $letter (@{$page->{Letters}}) + { + $l = t2h_anchor('', "$page->{href}#${name}_$letter", "$letter", + 0, 'style="text-decoration:none"') . "\n   \n"; + if ($letter =~ /^[A-Za-z]/) + { + $l2 .= $l; + } + else + { + $l1 .= $l; + } + } + } + $summary .= $l1 . "
    \n" if ($l1); + $summary .= $l2 . '
    '; + return $summary; +} + +sub PrintIndexPage +{ + my $lines = shift; + my $summary = shift; + my $page = shift; + my $name = shift; + + push @$lines, $summary; + + push @$lines , <

    + + + +EOT + + for $letter (@{$page->{Letters}}) + { + push @$lines, "\n"; + for $entry (@{$page->{EntriesByLetter}->{$letter}}) + { + push @$lines, + "\n"; + } + push @$lines, "\n"; + } + push @$lines, "
    Index Entry Section

    ".protect_html($letter)."
    " . + t2h_anchor('', $entry->{href}, $entry->{html_key}) . + "" . + t2h_anchor('', sec_href($entry->{section}), clean_name($entry->{section})) . + "

    "; + push @$lines, $summary; +} + +sub PrintIndex +{ + my $lines = shift; + my $name = shift; + my $section = shift; + $section = 'Top' unless $section; + my $prefix = IndexName2Prefix($name); + + warn ("$ERROR printindex: bad index name: $name"), return + unless $prefix; + + if ($index_properties->{$prefix}->{code}) + { + $index_properties->{$prefix}->{from_code}->{$prefix} = 1; + } + else + { + $index_properties->{$prefix}->{from}->{$prefix}= 1; + } + + my $Entries = GetIndexEntries($index_properties->{$prefix}->{from}, + $index_properties->{$prefix}->{from_code}); + return unless %$Entries; + + if ($T2H_IDX_SUMMARY) + { + my $key; + open(FHIDX, ">$docu_rdir$docu_name" . "_$name.idx") + || die "Can't open > $docu_rdir$docu_name" . "_$name.idx for writing: $!\n"; + print "# writing $name index summary in $docu_rdir$docu_name" . "_$name.idx...\n" if $T2H_VERBOSE; + + for $key (sort keys %$Entries) + { + print FHIDX "$key\t$Entries->{$key}->{href}\n"; + } + } + + my $Pages = GetIndexPages($Entries); + my $page; + my $first_page = shift @$Pages; + my $sec_name = $section; + + # remove section number + $sec_name =~ s/.*? // if $sec_name =~ /^([A-Z]|\d+)\./; + + ($first_page->{href} = sec_href($section)) =~ s/\#.*$//; + $node2prev{$section} = Sec2PrevNode($node2sec{$section}); + $prev_node = $section; + # Update tree structure of document + if (@$Pages) + { + my $sec; + my @after; + + while (@sections && $sections[$#sections] ne $section) + { + unshift @after, pop @sections; + } + + for $page (@$Pages) + { + my $node = ($page->{First} ne $page->{Last} ? + "$sec_name: $page->{First} -- $page->{Last}" : + "$sec_name: $page->{First}"); + push @sections, $node; + $node2sec{$node} = $node; + $sec2node{$node} = $node; + $node2up{$node} = $section; + $page->{href} = next_doc(); + $page->{name} = $node; + $node2href{$node} = $page->{href}; + if ($prev_node) + { + $node2next{$prev_node} = $node; + $node2prev{$node} = $prev_node; + } + $prev_node = $node; + } + # Full circle - Next on last index page goes to Top + $node2next{$prev_node} = "Top"; + push @sections, @after; + } + + my $summary = GetIndexSummary($first_page, $Pages, $name); + PrintIndexPage($lines, $summary, $first_page, $name); + for $page (@$Pages) + { + push @$lines, ($T2H_SPLIT eq 'chapter' ? $CHAPTEREND : $SECTIONEND); + push @$lines, "

    $page->{name}

    \n"; + PrintIndexPage($lines, $summary, $page, $name); + } +} + + +#+++############################################################################ +# # +# Pass 2/3: handle style, menu, index, cross-reference # +# # +#---############################################################################ +sub pass2 +{ + my $sec; + my $href; + @lines2 = (); # whole document (2nd pass) + @lines3 = (); # whole document (3rd pass) + my $in_menu = 0; # am I inside a menu + my $in_menu_listing; + + while (@lines) + { + $_ = shift(@lines); + # + # special case (protected sections) + # + if (/^$PROTECTTAG/o) + { + push(@lines2, $_); + next; + } + # + # menu + # + if (/^\@menu\b/) + { + $in_menu = 1; + $in_menu_listing = 1; + # APA: implicitly ends paragraph, so let's do it + # explicitly to keep our HTML stack in sync. + if ($html_element eq 'P') + { + push (@lines2, &debug("

    \n", __LINE__)); + &html_pop(); + } + push(@lines2, &debug("
    \n", __LINE__)); + next; + } + if (/^\@end\s+menu\b/) + { + if ($in_menu_listing) + { + push(@lines2, &debug("
    \n", __LINE__)); + } + $in_menu = 0; + $in_menu_listing = 0; + next; + } + if ($in_menu) + { + my ($node, $name, $descr); + if (/^\*\s+($NODERE)::/o) + { + $node = $1; + $descr = $'; + } + elsif (/^\*\s+(.+):\s+([^\t,\.\n]+)[\t,\.\n]/) + { + $name = $1; + $node = $2; + $descr = $'; + } + elsif (/^\*/) + { + warn "$ERROR Bad menu line: $_"; + } + else + { + if ($in_menu_listing) + { + # APA: Handle menu comment lines. These don't end the menu! + # $in_menu_listing = 0; + push(@lines2,&debug('' . $_ . ' +', __LINE__)); + } + } + if ($node) + { + if (! $in_menu_listing) + { + $in_menu_listing = 1; + push(@lines2, &debug("\n", __LINE__)); + } + # look for continuation + while ($lines[0] =~ /^\s+\w+/) + { + $descr .= shift(@lines); + } + &menu_entry($node, $name, $descr); + } + next; + } + # + # printindex + # + PrintIndex(\@lines2, $2, $1), next + if (/^\@printindex\s+(\w+)/); + # + # simple style substitutions + # + $_ = &substitute_style($_); + # + # xref + # + while (/\@(x|px|info|)ref{([^{}]+)(}?)/) + { + # note: Texinfo may accept other characters + ($type, $nodes, $full) = ($1, $2, $3); + ($before, $after) = ($`, $'); + if (! $full && $after) + { + warn "$ERROR Bad xref (no ending } on line): $_"; + $_ = "$before$;0${type}ref\{$nodes$after"; + next; # while xref + } + if ($type eq 'x') + { + $type = "$T2H_WORDS->{$T2H_LANG}->{'See'} "; + } + elsif ($type eq 'px') + { + $type = "$T2H_WORDS->{$T2H_LANG}->{'see'} "; + } + elsif ($type eq 'info') + { + $type = "$T2H_WORDS->{$T2H_LANG}->{'See'} Info"; + } + else + { + $type = ''; + } + unless ($full) + { + $next = shift(@lines); + $next = &substitute_style($next); + chop($nodes); # remove final newline + if ($next =~ /\}/) + { # split on 2 lines + $nodes .= " $`"; + $after = $'; + } + else + { + $nodes .= " $next"; + $next = shift(@lines); + $next = &substitute_style($next); + chop($nodes); + if ($next =~ /\}/) + { # split on 3 lines + $nodes .= " $`"; + $after = $'; + } + else + { + warn "$ERROR Bad xref (no ending }): $_"; + $_ = "$before$;0xref\{$nodes$after"; + unshift(@lines, $next); + next; # while xref + } + } + } + $nodes =~ s/\s+/ /go; # remove useless spaces + @args = split(/\s*,\s*/, $nodes); + $node = $args[0]; # the node is always the first arg + $node = &normalise_node($node); + $sec = $args[2] || $args[1] || $node2sec{$node}; + $href = $node2href{$node}; + if (@args == 5) + { # reference to another manual + $sec = $args[2] || $node; + $man = $args[4] || $args[3]; + $_ = "${before}${type}$T2H_WORDS->{$T2H_LANG}->{'section'} `$sec' in \@cite{$man}$after"; + } + elsif ($type =~ /Info/) + { # inforef + warn "$ERROR Wrong number of arguments: $_" unless @args == 3; + ($nn, $_, $in) = @args; + $_ = "${before}${type} file `$in', node `$nn'$after"; + } + elsif ($sec && $href && ! $T2H_SHORT_REF) + { + $_ = "${before}${type}"; + $_ .= "$T2H_WORDS->{$T2H_LANG}->{'section'} " if $type; + $_ .= &t2h_anchor('', $href, $sec) . $after; + } + elsif ($href) + { + $_ = "${before}${type} " . + &t2h_anchor('', $href, $args[2] || $args[1] || $node) . + $after; + } + else + { + warn "$ERROR Undefined node ($node): $_"; + $_ = "$before$;0xref{$nodes}$after"; + } + } + + # replace images + s[\@image\s*{(.+?)}] + { + my @args = split (/\s*,\s*/, $1); + my $base = $args[0]; + my $image = + LocateIncludeFile("$base.png") || + LocateIncludeFile("$base.jpg") || + LocateIncludeFile("$base.gif"); + warn "$ERROR no image file for $base: $_" unless ($image && -e $image); + ($T2H_CENTER_IMAGE ? + "
    \"$base\"
    " : + "\"$base\""); + }eg; + + # + # try to guess bibliography references or glossary terms + # + unless (/^/) + { + $done .= $pre . &t2h_anchor('', $href, $what); + } + else + { + $done .= "$pre$what"; + } + $_ = $post; + } + $_ = $done . $_; + } + if ($T2H_USE_GLOSSARY) + { + $done = ''; + while (/\b\w+\b/) + { + ($pre, $what, $post) = ($`, $&, $'); + $entry = $what; + $entry =~ tr/A-Z/a-z/ unless $entry =~ /^[A-Z\s]+$/; + $href = $gloss2href{$entry}; + if (defined($href) && $post !~ /^[^<]*<\/A>/) + { + $done .= $pre . &t2h_anchor('', $href, $what); + } + else + { + $done .= "$pre$what"; + } + $_ = $post; + } + $_ = $done . $_; + } + } + # otherwise + push(@lines2, $_); + } + print "# end of pass 2\n" if $T2H_VERBOSE; +} + +sub pass3 +{ + # + # split style substitutions + # + my $text; + while (@lines2) + { + $_ = shift(@lines2); + # + # special case (protected sections) + # + if (/^$PROTECTTAG/o) + { + push(@lines3, $_); + next; + } + # + # split style substitutions + # + $old = ''; + while ($old ne $_) + { + $old = $_; + if (/\@(\w+)\{/) + { + ($before, $style, $after) = ($`, $1, $'); + if (defined($style_map{$style})) + { + $_ = $after; + $text = ''; + $after = ''; + $failed = 1; + while (@lines2) + { + if (/\}/) + { + $text .= $`; + $after = $'; + $failed = 0; + last; + } + else + { + $text .= $_; + $_ = shift(@lines2); + } + } + if ($failed) + { + die "* Bad syntax (\@$style) after: $before\n"; + } + else + { + $text = &apply_style($style, $text); + $_ = "$before$text$after"; + } + } + } + } + # otherwise + push(@lines3, $_); + } + print "# end of pass 3\n" if $T2H_VERBOSE; +} + +#+++############################################################################ +# # +# Pass 4: foot notes, final cleanup # +# # +#---############################################################################ +sub pass4 +{ + my $text; + my $name; + @foot_lines = (); # footnotes + @doc_lines = (); # final document + $end_of_para = 0; # true if last line is

    + + # APA: There aint no paragraph before the first one! + # This fixes a HTML validation error. + $lines3[0] =~ s|^

    \n|\n|; + while (@lines3) + { + $_ = shift(@lines3); + # + # special case (protected sections) + # + if (/^$PROTECTTAG/o) + { + push(@doc_lines, $_); + $end_of_para = 0; + next; + } + # + # footnotes + # + while (/\@footnote([^\{\s]+)\{/) + { + ($before, $d, $after) = ($`, $1, $'); + $_ = $after; + $text = ''; + $after = ''; + $failed = 1; + while (@lines3) + { + if (/\}/) + { + $text .= $`; + $after = $'; + $failed = 0; + last; + } + else + { + $text .= $_; + $_ = shift(@lines3); + } + } + if ($failed) + { + die "* Bad syntax (\@footnote) after: $before\n"; + } + else + { + $foot_num++; + $docid = "DOCF$foot_num"; + $footid = "FOOT$foot_num"; + $foot = "($foot_num)"; + push(@foot_lines, "

    " . &t2h_anchor($footid, "$d#$docid", $foot) . "

    \n"); + $text = "

    $text" unless $text =~ /^\s*

    /; + push(@foot_lines, "$text\n"); + $_ = $before . &t2h_anchor($docid, "$docu_foot#$footid", $foot) . $after; + } + } + # + # remove unnecessary

    + # + if (/^\s*

    \s*$/) + { + next if $end_of_para++; + } + else + { + $end_of_para = 0; + } + # otherwise + push(@doc_lines, $_); + } + + print "# end of pass 4\n" if $T2H_VERBOSE; +} + +#+++############################################################################ +# # +# Pass 5: print things # +# # +#---############################################################################ +sub pass5 +{ + $T2H_L2H = &l2h_FinishToLatex if ($T2H_L2H); + $T2H_L2H = &l2h_ToHtml if ($T2H_L2H); + $T2H_L2H = &l2h_InitFromHtml if ($T2H_L2H); + + T2H_InitGlobals(); + + # fix node2up, node2prev, node2next, if desired + if ($has_top_command) + { + for $section (keys %sec2number) + { + $node2href{$sec2node{$section}} =~ /SEC(\d+)$/; + $node = $sec2node{$section}; + $node2up{$node} = Sec2UpNode($section) unless $node2up{$node}; + $node2prev{$node} = Sec2PrevNode($section) unless $node2prev{$node}; + $node2next{$node} = Sec2NextNode($section) unless $node2next{$node}; + } + } + + # prepare %T2H_THISDOC + $T2H_THISDOC{fulltitle} = $value{'_title'} || $value{'_settitle'} || "Untitled Document"; + $T2H_THISDOC{title} = $value{'_settitle'} || $T2H_THISDOC{fulltitle}; + $T2H_THISDOC{author} = $value{'_author'}; + $T2H_THISDOC{subtitle} = $value{'_subtitle'}; + $T2H_THISDOC{shorttitle} = $value{'_shorttitle'}; + for $key (keys %T2H_THISDOC) + { + $_ = &substitute_style($T2H_THISDOC{$key}); + &unprotect_texi; + s/\s*$//; + $T2H_THISDOC{$key} = $_; + } + + # if no sections, then simply print document as is + unless (@sections) + { + print "# Writing content into $docu_top_file \n" if $T2H_VERBOSE; + open(FILE, "> $docu_top_file") + || die "$ERROR: Can't open $docu_top_file for writing: $!\n"; + + &$T2H_print_page_head(\*FILE); + $T2H_THIS_SECTION = \@doc_lines; + t2h_print_lines(\*FILE); + &$T2H_print_foot_navigation(\*FILE); + &$T2H_print_page_foot(\*FILE); + close(FILE); + goto Finish; + } + + # initialize $T2H_HREF, $T2H_NAME + %T2H_HREF = + ( + 'First' , sec_href($sections[0]), + 'Last', sec_href($sections[$#sections]), + 'About', $docu_about. '#SEC_About', + ); + + # prepare TOC, OVERVIEW, TOP + $T2H_TOC = \@toc_lines; + $T2H_OVERVIEW = \@stoc_lines; + if ($has_top) + { + while (1) + { + $_ = shift @doc_lines; + last if /$TOPEND/; + push @$T2H_TOP, $_; + } + $T2H_HREF{'Top'} = $docu_top . '#SEC_Top'; + } + else + { + $T2H_HREF{'Top'} = $T2H_HREF{First}; + } + + $node2href{Top} = $T2H_HREF{Top}; + $T2H_HREF{Contents} = $docu_toc.'#SEC_Contents' if @toc_lines; + $T2H_HREF{Overview} = $docu_stoc.'#SEC_OVERVIEW' if @stoc_lines; + + # settle on index + if ($T2H_INDEX_CHAPTER) + { + $T2H_HREF{Index} = $node2href{normalise_node($T2H_INDEX_CHAPTER)}; + warn "$ERROR T2H_INDEX_CHAPTER '$T2H_INDEX_CHAPTER' not found\n" + unless $T2H_HREF{Index}; + } + if (! $T2H_HREF{Index} && $first_index_chapter) + { + $T2H_INDEX_CHAPTER = $first_index_chapter; + $T2H_HREF{Index} = $node2href{$T2H_INDEX_CHAPTER}; + } + + print "# Using '" . clean_name($T2H_INDEX_CHAPTER) . "' as index page\n" + if ($T2H_VERBOSE && $T2H_HREF{Index}); + + %T2H_NAME = + ( + 'First', clean_name($sec2node{$sections[0]}), + 'Last', clean_name($sec2node{$sections[$#sections]}), + 'About', $T2H_WORDS->{$T2H_LANG}->{'About_Title'}, + 'Contents', $T2H_WORDS->{$T2H_LANG}->{'ToC_Title'}, + 'Overview', $T2H_WORDS->{$T2H_LANG}->{'Overview_Title'}, + 'Index' , clean_name($T2H_INDEX_CHAPTER), + 'Top', clean_name($T2H_TOP_HEADING || $T2H_THISDOC{'title'} || $T2H_THISDOC{'shorttitle'}), + ); + + ############################################################################# + # print frame and frame toc file + # + if ( $T2H_FRAMES ) + { + open(FILE, "> $docu_frame_file") + || die "$ERROR: Can't open $docu_frame_file for writing: $!\n"; + print "# Creating frame in $docu_frame_file ...\n" if $T2H_VERBOSE; + &$T2H_print_frame(\*FILE); + close(FILE); + + open(FILE, "> $docu_toc_frame_file") + || die "$ERROR: Can't open $docu_toc_frame_file for writing: $!\n"; + print "# Creating toc frame in $docu_frame_file ...\n" if $T2H_VERBOSE; + &$T2H_print_toc_frame(\*FILE); + close(FILE); + } + + + ############################################################################# + # Monolithic beginning. + # + unless ($T2H_SPLIT) + { + open(FILE, "> $docu_doc_file") + || die "$ERROR: Can't open $docu_doc_file for writing: $!\n"; + &$T2H_print_page_head(\*FILE); + } + + + ############################################################################# + # print Top + # + if ($has_top) + { + if ($T2H_SPLIT) + { + open(FILE, "> $docu_top_file") + || die "$ERROR: Can't open $docu_top_file for writing: $!\n"; + } + + print "# Creating Top in $docu_top_file ...\n" if $T2H_VERBOSE; + $T2H_THIS_SECTION = $T2H_TOP; + $T2H_HREF{This} = $T2H_HREF{Top}; + $T2H_NAME{This} = $T2H_NAME{Top}; + &$T2H_print_Top(\*FILE); + + if ($T2H_SPLIT) + { + close(FILE) + || die "$ERROR: Error occurred when closing $docu_top_file: $!\n"; + } + } + + + ############################################################################# + # Print sections + # + $T2H_NODE{Forward} = $sec2node{$sections[0]}; + $T2H_NAME{Forward} = &clean_name($sec2node{$sections[0]}); + $T2H_HREF{Forward} = sec_href($sections[0]); + $T2H_NODE{This} = 'Top'; + $T2H_NAME{This} = $T2H_NAME{Top}; + $T2H_HREF{This} = $T2H_HREF{Top}; + if ($T2H_SPLIT) + { + print "# writing " . scalar(@sections) . + " sections into $docu_rdir$docu_name"."_[1..$doc_num].$docu_ext" + if $T2H_VERBOSE; + $previous = ($T2H_SPLIT eq 'chapter' ? $CHAPTEREND : $SECTIONEND); + undef $FH; + $doc_num = 0; + } + else + { + print "# writing " . scalar(@sections) . " sections in $docu_top_file ..." + if $T2H_VERBOSE; + $FH = \*FILE; + $previous = ''; + } + + $counter = 0; + # loop through sections + while ($section = shift(@sections)) + { + if ($T2H_SPLIT && ($T2H_SPLIT eq 'section' || $previous eq $CHAPTEREND)) + { + if ($FH) + { + #close previous page + &$T2H_print_chapter_footer($FH) if $T2H_SPLIT eq 'chapter'; + &$T2H_print_page_foot($FH); + close($FH); + undef $FH; + } + } + $T2H_NAME{Back} = $T2H_NAME{This}; + $T2H_HREF{Back} = $T2H_HREF{This}; + $T2H_NODE{Back} = $T2H_NODE{This}; + $T2H_NAME{This} = $T2H_NAME{Forward}; + $T2H_HREF{This} = $T2H_HREF{Forward}; + $T2H_NODE{This} = $T2H_NODE{Forward}; + if ($sections[0]) + { + $T2H_NODE{Forward} = $sec2node{$sections[0]}; + $T2H_NAME{Forward} = &clean_name($T2H_NODE{Forward}); + $T2H_HREF{Forward} = sec_href($sections[0]); + } + else + { + delete $T2H_HREF{Forward}; + delete $T2H_NODE{Forward}; + delete $T2H_NAME{Forward}; + } + + $node = $node2up{$T2H_NODE{This}}; + $T2H_HREF{Up} = $node2href{$node}; + if ($T2H_HREF{Up} eq $T2H_HREF{This} || ! $T2H_HREF{Up}) + { + $T2H_NAME{Up} = $T2H_NAME{Top}; + $T2H_HREF{Up} = $T2H_HREF{Top}; + $T2H_NODE{Up} = 'Up'; + } + else + { + $T2H_NAME{Up} = &clean_name($node); + $T2H_NODE{Up} = $node; + } + + $node = $node2prev{$T2H_NODE{This}}; + $T2H_NAME{Prev} = &clean_name($node); + $T2H_HREF{Prev} = $node2href{$node}; + $T2H_NODE{Prev} = $node; + + $node = Node2FastBack($T2H_NODE{This}); + $T2H_NAME{FastBack} = &clean_name($node); + $T2H_HREF{FastBack} = $node2href{$node}; + $T2H_NODE{FastBack} = $node; + + $node = $node2next{$T2H_NODE{This}}; + $T2H_NAME{Next} = &clean_name($node); + $T2H_HREF{Next} = $node2href{$node}; + $T2H_NODE{Next} = $node; + + $node = Node2FastForward($T2H_NODE{This}); + $T2H_NAME{FastForward} = &clean_name($node); + $T2H_HREF{FastForward} = $node2href{$node}; + $T2H_NODE{FastForward} = $node; + + if (! defined($FH)) + { + my $file = $T2H_HREF{This}; + $file =~ s/\#.*$//; + open(FILE, "> $docu_rdir$file") || + die "$ERROR: Can't open $docu_rdir$file for writing: $!\n"; + $FH = \*FILE; + &$T2H_print_page_head($FH); + t2h_print_label($FH); + &$T2H_print_chapter_header($FH) if $T2H_SPLIT eq 'chapter'; + } + else + { + t2h_print_label($FH); + } + + $T2H_THIS_SECTION = []; + while (@doc_lines) + { + $_ = shift(@doc_lines); + last if ($_ eq $SECTIONEND || $_ eq $CHAPTEREND); + push(@$T2H_THIS_SECTION, $_); + } + $previous = $_; + &$T2H_print_section($FH); + + if ($T2H_VERBOSE) + { + $counter++; + print "." if $counter =~ /00$/; + } + } + if ($T2H_SPLIT) + { + &$T2H_print_chapter_footer($FH) if $T2H_SPLIT eq 'chapter'; + &$T2H_print_page_foot($FH); + close($FH); + } + print "\n" if $T2H_VERBOSE; + + ############################################################################# + # Print ToC, Overview, Footnotes + # + delete $T2H_HREF{Prev}; + delete $T2H_HREF{Next}; + delete $T2H_HREF{Back}; + delete $T2H_HREF{Forward}; + delete $T2H_HREF{Up}; + + if (@foot_lines) + { + print "# writing Footnotes in $docu_foot_file...\n" if $T2H_VERBOSE; + open (FILE, "> $docu_foot_file") || die "$ERROR: Can't open $docu_foot_file for writing: $!\n" + if $T2H_SPLIT; + $T2H_HREF{This} = $docu_foot; + $T2H_NAME{This} = $T2H_WORDS->{$T2H_LANG}->{'Footnotes_Title'}; + $T2H_THIS_SECTION = \@foot_lines; + &$T2H_print_Footnotes(\*FILE); + close(FILE) if $T2H_SPLIT; + } + + if (@toc_lines) + { + print "# writing Toc in $docu_toc_file...\n" if $T2H_VERBOSE; + open (FILE, "> $docu_toc_file") || die "$ERROR: Can't open $docu_toc_file for writing: $!\n" + if $T2H_SPLIT; + $T2H_HREF{This} = $T2H_HREF{Contents}; + $T2H_NAME{This} = $T2H_NAME{Contents}; + $T2H_THIS_SECTION = \@toc_lines; + &$T2H_print_Toc(\*FILE); + close(FILE) if $T2H_SPLIT; + } + + if (@stoc_lines) + { + print "# writing Overview in $docu_stoc_file...\n" if $T2H_VERBOSE; + open (FILE, "> $docu_stoc_file") || die "$ERROR: Can't open $docu_stoc_file for writing: $!\n" + if $T2H_SPLIT; + $T2H_HREF{This} = $T2H_HREF{Overview}; + $T2H_NAME{This} = $T2H_NAME{Overview}; + $T2H_THIS_SECTION = \@stoc_lines; + unshift @$T2H_THIS_SECTION, "

    \n"; + push @$T2H_THIS_SECTION, "\n
    \n"; + &$T2H_print_Overview(\*FILE); + close(FILE) if $T2H_SPLIT; + } + + if ($about_body = &$T2H_about_body()) + { + print "# writing About in $docu_about_file...\n" if $T2H_VERBOSE; + open (FILE, "> $docu_about_file") || die "$ERROR: Can't open $docu_about_file for writing: $!\n" + if $T2H_SPLIT; + + $T2H_HREF{This} = $T2H_HREF{About}; + $T2H_NAME{This} = $T2H_NAME{About}; + $T2H_THIS_SECTION = [$about_body]; + &$T2H_print_About(\*FILE); + close(FILE) if $T2H_SPLIT; + } + + unless ($T2H_SPLIT) + { + &$T2H_print_page_foot(\*FILE); + close (FILE); + } + + Finish: + &l2h_FinishFromHtml if ($T2H_L2H); + &l2h_Finish if($T2H_L2H); + print "# that's all folks\n" if $T2H_VERBOSE; + + exit(0); +} + +#+++############################################################################ +# # +# Low level functions # +# # +#---############################################################################ + +sub LocateIncludeFile +{ + my $file = shift; + my $dir; + + # APA: Don't implicitely search ., to conform with the docs! + # return $file if (-e $file && -r $file); + foreach $dir (@T2H_INCLUDE_DIRS) + { + return "$dir/$file" if (-e "$dir/$file" && -r "$dir/$file"); + } + return undef; +} + +sub clean_name +{ + local ($_); + $_ = &remove_style($_[0]); + &unprotect_texi; + return $_; +} + +sub update_sec_num +{ + my($name, $level) = @_; + my $ret; + + $level--; # here we start at 0 + if ($name =~ /^appendix/ || defined(@appendix_sec_num)) + { + # appendix style + if (defined(@appendix_sec_num)) + { + &incr_sec_num($level, @appendix_sec_num); + } + else + { + @appendix_sec_num = ('A', 0, 0, 0); + } + $ret = join('.', @appendix_sec_num[0..$level]); + } + else + { + # normal style + if (defined(@normal_sec_num)) + { + &incr_sec_num($level, @normal_sec_num); + } + else + { + @normal_sec_num = (1, 0, 0, 0); + } + $ret = join('.', @normal_sec_num[0..$level]); + } + $ret .= "." if $level == 0; + return $ret; +} + +sub incr_sec_num +{ + local($level, $l); + $level = shift(@_); + $_[$level]++; + foreach $l ($level+1 .. 3) + { + $_[$l] = 0; + } +} + +sub Sec2UpNode +{ + my $sec = shift; + my $num = $sec2number{$sec}; + + return '' unless $num; + return 'Top' unless $num =~ /\.\d+/; + $num =~ s/\.[^\.]*$//; + $num = $num . '.' unless $num =~ /\./; + return $sec2node{$number2sec{$num}}; +} + +# Return previous node or "Top" +sub Sec2PrevNode +{ + my $sec = shift; + my $sec_num = $sec2seccount{$sec} - 1; + return "Top" if !$sec_num || $sec_num < 1; + return $sec2node{$seccount2sec{$sec_num}}; +} + +# Return next node or "Top" +sub Sec2NextNode +{ + my $sec = shift; + my $sec_num = $sec2seccount{$sec} + 1; + return "Top" unless exists $seccount2sec{$sec_num}; + return $sec2node{$seccount2sec{$sec_num}}; +} + +# +# sub Node2FastBack NODE +# +# INPUTS +# NODE A node +# +# RETURNS +# The beginning of this chapter, or if already there, the beginning of the +# previous chapter. +# +sub Node2FastBack +{ + my $node = shift; + my $num = $sec2number{$node2sec{$node}}; + my $n; + + # Index Pages have no section number and 1. should go back to Top + return $node2prev{$node} if !$num or $num eq "1."; + + # Get the current chapter + $num =~ /^([A-Z\d]+)\./; + $n = $1; + + # If the first section of this chapter, decrement chapter + $n = $n eq 'A' ? $normal_sec_num[0] : $n =~ /^\d+$/ ? --$n : chr(ord($n)-1) + if $n . '.' eq $num; + + # Return node name for section number "$n." + return $sec2node{$number2sec{$n . '.'}} || $node2prev{$node}; +} + +# +# sub Node2FastForward NODE +# +# INPUTS +# NODE A node +# +# RETURNS +# The beginning of the next chapter. +# +sub Node2FastForward +{ + my $node = shift; + my $num = $sec2number{$node2sec{$node}}; + my $n; + + # Index pages + return $node2next{$node} if !$num; + + # Get current chapter + $num =~ /^([A-Z\d]+)\./; + $n = $1; + + # Increment chapter + $n = $n eq $normal_sec_num[0] ? 'A' : ++$n; + + # Return node name + return $sec2node{$number2sec{$n . '.'}} || $node2next{$node}; +} + +sub check +{ + local($_, %seen, %context, $before, $match, $after); + + while (<>) + { + if (/\@(\*|\.|\:|\@|\{|\})/) + { + $seen{$&}++; + $context{$&} .= "> $_" if $T2H_VERBOSE; + $_ = "$`XX$'"; + redo; + } + if (/\@(\w+)/) + { + ($before, $match, $after) = ($`, $&, $'); + if ($before =~ /\b[-\w]+$/ && $after =~ /^[-\w.]*\b/) + { # e-mail address + $seen{'e-mail address'}++; + $context{'e-mail address'} .= "> $_" if $T2H_VERBOSE; + } + else + { + $seen{$match}++; + $context{$match} .= "> $_" if $T2H_VERBOSE; + } + $match =~ s/^\@/X/; + $_ = "$before$match$after"; + redo; + } + } + + foreach (sort(keys(%seen))) + { + if ($T2H_VERBOSE) + { + print "$_\n"; + print $context{$_}; + } + else + { + print "$_ ($seen{$_})\n"; + } + } +} + +sub open +{ + my($name) = @_; + + ++$fh_name; + no strict "refs"; + if (open($fh_name, $name)) + { + unshift(@fhs, $fh_name); + } + else + { + warn "$ERROR Can't read file $name: $!\n"; + } + use strict "refs"; +} + +sub init_input +{ + @fhs = (); # hold the file handles to read + @input_spool = (); # spooled lines to read + $fh_name = 'FH000'; + &open($docu); +} + +sub next_line +{ + my($fh, $line); + + if (@input_spool) + { + $line = shift(@input_spool); + return($line); + } + while (@fhs) + { + $fh = $fhs[0]; + $line = <$fh>; + return($line) if $line; + close($fh); + shift(@fhs); + } + return(undef); +} + +# used in pass 1, use &next_line +sub skip_until +{ + local($tag) = @_; + local($_); + + while ($_ = &next_line) + { + return if /^\@end\s+$tag\s*$/; + } + die "* Failed to find '$tag' after: " . $lines[$#lines]; +} + +# used in pass 1 for l2h use &next_line +sub string_until +{ + local($tag) = @_; + local($_, $string); + + while ($_ = &next_line) + { + return $string if /^\@end\s+$tag\s*$/; + # $_ =~ s/hbox/mbox/g; + $string = $string.$_; + } + die "* Failed to find '$tag' after: " . $lines[$#lines]; +} + +# +# HTML stacking to have a better HTML output +# + +sub html_reset +{ + @html_stack = ('html'); + $html_element = 'body'; +} + +sub html_push +{ + local($what) = @_; + push(@html_stack, $html_element); + $html_element = $what; +} + +sub html_push_if +{ + local($what) = @_; + push(@html_stack, $html_element) + if ($html_element && $html_element ne 'P'); + $html_element = $what; +} + +sub html_pop +{ + $html_element = pop(@html_stack); +} + +sub html_pop_if +{ + local($elt); + + if (@_) + { + foreach $elt (@_) + { + if ($elt eq $html_element) + { + $html_element = pop(@html_stack) if @html_stack; + last; + } + } + } + else + { + $html_element = pop(@html_stack) if @html_stack; + } +} + +sub html_debug +{ + my($what, $line) = @_; + if ($T2H_DEBUG & $DEBUG_HTML) + { + $what = "\n" unless $what; + return("$what") + } + return($what); +} + +# to debug the output... +sub debug +{ + my($what, $line) = @_; + return("$what") + if $T2H_DEBUG & $DEBUG_HTML; + return($what); +} + +sub SimpleTexi2Html +{ + local $_ = $_[0]; + &protect_texi; + &protect_html; + $_ = substitute_style($_); + $_[0] = $_; +} + +sub normalise_node +{ + local $_ = $_[0]; + s/\s+/ /go; + s/ $//; + s/^ //; + &protect_texi; + &protect_html; + $_ = substitute_style($_); + $_[0] = $_; +} + +sub menu_entry +{ + my ($node, $name, $descr) = @_; + my ($href, $entry); + + &normalise_node($node); + $href = $node2href{$node}; + if ($href) + { + $descr =~ s/^\s+//; + $descr =~ s/\s*$//; + $descr = SimpleTexi2Html($descr); + if ($T2H_NUMBER_SECTIONS && !$T2H_NODE_NAME_IN_MENU && $node2sec{$node}) + { + $entry = $node2sec{$node}; + $name = ''; + } + else + { + &normalise_node($name); + $entry = ($name && ($name ne $node || ! $T2H_AVOID_MENU_REDUNDANCY) + ? "$name : $node" : $node); + } + + if ($T2H_AVOID_MENU_REDUNDANCY && $descr) + { + my $clean_entry = $entry; + $clean_entry =~ s/^.*? // if ($clean_entry =~ /^([A-Z]|\d+)\.[\d\.]* /); + $clean_entry =~ s/[^\w]//g; + my $clean_descr = $descr; + $clean_descr =~ s/[^\w]//g; + $descr = '' if ($clean_entry eq $clean_descr) + } + push(@lines2,&debug('
    \n", __LINE__)); + } + elsif ($node =~ /^\(.*\)\w+/) + { + push(@lines2,&debug('\n", __LINE__)) + } + else + { + warn "$ERROR Undefined node of menu_entry ($node): $_"; + } +} + +sub do_ctrl { "^$_[0]" } + +sub do_email +{ + my($addr, $text) = split(/,\s*/, $_[0]); + + $text = $addr unless $text; + &t2h_anchor('', "mailto:$addr", $text); +} + +sub do_sc +{ + # l2h does this much better + return &l2h_ToLatex("{\\sc ".&unprotect_html($_[0])."}") if ($T2H_L2H); + return "\U$_[0]\E"; +} + +sub do_math +{ + # APA: FIXME + # This sub doesn't seem to be used. + # What are $_[0] and $text? + my $text; + return &l2h_ToLatex("\$".&unprotect_html($_[0])."\$") if ($T2H_L2H); + return "".$text.""; +} + +sub do_uref +{ + my($url, $text, $only_text) = split(/,\s*/, $_[0]); + # APA: Don't markup obviously bad links. + # e.g. texinfo.texi 4.0 has this, which would lead to a broken + # link: + # @section @code{@@uref@{@var{url}[, @var{text}][, @var{replacement}]@}} + return if $url =~ /[<>]/; + $text = $only_text if $only_text; + $text = $url unless $text; + &t2h_anchor('', $url, $text); +} + +sub do_url { &t2h_anchor('', $_[0], $_[0]) } + +sub do_acronym +{ + return '' . $_[0] . ''; +} + +sub do_accent +{ + return "&$_[0]acute;" if $_[1] eq 'H'; + return "$_[0]." if $_[1] eq 'dotaccent'; + return "$_[0]*" if $_[1] eq 'ringaccent'; + return "$_[0]".'[' if $_[1] eq 'tieaccent'; + return "$_[0]".'(' if $_[1] eq 'u'; + return "$_[0]_" if $_[1] eq 'ubaraccent'; + return ".$_[0]" if $_[1] eq 'udotaccent'; + return "$_[0]<" if $_[1] eq 'v'; + return "&$_[0]cedil;" if $_[1] eq ','; + return "$_[0]" if $_[1] eq 'dotless'; + return undef; +} + +sub apply_style +{ + my($texi_style, $text) = @_; + my($style); + + $style = $style_map{$texi_style}; + if (defined($style)) + { # known style + my $do_quotes = 0; + if ($style =~ /^\"/) + { # add quotes + $style = $'; + $do_quotes = 1; + } + if ($style =~ /^\&/) + { # custom + $style = $'; + no strict "refs"; + $text = &$style($text, $texi_style); + use strict "refs"; + } + elsif ($style) + { # good style + $text = "<$style>$text"; + } + else + { # no style + } + $text = "\`$text\'" if $do_quotes; + } + else + { # unknown style + $text = undef; + } + return($text); +} + +# remove Texinfo styles +sub remove_style +{ + local($_) = @_; + 1 while(s/\@\w+{([^\{\}]+)}/$1/g); + return($_); +} + +sub remove_things +{ + local ($_) = @_; + s|\@(\w+)\{\}|$1|g; + return $_; +} + +sub substitute_style +{ + local($_) = @_; + my($changed, $done, $style, $text); + + &simple_substitutions; + $changed = 1; + while ($changed) + { + $changed = 0; + $done = ''; + while (/\@(\w+){([^\{\}]+)}/ || /\@(,){([^\{\}]+)}/) + { + $text = &apply_style($1, $2); + if ($text) + { + $_ = "$`$text$'"; + $changed = 1; + } + else + { + $done .= "$`\@$1"; + $_ = "{$2}$'"; + } + } + $_ = $done . $_; + } + return($_); +} + +sub t2h_anchor +{ + my($name, $href, $text, $newline, $extra_attribs) = @_; + my($result); + + $result = ". + # APA: Keep it simple. This is what perl's CGI::espaceHTML does. + # We may consider using that instead. + # If raw HTML is used outside @ifhtml or @html it's an error + # anyway. + $what =~ s/\&/\&/go; + $what =~ s/\"/\"/go; + $what =~ s/\/\>/go; + return($what); +} + +sub unprotect_texi +{ + s/$;0/\@/go; + s/$;1/\{/go; + s/$;2/\}/go; + s/$;3/\`/go; + s/$;4/\'/go; +} + +sub Unprotect_texi +{ + local $_ = shift; + &unprotect_texi; + return($_); +} + +sub unprotect_html +{ + local($what) = @_; + # APA: Use + # Character entity references (eg. <) + # instead of + # Numeric character references (eg. <) + $what =~ s/\&/\&/go; + $what =~ s/\"/\"/go; + $what =~ s/\</\/go; + return($what); +} + +sub t2h_print_label +{ + my $fh = shift; + my $href = shift || $T2H_HREF{This}; + $href =~ s/.*#(.*)$/$1/; + print $fh qq{\n}; +} + +sub main +{ + SetDocumentLanguage('en') unless ($T2H_LANG); + # APA: There's got to be a better way: + $things_map{'today'} = &pretty_date; + # Identity: + $T2H_TODAY = &pretty_date; # like "20 September 1993" + # the eval prevents this from breaking on system which do not have + # a proper getpwuid implemented + eval { ($T2H_USER = (getpwuid ($<))[6]) =~ s/,.*//;}; # Who am i + # APA: Provide Windows NT workaround until getpwuid gets + # implemented there. + $T2H_USER = $ENV{'USERNAME'} unless defined $T2H_USER; + &pass1(); + &pass2(); + &pass3(); + &pass4(); + &pass5(); +} + +&main(); + +############################################################################## + +# These next few lines are legal in both Perl and nroff. + +.00 ; # finish .ig + +'di \" finish diversion--previous line must be blank +.nr nl 0-1 \" fake up transition to first page again +.nr % 0 \" start at page 1 +'; __END__ ############# From here on it's a standard manual page ############ + .so /usr/share/man/man1/texi2html.1 diff --git a/doc/threads.texi b/doc/threads.texi index 6a36e08..d353f22 100644 --- a/doc/threads.texi +++ b/doc/threads.texi @@ -502,9 +502,6 @@ it on by inserting the line @code{#define MLFQS 1} in @node Threads FAQ @section FAQ -@enumerate 1 -@item General FAQs - @enumerate 1 @item @b{I am adding a new @file{.h} or @file{.c} file. How do I fix the @@ -587,7 +584,15 @@ the function isn't actually used by other @file{.c} files, make it @code{static}. @end enumerate -@item Alarm Clock FAQs +@menu +* Problem 1-1 Alarm Clock FAQ:: +* Problem 1-2 Join FAQ:: +* Problem 1-3 Priority Scheduling FAQ:: +* Problem 1-4 Advanced Scheduler FAQ:: +@end menu + +@node Problem 1-1 Alarm Clock FAQ +@subsection Problem 1-1: Alarm Clock FAQ @enumerate 1 @item @@ -630,7 +635,8 @@ values are expressed as signed 63-bit numbers, which at 100 ticks per second should be good for almost 2,924,712,087 years. @end enumerate -@item Join FAQs +@node Problem 1-2 Join FAQ +@subsection Problem 1-2: Join FAQ @enumerate 1 @item @@ -642,7 +648,8 @@ A parent joining a child that has completed should be handled gracefully and should act as a no-op. @end enumerate -@item Priority Scheduling FAQs +@node Problem 1-3 Priority Scheduling FAQ +@subsection Problem 1-3: Priority Scheduling FAQ @enumerate 1 @item @@ -768,7 +775,8 @@ its priority has been increased by a donation?} The higher (donated) priority. @end enumerate -@item Advanced Scheduler FAQs +@node Problem 1-4 Advanced Scheduler FAQ +@subsection Problem 1-4: Advanced Scheduler FAQ @enumerate 1 @item @@ -816,4 +824,3 @@ However, you are free to do so. No. Hard-coding the dispatch table values is fine. @end enumerate -@end enumerate diff --git a/doc/userprog.texi b/doc/userprog.texi index 1e18511..3601233 100644 --- a/doc/userprog.texi +++ b/doc/userprog.texi @@ -390,9 +390,6 @@ exception is a call to the @code{halt} system call. @node User Programs FAQ @section FAQ -@enumerate 1 -@item General FAQs - @enumerate 1 @item @b{Do we need a working project 1 to implement project 2?} @@ -535,7 +532,13 @@ Serial input isn't implemented. Don't use @option{-v} if you want to use the shell or otherwise type at the keyboard. @end enumerate -@item Argument Passing FAQs +@menu +* Problem 2-1 Argument Passing FAQ:: +* Problem 2-2 System Calls FAQ:: +@end menu + +@node Problem 2-1 Argument Passing FAQ +@subsection Problem 2-1: Argument Passing FAQ @enumerate 1 @item @@ -578,7 +581,8 @@ any multiple of @t{0x10000000} from @t{0x80000000} to @t{0xc0000000}, simply via recompilation. @end enumerate -@item System Calls FAQs +@node Problem 2-2 System Calls FAQ +@subsection Problem 2-2: System Calls FAQ @enumerate 1 @item @@ -606,6 +610,7 @@ maximum. That said, if your design calls for it, you may impose a limit of 128 open files per process (as the Solaris machines here do). @item +@anchor{Removing an Open File} @b{What happens when two (or more) processes have a file open and one of them removes it?} @@ -639,7 +644,6 @@ You should print the complete thread name (as specified in the @code{SYS_exec} call) followed by the exit status code, e.g.@: @samp{example 1 2 3 4: 0}. @end enumerate -@end enumerate @node 80x86 Calling Convention @section 80@var{x}86 Calling Convention diff --git a/doc/vm.texi b/doc/vm.texi index 094d182..b7f766e 100644 --- a/doc/vm.texi +++ b/doc/vm.texi @@ -8,14 +8,24 @@ multiple user programs at once. However, when loading user programs, your OS is limited by how much main memory the simulated machine has. In this assignment, you will remove that limitation. -You will be using the @file{vm} directory for this project. There is -no new code to get acquainted with for this assignment. The @file{vm} -directory contains only the @file{Makefile}s. The only change from -@file{userprog} is that this new @file{Makefile} turns on the setting -@option{-DVM}. All code you write will either be newly generated -files (e.g.@: if you choose to implement your paging code in their own -source files), or will be modifications to pre-existing code (e.g.@: -you will change the behavior of @file{process.c} significantly). +You will be using the @file{vm} directory for this project. The +@file{vm} directory contains only the @file{Makefile}s. The only +change from @file{userprog} is that this new @file{Makefile} turns on +the setting @option{-DVM}. All code you write will either be newly +generated files (e.g.@: if you choose to implement your paging code in +their own source files), or will be modifications to pre-existing code +(e.g.@: you will change the behavior of @file{process.c} +significantly). + +There are only a couple of source files you will probably be +encountering for the first time: + +@table @file +@item devices/disk.h +@itemx devices/disk.c +Provides access to the physical disk, abstracting away the rather +awful IDE interface. +@end table You will be building this assignment on the last one. It will benefit you to get your project 2 in good working order before this assignment @@ -76,14 +86,21 @@ that the page must be brought in from a disk file or from swap. You will have to implement a more sophisticated page fault handler to handle these cases. -On the 80@var{x}86, the page table format is fixed by hardware. The -top-level data structure is a 4 kB page called the ``page directory'' -(PD) arranged as an array of 1,024 32-bit page directory entries -(PDEs), each of which represents 4 MB of virtual memory. Each PDE may -point to the physical address of another 4 kB page called a ``page -table'' (PT) arranged in the same fashion as an array of 1,024 32-bit -page table entries (PTEs), each of which translates a single 4 kB -virtual page into physical memory. +On the 80@var{x}86, the page table format is fixed by hardware. We +have provided code for managing page tables for you to use in +@file{userprog/pagedir.c}. The functions in there should provide an +abstract interface to all the page table functionality that you need +to complete the project. However, you may still find it worthwhile to +understand a little about the hardware page table format, so we'll go +into a little of detail about that in this section. + +The top-level paging data structure is a 4 kB page called the ``page +directory'' (PD) arranged as an array of 1,024 32-bit page directory +entries (PDEs), each of which represents 4 MB of virtual memory. Each +PDE may point to the physical address of another 4 kB page called a +``page table'' (PT) arranged in the same fashion as an array of 1,024 +32-bit page table entries (PTEs), each of which translates a single 4 +kB virtual page into physical memory. Thus, translation of a virtual address into a physical address follows the three-step process illustrated in the diagram @@ -224,9 +241,9 @@ In project 2, the stack was a single page at the top of the user virtual address space. The stack's location does not change in this project, but your kernel should allocate additional pages to the stack on demand. That is, if the stack grows past its current bottom, the -system should allocate additional pages for the stack as necessary, -unless those pages are unavailable because they are in use by another -segment, in which case some sort of fault should occur. +system should allocate additional pages for the stack as necessary +(unless those pages are unavailable because they are in use by another +segment). @node Problem 3-1 Page Table Management @section Problem 3-1: Page Table Management @@ -238,8 +255,8 @@ tasks: @itemize @bullet @item Some way of translating in software from virtual page frames to -physical page frames (consider using a hash table---note -that we provide one in @file{lib/kernel}). +physical page frames. Consider using a hash table (@pxref{Hash +Table}). @item Some way of translating from physical page frames back to virtual @@ -252,7 +269,8 @@ need this data structure until part 2, but planning ahead is a good idea. @end itemize -You need to do the roughly the following to handle a page fault: +The page fault handler, @code{page_fault()} in +@file{threads/exception.c}, needs to do roughly the following: @enumerate 1 @item @@ -274,19 +292,8 @@ If necessary to make room, first evict some other page from memory. any page table that refers to it.) @item -Each user process's @code{struct thread} has a @samp{pagedir} member -that points to its own per-process page directory. Read the PDE for -the faulting virtual address. - -@item -If the PDE is marked ``not present'' then allocate a new page table -page and initialize the PDE to point to the new page table. As when -you allocated a data page, you might have to first evict some other -page from memory. - -@item -Follow the PDE to the page table. Point the PTE for the faulting -virtual address to the physical page found in step 2. +Point the page table entry for the faulting virtual address to the +physical page. You can use the functions in @file{userprog/pagedir.c}. @end enumerate You'll need to modify the ELF loader in @file{userprog/process.c} to @@ -298,14 +305,14 @@ use your new page table management code to construct the page tables only as page faults occur for them. There are many possible ways to implement virtual memory. The above -is simply an outline of our suggested implementation. You may choose -any implementation you like, as long as it accomplishes the goal. +is simply an outline of our suggested implementation. @node Problem 3-2 Paging To and From Disk @section Problem 3-2: Paging To and From Disk Implement paging to and from files and the swap disk. You may use the -disk on interface @code{hd1:1} as the swap disk. +disk on interface @code{hd1:1} as the swap disk, using the disk +interface prototyped in @code{devices/disk.h}. You will need routines to move a page from memory to disk and from disk to memory, where ``disk'' is either a file or the swap disk. If @@ -322,16 +329,17 @@ structures that you designed in part 1 should do most of the work for you. You will need a page replacement algorithm. The hardware sets the -accessed and dirty bits when it accesses memory. Therefore, you -should be able to take advantage of this information to implement some -algorithm which attempts to achieve LRU-type behavior. We expect that -your algorithm perform at least as well as a reasonable implementation -of the second-chance (clock) algorithm. You will need to show in your -test cases the value of your page replacement algorithm by -demonstrating for some workload that it pages less frequently using -your algorithm than using some inferior page replacement policy. The -canonical example of a poor page replacement policy is random -replacement. +accessed and dirty bits when it accesses memory. You can gain access +this information using the functions prototyped in +@file{userprog/pagedir.h}. You should be able to take advantage of +this information to implement some algorithm which attempts to achieve +LRU-type behavior. We expect that your algorithm perform at least as +well as a reasonable implementation of the second-chance (clock) +algorithm. You will need to show in your test cases the value of your +page replacement algorithm by demonstrating for some workload that it +pages less frequently using your algorithm than using some inferior +page replacement policy. The canonical example of a poor page +replacement policy is random replacement. Since you will already be paging from disk, you should implement a ``lazy'' loading scheme for new processes. When a process is created, @@ -366,11 +374,11 @@ first page fault. @item If neither @code{read_bytes} nor @code{zero_bytes} equals @code{PGSIZE}, then part of the page is to be read from disk and the -remainder zeroed. This is a special case. You may handle it by -reading the partial page from disk at executable load time and zeroing -the rest of the page. This is the only case in which we will allow -you to load a page in a non-``lazy'' fashion. Many real OSes such as -Linux do not load partial pages lazily. +remainder zeroed. This is a special case. You are allowed to handle +it by reading the partial page from disk at executable load time and +zeroing the rest of the page. This is the only case in which we will +allow you to load a page in a non-``lazy'' fashion. Many real OSes +such as Linux do not load partial pages lazily. @end itemize Incidentally, if you have trouble handling the third case above, you @@ -379,9 +387,9 @@ special ``linker script.'' Read @file{tests/userprog/Makefile} for details. We will not test your submission with this special linker script, so the code you turn in must properly handle all cases. -You may optionally implement sharing: when multiple processes are -created that use the same executable file, share read-only pages among -those processes instead of creating separate copies of read-only +For extra credit, you may implement sharing: when multiple processes +are created that use the same executable file, share read-only pages +among those processes instead of creating separate copies of read-only segments for each process. If you carefully designed your data structures in part 1, sharing of read-only pages should not make this part significantly harder. @@ -393,7 +401,7 @@ Implement memory mapped files. You will need to implement the following system calls: -@table @asis +@table @code @item SYS_mmap @itemx bool mmap (int @var{fd}, void *@var{addr}, unsigned @var{length}) @@ -412,17 +420,18 @@ list of used virtual pages. @end table Calls to @code{mmap} must fail if the address is not page-aligned, if -the length is not positive and a multiple of @var{PGSIZE}. You also -must error check to make sure that the new segment does not overlap -already existing segments, and fail if it isn't. If the length passed -to @code{mmap} is less than the file's length, you should only map the -first part of the file. If the length passed to @code{mmap} is longer -than the file, the file should grow to the requested length. Similar -to the code segment, your VM system should be able to use the -@code{mmap}'d file itself as backing store for the mmap segment, since -the changes to the @code{mmap} segment will eventually be written to -the file. (In fact, you may choose to implement executable mappings -as a special case of file mappings.) +the length is not positive, or if the length is not a multiple of +@code{PGSIZE}. You also must error check to make sure that the new +segment does not overlap already existing segments, and fail if it +does. If the length passed to @code{mmap} is less than the file's +length, you should only map the first part of the file. If the length +passed to @code{mmap} is longer than the file, the call should fail. +(Ideally it should extend the file, but our file system does not yet +support growing files.) Similar to the code segment, your VM system +should be able to use the @code{mmap}'d file itself as backing store +for the mapped segment, since the changes to the @code{mmap} segment +will eventually be written to the file. (In fact, you may choose to +implement executable mappings as a special case of file mappings.) @node Virtual Memory FAQ @section FAQ @@ -434,6 +443,7 @@ as a special case of file mappings.) Yes. @item +@anchor{Hash Table} @b{How do I use the hash table provided in @file{lib/kernel/hash.c}?} First, you need to embed a @code{hash_elem} object as a member of the @@ -504,6 +514,24 @@ If you have any other questions about hash tables, the CS109 and CS161 textbooks have good chapters on them, or you can come to any of the TA's office hours for further clarification. +@item +@b{What are the @var{aux} parameters to the hash table functions good +for?} + +In simple cases you won't have any need for the @var{aux} parameters. +In these cases you can just pass a null pointer to @code{hash_init()} +for @var{aux} and ignore the values passed to the hash function and +comparison functions. (You'll get a compiler warning if you don't use +the @var{aux} parameter, but you can turn that off with the +@code{UNUSED} macro, as shown above, or you can just ignore it.) + +@var{aux} is useful when you have some property of the data in the +hash table that's both constant and needed for hashing or comparisons, +but which is not stored in the data items themselves. For example, if +the items in a hash table contain fixed-length strings, but the items +themselves don't indicate what that fixed length is, you could pass +the length as an @var{aux} parameter. + @item @b{The current implementation of the hash table does not do something that we need it to do. What gives?} @@ -517,33 +545,18 @@ whatever it takes to make it work the way you want. The linker is responsible for the layout of a user program in memory. The linker is directed by a ``linker script'' which tells it -the names and locations of the various program segments. The -test/script and testvm/script files are the linker scripts for the -multiprogramming and virtual memory assignments respectively. You can +the names and locations of the various program segments. You can learn more about linker scripts by reading the ``Scripts'' chapter in the linker manual, accessible via @samp{info ld}. - -@item Page Table Management FAQs -@enumerate 1 -@item -@b{Do page tables need to created lazily?} - -No. You can create the page tables at load time (or @code{mmap} -time). Real OSes often manage their page tables lazily, but it's just -an unneeded complication for our purposes. - -@item -@b{Our code handles the PageFault exceptions. However, the number of -page faults handled does not show up in the final stats output. Is -there a counter that we must increment to correct this problem?} - -FIXME - -Yes, you'll need to update kernel->stats->numPageFaults when -you handle a page fault in your code. @end enumerate -@item Paging FAQs +@menu +* Problem 3-1 and 3-2 FAQ:: +* Problem 3-3 Memory Mapped File FAQ:: +@end menu + +@node Problem 3-1 and 3-2 FAQ +@subsection Problem 3-1 and 3-2 FAQ @enumerate 1 @item @@ -570,9 +583,8 @@ segment?} No. The size of the data segment is determined by the linker. We still have no dynamic allocation in Pintos (although it is possible to -``fake'' it at the user level by using memory-mapped files). -Implementing @code{sbrk()} has been an extra-credit assignment in -previous years, but adds little additional complexity to a +``fake'' it at the user level by using memory-mapped files). However, +implementing it would add little additional complexity to a well-designed system. @item @@ -587,17 +599,10 @@ heuristic to figure this out. Make a reasonable decision and document it in your code and in your design document. Please make sure to justify your decision. - -@item -@b{How big should the file(s) we're using as a backing store for memory -be?} - -These files will need to be able to grow based on the number of pages -you're committed to storing on behalf of the processes currently in -memory. They should be able to grow to the full size of the disk. @end enumerate -@item Memory Mapped File FAQs +@node Problem 3-3 Memory Mapped File FAQ +@subsection Problem 3-3: Memory Mapped File FAQ @enumerate 1 @item @@ -605,7 +610,7 @@ memory. They should be able to grow to the full size of the disk. Let's say you want to map a file called @file{foo} into your address space at address @t{0x10000000}. You open the file, determine its -length, and then use Mmap: +length, and then use @code{mmap}: @example #include @@ -659,19 +664,18 @@ private (i.e.@: copy-on-write). @item @b{What happens if a user removes a @code{mmap}'d file?} -@item You should follow the Unix convention and the mapping should still be -valid. This is similar to the question in the User Programs FAQ about -a process with a file descriptor to a file that has been removed. +valid. @xref{Removing an Open File}, for more information. @item @b{What if a process writes to a page that is memory-mapped, but the location written to in the memory-mapped page is past the end of the memory-mapped file?} -Can't happen. @code{mmap} extends the file to the requested length, -and Pintos provides no way to shorten a file. You can remove a file, -but the mapping remains valid (see the previous question). +Can't happen. @code{mmap} checks that the mapped region is within the +file's length and Pintos provides no way to shorten a file. (Until +project 4, there's no way to extend a file either.) You can remove a +file, but the mapping remains valid (see the previous question). @item @b{Do we have to handle memory mapping @code{stdin} or @code{stdout}?} @@ -682,18 +686,17 @@ neither of these properties, @code{mmap} should return false when the user attempts to memory map a file descriptor for the console device. @item -@b{What happens when a process exits with mmap'd files?} +@b{What happens when a process exits with mapped files?} -When a process finishes each of its @code{mmap}'d files is implicitly +When a process finishes, each of its mapped files is implicitly unmapped. When a process @code{mmap}s a file and then writes into the area for the file it is making the assumption the changes will be written to the file. @item -@b{If a user closes a mmaped file, should be automatically unmap it -for them?} +@b{If a user closes a mapped file, should it be automatically +unmapped?} No, once created the mapping is valid until @code{munmap} is called or the process exits. @end enumerate -@end enumerate -- 2.30.2
    ' . + &t2h_anchor('', $href, $entry) . + '  ' . + $descr . + "
    ' . + $entry . + '' . $descr . + "