diff options
Diffstat (limited to 'build-aux')
-rwxr-xr-x | build-aux/compile | 142 | ||||
-rwxr-xr-x | build-aux/config.guess | 1533 | ||||
-rwxr-xr-x | build-aux/config.rpath | 672 | ||||
-rwxr-xr-x | build-aux/config.sub | 1693 | ||||
-rwxr-xr-x | build-aux/depcomp | 589 | ||||
-rwxr-xr-x | build-aux/fixaclocal | 35 | ||||
-rwxr-xr-x | build-aux/install-sh | 519 | ||||
-rw-r--r-- | build-aux/link-warning.h | 28 | ||||
-rw-r--r-- | build-aux/ltmain.sh | 8526 | ||||
-rwxr-xr-x | build-aux/mdate-sh | 205 | ||||
-rwxr-xr-x | build-aux/missing | 367 | ||||
-rwxr-xr-x | build-aux/run-test | 139 | ||||
-rwxr-xr-x | build-aux/texi2html | 19554 | ||||
-rw-r--r-- | build-aux/texinfo.tex | 8997 | ||||
-rwxr-xr-x | build-aux/windres-options | 45 |
15 files changed, 43044 insertions, 0 deletions
diff --git a/build-aux/compile b/build-aux/compile new file mode 100755 index 00000000..1b1d2321 --- /dev/null +++ b/build-aux/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey <tromey@cygnus.com>. +# +# 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/build-aux/config.guess b/build-aux/config.guess new file mode 100755 index 00000000..e3a2116a --- /dev/null +++ b/build-aux/config.guess @@ -0,0 +1,1533 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-10' + +# This file 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., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner <per@bothner.com>. +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd | genuineintel) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +and + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build-aux/config.rpath b/build-aux/config.rpath new file mode 100755 index 00000000..85c2f209 --- /dev/null +++ b/build-aux/config.rpath @@ -0,0 +1,672 @@ +#! /bin/sh +# Output a system dependent set of variables, describing how to set the +# run time search path of shared libraries in an executable. +# +# Copyright 1996-2008 Free Software Foundation, Inc. +# Taken from GNU libtool, 2001 +# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# The first argument passed to this file is the canonical host specification, +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# The environment variables CC, GCC, LDFLAGS, LD, with_gnu_ld +# should be set by the caller. +# +# The set of defined variables is at the end of this script. + +# Known limitations: +# - On IRIX 6.5 with CC="cc", the run time search patch must not be longer +# than 256 bytes, otherwise the compiler driver will dump core. The only +# known workaround is to choose shorter directory names for the build +# directory and/or the installation directory. + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +shrext=.so + +host="$1" +host_cpu=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo "$host" | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +# Code taken from libtool.m4's _LT_CC_BASENAME. + +for cc_temp in $CC""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'` + +# Code taken from libtool.m4's _LT_COMPILER_PIC. + +wl= +if test "$GCC" = yes; then + wl='-Wl,' +else + case "$host_os" in + aix*) + wl='-Wl,' + ;; + darwin*) + case $cc_basename in + xlc*) + wl='-Wl,' + ;; + esac + ;; + mingw* | cygwin* | pw32* | os2* | cegcc*) + ;; + hpux9* | hpux10* | hpux11*) + wl='-Wl,' + ;; + irix5* | irix6* | nonstopux*) + wl='-Wl,' + ;; + newsos6) + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + ecc*) + wl='-Wl,' + ;; + icc* | ifort*) + wl='-Wl,' + ;; + lf95*) + wl='-Wl,' + ;; + pgcc | pgf77 | pgf90) + wl='-Wl,' + ;; + ccc*) + wl='-Wl,' + ;; + como) + wl='-lopt=' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + wl='-Wl,' + ;; + esac + ;; + esac + ;; + osf3* | osf4* | osf5*) + wl='-Wl,' + ;; + rdos*) + ;; + solaris*) + wl='-Wl,' + ;; + sunos4*) + wl='-Qoption ld ' + ;; + sysv4 | sysv4.2uw2* | sysv4.3*) + wl='-Wl,' + ;; + sysv4*MP*) + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + wl='-Wl,' + ;; + unicos*) + wl='-Wl,' + ;; + uts4*) + ;; + esac +fi + +# Code taken from libtool.m4's _LT_LINKER_SHLIBS. + +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no + +case "$host_os" in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + # Unlike libtool, we use -rpath here, not --rpath, since the documented + # option of GNU ld is called -rpath, not --rpath. + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + case "$host_os" in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # Samuel A. Falvo II <kc5tja@dolphin.openprojects.net> reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we cannot use + # them. + ld_shlibs=no + ;; + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + cygwin* | mingw* | pw32* | cegcc*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + interix[3-9]*) + hardcode_direct=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + gnu* | linux* | k*bsd*-gnu) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + netbsd*) + ;; + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + else + ld_shlibs=no + fi + ;; + esac + ;; + sunos4*) + hardcode_direct=yes + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + : + else + ld_shlibs=no + fi + ;; + esac + if test "$ld_shlibs" = no; then + hardcode_libdir_flag_spec= + fi +else + case "$host_os" in + aix3*) + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + else + aix_use_runtimelinking=no + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + fi + hardcode_direct=yes + hardcode_libdir_separator=':' + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + fi + # Begin _LT_AC_SYS_LIBPATH_AIX. + echo 'int main () { return 0; }' > conftest.c + ${CC} ${LDFLAGS} conftest.c -o conftest + aix_libpath=`dump -H conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest 2>/dev/null | sed -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` + fi + if test -z "$aix_libpath"; then + aix_libpath="/usr/lib:/lib" + fi + rm -f conftest.c conftest + # End _LT_AC_SYS_LIBPATH_AIX. + if test "$aix_use_runtimelinking" = yes; then + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + else + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + fi + fi + ;; + amigaos*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + bsdi[45]*) + ;; + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + libext=lib + ;; + darwin* | rhapsody*) + hardcode_direct=no + if test "$GCC" = yes ; then + : + else + case $cc_basename in + xlc*) + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + freebsd1*) + ld_shlibs=no + ;; + freebsd2.2*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + freebsd2*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; + freebsd* | dragonfly*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + hpux9*) + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + hpux10*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + hpux11*) + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + ;; + *) + hardcode_direct=yes + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + irix5* | irix6* | nonstopux*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + netbsd*) + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + ;; + newsos6) + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + else + case "$host_os" in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + osf3*) + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + osf4* | osf5*) + if test "$GCC" = yes; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + # Both cc and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + solaris*) + hardcode_libdir_flag_spec='-R$libdir' + ;; + sunos4*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + ;; + sysv4) + case $host_vendor in + sni) + hardcode_direct=yes # is this really true??? + ;; + siemens) + hardcode_direct=no + ;; + motorola) + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + ;; + sysv4.3*) + ;; + sysv4*MP*) + if test -d /usr/nec; then + ld_shlibs=yes + fi + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + ;; + sysv5* | sco3.2v5* | sco5v6*) + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + ;; + uts4*) + hardcode_libdir_flag_spec='-L$libdir' + ;; + *) + ld_shlibs=no + ;; + esac +fi + +# Check dynamic linker characteristics +# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER. +# Unlike libtool.m4, here we don't care about _all_ names of the library, but +# only about the one the linker finds when passed -lNAME. This is the last +# element of library_names_spec in libtool.m4, or possibly two of them if the +# linker has special search rules. +library_names_spec= # the last element of library_names_spec in libtool.m4 +libname_spec='lib$name' +case "$host_os" in + aix3*) + library_names_spec='$libname.a' + ;; + aix[4-9]*) + library_names_spec='$libname$shrext' + ;; + amigaos*) + library_names_spec='$libname.a' + ;; + beos*) + library_names_spec='$libname$shrext' + ;; + bsdi[45]*) + library_names_spec='$libname$shrext' + ;; + cygwin* | mingw* | pw32* | cegcc*) + shrext=.dll + library_names_spec='$libname.dll.a $libname.lib' + ;; + darwin* | rhapsody*) + shrext=.dylib + library_names_spec='$libname$shrext' + ;; + dgux*) + library_names_spec='$libname$shrext' + ;; + freebsd1*) + ;; + freebsd* | dragonfly*) + case "$host_os" in + freebsd[123]*) + library_names_spec='$libname$shrext$versuffix' ;; + *) + library_names_spec='$libname$shrext' ;; + esac + ;; + gnu*) + library_names_spec='$libname$shrext' + ;; + hpux9* | hpux10* | hpux11*) + case $host_cpu in + ia64*) + shrext=.so + ;; + hppa*64*) + shrext=.sl + ;; + *) + shrext=.sl + ;; + esac + library_names_spec='$libname$shrext' + ;; + interix[3-9]*) + library_names_spec='$libname$shrext' + ;; + irix5* | irix6* | nonstopux*) + library_names_spec='$libname$shrext' + case "$host_os" in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= ;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 ;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 ;; + *) libsuff= shlibsuff= ;; + esac + ;; + esac + ;; + linux*oldld* | linux*aout* | linux*coff*) + ;; + linux* | k*bsd*-gnu) + library_names_spec='$libname$shrext' + ;; + knetbsd*-gnu) + library_names_spec='$libname$shrext' + ;; + netbsd*) + library_names_spec='$libname$shrext' + ;; + newsos6) + library_names_spec='$libname$shrext' + ;; + nto-qnx*) + library_names_spec='$libname$shrext' + ;; + openbsd*) + library_names_spec='$libname$shrext$versuffix' + ;; + os2*) + libname_spec='$name' + shrext=.dll + library_names_spec='$libname.a' + ;; + osf3* | osf4* | osf5*) + library_names_spec='$libname$shrext' + ;; + rdos*) + ;; + solaris*) + library_names_spec='$libname$shrext' + ;; + sunos4*) + library_names_spec='$libname$shrext$versuffix' + ;; + sysv4 | sysv4.3*) + library_names_spec='$libname$shrext' + ;; + sysv4*MP*) + library_names_spec='$libname$shrext' + ;; + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + library_names_spec='$libname$shrext' + ;; + uts4*) + library_names_spec='$libname$shrext' + ;; +esac + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"` +shlibext=`echo "$shrext" | sed -e 's,^\.,,'` +escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` +escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"` + +LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF + +# How to pass a linker flag through the compiler. +wl="$escaped_wl" + +# Static library suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally "so"). +shlibext="$shlibext" + +# Format of library name prefix. +libname_spec="$escaped_libname_spec" + +# Library names that the linker finds when passed -lNAME. +library_names_spec="$escaped_library_names_spec" + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec" + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator="$hardcode_libdir_separator" + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct="$hardcode_direct" + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L="$hardcode_minus_L" + +EOF diff --git a/build-aux/config.sub b/build-aux/config.sub new file mode 100755 index 00000000..eb0389a6 --- /dev/null +++ b/build-aux/config.sub @@ -0,0 +1,1693 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-11' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/build-aux/depcomp b/build-aux/depcomp new file mode 100755 index 00000000..e5f9736c --- /dev/null +++ b/build-aux/depcomp @@ -0,0 +1,589 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2007-03-29.01 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/build-aux/fixaclocal b/build-aux/fixaclocal new file mode 100755 index 00000000..10ff8e41 --- /dev/null +++ b/build-aux/fixaclocal @@ -0,0 +1,35 @@ +#!/bin/sh +# Script for fixing aclocal.m4 files produced by 'aclocal' from automake 1.10. +# Copyright (C) 2006, 2008 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 3 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, see <http://www.gnu.org/licenses/>. + +# Usage: fixaclocal aclocal [OPTIONS] + +"$@" +result=$? +if test $result = 0 && test -f aclocal.m4; then + # Remove the block of 4 lines starting with 'm4_if(m4_PACKAGE_VERSION' + # and the block of 5 lines starting with 'm4_if(AC_AUTOCONF_VERSION' + # (automake <= 1.10.1) or with 'm4_if(m4_defn([AC_AUTOCONF_VERSION])' + # (automake >= 1.10.2). + sed -e '/m4_if(m4_PACKAGE_VERSION/{N;N;N;d}' -e '/m4_if(AC_AUTOCONF_VERSION/{N;N;N;N;d}' -e '/m4_if(m4_defn(\[AC_AUTOCONF_VERSION\])/{N;N;N;N;d}' < aclocal.m4 > aclocal.m4.tmp + if cmp aclocal.m4 aclocal.m4.tmp > /dev/null; then + rm -f aclocal.m4.tmp + else + mv aclocal.m4.tmp aclocal.m4 + fi +else + exit $result +fi diff --git a/build-aux/install-sh b/build-aux/install-sh new file mode 100755 index 00000000..a5897de6 --- /dev/null +++ b/build-aux/install-sh @@ -0,0 +1,519 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2006-12-25.00 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/build-aux/link-warning.h b/build-aux/link-warning.h new file mode 100644 index 00000000..fda01941 --- /dev/null +++ b/build-aux/link-warning.h @@ -0,0 +1,28 @@ +/* GL_LINK_WARNING("literal string") arranges to emit the literal string as + a linker warning on most glibc systems. + We use a linker warning rather than a preprocessor warning, because + #warning cannot be used inside macros. */ +#ifndef GL_LINK_WARNING + /* This works on platforms with GNU ld and ELF object format. + Testing __GLIBC__ is sufficient for asserting that GNU ld is in use. + Testing __ELF__ guarantees the ELF object format. + Testing __GNUC__ is necessary for the compound expression syntax. */ +# if defined __GLIBC__ && defined __ELF__ && defined __GNUC__ +# define GL_LINK_WARNING(message) \ + GL_LINK_WARNING1 (__FILE__, __LINE__, message) +# define GL_LINK_WARNING1(file, line, message) \ + GL_LINK_WARNING2 (file, line, message) /* macroexpand file and line */ +# define GL_LINK_WARNING2(file, line, message) \ + GL_LINK_WARNING3 (file ":" #line ": warning: " message) +# define GL_LINK_WARNING3(message) \ + ({ static const char warning[sizeof (message)] \ + __attribute__ ((__unused__, \ + __section__ (".gnu.warning"), \ + __aligned__ (1))) \ + = message "\n"; \ + (void)0; \ + }) +# else +# define GL_LINK_WARNING(message) ((void) 0) +# endif +#endif diff --git a/build-aux/ltmain.sh b/build-aux/ltmain.sh new file mode 100644 index 00000000..271873d3 --- /dev/null +++ b/build-aux/ltmain.sh @@ -0,0 +1,8526 @@ +# Generated from ltmain.m4sh. + +# ltmain.sh (GNU libtool) 2.2.6 +# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool 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. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print informational messages (default) +# --version print version information +# -h, --help print short or long help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.6 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to <bug-libtool@gnu.org>. + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=2.2.6 +TIMESTAMP="" +package_revision=1.3012 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + +: ${CP="cp -f"} +: ${ECHO="echo"} +: ${EGREP="/usr/bin/grep -E"} +: ${FGREP="/usr/bin/grep -F"} +: ${GREP="/usr/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/opt/local/bin/gsed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +# Generated shell functions inserted here. + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +# In the unlikely event $progname began with a '-', it would play havoc with +# func_echo (imagine progname=-n), so we prepend ./ in that case: +func_dirname_and_basename "$progpath" +progname=$func_basename_result +case $progname in + -*) progname=./$progname ;; +esac + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + done + my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "X$my_tmpdir" | $Xsed +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "X$1" | $Xsed \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/# -h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + $ECHO + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help +# Echo long help message to standard output and exit. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + exit $? +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + +# Check that we have a working $ECHO. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell, and then maybe $ECHO will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF +$* +EOF + exit $EXIT_SUCCESS +fi + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +# $mode is unset +nonopt= +execute_dlfiles= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +opt_dry_run=false +opt_duplicate_deps=false +opt_silent=false +opt_debug=: + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + $ECHO "host: $host" + if test "$build_libtool_libs" = yes; then + $ECHO "enable shared libraries" + else + $ECHO "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $ECHO "enable static libraries" + else + $ECHO "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case "$@ " in + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <<EOF +# $write_libobj - a libtool object file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object=$write_lobj + +# Name of the non-PIC object +non_pic_object=$write_oldobj + +EOF + $MV "${write_libobj}T" "${write_libobj}" + } +} + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + pie_flag="$pie_flag $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_quote_for_eval "$arg" + lastarg="$lastarg $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_quote_for_eval "$lastarg" + base_compile="$base_compile $func_quote_for_eval_result" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.obj | *.sx) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { +test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + $ECHO + $ECHO "Try \`$progname --help' for more information about other modes." + + exit $? +} + + # Now that we've collected a possible --mode arg, show help if necessary + $opt_help && func_mode_help + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + $ECHO "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + $ECHO "X----------------------------------------------------------------------" | $Xsed + $ECHO "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + $ECHO + $ECHO "If you ever happen to want to link against installed libraries" + $ECHO "in a given directory, LIBDIR, you must either use libtool, and" + $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" + $ECHO "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" + $ECHO " during execution" + fi + if test -n "$runpath_var"; then + $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" + $ECHO " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $ECHO + + $ECHO "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" + $ECHO "pages." + ;; + *) + $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + $ECHO "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 </dev/null >/dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + $ECHO >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + $ECHO >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + $ECHO >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + $ECHO >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + + +# func_emit_wrapper_part1 [arg=no] +# +# Emit the first part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part1 () +{ + func_emit_wrapper_part1_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part1_arg1=$1 + fi + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + ECHO=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$ECHO works! + : + else + # Restart under the correct shell, and then maybe \$ECHO will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $ECHO "\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done +" +} +# end: func_emit_wrapper_part1 + +# func_emit_wrapper_part2 [arg=no] +# +# Emit the second part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part2 () +{ + func_emit_wrapper_part2_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part2_arg1=$1 + fi + + $ECHO "\ + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} +# end: func_emit_wrapper_part2 + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=no + if test -n "$1" ; then + func_emit_wrapper_arg1=$1 + fi + + # split this up so that func_emit_cwrapperexe_src + # can call each part independently. + func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" + func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_path_tmp1=`( cmd //c echo "$1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_tmp1=`cygpath -w "$1"` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result="" + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_to_host_pathlist_tmp2="$1" + # Once set for this call, this variable should not be + # reassigned. It is used in tha fallback case. + func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e 's|^:*||' -e 's|:*$||'` + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" + fi + fi + fi + IFS=: + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result" ; then + func_error "Could not determine the host path(s) corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat <<EOF + +/* $cwrappersource - temporary wrapper executable for $objdir/$outputname + Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION + + The $output program cannot be directly executed until all the libtool + libraries that it depends on are installed. + + This wrapper executable should never be moved out of the build directory. + If it is, it will not operate correctly. + + Currently, it simply execs the wrapper *script* "$SHELL $output", + but could eventually absorb all of the scripts functionality and + exec $objdir/$outputname directly. +*/ +EOF + cat <<"EOF" +#include <stdio.h> +#include <stdlib.h> +#ifdef _MSC_VER +# include <direct.h> +# include <process.h> +# include <io.h> +# define setmode _setmode +#else +# include <unistd.h> +# include <stdint.h> +# ifdef __CYGWIN__ +# include <io.h> +# define HAVE_SETENV +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +# endif +#endif +#include <malloc.h> +#include <stdarg.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +#ifdef _MSC_VER +# define S_IXUSR _S_IEXEC +# define stat _stat +# ifndef _INTPTR_T_DEFINED +# define intptr_t int +# endif +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifdef __CYGWIN__ +# define FOPEN_WB "wb" +#endif + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_opt_process_env_set (const char *arg); +void lt_opt_process_env_prepend (const char *arg); +void lt_opt_process_env_append (const char *arg); +int lt_split_name_value (const char *arg, char** name, char** value); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); + +static const char *script_text_part1 = +EOF + + func_emit_wrapper_part1 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + cat <<EOF + +static const char *script_text_part2 = +EOF + func_emit_wrapper_part2 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + + cat <<EOF +const char * MAGIC_EXE = "$magic_exe"; +const char * LIB_PATH_VARNAME = "$shlibpath_var"; +EOF + + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + func_to_host_pathlist "$temp_rpath" + cat <<EOF +const char * LIB_PATH_VALUE = "$func_to_host_pathlist_result"; +EOF + else + cat <<"EOF" +const char * LIB_PATH_VALUE = ""; +EOF + fi + + if test -n "$dllsearchpath"; then + func_to_host_pathlist "$dllsearchpath:" + cat <<EOF +const char * EXE_PATH_VARNAME = "PATH"; +const char * EXE_PATH_VALUE = "$func_to_host_pathlist_result"; +EOF + else + cat <<"EOF" +const char * EXE_PATH_VARNAME = ""; +const char * EXE_PATH_VALUE = ""; +EOF + fi + + if test "$fast_install" = yes; then + cat <<EOF +const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */ +EOF + else + cat <<EOF +const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */ +EOF + fi + + + cat <<"EOF" + +#define LTWRAPPER_OPTION_PREFIX "--lt-" +#define LTWRAPPER_OPTION_PREFIX_LENGTH 5 + +static const size_t opt_prefix_len = LTWRAPPER_OPTION_PREFIX_LENGTH; +static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX; + +static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script"; + +static const size_t env_set_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 7; +static const char *env_set_opt = LTWRAPPER_OPTION_PREFIX "env-set"; + /* argument is putenv-style "foo=bar", value of foo is set to bar */ + +static const size_t env_prepend_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 11; +static const char *env_prepend_opt = LTWRAPPER_OPTION_PREFIX "env-prepend"; + /* argument is putenv-style "foo=bar", new value of foo is bar${foo} */ + +static const size_t env_append_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 10; +static const char *env_append_opt = LTWRAPPER_OPTION_PREFIX "env-append"; + /* argument is putenv-style "foo=bar", new value of foo is ${foo}bar */ + +int +main (int argc, char *argv[]) +{ + char **newargz; + int newargc; + char *tmp_pathspec; + char *actual_cwrapper_path; + char *actual_cwrapper_name; + char *target_name; + char *lt_argv_zero; + intptr_t rval = 127; + + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + LTWRAPPER_DEBUGPRINTF (("(main) argv[0] : %s\n", argv[0])); + LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name)); + + /* very simple arg parsing; don't want to rely on getopt */ + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], dumpscript_opt) == 0) + { +EOF + case "$host" in + *mingw* | *cygwin* ) + # make stdout use "unix" line endings + echo " setmode(1,_O_BINARY);" + ;; + esac + + cat <<"EOF" + printf ("%s", script_text_part1); + printf ("%s", script_text_part2); + return 0; + } + } + + newargz = XMALLOC (char *, argc + 1); + tmp_pathspec = find_executable (argv[0]); + if (tmp_pathspec == NULL) + lt_fatal ("Couldn't find %s", argv[0]); + LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n", + tmp_pathspec)); + + actual_cwrapper_path = chase_symlinks (tmp_pathspec); + LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n", + actual_cwrapper_path)); + XFREE (tmp_pathspec); + + actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path)); + strendzap (actual_cwrapper_path, actual_cwrapper_name); + + /* wrapper name transforms */ + strendzap (actual_cwrapper_name, ".exe"); + tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1); + XFREE (actual_cwrapper_name); + actual_cwrapper_name = tmp_pathspec; + tmp_pathspec = 0; + + /* target_name transforms -- use actual target program name; might have lt- prefix */ + target_name = xstrdup (base_name (TARGET_PROGRAM_NAME)); + strendzap (target_name, ".exe"); + tmp_pathspec = lt_extend_str (target_name, ".exe", 1); + XFREE (target_name); + target_name = tmp_pathspec; + tmp_pathspec = 0; + + LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n", + target_name)); +EOF + + cat <<EOF + newargz[0] = + XMALLOC (char, (strlen (actual_cwrapper_path) + + strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1)); + strcpy (newargz[0], actual_cwrapper_path); + strcat (newargz[0], "$objdir"); + strcat (newargz[0], "/"); +EOF + + cat <<"EOF" + /* stop here, and copy so we don't have to do this twice */ + tmp_pathspec = xstrdup (newargz[0]); + + /* do NOT want the lt- prefix here, so use actual_cwrapper_name */ + strcat (newargz[0], actual_cwrapper_name); + + /* DO want the lt- prefix here if it exists, so use target_name */ + lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1); + XFREE (tmp_pathspec); + tmp_pathspec = NULL; +EOF + + case $host_os in + mingw*) + cat <<"EOF" + { + char* p; + while ((p = strchr (newargz[0], '\\')) != NULL) + { + *p = '/'; + } + while ((p = strchr (lt_argv_zero, '\\')) != NULL) + { + *p = '/'; + } + } +EOF + ;; + esac + + cat <<"EOF" + XFREE (target_name); + XFREE (actual_cwrapper_path); + XFREE (actual_cwrapper_name); + + lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */ + lt_setenv ("DUALCASE", "1"); /* for MSK sh */ + lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE); + lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE); + + newargc=0; + for (i = 1; i < argc; i++) + { + if (strncmp (argv[i], env_set_opt, env_set_opt_len) == 0) + { + if (argv[i][env_set_opt_len] == '=') + { + const char *p = argv[i] + env_set_opt_len + 1; + lt_opt_process_env_set (p); + } + else if (argv[i][env_set_opt_len] == '\0' && i + 1 < argc) + { + lt_opt_process_env_set (argv[++i]); /* don't copy */ + } + else + lt_fatal ("%s missing required argument", env_set_opt); + continue; + } + if (strncmp (argv[i], env_prepend_opt, env_prepend_opt_len) == 0) + { + if (argv[i][env_prepend_opt_len] == '=') + { + const char *p = argv[i] + env_prepend_opt_len + 1; + lt_opt_process_env_prepend (p); + } + else if (argv[i][env_prepend_opt_len] == '\0' && i + 1 < argc) + { + lt_opt_process_env_prepend (argv[++i]); /* don't copy */ + } + else + lt_fatal ("%s missing required argument", env_prepend_opt); + continue; + } + if (strncmp (argv[i], env_append_opt, env_append_opt_len) == 0) + { + if (argv[i][env_append_opt_len] == '=') + { + const char *p = argv[i] + env_append_opt_len + 1; + lt_opt_process_env_append (p); + } + else if (argv[i][env_append_opt_len] == '\0' && i + 1 < argc) + { + lt_opt_process_env_append (argv[++i]); /* don't copy */ + } + else + lt_fatal ("%s missing required argument", env_append_opt); + continue; + } + if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0) + { + /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX + namespace, but it is not one of the ones we know about and + have already dealt with, above (inluding dump-script), then + report an error. Otherwise, targets might begin to believe + they are allowed to use options in the LTWRAPPER_OPTION_PREFIX + namespace. The first time any user complains about this, we'll + need to make LTWRAPPER_OPTION_PREFIX a configure-time option + or a configure.ac-settable value. + */ + lt_fatal ("Unrecognized option in %s namespace: '%s'", + ltwrapper_option_prefix, argv[i]); + } + /* otherwise ... */ + newargz[++newargc] = xstrdup (argv[i]); + } + newargz[++newargc] = NULL; + + LTWRAPPER_DEBUGPRINTF (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>"))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + newargz = prepare_spawn (newargz); + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : "<NULL>"), + (value ? value : "<NULL>"))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +int +lt_split_name_value (const char *arg, char** name, char** value) +{ + const char *p; + int len; + if (!arg || !*arg) + return 1; + + p = strchr (arg, (int)'='); + + if (!p) + return 1; + + *value = xstrdup (++p); + + len = strlen (arg) - strlen (*value); + *name = XMALLOC (char, len); + strncpy (*name, arg, len-1); + (*name)[len - 1] = '\0'; + + return 0; +} + +void +lt_opt_process_env_set (const char *arg) +{ + char *name = NULL; + char *value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); + } + + lt_setenv (name, value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_prepend (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_append (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 1); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : "<NULL>"), + (value ? value : "<NULL>"))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : "<NULL>"), + (value ? value : "<NULL>"))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac +} +# end: func_emit_cwrapperexe_src + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $ECHO + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because the file extensions .$libext of this argument makes me believe" + $ECHO "*** that it is just a static archive that I should not use here." + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + $ECHO + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $ECHO + $ECHO "*** And there doesn't seem to be a static archive available" + $ECHO "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $ECHO + $ECHO "*** Warning: This system can not link to static lib archive $lib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $ECHO "*** But as you try to build a module library, libtool will still create " + $ECHO "*** a static module, that should work as long as the dlopening application" + $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` + # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` + # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then + ldd_output=`ldd conftest` + for i in $deplibs; do + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + deplib_matches=`eval "\\$ECHO \"$library_names_spec\""` + set dummy $deplib_matches; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $ECHO + $ECHO "*** Warning: dynamic linker does not accept needed library $i." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which I believe you do not have" + $ECHO "*** because a test_compile did reveal that the linker did not use it for" + $ECHO "*** its dynamic dependency list that programs get resolved with at runtime." + fi + fi + ;; + *) + newdeplibs="$newdeplibs $i" + ;; + esac + done + else + # Error occurred in the first compile. Let's try to salvage + # the situation: Compile a separate program for each library. + for i in $deplibs; do + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $i; then + ldd_output=`ldd conftest` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + newdeplibs="$newdeplibs $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + deplib_matches=`eval "\\$ECHO \"$library_names_spec\""` + set dummy $deplib_matches; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + newdeplibs="$newdeplibs $i" + else + droppeddeps=yes + $ECHO + $ECHO "*** Warning: dynamic linker does not accept needed library $i." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because a test_compile did reveal that the linker did not use this one" + $ECHO "*** as a dynamic dependency that programs can get resolved with at runtime." + fi + fi + else + droppeddeps=yes + $ECHO + $ECHO "*** Warning! Library $i is needed by this library but I was not able to" + $ECHO "*** make it link in! You will probably need to install it or some" + $ECHO "*** library that it depends on before this library will be fully" + $ECHO "*** functional. Installing it before continuing would be even better." + fi + ;; + *) + newdeplibs="$newdeplibs $i" + ;; + esac + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method; shift + file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ + -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + done + fi + if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | + $GREP . >/dev/null; then + $ECHO + if test "X$deplibs_check_method" = "Xnone"; then + $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + else + $ECHO "*** Warning: inter-library dependencies are not known to be supported." + fi + $ECHO "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $ECHO + $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + $ECHO "*** a static module, that should work as long as the dlopening" + $ECHO "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $ECHO "*** The inter-library dependencies that have been dropped here will be" + $ECHO "*** automatically added whenever a program is linked with this library" + $ECHO "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $ECHO + $ECHO "*** Since this library must not contain undefined symbols," + $ECHO "*** because either the platform does not support them or" + $ECHO "*** it was explicitly requested with -no-undefined," + $ECHO "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + $ECHO 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + $ECHO ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *cegcc) + # Disable wrappers for cegcc, we are cross compiling anyway. + wrappers_required=no + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $ECHO for shipping. + if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $ECHO "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/build-aux/mdate-sh b/build-aux/mdate-sh new file mode 100755 index 00000000..83d27009 --- /dev/null +++ b/build-aux/mdate-sh @@ -0,0 +1,205 @@ +#!/bin/sh +# Get modification time of a file or directory and pretty-print it. + +scriptversion=2007-03-30.02 + +# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005, 2007 Free Software +# Foundation, Inc. +# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995 +# +# 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +case $1 in + '') + echo "$0: No file. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: mdate-sh [--help] [--version] FILE + +Pretty-print the modification time of FILE. + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "mdate-sh $scriptversion" + exit $? + ;; +esac + +# Prevent date giving response in another language. +LANG=C +export LANG +LC_ALL=C +export LC_ALL +LC_TIME=C +export LC_TIME + +# GNU ls changes its time format in response to the TIME_STYLE +# variable. Since we cannot assume `unset' works, revert this +# variable to its documented default. +if test "${TIME_STYLE+set}" = set; then + TIME_STYLE=posix-long-iso + export TIME_STYLE +fi + +save_arg1=$1 + +# Find out how to get the extended ls output of a file or directory. +if ls -L /dev/null 1>/dev/null 2>&1; then + ls_command='ls -L -l -d' +else + ls_command='ls -l -d' +fi +# Avoid user/group names that might have spaces, when possible. +if ls -n /dev/null 1>/dev/null 2>&1; then + ls_command="$ls_command -n" +fi + +# A `ls -l' line looks as follows on OS/2. +# drwxrwx--- 0 Aug 11 2001 foo +# This differs from Unix, which adds ownership information. +# drwxrwx--- 2 root root 4096 Aug 11 2001 foo +# +# To find the date, we split the line on spaces and iterate on words +# until we find a month. This cannot work with files whose owner is a +# user named `Jan', or `Feb', etc. However, it's unlikely that `/' +# will be owned by a user whose name is a month. So we first look at +# the extended ls output of the root directory to decide how many +# words should be skipped to get the date. + +# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. +set x`$ls_command /` + +# Find which argument is the month. +month= +command= +until test $month +do + shift + # Add another shift to the command. + command="$command shift;" + case $1 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; + esac +done + +# Get the extended ls output of the file or directory. +set dummy x`eval "$ls_command \"\$save_arg1\""` + +# Remove all preceding arguments +eval $command + +# Because of the dummy argument above, month is in $2. +# +# On a POSIX system, we should have +# +# $# = 5 +# $1 = file size +# $2 = month +# $3 = day +# $4 = year or time +# $5 = filename +# +# On Darwin 7.7.0 and 7.6.0, we have +# +# $# = 4 +# $1 = day +# $2 = month +# $3 = year or time +# $4 = filename + +# Get the month. +case $2 in + Jan) month=January; nummonth=1;; + Feb) month=February; nummonth=2;; + Mar) month=March; nummonth=3;; + Apr) month=April; nummonth=4;; + May) month=May; nummonth=5;; + Jun) month=June; nummonth=6;; + Jul) month=July; nummonth=7;; + Aug) month=August; nummonth=8;; + Sep) month=September; nummonth=9;; + Oct) month=October; nummonth=10;; + Nov) month=November; nummonth=11;; + Dec) month=December; nummonth=12;; +esac + +case $3 in + ???*) day=$1;; + *) day=$3; shift;; +esac + +# Here we have to deal with the problem that the ls output gives either +# the time of day or the year. +case $3 in + *:*) set `date`; eval year=\$$# + case $2 in + Jan) nummonthtod=1;; + Feb) nummonthtod=2;; + Mar) nummonthtod=3;; + Apr) nummonthtod=4;; + May) nummonthtod=5;; + Jun) nummonthtod=6;; + Jul) nummonthtod=7;; + Aug) nummonthtod=8;; + Sep) nummonthtod=9;; + Oct) nummonthtod=10;; + Nov) nummonthtod=11;; + Dec) nummonthtod=12;; + esac + # For the first six month of the year the time notation can also + # be used for files modified in the last year. + if (expr $nummonth \> $nummonthtod) > /dev/null; + then + year=`expr $year - 1` + fi;; + *) year=$3;; +esac + +# The result. +echo $day $month $year + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/build-aux/missing b/build-aux/missing new file mode 100755 index 00000000..1c8ff704 --- /dev/null +++ b/build-aux/missing @@ -0,0 +1,367 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2006-05-10.23 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. + +# 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to <bug-automake@gnu.org>." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case $1 in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $1 in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/build-aux/run-test b/build-aux/run-test new file mode 100755 index 00000000..cfa77518 --- /dev/null +++ b/build-aux/run-test @@ -0,0 +1,139 @@ +#!/bin/sh +# +# Copyright (C) 2009 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 3 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, see <http://www.gnu.org/licenses/>. +# + +# This program is a test driver that supports running a test under valgrind. +# Usage: run-test CHECKER PROGRAM [ARGUMENT...] + +progname=$0 + +# func_usage +# outputs to stdout the --help usage message. +func_usage () +{ + echo "\ +Usage: run-test [OPTION...] CHECKER PROGRAM [ARGUMENT...] + +Runs PROGRAM under the control of CHECKER. + +CHECKER may be empty or a valgrind command with some options, such as +'valgrind --tool=memcheck --num-callers=20 --leak-check=yes --leak-resolution=high --show-reachable=yes'. + +When CHECKER is not empty, it is recommended that the package has been +configured with + --disable-shared so that tests are real executables and not libtool + wrapper scripts, and + CFLAGS=\"-g\" so that valgrind shows line numbers. + +Report bugs to Bruno Haible." +} + +# func_version +# outputs to stdout the --version message. +func_version () +{ + echo "\ +run-test (GNU libunistring) +Copyright (C) 2009 Free Software Foundation, Inc. +License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. + +Written by" "Bruno Haible" +} + +# func_fatal_error message +# outputs to stderr a fatal error message, and terminates the program. +# Input: +# - progname name of this program +func_fatal_error () +{ + echo "$progname: *** $1" 1>&2 + echo "$progname: *** Stop." 1>&2 + func_exit 1 +} + +# Command-line option processing. +# Removes the OPTIONS from the arguments. Sets the variables: +# - checker wrapper program for executables +{ + while test $# -gt 0; do + case "$1" in + --help | --hel | --he | --h ) + func_usage + exit $? ;; + --version | --versio | --versi | --vers | --ver | --ve | --v ) + func_version + exit $? ;; + -- ) + # Stop option processing + shift + break ;; + -* ) + echo "run-test: unknown option $1" 1>&2 + echo "Try 'run-test --help' for more information." 1>&2 + exit 1 ;; + * ) + break ;; + esac + done + + if test $# -lt 2; then + echo "run-test: too few arguments" 1>&2 + echo "Try 'run-test --help' for more information." 1>&2 + exit 1 + fi + + checker="$1" + shift +} + +if test -z "$checker"; then + # No checker. Run the test directly. + exec "$@" +else + # Using valgrind. We want to apply valgrind only to executables, not to + # shell script, because + # 1. we don't want to look for memory leaks in bash, + # 2. on a bi-arch system, we would get an error message such as + # "valgrind: wrong executable class (eg. 32-bit instead of 64-bit)". + case "$1" in + *.sh) + # A shell script. Ignore the checker. + exec "$@" + ;; + *) + # The 'file' command is not portable enough. So, look + # at the first two bytes of the file. Are they '#!'? + if { if od -A x < /dev/null >/dev/null 2>/dev/null; then + # Use POSIX od. + firstbytes=`od -A n -t o1 -N 2 < "$1" | tr -d ' '` + else + # Use BSD hexdump. + firstbytes=`dd if="$1" bs=1 count=2 2>/dev/null | hexdump -e '1/1 "%03o"'` + fi + test "$firstbytes" = "043041" + }; then + # A shell script. Ignore the checker. + exec "$@" + else + # An executable. Use the checker. + exec $checker "$@" + fi + ;; + esac +fi diff --git a/build-aux/texi2html b/build-aux/texi2html new file mode 100755 index 00000000..a0343665 --- /dev/null +++ b/build-aux/texi2html @@ -0,0 +1,19554 @@ +#! /usr/bin/perl -- # perl +'di '; +'ig 00 '; +#+############################################################################## +# +# texi2html: Program to transform Texinfo documents to HTML +# +# Copyright (C) 1999-2005 Patrice Dumas <dumas@centre-cired.fr>, +# Derek Price <derek@ximbiot.com>, +# Adrian Aichner <adrian@xemacs.org>, +# & others. +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA +# +#-############################################################################## +# The man page for this program is included at the end of this file and can be +# viewed using the command 'nroff -man texi2html'. + +# for POSIX::setlocale and File::Spec +require 5.00405; +# Perl pragma to restrict unsafe constructs +use strict; +# used in case of tests, to revert to "C" locale. +use POSIX qw(setlocale LC_ALL LC_CTYPE); +# used to obtain the name of the current working directory +use Cwd; +# used to find a relative path back to the current working directory +use File::Spec; + +# +# 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; + +#++########################################################################## +# +# 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, T2h_i18n.pm, translations.pl, l2h.init, +# T2h_l2h.pm files +# +#--########################################################################## + +# CVS version: +# $Id: texi2html.pl,v 1.182 2007/05/07 22:56:02 pertusus Exp $ + +# Homepage: +my $T2H_HOMEPAGE = "http://www.nongnu.org/texi2html/"; + +# Authors (appears in comments): +my $T2H_AUTHORS = <<EOT; +Written by: Lionel Cons <Lionel.Cons\@cern.ch> (original author) + Karl Berry <karl\@freefriends.org> + Olaf Bachmann <obachman\@mathematik.uni-kl.de> + and many others. +Maintained by: Many creative people. +Send bugs and suggestions to <texi2html-bug\@nongnu.org> +EOT + +# Version: set in configure.in +my $THISVERSION = '1.78a'; +my $THISPROG = "texi2html $THISVERSION"; # program name and version + +#+++######################################################################## +# # +# Paths and file names # +# # +#---######################################################################## + +# set by configure, prefix for the sysconfdir and so on +my $prefix = '/usr/local'; +my $sysconfdir; +my $pkgdatadir; +my $datadir; + +# We need to eval as $prefix has to be expanded. However when we haven't +# run configure @sysconfdir will be expanded as an array, thus we verify +# whether configure was run or not +if ('${prefix}/etc' ne '@' . 'sysconfdir@') +{ + $sysconfdir = eval '"${prefix}/etc"'; +} +else +{ + $sysconfdir = "/usr/local/etc"; +} + +if ('${prefix}/share' ne '@' . 'datadir@') +{ + $pkgdatadir = eval '"${prefix}/share/texi2html"'; + $datadir = eval '"${prefix}/share"'; +} +else +{ + $pkgdatadir = "/usr/local/share/texi2html"; + $datadir = "/usr/local/share"; +} + +my $i18n_dir = 'i18n'; # name of the directory containing the per language files +my $conf_file_name = 'Config' ; +my $texinfo_htmlxref = 'htmlxref.cnf'; + +# directories for texi2html init files +my @texi2html_config_dirs = ('./'); +push @texi2html_config_dirs, "$ENV{'HOME'}/.texi2html/" if (defined($ENV{'HOME'})); +push @texi2html_config_dirs, "$sysconfdir/texi2html/" if (defined($sysconfdir)); +push @texi2html_config_dirs, "$pkgdatadir" if (defined($pkgdatadir)); + +# directories for texinfo configuration files +my @texinfo_config_dirs = ('./.texinfo/'); +push @texinfo_config_dirs, "$ENV{'HOME'}/.texinfo/" if (defined($ENV{'HOME'})); +push @texinfo_config_dirs, "$sysconfdir/texinfo/" if (defined($sysconfdir)); +push @texinfo_config_dirs, "$datadir/texinfo/" if (defined($datadir)); + + +#+++######################################################################## +# # +# Constants # +# # +#---######################################################################## + +my $DEBUG_MENU = 1; +my $DEBUG_INDEX = 2; +my $DEBUG_TEXI = 4; +my $DEBUG_MACROS = 8; +my $DEBUG_FORMATS = 16; +my $DEBUG_ELEMENTS = 32; +my $DEBUG_USER = 64; +my $DEBUG_L2H = 128; + +my $ERROR = "***"; # prefix for errors +my $WARN = "**"; # prefix for warnings + +my $VARRE = '[\w\-]+'; # RE for a variable name +my $NODERE = '[^:]+'; # RE for node names + +my $MAX_LEVEL = 4; +my $MIN_LEVEL = 1; + +#+++########################################################################### +# # +# Initialization # +# Some declarations, some functions that are GPL and therefore cannot be in # +# texi2html.init, some functions that are not to be customized. # +# Pasted content of File $(srcdir)/texi2html.init: Default initializations # +# # +#---########################################################################### + +{ +package Texi2HTML::Config; + + +sub load($) +{ + my $file = shift; + eval { require($file) ;}; + if ($@ ne '') + { + print STDERR "error loading $file: $@\n"; + return 0; + } + return 1; +} + +# customization options variables + +use vars qw( +$DEBUG +$PREFIX +$VERBOSE +$SUBDIR +$IDX_SUMMARY +$SPLIT +$SHORT_REF +@EXPAND +$EXPAND +$TOP +$DOCTYPE +$FRAMESET_DOCTYPE +$CHECK +$TEST +$DUMP_TEXI +$MACRO_EXPAND +$USE_GLOSSARY +$INVISIBLE_MARK +$USE_ISO +$TOP_FILE +$TOC_FILE +$FRAMES +$SHOW_MENU +$NUMBER_SECTIONS +$USE_NODES +$USE_UNICODE +$USE_UNIDECODE +$TRANSLITERATE_NODE +$NODE_FILES +$NODE_NAME_IN_MENU +$AVOID_MENU_REDUNDANCY +$SECTION_NAVIGATION +$SHORTEXTN +$EXTENSION +$OUT +$NOVALIDATE +$DEF_TABLE +$LANG +$DO_CONTENTS +$DO_SCONTENTS +$SEPARATED_FOOTNOTES +$TOC_LINKS +$L2H +$L2H_L2H +$L2H_SKIP +$L2H_TMP +$L2H_CLEAN +$L2H_FILE +$L2H_HTML_VERSION +$EXTERNAL_DIR +@INCLUDE_DIRS +@PREPEND_DIRS +@CONF_DIRS +$IGNORE_PREAMBLE_TEXT +@CSS_FILES +$INLINE_CONTENTS +); + +# customization variables +# ENCODING is deprecated +use vars qw( +$ENCODING + +$ENCODING_NAME +$DOCUMENT_ENCODING +$OUT_ENCODING +$IN_ENCODING +$DEFAULT_ENCODING +$MENU_PRE_STYLE +$CENTER_IMAGE +$EXAMPLE_INDENT_CELL +$SMALL_EXAMPLE_INDENT_CELL +$SMALL_FONT_SIZE +$SMALL_RULE +$DEFAULT_RULE +$MIDDLE_RULE +$BIG_RULE +$TOP_HEADING +$INDEX_CHAPTER +$SPLIT_INDEX +$HREF_DIR_INSTEAD_FILE +$USE_MENU_DIRECTIONS +$AFTER_BODY_OPEN +$PRE_BODY_CLOSE +$EXTRA_HEAD +$VERTICAL_HEAD_NAVIGATION +$WORDS_IN_PAGE +$ICONS +$UNNUMBERED_SYMBOL_IN_MENU +$SIMPLE_MENU +$MENU_SYMBOL +$OPEN_QUOTE_SYMBOL +$CLOSE_QUOTE_SYMBOL +$TOC_LIST_STYLE +$TOC_LIST_ATTRIBUTE +$TOP_NODE_FILE +$TOP_NODE_UP +$NODE_FILE_EXTENSION +$BEFORE_OVERVIEW +$AFTER_OVERVIEW +$BEFORE_TOC_LINES +$AFTER_TOC_LINES +$NEW_CROSSREF_STYLE +$USER +$USE_NUMERIC_ENTITY +$DATE +%ACTIVE_ICONS +%NAVIGATION_TEXT +%PASSIVE_ICONS +%BUTTONS_NAME +%BUTTONS_GOTO +%BUTTONS_EXAMPLE +@CHAPTER_BUTTONS +@MISC_BUTTONS +@SECTION_BUTTONS +@SECTION_FOOTER_BUTTONS +@NODE_FOOTER_BUTTONS +@IMAGE_EXTENSIONS +); + +# customization variables which may be guessed in the script +#our $ADDRESS; +use vars qw( +$BODYTEXT +$CSS_LINES +$DOCUMENT_DESCRIPTION +$EXTERNAL_CROSSREF_SPLIT +); + +# I18n +use vars qw( +$I +$LANGUAGES +); + +# customizable subroutines references +use vars qw( +$print_section +$one_section +$end_section +$print_Top_header +$print_Top_footer +$print_Top +$print_Toc +$print_Overview +$print_Footnotes +$print_About +$print_misc_header +$print_misc_footer +$print_misc +$print_section_header +$print_section_footer +$print_chapter_header +$print_chapter_footer +$print_page_head +$print_page_foot +$print_head_navigation +$print_foot_navigation +$button_icon_img +$print_navigation +$about_body +$print_frame +$print_toc_frame +$toc_body +$titlepage +$css_lines +$print_redirection_page +$init_out +$finish_out +$node_file_name +$element_file_name +$inline_contents + +$protect_text +$anchor +$def_item +$def +$menu +$menu_link +$menu_description +$menu_comment +$simple_menu_link +$ref_beginning +$info_ref +$book_ref +$external_href +$external_ref +$internal_ref +$table_item +$table_line +$row +$cell +$list_item +$comment +$def_line +$def_line_no_texi +$raw +$raw_no_texi +$heading +$paragraph +$preformatted +$foot_line_and_ref +$foot_section +$address +$image +$image_files +$index_entry_label +$index_entry +$index_letter +$print_index +$index_summary +$summary_letter +$complex_format +$cartouche +$sp +$definition_category +$table_list +$copying_comment +$index_summary_file_entry +$index_summary_file_end +$index_summary_file_begin +$style +$format +$normal_text +$empty_line +$unknown +$unknown_style +$float +$caption_shortcaption +$listoffloats +$listoffloats_entry +$listoffloats_caption +$listoffloats_float_style +$listoffloats_style +$acronym_like +$quotation +$quotation_prepend_text +$paragraph_style_command +$heading_texi +$index_element_heading_texi + +$PRE_ABOUT +$AFTER_ABOUT +); + +# hash which entries might be redefined by the user +use vars qw( +$complex_format_map +%accent_map +%def_map +%format_map +%simple_map +%simple_map_pre +%simple_map_texi +%style_map +%style_map_pre +%style_map_texi +%simple_format_simple_map_texi +%simple_format_style_map_texi +%simple_format_texi_map +%command_type +%paragraph_style +%things_map +%pre_map +%texi_map +%unicode_map +%unicode_diacritical +%transliterate_map +%transliterate_accent_map +%no_transliterate_map +%ascii_character_map +%ascii_simple_map +%ascii_things_map +%numeric_entity_map +%perl_charset_to_html +%iso_symbols +%misc_command +%css_map +%format_in_paragraph +%special_list_commands +%accent_letters +%unicode_accents +%special_accents +@command_handler_init +@command_handler_process +@command_handler_finish +%command_handler +); + +# needed in this namespace for translations +$I = \&Texi2HTML::I18n::get_string; + +# +# Function refs covered by the GPL as part of the texi2html.pl original +# code. As such they cannot appear in texi2html.init which is public +# domain (at least the things coded by me, and, if I'm not wrong also the +# things coded by Olaf -- Pat). +# + +$toc_body = \&T2H_GPL_toc_body; +$style = \&T2H_GPL_style; +$format = \&T2H_GPL_format; + +sub T2H_GPL_toc_body($) +{ + my $elements_list = shift; + return unless ($DO_CONTENTS or $DO_SCONTENTS or $FRAMES); + my $current_level = 0; + my $ul_style = $NUMBER_SECTIONS ? $TOC_LIST_ATTRIBUTE : ''; + foreach my $element (@$elements_list) + { + next if ($element->{'top'} or $element->{'index_page'}); + my $ind = ' ' x $current_level; + my $level = $element->{'toc_level'}; + print STDERR "Bug no toc_level for ($element) $element->{'texi'}\n" if (!defined ($level)); + if ($level > $current_level) + { + while ($level > $current_level) + { + $current_level++; + my $ln = "\n$ind<ul${ul_style}>\n"; + $ind = ' ' x $current_level; + push(@{$Texi2HTML::TOC_LINES}, $ln); + } + } + elsif ($level < $current_level) + { + while ($level < $current_level) + { + $current_level--; + $ind = ' ' x $current_level; + my $line = "</li>\n$ind</ul>"; + $line .= "</li>" if ($level == $current_level); + push(@{$Texi2HTML::TOC_LINES}, "$line\n"); + + } + } + else + { + push(@{$Texi2HTML::TOC_LINES}, "</li>\n"); + } + my $file = ''; + $file = $element->{'file'} if ($SPLIT); + my $text = $element->{'text'}; + #$text = $element->{'name'} unless ($NUMBER_SECTIONS); + my $entry = "<li>" . &$anchor ($element->{'tocid'}, "$file#$element->{'id'}",$text); + push (@{$Texi2HTML::TOC_LINES}, $ind . $entry); + push(@{$Texi2HTML::OVERVIEW}, $entry. "</li>\n") if ($level == 1); + } + while (0 < $current_level) + { + $current_level--; + my $ind = ' ' x $current_level; + push(@{$Texi2HTML::TOC_LINES}, "</li>\n$ind</ul>\n"); + } + @{$Texi2HTML::TOC_LINES} = () unless ($DO_CONTENTS); + if (@{$Texi2HTML::TOC_LINES}) + { + unshift @{$Texi2HTML::TOC_LINES}, $BEFORE_TOC_LINES; + push @{$Texi2HTML::TOC_LINES}, $AFTER_TOC_LINES; + } + @{$Texi2HTML::OVERVIEW} = () unless ($DO_SCONTENTS or $FRAMES); + if (@{$Texi2HTML::OVERVIEW}) + { + unshift @{$Texi2HTML::OVERVIEW}, "<ul${ul_style}>\n"; + push @{$Texi2HTML::OVERVIEW}, "</ul>\n"; + unshift @{$Texi2HTML::OVERVIEW}, $BEFORE_OVERVIEW; + push @{$Texi2HTML::OVERVIEW}, $AFTER_OVERVIEW; + } +} + +sub T2H_GPL_style($$$$$$$$$) +{ # known style + my $style = shift; + my $command = shift; + my $text = shift; + my $args = shift; + my $no_close = shift; + my $no_open = shift; + my $line_nr = shift; + my $state = shift; + my $style_stack = shift; + + my $do_quotes = 0; + my $use_attribute = 0; + my $use_begin_end = 0; + if (ref($style) eq 'HASH') + { + #print STDERR "GPL_STYLE $command\n"; + #print STDERR " @$args\n"; + $do_quotes = $style->{'quote'}; + if ((@{$style->{'args'}} == 1) and defined($style->{'attribute'})) + { + $style = $style->{'attribute'}; + $use_attribute = 1; + $text = $args->[0]; + } + elsif (defined($style->{'function'})) + { + $text = &{$style->{'function'}}($command, $args, $style_stack, $state, $line_nr); + } + } + else + { + if ($style =~ s/^\"//) + { # add quotes + $do_quotes = 1; + } + if ($style =~ s/^\&//) + { # custom + $style = 'Texi2HTML::Config::' . $style; + eval "\$text = &$style(\$text, \$command, \$style_stack)"; + } + elsif ($style ne '') + { + $use_attribute = 1; + } + else + { # no style + } + } + if ($use_attribute) + { # good style + my $attribute_text = ''; + if ($style =~ /^(\w+)(\s+.*)/) + { + $style = $1; + $attribute_text = $2; + } +# $text = "<${style}$attribute_text>$text</$style>" ; + $text = "<${style}$attribute_text>" . "$text" if (!$no_open); + $text .= "</$style>" if (!$no_close); + if ($do_quotes) + { + $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open); + $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close); + } + } + if (ref($style) eq 'HASH') + { + if (defined($style->{'begin'}) and !$no_open) + { + $text = $style->{'begin'} . $text; + } + if (defined($style->{'end'}) and !$no_close) + { + $text = $text . $style->{'end'}; + } + } + if ($do_quotes and !$use_attribute) + { + $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open); + $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close); + } + return $text; +} + +sub T2H_GPL_format($$$) +{ + my $tag = shift; + my $element = shift; + my $text = shift; + return '' if (!defined($element) or ($text !~ /\S/)); + return $text if ($element eq ''); + my $attribute_text = ''; + if ($element =~ /^(\w+)(\s+.*)/) + { + $element = $1; + $attribute_text = $2; + } + return "<${element}$attribute_text>\n" . $text. "</$element>\n"; +} + +# leave this within comments, and keep the require statement +# This way, you can directly run texi2html.pl, if +# $ENV{T2H_HOME}/texi2html.init exists. + +# @INIT@ +# -*-perl-*- +###################################################################### +# File: texi2html.init +# +# Default values for command-line arguments and for various customizable +# procedures are set in this file. +# +# A copy of this file is pasted into the beginning of texi2html by +# running './configure'. +# +# Copy this file, rename it and make changes to it, if you like. +# Afterwards, load the file with command-line +# option -init-file <your_init_file> +# +# $Id: texi2html.init,v 1.116 2007/05/07 22:56:02 pertusus Exp $ + +###################################################################### +# The following variables can also be set by command-line options +# +# +# The default values are set in this file, texi2html.init and the content +# of this file is included at the beginning of the texi2html script file. +# Those values may be overrided by values set in $sysconfdir/texi2htmlrc +# and then by values set in $HOME/texi2htmlrc. +# +# command line switches may override these values, and values set in files +# specified by -init-file are also taken into account. +# values set in these files overwrite values set by the command-line +# options appearing before -init-file and might still be overwritten by +# command-line arguments following the -init-file option. + +# -debug +# The integer value specifies what kind of debugging output is generated. +$DEBUG = 0; + +# -doctype +# The value is the 'SystemLiteral' which identifies the canonical DTD +# for the document. +# 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 +$DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html401/loose.dtd">'; + +# -frameset-doctype +# When frames are used, this SystemLiteral identifies the DTD used for +# the file containing the frame description. +$FRAMESET_DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html401/frameset.dtd">'; + +# -test +# If this value is true, some variables which should be dynamically generated +# (the date, the user running texi2html, the version of texi2html) are set to +# fix and given values. This is usefull in case the resulting manual is +# compared with a reference. For example this is used in the tests of test.sh. +$TEST = 0; + +# -dump-texi +# This value is usefull for debugging purposes. The result of the first pass is +# put in <document name>.passtexi, the result of the second pass is put in +# <document name>.passfirst. +$DUMP_TEXI = 0; + +# -expand +# the @EXPAND array contains the expanded section names. +@EXPAND = ('html'); + +# -invisible +# This seems obsolete and is not used anywhere. +# This was a workaround for a known bug of many WWW browsers, including +# netscape. This was used to create invisible destination in anchors. +$INVISIBLE_MARK = ''; +# $INVISIBLE_MARK = ' '; + +# -iso +# if this value is true, ISO8859 characters are used for special symbols +# (like copyright, etc). +$USE_ISO = 1; + +# -I +# add a directory to the list of directories where @include files are +# searched for (besides the directory of the file). additional '-I' +# args are appended to this list. +# (APA: Don't implicitely search ., to conform with the docs!) +# my @INCLUDE_DIRS = ("."); +@INCLUDE_DIRS = (); + +# -P +# prepend a directory to the list of directories where @include files are +# searched for before the directory of the file. additional '-P' +# args are prepended to this list. +@PREPEND_DIRS = (); + +# --conf-dir +# append to the files searched for init files. +@CONF_DIRS = (); + +# -top-file +# This file name is used for the top-level file. +# The extension is set appropriately, if necessary. +# If empty, <basename of document>.html is used. +# Typically, you would set this to "index.html". +$TOP_FILE = ''; + +# -toc-file +# This file name is used for the table of contents. The +# extension is set appropriately, if necessary. +# If empty, <basename of document>_toc.html is used. +$TOC_FILE = ''; + +# -frames +# if the value is true, HTML 4.0 "frames" are used. +# A file describing the frame layout is generated, together with a file +# with the short table of contents. +$FRAMES = 0; + +# -menu | -nomenu +# if the value is true the Texinfo menus are shown. +$SHOW_MENU = 1; + +# -number | -nonumber +# if this is set the sections are numbered, and section names and numbers +# are used in references and menus (instead of node names). +$NUMBER_SECTIONS = 1; + +# -use-nodes +# if this is set the nodes are used as sectionning elements. +# Otherwise the nodes are incorporated in sections. +$USE_NODES = 0; + +# -node-files +# if this is set one file per node is generated, which can be a target for +# cross manual references. +$NODE_FILES = 0; + +# -split section|chapter|node|none +# if $SPLIT is set to 'section' (resp. 'chapter') one html file per section +# (resp. chapter) is generated. If $SPLIT is set to 'node' one html file per +# node or sectionning element is generated. In all these cases separate pages +# for Top, Table of content (Toc), Overview and About are generated. +# Otherwise a monolithic html file that contains the whole document is +# created. +#$SPLIT = 'section'; +$SPLIT = ''; + +# -sec-nav|-nosec-nav +# if this is set then navigation panels are printed at the beginning of each +# section. +# If the document is split at nodes then navigation panels are +# printed at the end if there were more than $WORDS_IN_PAGE words on page. +# +# If the document is split at sections this is ignored. +# +# This is most useful if you do not want to have section navigation +# with -split chapter. There will be chapter navigation panel at the +# beginning and at the end of chapters anyway. +$SECTION_NAVIGATION = 1; + +# -separated-footnotes +# if this is set footnotes are on a separated page. Otherwise they are at +# the end of each file (if the document is split). +$SEPARATED_FOOTNOTES = 1; + +# -toc-links +# if this is set, links from headings to toc entries are created. +$TOC_LINKS = 0; + +# -subdir +# If this is set, then put result files into the specified directory. +# If not set, then result files are put into the current directory. +#$SUBDIR = 'html'; +$SUBDIR = ''; + +# -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. +$SHORTEXTN = 0; + +# -prefix +# This set the output file prefix, prepended to all .html, .gif and .pl files. +# By default, this is the basename of the document. +$PREFIX = ''; + +# -o filename +# If this is set a monolithic document is outputted into $filename. +$OUT = ''; + +# -no-validate +# suppress node cross-reference validation +$NOVALIDATE = 0; + +# -short-ref +# if this is set cross-references are given without section numbers. +$SHORT_REF = ''; + +# -idx-sum +# if value is set, then for each @printindex <index name> +# <document name>_<index name>.idx is created which contains lines of the form +# key ref sorted alphabetically (case matters). +$IDX_SUMMARY = 0; + +# -def-table +# If this is set a table construction for @def.... instead of definition +# lists. +# (New Option: 27.07.2000 Karl Heinz Marbaise) +$DEF_TABLE = 0; + +# -verbose +# if this is set chatter about what we are doing. +$VERBOSE = ''; + +# -lang +# use &$I('my string') if you want to have translations of 'my string' +# and provide the translations in $LANGUAGES->{$LANG} with 'my string' +# as key. +# To add a new language use ISO 639 language codes (see e.g. perl module +# Locale-Codes-1.02 for definitions). Supply translations in the +# $LANGUAGES hash and put it in a file with $LANG as name in an i18n +# directory. +# Default's to 'en' if not set or no @documentlanguage is specified. +$LANG = 'en'; + +# -ignore-preamble-text +# If this is set the text before @node and sectionning commands is ignored. +$IGNORE_PREAMBLE_TEXT = 0; + +# -html-xref-prefix +# base directory for external manuals. +#$EXTERNAL_DIR = '../'; +$EXTERNAL_DIR = undef; + +# -l2h +# if this is set, latex2html is used for generation of math content. +$L2H = ''; + +# -css-include +# All the specified css files are used. More precisely the @import sections +# are added to the beginning of the CSS_LINES the remaining is added at +# the end of the CSS_LINES (after the css rules generated by texi2html). +# cf texinfo manual for more info. +# - means STDIN +@CSS_FILES = (); + +###################### +# The following options are only relevant if $L2H is set +# +# -l2h-l2h +# name/location of latex2html program +$L2H_L2H = "latex2html"; + +# -l2h-skip +# If this is set the actual call to latex2html is skipped. The previously +# generated content is reused, instead. +$L2H_SKIP = ''; + +# -l2h-tmp +# If this is 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. +$L2H_TMP = ''; + +# -l2h-file +# If set, l2h uses the file as latex2html init file +$L2H_FILE = 'l2h.init'; + +# -l2h-clean +# if this is set the intermediate files generated by texi2html in relation with +# latex2html are cleaned (they all have the prefix <document name>_l2h_). +$L2H_CLEAN = 1; + +############################################################################## +# +# The following can only be set in the init file +# +############################################################################## + +# If true do table of contents even if there is no @content +$DO_CONTENTS = 0; + +# If true do short table of contents even if there is no @shortcontent +$DO_SCONTENTS = 0; + +# if set, output the contents where the command is located +$INLINE_CONTENTS = 1; + +# if this variable is true, numeric entities are used when there is no +# corresponding textual entity. +$USE_NUMERIC_ENTITY = 1; + +# if set, then use node names in menu entries, instead of section names +$NODE_NAME_IN_MENU = 0; + +# new style for crossrefs +$NEW_CROSSREF_STYLE = 1; + +# transliterate node names for external refs (and internal if NODE_FILES) +$TRANSLITERATE_NODE = 1; + +# if set and menu entry equals menu description, then do not print +# menu description. +# Likewise, if node name equals entry name, do not print entry name. +$AVOID_MENU_REDUNDANCY = 1; + +# if set, center @image by default +# otherwise, do not center by default +# Deprecated and not used anymore +$CENTER_IMAGE = 1; + +# used as identation for block enclosing command @example, etc +# If not empty, must be enclosed in <td></td> +$EXAMPLE_INDENT_CELL = '<td> </td>'; + +# same as above, only for @small +$SMALL_EXAMPLE_INDENT_CELL = '<td> </td>'; + +# font size for @small +$SMALL_FONT_SIZE = '-1'; + +# horizontal rules +$SMALL_RULE = '<hr size="1">'; +$DEFAULT_RULE = '<hr>'; +$MIDDLE_RULE = '<hr size="2">'; +$BIG_RULE = '<hr size="6">'; + +# 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) +$TOP_HEADING = ''; + +# if set, use this chapter for 'Index' button, else +# use first chapter with @printindex +$INDEX_CHAPTER = ''; + +# if set and $SPLIT is set, then split index pages at the next letter +# after they have more than that many entries +$SPLIT_INDEX = 100; + +# symbol put at the beginning of nodes entry in menu (and optionnaly of +# unnumbered in menus, see next variable) +$MENU_SYMBOL = '•'; +#$MENU_SYMBOL = '*'; + +$SIMPLE_MENU = 0; + +$OPEN_QUOTE_SYMBOL = "\`"; +$CLOSE_QUOTE_SYMBOL = "'"; + +# if true put a $MENU_SYMBOL before unnumbered in menus +$UNNUMBERED_SYMBOL_IN_MENU = 0; + +# extension for nodes files when NODE_FILES is true +$NODE_FILE_EXTENSION = "html"; + +# extension +$EXTENSION = "html"; + +# file name used for Top node when NODE_FILES is true +$TOP_NODE_FILE = "index"; + +# node name used for Top node when automatic node directions are used +$TOP_NODE_UP = '(dir)'; + +# this controls the pre style for menus +$MENU_PRE_STYLE = 'font-family: serif'; + +# This controls the ul style for toc +$TOC_LIST_STYLE = 'list-style: none'; +$TOC_LIST_ATTRIBUTE = ' class="toc"'; + +# These lines are inserted before and after the shortcontents +$BEFORE_OVERVIEW = "<div class=\"shortcontents\">\n"; +$AFTER_OVERVIEW = "</div>\n"; + +# These lines are inserted before and after the contents +$BEFORE_TOC_LINES = "<div class=\"contents\">\n"; +$AFTER_TOC_LINES = "</div>\n"; + +# if set (e.g., to index.html) replace hrefs to this file +# (i.e., to index.html) by ./ +# Obsolete. Worked around a bug that is fixed now. +$HREF_DIR_INSTEAD_FILE = ''; + +# text inserted after <body ...> +$AFTER_BODY_OPEN = ''; + +# text inserted before </body>, this will be automatically inside <p></p> +$PRE_BODY_CLOSE = ''; + +# this is added inside <head></head> after <title> and some <meta name> +# stuff, it can be used for eg. <style>, <script>, <meta> etc. tags. +$EXTRA_HEAD = ''; + +# Specifies the minimum page length required before a navigation panel +# is placed at the bottom of a page +# FIXME this is not true: +# THIS_WORDS_IN_PAGE holds number of words of current page +$WORDS_IN_PAGE = 300; + +# if this is set a vertical navigation panel is used. +$VERTICAL_HEAD_NAVIGATION = 0; + +# html version for latex2html +$L2H_HTML_VERSION = "4.0"; + +# use the information given by menus to complete the node directions +$USE_MENU_DIRECTIONS = 1; + +# specify in this array which "buttons" should appear in which order +# in the navigation panel for sections; use ' ' for empty buttons (space) +@SECTION_BUTTONS = + ( + 'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward', + ' ', ' ', ' ', ' ', + 'Top', 'Contents', 'Index', 'About', + ); + +# buttons for misc stuff +@MISC_BUTTONS = ('Top', 'Contents', 'Index', 'About'); + +# buttons for chapter file footers +# (and headers but only if SECTION_NAVIGATION is false) +@CHAPTER_BUTTONS = + ( + 'FastBack', 'FastForward', ' ', + ' ', ' ', ' ', ' ', + 'Top', 'Contents', 'Index', 'About', + ); + +# buttons for section file footers +@SECTION_FOOTER_BUTTONS = + ( + 'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward' + ); + +@NODE_FOOTER_BUTTONS = + ( + 'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward', + ' ', ' ', ' ', ' ', + 'Top', 'Contents', 'Index', 'About', +# 'Back', 'Forward', ' ', 'FastBack', 'Up', 'FastForward' + ); + +$ICONS = 0; + +# insert here name of icon images for buttons +# Icons are used, if $ICONS and resp. value are set +%ACTIVE_ICONS = + ( + 'Top', '', + 'Contents', '', + 'Overview', '', + 'Index', '', + 'This', '', + 'Back', '', + 'FastBack', '', + 'Prev', '', + 'Up', '', + 'Next', '', + 'NodeUp', '', + 'NodeNext', '', + 'NodePrev', '', + 'Following', '', + 'Forward', '', + 'FastForward', '', + 'About' , '', + 'First', '', + 'Last', '', + ' ', '' + ); + +# insert here name of icon images for these, if button is inactive +%PASSIVE_ICONS = + ( + 'Top', '', + 'Contents', '', + 'Overview', '', + 'Index', '', + 'This', '', + 'Back', '', + 'FastBack', '', + 'Prev', '', + 'Up', '', + 'Next', '', + 'NodeUp', '', + 'NodeNext', '', + 'NodePrev', '', + 'Following', '', + 'Forward', '', + 'FastForward', '', + 'About', '', + 'First', '', + 'Last', '', + ); + +@IMAGE_EXTENSIONS = ('png','jpg','jpeg','gif'); + +$init_out = \&t2h_default_init_out; +$finish_out = \&t2h_default_finish_out; + +# We have to do this dynamically because of internationalization and because +# in body $LANG could be used. +sub t2h_default_init_out() +{ +# Names of text as alternative for icons +# FIXME maybe get those in simple_format? + %NAVIGATION_TEXT = + ( + 'Top', &$I('Top'), + 'Contents', &$I('Contents'), + 'Overview', &$I('Overview'), + 'Index', &$I('Index'), + ' ', ' ', + 'This', &$I('current'), + 'Back', ' < ', + 'FastBack', ' << ', + 'Prev', &$I('Prev'), + 'Up', &$I(' Up '), + 'Next', &$I('Next'), + 'NodeUp', &$I('Node up'), + 'NodeNext', &$I('Next node'), + 'NodePrev', &$I('Previous node'), + 'Following', &$I('Following node'), + 'Forward', ' > ', + 'FastForward', ' >> ', + 'About', ' ? ', + 'First', ' |< ', + 'Last', ' >| ' + ); + + %BUTTONS_GOTO = + ( + 'Top', &$I('Cover (top) of document'), + 'Contents', &$I('Table of contents'), + 'Overview', &$I('Short table of contents'), + 'Index', &$I('Index'), + 'This', &$I('Current section'), + 'Back', &$I('Previous section in reading order'), + 'FastBack', &$I('Beginning of this chapter or previous chapter'), + 'Prev', &$I('Previous section on same level'), + 'Up', &$I('Up section'), + 'Next', &$I('Next section on same level'), + 'NodeUp', &$I('Up node'), + 'NodeNext', &$I('Next node'), + 'NodePrev', &$I('Previous node'), + 'Following', &$I('Node following in node reading order'), + 'Forward', &$I('Next section in reading order'), + 'FastForward', &$I('Next chapter'), + 'About' , &$I('About (help)'), + 'First', &$I('First section in reading order'), + 'Last', &$I('Last section in reading order'), + ); + + %BUTTONS_NAME = + ( + 'Top', &$I('Top'), + 'Contents', &$I('Contents'), + 'Overview', &$I('Overview'), + 'Index', &$I('Index'), + ' ', ' ', + 'This', &$I('This'), + 'Back', &$I('Back'), + 'FastBack', &$I('FastBack'), + 'Prev', &$I('Prev'), + 'Up', &$I('Up'), + 'Next', &$I('Next'), + 'NodeUp', &$I('NodeUp'), + 'NodeNext', &$I('NodeNext'), + 'NodePrev', &$I('NodePrev'), + 'Following', &$I('Following'), + 'Forward', &$I('Forward'), + 'FastForward', &$I('FastForward'), + 'About', &$I('About'), + 'First', &$I('First'), + 'Last', &$I('Last') + ); + + # Set the default body text, inserted between <body ... > + $BODYTEXT = 'lang="' . $LANG . '" bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000"' unless (defined($BODYTEXT)); + if (!defined($EXTERNAL_CROSSREF_SPLIT)) + { + if ($SPLIT) + { + $EXTERNAL_CROSSREF_SPLIT = 1; + } + else + { + $EXTERNAL_CROSSREF_SPLIT = 0; + } + } + + $ENCODING_NAME = $ENCODING if (!defined($ENCODING_NAME) and + defined($ENCODING)); + + if (!defined($OUT_ENCODING) and (defined($ENCODING_NAME))) + { + $OUT_ENCODING = main::encoding_alias ($ENCODING_NAME); + $OUT_ENCODING = $ENCODING_NAME if (!defined($OUT_ENCODING)); + } + if (!defined($OUT_ENCODING) and (defined($IN_ENCODING))) + { + $OUT_ENCODING = $IN_ENCODING; + } + if (!defined($OUT_ENCODING) and (defined($DOCUMENT_ENCODING))) + { + $OUT_ENCODING = main::encoding_alias ($DOCUMENT_ENCODING); + $OUT_ENCODING = $DOCUMENT_ENCODING if (!defined($OUT_ENCODING)); + } + + if (!defined($ENCODING_NAME)) + { + if (defined($OUT_ENCODING) and defined($perl_charset_to_html{$OUT_ENCODING})) + { + $ENCODING_NAME = $perl_charset_to_html{$OUT_ENCODING}; + } + elsif (defined($IN_ENCODING) and defined($perl_charset_to_html{$IN_ENCODING})) + { + $ENCODING_NAME = $perl_charset_to_html{$IN_ENCODING}; + } + elsif (defined($DOCUMENT_ENCODING) and defined($perl_charset_to_html{$DOCUMENT_ENCODING})) + { + $ENCODING_NAME = $perl_charset_to_html{$DOCUMENT_ENCODING}; + } + elsif (defined($OUT_ENCODING)) + { + $ENCODING_NAME = $OUT_ENCODING; + } + elsif (defined($IN_ENCODING)) + { + $ENCODING_NAME = $IN_ENCODING; + } + elsif (defined($DOCUMENT_ENCODING)) + { + $ENCODING_NAME = $DOCUMENT_ENCODING; + } + elsif (defined($perl_charset_to_html{$DEFAULT_ENCODING})) + { + $ENCODING_NAME = $perl_charset_to_html{$DEFAULT_ENCODING}; + } + else + { + $ENCODING_NAME = 'us-ascii'; + } + } + my $out_encoding = $OUT_ENCODING; + $out_encoding = 'UNDEF' if (!defined($out_encoding)); + my $in_encoding = $IN_ENCODING; + $in_encoding = 'UNDEF' if (!defined($in_encoding)); + my $document_encoding = $DOCUMENT_ENCODING; + $document_encoding = 'UNDEF' if (!defined($document_encoding)); + print STDERR "# Encodings: doc $document_encoding, in $in_encoding out $out_encoding, name $ENCODING_NAME\n" if ($VERBOSE); + + if ($SIMPLE_MENU and !defined($complex_format_map->{'menu'})) + { + $complex_format_map->{'menu'} = { 'begin' => q{''} , 'end' => q{''}, + 'pre_style' => "$MENU_PRE_STYLE", 'class' => 'menu-preformatted' }; + } + + return $OUT_ENCODING; +}; + +sub t2h_default_finish_out() +{ +} + +####################################################################### +# +# Values guessed if not set here, set in init_out +# +####################################################################### + +$BODYTEXT = undef; + +# default used in init_out for the setting of the ENCODING_NAME variable +$DEFAULT_ENCODING = 'utf8'; + +# In file encoding. The @documentencoding overrides that variable. +$DOCUMENT_ENCODING = undef; + +# In file encoding, understandable by perl. Set according to DOCUMENT_ENCODING +$IN_ENCODING = undef; + +# Formatted document encoding name. If undef, set in init_out based on +# $OUT_ENCODING or $DOCUMENT_ENCODING if they are defined +$ENCODING_NAME = undef; + +# Out files encoding, understandable by perl. If undef, set in init_out +# using $ENCODING_NAME or $IN_ENCODING if they are defined +$OUT_ENCODING = undef; + +# if undef set to @documentdescription. If there is no @documentdescription, +# set in page_head +$DOCUMENT_DESCRIPTION = undef; + +# if undef set 1 if SPLIT, to 0 otherwise +$EXTERNAL_CROSSREF_SPLIT = undef; + +$USER = undef; +$DATE = undef; + + +######################################################################## +# 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_<fnc>* routines, +# give them another name, and assign them to the respective +# $<fnc> variable. + +# As a general interface, the hashes Texi2HTML::HREF, Texi2HTML::NAME, Texi2HTML::NODE, Texi2HTML::NO_TEXI, hold +# href, html-name, node-name, name after removal of texi commands of +# This -- current section (resp. html page) +# Top -- top element +# Contents -- Table of contents element +# Overview -- Short table of contents element +# Index -- Index page element +# About -- page which explain "navigation buttons" element +# First -- first node element +# Last -- last node element +# +# Whether or not the following hash values are set, depends on the context +# (all values are w.r.t. 'This' section) +# Next -- next element of texinfo +# Prev -- previous element of texinfo +# NodeUp -- up node of texinfo +# Following -- following node in node reading order, taking menu into account +# Forward -- next node in reading order +# Back -- previous node in reading order +# Up -- parent given by sectionning commands +# 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: +# $Texi2HTML::THISDOC{title} -- title as set by @setttile +# $Texi2HTML::THISDOC{title_no_texi} -- title without texi (without html elements) +# $Texi2HTML::THISDOC{title_texi} -- title with texinfo @-commands +# $Texi2HTML::THISDOC{fulltitle} -- full title as set by @title... +# $Texi2HTML::THISDOC{subtitle} -- subtitle as set by @subtitle +# $Texi2HTML::THISDOC{author} -- author as set by @author +# $Texi2HTML::THISDOC{copying} -- text of @copying and @end copying in comment +# +# $Texi2HTML::THISDOC{program} -- name and version of texi2html +# $Texi2HTML::THISDOC{program_homepage} -- homepage for texi2html +# $Texi2HTML::THISDOC{program_authors} -- authors of texi2html +# $Texi2HTML::THISDOC{today} -- date formatted with pretty_date +# $Texi2HTML::THISDOC{toc_file} -- table of contents file +# $Texi2HTML::THISDOC{file_base_name} -- base name of the texinfo manual file +# $Texi2HTML::THISDOC{destination_directory} + # -- directory for the resulting files +# $Texi2HTML::THISDOC{user} -- user running the script +# $Texi2HTML::THISDOC{css_import_lines} -- ref on @import lines in css files +# $Texi2HTML::THISDOC{css_lines} -- ref on css rules lines +# other $Texi2HTML::THISDOC keys corresponds with texinfo commands, the value +# being the command arg, for the following commands: +# kbdinputstyle, paragraphindent, setchapternewpage, headings, footnotestyle, +# exampleindent, firstparagraphindent, everyheading, everyfooting, +# evenheading, evenfooting, oddheading, oddfooting +# +# and pointer to arrays of lines which need to be printed by main::print_lines +# $Texi2HTML::THIS_SECTION -- lines of 'This' section +# $Texi2HTML::THIS_HEADER -- lines preceding navigation panel of 'This' section +# $Texi2HTML::OVERVIEW -- lines of short table of contents +# $Texi2HTML::TOC_LINES -- lines of table of contents +# $Texi2HTML::TITLEPAGE -- lines of title page +# +# $Texi2HTML::THIS_ELEMENT holds the element reference. + +# +# There are the following subs which control the layout: +# +$print_section = \&T2H_DEFAULT_print_section; +$end_section = \&T2H_DEFAULT_end_section; +$one_section = \&T2H_DEFAULT_one_section; +$print_Top_header = \&T2H_DEFAULT_print_Top_header; +$print_Top_footer = \&T2H_DEFAULT_print_Top_footer; +$print_Top = \&T2H_DEFAULT_print_Top; +$print_Toc = \&T2H_DEFAULT_print_Toc; +$print_Overview = \&T2H_DEFAULT_print_Overview; +$print_Footnotes = \&T2H_DEFAULT_print_Footnotes; +$print_About = \&T2H_DEFAULT_print_About; +$print_misc_header = \&T2H_DEFAULT_print_misc_header; +$print_misc_footer = \&T2H_DEFAULT_print_misc_footer; +$print_misc = \&T2H_DEFAULT_print_misc; +$print_section_footer = \&T2H_DEFAULT_print_section_footer; +$print_chapter_header = \&T2H_DEFAULT_print_chapter_header; +$print_section_header = \&T2H_DEFAULT_print_section_header; +$print_chapter_footer = \&T2H_DEFAULT_print_chapter_footer; +$print_page_head = \&T2H_DEFAULT_print_page_head; +$print_page_foot = \&T2H_DEFAULT_print_page_foot; +$print_head_navigation = \&T2H_DEFAULT_print_head_navigation; +$print_foot_navigation = \&T2H_DEFAULT_print_foot_navigation; +$button_icon_img = \&T2H_DEFAULT_button_icon_img; +$print_navigation = \&T2H_DEFAULT_print_navigation; +$about_body = \&T2H_DEFAULT_about_body; +$print_frame = \&T2H_DEFAULT_print_frame; +$print_toc_frame = \&T2H_DEFAULT_print_toc_frame; +#$toc_body = \&T2H_DEFAULT_toc_body; +$titlepage = \&T2H_DEFAULT_titlepage; +$css_lines = \&T2H_DEFAULT_css_lines; +$print_redirection_page = \&T2H_DEFAULT_print_redirection_page; +$node_file_name = \&T2H_DEFAULT_node_file_name; +$inline_contents = \&T2H_DEFAULT_inline_contents; + +######################################################################## +# Layout for html for every sections +# +sub T2H_DEFAULT_print_section +{ + my $fh = shift; + my $first_in_page = shift; + my $previous_is_top = shift; + my $buttons = \@SECTION_BUTTONS; + + if ($first_in_page and $SECTION_NAVIGATION) + { + &$print_head_navigation($fh, $buttons); + } + else + { # got to do this here, as it isn't done in print_head_navigation + main::print_lines($fh, $Texi2HTML::THIS_HEADER); + &$print_navigation($fh, $buttons) if ($SECTION_NAVIGATION); + } + my $nw = main::print_lines($fh); + if (defined $SPLIT + and (($SPLIT eq 'node') && $SECTION_NAVIGATION)) + { + &$print_foot_navigation($fh); + print $fh "$SMALL_RULE\n"; + &$print_navigation($fh, \@NODE_FOOTER_BUTTONS) if (!defined($WORDS_IN_PAGE) or (defined ($nw) + and $nw >= $WORDS_IN_PAGE)); + } +} + +sub T2H_DEFAULT_one_section($) +{ + my $fh = shift; + main::print_lines($fh, $Texi2HTML::THIS_HEADER); + main::print_lines($fh); + print $fh "$SMALL_RULE\n"; + &$print_foot_navigation($fh); + &$print_page_foot($fh); +} + +################################################################### +# 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 +# Texi2HTML::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($$) +{ + my $fh = shift; + my $do_page_head = shift; + &$print_page_head($fh) if ($do_page_head); +} +sub T2H_DEFAULT_print_Top_footer($$) +{ + my $fh = shift; + my $end_page = shift; + my $buttons = \@MISC_BUTTONS; + &$print_foot_navigation($fh); + print $fh "$SMALL_RULE\n"; + if ($end_page) + { + &$print_navigation($fh, $buttons); + &$print_page_foot($fh); + } +} +sub T2H_DEFAULT_print_Top($$) +{ + my $fh = shift; + my $has_top_heading = shift; + + # for redefining navigation buttons use: + # my $buttons = [...]; + # as it is, 'Top', 'Contents', 'Index', 'About' are printed + my $buttons = \@MISC_BUTTONS; + &$print_head_navigation($fh, $buttons) if ($SPLIT or $SECTION_NAVIGATION); + my $nw; + if (@$Texi2HTML::THIS_SECTION) + { + # if top-level node has content, then print it with extra header + #print $fh "<h1>$Texi2HTML::NAME{Top}</h1>\n" + print $fh "<h1 class=\"settitle\">$Texi2HTML::NAME{Top}</h1>\n" + unless ($has_top_heading); + $nw = main::print_lines($fh, $Texi2HTML::THIS_SECTION); + } + else + { + # top-level node is fully enclosed in @ifnothtml + # print fulltitle, subtitle, author, Overview or table of contents + print $fh $Texi2HTML::TITLEPAGE; + if (@{$Texi2HTML::OVERVIEW} and !$Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'}) + { + print $fh '<h2> ' . $Texi2HTML::NAME{'Overview'} . "</h2>\n" . "<blockquote\n"; + my $nw = main::print_lines($fh, $Texi2HTML::OVERVIEW); + print $fh "</blockquote>\n"; + } + elsif (@{$Texi2HTML::TOC_LINES} and !$Texi2HTML::THISDOC{'setcontentsaftertitlepage'}) + { + print $fh '<h1> ' . $Texi2HTML::NAME{'Contents'} . "</h1>\n"; + my $nw = main::print_lines($fh, $Texi2HTML::TOC_LINES); + } + } +} + +################################################################### +# Layout of Toc, Overview, and Footnotes pages +# By default, we use "normal" layout +# Texi2HTML::HREF of Next, Prev, Up, Forward, Back, etc are not defined +# use: my $buttons = [...] to redefine navigation buttons +sub T2H_DEFAULT_print_Toc +{ + return &$print_misc(@_); +} +sub T2H_DEFAULT_print_Overview +{ + return &$print_misc(@_); +} +sub T2H_DEFAULT_print_Footnotes +{ + return &$print_misc(@_); +} +sub T2H_DEFAULT_print_About +{ + # if there is no section navigation and it is not split, the + # navigation information is useless + return &$print_misc(@_) if ($SPLIT or $SECTION_NAVIGATION); +} + +sub T2H_DEFAULT_print_misc_header +{ + my $fh = shift; + my $buttons = shift; + &$print_page_head($fh) if $SPLIT; + &$print_head_navigation($fh, $buttons) if ($SPLIT or $SECTION_NAVIGATION); +} + +sub T2H_DEFAULT_print_misc_footer +{ + my $fh = shift; + my $buttons = shift; + my $nwords = shift; + &$print_foot_navigation($fh, $buttons); + print $fh "$SMALL_RULE\n"; + if ($SPLIT) + { + &$print_navigation($fh, $buttons);# if ($SPLIT ne 'node'); + &$print_page_foot($fh); + } +} + +sub T2H_DEFAULT_print_misc +{ + my $fh = shift; + my $buttons = \@MISC_BUTTONS; + &$print_misc_header($fh, $buttons); + print $fh "<h1>$Texi2HTML::NAME{This}</h1>\n"; + main::print_lines($fh); + &$print_misc_footer($fh, $buttons); +} +################################################################## +# section_footer is only called if SPLIT eq 'section' +# section_footer: after print_section of last section, before print_page_foot +# + +sub T2H_DEFAULT_print_section_footer +{ + my $fh = shift; + my $buttons = \@SECTION_FOOTER_BUTTONS; + &$end_section ($fh, 1); + &$print_navigation($fh, $buttons); +} + +################################################################### +# chapter_header and chapter_footer are only called if +# 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 +sub T2H_DEFAULT_print_chapter_header +{ + # nothing to do there, by default, the navigation panel + # is the section navigation panel + if (! $SECTION_NAVIGATION) + { # in this case print_navigation is called here. + my $fh = shift; + my $buttons = \@CHAPTER_BUTTONS; + &$print_head_navigation($fh, $buttons); #do that instead ? + #&$print_head_navigation($fh, $buttons); # FIXME VERTICAL_HEAD_NAVIGATION ? + print $fh "\n$MIDDLE_RULE\n"; + } +} + +sub T2H_DEFAULT_print_chapter_footer +{ + my $fh = shift; + my $buttons = \@CHAPTER_BUTTONS; + &$print_foot_navigation($fh); + print $fh "$BIG_RULE\n"; + &$print_navigation($fh, $buttons); +} + +sub T2H_DEFAULT_print_section_header +{ + # nothing to do there, by default + if (! $SECTION_NAVIGATION) + { # in this case print_navigation is called here. + my $fh = shift; + my $buttons = \@SECTION_BUTTONS; + &$print_head_navigation($fh, $buttons); + } +} + +################################################################### +# Layout of standard header and footer +# + +sub T2H_DEFAULT_print_page_head($) +{ + my $fh = shift; + my $longtitle = "$Texi2HTML::THISDOC{'title_simple_format'}"; + $longtitle .= ": $Texi2HTML::SIMPLE_TEXT{'This'}" if (defined ($Texi2HTML::SIMPLE_TEXT{'This'}) and ($Texi2HTML::SIMPLE_TEXT{'This'} !~ /^\s*$/) and $SPLIT); + my $description = $DOCUMENT_DESCRIPTION; + $description = $longtitle if (!defined($description)); + $description = "<meta name=\"description\" content=\"$description\">" if + ($description ne ''); + my $encoding = ''; + $encoding = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$ENCODING_NAME\">" if (defined($ENCODING_NAME) and ($ENCODING_NAME ne '')); + print $fh <<EOT; +$DOCTYPE +<html> +$Texi2HTML::THISDOC{'copying'}<!-- Created on $Texi2HTML::THISDOC{today} by $Texi2HTML::THISDOC{program} --> +<!-- +$Texi2HTML::THISDOC{program_authors} +--> +<head> +<title>$longtitle</title> + +$description +<meta name="keywords" content="$longtitle"> +<meta name="resource-type" content="document"> +<meta name="distribution" content="global"> +<meta name="Generator" content="$Texi2HTML::THISDOC{program}"> +$encoding +$CSS_LINES +$EXTRA_HEAD +</head> + +<body $BODYTEXT> +$AFTER_BODY_OPEN +EOT +} + +sub program_string() +{ + my $user = $Texi2HTML::THISDOC{'user'}; + my $date = $Texi2HTML::THISDOC{'today'}; + $user = '' if (!defined($user)); + $date = '' if (!defined($date)); + if (($user ne '') and ($date ne '')) + { + return &$I('This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.', { + 'user' => $user, 'date' => $date, 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' => $Texi2HTML::THISDOC{'program'} }); + } + elsif ($user ne '') + { + return &$I('This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.', { + 'user' => $user, 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' => $Texi2HTML::THISDOC{'program'} }); + } + elsif ($date ne '') + { + return &$I('This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.', { + 'date' => $date, 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' => $Texi2HTML::THISDOC{'program'} }); + } + return &$I('This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.', { + 'program_homepage' => $Texi2HTML::THISDOC{'program_homepage'}, 'program' +=> $Texi2HTML::THISDOC{'program'} }); +} + +sub T2H_DEFAULT_end_section($$) +{ + my $fh = shift; + my $end_foot_navigation = shift; + &$print_foot_navigation($fh) if ($end_foot_navigation); + print $fh "$BIG_RULE\n"; +} + +sub T2H_DEFAULT_print_page_foot($) +{ + my $fh = shift; + my $program_string = program_string(); + print $fh <<EOT; +<p> + <font size="-1"> + $program_string + </font> + <br> +$PRE_BODY_CLOSE +</p> +</body> +</html> +EOT +} + +################################################################### +# Layout of navigation panel + +sub T2H_DEFAULT_print_head_navigation($$) +{ + my $fh = shift; + my $buttons = shift; + if ($VERTICAL_HEAD_NAVIGATION) + { + print $fh <<EOT; +<table border="0" cellpadding="0" cellspacing="0"> +<tr valign="top"> +<td align="left"> +EOT + } + main::print_lines($fh, $Texi2HTML::THIS_HEADER); + &$print_navigation($fh, $buttons, $VERTICAL_HEAD_NAVIGATION); + if ($VERTICAL_HEAD_NAVIGATION) + { + print $fh <<EOT; +</td> +<td align="left"> +EOT + } + elsif (defined $SPLIT + and ($SPLIT eq 'node')) + { + print $fh "$SMALL_RULE\n"; + } +} + +sub T2H_DEFAULT_print_foot_navigation +{ + my $fh = shift; + if ($VERTICAL_HEAD_NAVIGATION) + { + print $fh <<EOT; +</td> +</tr> +</table> +EOT + } +} + +###################################################################### +# navigation panel +# +# how to create IMG tag +sub T2H_DEFAULT_button_icon_img +{ + my $button = shift; + my $icon = shift; + my $name = shift; + return '' if (!defined($icon)); + $button = "" if (!defined ($button)); + $name = '' if (!defined($name)); + my $alt = ''; + if ($name ne '') + { + if ($button ne '') + { + $alt = "$button: $name"; + } + else + { + $alt = $name; + } + } + else + { + $alt = $button; + } + return qq{<img src="$icon" border="0" alt="$alt" align="middle">}; +} + +sub T2H_DEFAULT_print_navigation +{ + my $fh = shift; + my $buttons = shift; + my $vertical = shift; + my $spacing = 1; + print $fh '<table cellpadding="', $spacing, '" cellspacing="', $spacing, + "\" border=\"0\">\n"; + + print $fh "<tr>" unless $vertical; + for my $button (@$buttons) + { + print $fh qq{<tr valign="top" align="left">\n} if $vertical; + print $fh qq{<td valign="middle" align="left">}; + + if (ref($button) eq 'CODE') + { + &$button($fh, $vertical); + } + elsif (ref($button) eq 'SCALAR') + { + print $fh "$$button" if defined($$button); + } + elsif (ref($button) eq 'ARRAY') + { + my $text = $button->[1]; + my $button_href = $button->[0]; + # verify that $button_href is simple text and text is a reference + if (defined($button_href) and !ref($button_href) + and defined($text) and (ref($text) eq 'SCALAR') and defined($$text)) + { # use given text + if ($Texi2HTML::HREF{$button_href}) + { + print $fh "" . + &$anchor('', + $Texi2HTML::HREF{$button_href}, + $$text + ) + ; + } + else + { + print $fh $$text; + } + } + } + elsif ($button eq ' ') + { # handle space button + print $fh + ($ICONS && $ACTIVE_ICONS{' '}) ? + &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{' '}) : + $NAVIGATION_TEXT{' '}; + #next; + } + elsif ($Texi2HTML::HREF{$button}) + { # button is active + my $btitle = $BUTTONS_GOTO{$button} ? + 'title="' . $BUTTONS_GOTO{$button} . '"' : ''; + if ($ICONS && $ACTIVE_ICONS{$button}) + { # use icon + print $fh '' . + &$anchor('', + $Texi2HTML::HREF{$button}, + &$button_icon_img($BUTTONS_NAME{$button}, + $ACTIVE_ICONS{$button}, + $Texi2HTML::SIMPLE_TEXT{$button}), + $btitle + ); + } + else + { # use text + print $fh + '[' . + &$anchor('', + $Texi2HTML::HREF{$button}, + $NAVIGATION_TEXT{$button}, + $btitle + ) . + ']'; + } + } + else + { # button is passive + print $fh + $ICONS && $PASSIVE_ICONS{$button} ? + &$button_icon_img($BUTTONS_NAME{$button}, + $PASSIVE_ICONS{$button}, + $Texi2HTML::SIMPLE_TEXT{$button}) : + + "[" . $NAVIGATION_TEXT{$button} . "]"; + } + print $fh "</td>\n"; + print $fh "</tr>\n" if $vertical; + } + print $fh "</tr>" unless $vertical; + print $fh "</table>\n"; +} + +###################################################################### +# Frames: this is from "Richard Y. Kim" <ryk@coho.net> +# Should be improved to be more conforming to other _print* functions +# FIXME pass toc_file and main_file as args or in $Texi2HTML::THISDOC ? + +sub T2H_DEFAULT_print_frame +{ + my $fh = shift; + my $toc_file = shift; + my $main_file = shift; + print $fh <<EOT; +$FRAMESET_DOCTYPE +<html> +<head><title>$Texi2HTML::THISDOC{title}</title></head> +<frameset cols="140,*"> + <frame name="toc" src="$toc_file"> + <frame name="main" src="$main_file"> +</frameset> +</html> +EOT +} + +sub T2H_DEFAULT_print_toc_frame +{ + my $fh = shift; + my $stoc_lines = shift; + &$print_page_head($fh); + print $fh <<EOT; +<h2>Content</h2> +EOT + print $fh map {s/\bhref=/target="main" href=/; $_;} @$stoc_lines; + print $fh "</body></html>\n"; +} + +# This subroutine is intended to fill @Texi2HTML::TOC_LINES and +# @Texi2HTML::OVERVIEW with the table of contents and short table of +# contents. +# +# arguments: +# ref on an array containing all the elements + +# each element is a reference on a hash. The following keys might be of +# use: +# 'top': true if this is the top element +# 'index_page': true if the element is an index page added because of index +# splitting +# 'toc_level': level of the element in the table of content. Highest level +# is 1 for the @top element and for chapters, appendix and so on, +# 2 for section, unnumberedsec and so on... +# 'tocid': label used for reference linking to the element in table of +# contents +# 'file': the file containing the element, usefull to do href to that file +# in case the document is split. +# 'text': text of the element, with section number +# 'text_nonumber': text of the element, without section number + +# Relevant configuration variables are: +# $NUMBER_SECTIONS +# $TOC_LIST_ATTRIBUTE: usefull in case a list is used +# $FRAMES: @Texi2HTML::OVERVIEW is used in one of the frames. +# $BEFORE_OVERVIEW +# $AFTER_OVERVIEW +# $BEFORE_TOC_LINES +# $AFTER_TOC_LINES +# $DO_CONTENTS +# $DO_SCONTENTS + +sub T2H_DEFAULT_toc_body($) +{ +} + +sub T2H_DEFAULT_inline_contents($$$) +{ + my $fh = shift; + my $command = shift; + my $element = shift; + my $name; + my $lines; + + my $result = undef; + + if ($command eq 'contents') + { + $name = $Texi2HTML::NAME{'Contents'}; + $lines = $Texi2HTML::TOC_LINES; + } + else + { + $name = $Texi2HTML::NAME{'Overview'}; + $lines = $Texi2HTML::OVERVIEW; + } + if (@{$lines}) + { + $result = [ "".&$anchor($element->{'id'})."\n", + "<h1>$name</h1>\n" ]; + push @$result, @$lines; + } + + return $result; +} + +sub T2H_DEFAULT_css_lines ($$) +{ + my $import_lines = shift; + my $rule_lines = shift; + return if (defined($CSS_LINES) or (!@$rule_lines and !@$import_lines and (! keys(%css_map)))); + $CSS_LINES = "<style type=\"text/css\">\n<!--\n"; + $CSS_LINES .= join('',@$import_lines) . "\n" if (@$import_lines); + foreach my $css_rule (sort(keys(%css_map))) + { + next unless ($css_map{$css_rule}); + $CSS_LINES .= "$css_rule {$css_map{$css_rule}}\n"; + } + $CSS_LINES .= join('',@$rule_lines) . "\n" if (@$rule_lines); + $CSS_LINES .= "-->\n</style>\n"; +} + +###################################################################### +# About page +# + +# PRE_ABOUT can be a function reference or a scalar. +# Note that if it is a scalar, T2H_InitGlobals has not been called, +# and all global variables like $ADDRESS are not available. +$PRE_ABOUT = sub +{ + return ' ' . program_string() . "\n"; +}; + +# If customizing $AFTER_ABOUT, be sure to put the content inside <p></p>. +$AFTER_ABOUT = ''; + +%BUTTONS_EXAMPLE = + ( + 'Top', ' ', + 'Contents', ' ', + 'Overview', ' ', + 'Index', ' ', + 'This', '1.2.3', + 'Back', '1.2.2', + 'FastBack', '1', + 'Prev', '1.2.2', + 'Up', '1.2', + 'Next', '1.2.4', + 'NodeUp', '1.2', + 'NodeNext', '1.2.4', + 'NodePrev', '1.2.2', + 'Following', '1.2.4', + 'Forward', '1.2.4', + 'FastForward', '2', + 'About', ' ', + 'First', '1.', + 'Last', '1.2.4', + ); + +sub T2H_DEFAULT_about_body +{ + my $about = "<p>\n"; + if (ref($PRE_ABOUT) eq 'CODE') + { + $about .= &$PRE_ABOUT(); + } + else + { + $about .= $PRE_ABOUT; + } + $about .= <<EOT; +</p> +<p> +EOT + $about .= &$I(' The buttons in the navigation panels have the following meaning:') . "\n"; + $about .= <<EOT; +</p> +<table border="1"> + <tr> +EOT + $about .= ' <th> ' . &$I('Button') . " </th>\n" . +' <th> ' . &$I('Name') . " </th>\n" . +' <th> ' . &$I('Go to') . " </th>\n" . +' <th> ' . &$I('From 1.2.3 go to') . "</th>\n" . " </tr>\n"; + + for my $button (@SECTION_BUTTONS) + { + next if $button eq ' ' || ref($button) eq 'CODE' || ref($button) eq 'SCALAR' || ref($button) eq 'ARRAY'; + $about .= " <tr>\n <td align=\"center\">"; + $about .= + ($ICONS && $ACTIVE_ICONS{$button} ? + &$button_icon_img($BUTTONS_NAME{$button}, $ACTIVE_ICONS{$button}) : + ' [' . $NAVIGATION_TEXT{$button} . '] '); + $about .= "</td>\n"; + $about .= <<EOT; + <td align="center">$BUTTONS_NAME{$button}</td> + <td>$BUTTONS_GOTO{$button}</td> + <td>$BUTTONS_EXAMPLE{$button}</td> + </tr> +EOT + } + + $about .= <<EOT; +</table> + +<p> +EOT + $about .= &$I(' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:') . "\n"; + +# where the <strong> Example </strong> assumes that the current position +# is at <strong> Subsubsection One-Two-Three </strong> of a document of +# the following structure: + $about .= <<EOT; +</p> + +<ul> +EOT + $about .= ' <li> 1. ' . &$I('Section One') . "\n" . +" <ul>\n" . +' <li>1.1 ' . &$I('Subsection One-One') . "\n"; + $about .= <<EOT; + <ul> + <li>...</li> + </ul> + </li> +EOT + $about .= ' <li>1.2 ' . &$I('Subsection One-Two') . "\n" . +" <ul>\n" . +' <li>1.2.1 ' . &$I('Subsubsection One-Two-One') . "</li>\n" . +' <li>1.2.2 ' . &$I('Subsubsection One-Two-Two') . "</li>\n" . +' <li>1.2.3 ' . &$I('Subsubsection One-Two-Three') . " \n" +. +' <strong><== ' . &$I('Current Position') . " </strong></li>\n" . +' <li>1.2.4 ' . &$I('Subsubsection One-Two-Four') . "</li>\n" . +" </ul>\n" . +" </li>\n" . +' <li>1.3 ' . &$I('Subsection One-Three') . "\n"; + $about .= <<EOT; + <ul> + <li>...</li> + </ul> + </li> +EOT + $about .= ' <li>1.4 ' . &$I('Subsection One-Four') . "</li>\n"; + $about .= <<EOT; + </ul> + </li> +</ul> +$AFTER_ABOUT +EOT + return $about; +} + +sub T2H_DEFAULT_titlepage() +{ + my $result = ''; + if (@{$Texi2HTML::THISDOC{'titles'}} + or @{$Texi2HTML::THISDOC{'subtitles'}} + or @{$Texi2HTML::THISDOC{'authors'}}) + { + $result = "<div align=\"center\">\n"; + foreach my $title (@{$Texi2HTML::THISDOC{'titles'}}) + { + $result .= '<h1>' . $title . "</h1>\n"; + } + foreach my $subtitle (@{$Texi2HTML::THISDOC{'subtitles'}}) + { + $result .= '<h2>' . $subtitle . "</h2>\n"; + } + foreach my $author (@{$Texi2HTML::THISDOC{'authors'}}) + { + $result .= '<strong> ' . $author . " </strong><br>\n"; + } + $result .= "</div>\n$DEFAULT_RULE\n"; + } + + $Texi2HTML::TITLEPAGE = $result . $Texi2HTML::TITLEPAGE; + + if ($Texi2HTML::THISDOC{'setcontentsaftertitlepage'} and @{$Texi2HTML::THISDOC{'inline_contents'}->{'contents'}}) + { + foreach my $line(@{$Texi2HTML::THISDOC{'inline_contents'}->{'contents'}}) + { + $Texi2HTML::TITLEPAGE .= $line; + } + $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n"; + } + if ($Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'} and @{$Texi2HTML::THISDOC{'inline_contents'}->{'shortcontents'}}) + { + foreach my $line(@{$Texi2HTML::THISDOC{'inline_contents'}->{'shortcontents'}}) + { + $Texi2HTML::TITLEPAGE .= $line; + } + $Texi2HTML::TITLEPAGE .= "$DEFAULT_RULE\n"; + } +} + +# FIXME Honor DOCUMENT_DESCRIPTION? +sub T2H_DEFAULT_print_redirection_page($) +{ + my $fh = shift; + my $longtitle = "$Texi2HTML::THISDOC{'title_simple_format'}"; + $longtitle .= ": $Texi2HTML::SIMPLE_TEXT{'This'}" if exists $Texi2HTML::SIMPLE_TEXT{'This'}; + my $description = $longtitle; + my $encoding = ''; + $encoding = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$ENCODING_NAME\">" if (defined($ENCODING_NAME) and ($ENCODING_NAME ne '')); + my $href = &$anchor('', $Texi2HTML::HREF{'This'}, $Texi2HTML::NAME{'This'}); + my $string = &$I('The node you are looking for is at %{href}.', + { 'href' => $href }); + print $fh <<EOT; +$DOCTYPE +<html> +<!-- Created on $Texi2HTML::THISDOC{'today'} by $Texi2HTML::THISDOC{'program'} --> +<!-- +$Texi2HTML::THISDOC{'program_authors'} +--> +<head> +<title>$longtitle</title> + +<meta name="description" content="$description"> +<meta name="keywords" content="$longtitle"> +<meta name="resource-type" content="document"> +<meta name="distribution" content="global"> +<meta name="Generator" content="$Texi2HTML::THISDOC{program}"> +$encoding +$CSS_LINES +<meta http-equiv="Refresh" content="2; url=$Texi2HTML::HREF{'This'}"> +$EXTRA_HEAD +</head> + +<body $BODYTEXT> +$AFTER_BODY_OPEN +<p>$string</p> +</body> +EOT +} + +sub T2H_DEFAULT_node_file_name($$) +{ + my $node = shift; + my $type = shift; + return undef if ($node->{'external_node'} or $node->{'index_page'} + or ($type eq 'top' and !$NEW_CROSSREF_STYLE)); + my $node_file_base; + if ($type eq 'top' and defined($TOP_NODE_FILE)) + { + $node_file_base = $TOP_NODE_FILE; + } + elsif ($NEW_CROSSREF_STYLE) + { + if ($TRANSLITERATE_NODE) + { + $node_file_base = $node->{'cross_manual_file'}; + } + else + { + $node_file_base = $node->{'cross_manual_target'}; + } + } + else + { + $node_file_base = main::remove_texi($node->{'texi'}); + $node_file_base =~ s/[^\w\.\-]/-/g; + } + if (defined($NODE_FILE_EXTENSION) and $NODE_FILE_EXTENSION ne '') + { + return ($node_file_base . ".$NODE_FILE_EXTENSION"); + } + return $node_file_base; +} + +######################################################################## +# Control of formatting: +# 1.) For some changes, it is often enough to change the value of +# some global map. It might necessitate building a little +# function along with the change in hash, if the change is the use +# of another function (in style_map). +# 2.) For other changes, reimplement one of the t2h_default_<fnc>* routines, +# give them another name, and assign them to the respective +# $<fnc> variable (below). + + +# +# This hash should have keys corresponding with the nonletter command accent +# whose following character is considered to be the argument +# This hash associates an accent macro to the ISO name for the accent if any. +# The customary use of this map is to find the ISO name appearing in html +# entity (like é) associated with a texinfo accent macro. +# +# The keys of the hash are +# ": umlaut +# ~: tilda accent +# ^: circumflex accent +# `: grave accent +# ': acute accent +# =: macron accent +%accent_map = ( + '"', 'uml', + '~', 'tilde', + '^', 'circ', + '`', 'grave', + "'", 'acute', + '=', '', + ); + +# +# texinfo "simple things" (@foo) to HTML ones +# +%simple_map = ( + "*", "<br>", # HTML+ + ' ', ' ', + "\t", ' ', + "\n", ' ', + # "­" or "­" could also be possible for @-, but it seems + # that some browser will consider this as an always visible hyphen mark + # which is not what we want (see http://www.cs.tut.fi/~jkorpela/shy.html) + '-', '', # hyphenation hint + '|', '', # used in formatting commands @evenfooting and friends + '/', '', + # spacing commands + ':', '', + '!', '!', + '?', '?', + '.', '.', + '@', '@', + '}', '}', + '{', '{', + ); + +# this map is used in preformatted text +%simple_map_pre = %simple_map; +$simple_map_pre{'*'} = "\n"; + +# +# texinfo "things" (@foo{}) to HTML ones +# +%things_map = ( + 'TeX' => 'TeX', + 'LaTeX' => 'LaTeX', +# pertusus: unknown by makeinfo, not in texinfo manual (@* is the right thing) +# 'br', '<br>', # paragraph break + 'bullet' => '*', +# #'copyright' => '(C)', + 'copyright' => '©', + 'registeredsymbol' => '®', + 'dots' => '<small class="dots">...</small>', + 'enddots' => '<small class="enddots">....</small>', + 'equiv' => '==', +# FIXME i18n + 'error' => 'error-->', + 'expansion' => '==>', + 'minus' => '-', + 'point' => '-!-', + 'print' => '-|', + 'result' => '=>', + # set in code using the language + # 'today', &pretty_date, + 'today' => '', + 'aa' => 'å', + 'AA' => 'Å', + 'ae' => 'æ', + 'oe' => 'œ', #pertusus: also œ. œ not in html 3.2 + 'AE' => 'Æ', + 'OE' => 'Œ', #pertusus: also Œ. Œ not in html 3.2 + 'o' => 'ø', + 'O' => 'Ø', + 'ss' => 'ß', + 'l' => 'ł', + 'L' => 'Ł', + 'exclamdown' => '¡', + 'questiondown' => '¿', + 'pounds' => '£', + 'ordf' => 'ª', + 'ordm' => 'º', + 'comma' => ',', + 'euro' => '€', + 'tie' => ' ', + ); + +# This map is used in preformatted environments +%pre_map = %things_map; +$pre_map{'dots'} = '...'; +$pre_map{'enddots'} = '....'; +#$pre_map{'br'} = "\n"; + +# ascii representation of @-commands +%ascii_simple_map = ( + "*", "\n", # HTML+ + ' ', ' ', + "\t", "\t", + "\n", "\n", + '-', '', # hyphenation hint + '|', '', # used in formatting commands @evenfooting and friends + '/', '', + ':', '', + '!', '!', + '?', '?', + '.', '.', + '@', '@', + '}', '}', + '{', '{', +); + +%ascii_things_map = ( + 'TeX' => 'TeX', + 'LaTeX' => 'LaTeX', + 'bullet' => '*', + 'copyright' => '(C)', + 'registeredsymbol' => '(R)', + 'dots' => '...', + 'enddots' => '....', + 'equiv' => '==', +# FIXME i18n + 'error' => 'error-->', + 'expansion' => '==>', + 'minus' => '-', + 'point' => '-!-', + 'print' => '-|', + 'result' => '=>', + 'today' => '', + 'aa' => 'aa', + 'AA' => 'AA', + 'ae' => 'ae', + 'oe' => 'oe', + 'AE' => 'AE', + 'OE' => 'OE', + 'o' => '/o', + 'O' => '/O', + 'ss' => 'ss', + 'l' => '/l', + 'L' => '/L', + 'exclamdown' => '?', + 'questiondown' => '!', + 'pounds' => '#', + 'ordf' => 'a', + 'ordm' => 'o', + 'comma' => ',', + 'euro' => 'Euro', + 'tie' => ' ', +); + +# +# This map is used when texi elements are removed and replaced +# by simple text +# +%simple_map_texi = ( + "*", "", + " ", " ", + "\t", " ", + "-", "-", # soft hyphen + "\n", "\n", + "|", "", + # spacing commands + ":", "", + "!", "!", + "?", "?", + ".", ".", + "-", "", + '@', '@', + '}', '}', + '{', '{', + ); + +# text replacing macros when texi commands are removed and plain text is +# produced +%texi_map = ( + 'TeX', 'TeX', + 'LaTeX', 'LaTeX', + 'bullet', '*', + 'copyright', 'C', + 'registeredsymbol', 'R', + 'dots', '...', + 'enddots', '....', + 'equiv', '==', + 'error', 'error-->', + 'expansion', '==>', + 'minus', '-', + 'point', '-!-', + 'print', '-|', + 'result', '=>', + 'today' => '', + 'aa', 'aa', + 'AA', 'AA', + 'ae', 'ae', + 'oe', 'oe', + 'AE', 'AE', + 'OE', 'OE', + 'o', 'o', + 'O', 'O', + 'ss', 'ss', + 'l', 'l', + 'L', 'L', + 'exclamdown', '! upside-down', + #'exclamdown', '¡', + 'questiondown', '? upside-down', + #'questiondown', '¿', + 'pounds', 'pound sterling', + #'pounds', '£' + 'ordf' => 'a', + 'ordm' => 'o', + 'comma' => ',', + 'euro' => 'Euro', + 'tie' => ' ', + ); + +# taken from +#Latin extended additionnal +#http://www.alanwood.net/unicode/latin_extended_additional.html +#C1 Controls and Latin-1 Supplement +#http://www.alanwood.net/unicode/latin_1_supplement.html +#Latin Extended-A +#http://www.alanwood.net/unicode/latin_extended_a.html +#Latin Extended-B +#http://www.alanwood.net/unicode/latin_extended_b.html +#dotless i: 0131 + +#http://www.alanwood.net/unicode/arrows.html 21** +#http://www.alanwood.net/unicode/general_punctuation.html 20** +#http://www.alanwood.net/unicode/mathematical_operators.html 22** + +%unicode_map = ( + 'bullet' => '2022', + 'copyright' => '00A9', + 'registeredsymbol' => '00AE', + 'dots' => '2026', + 'enddots' => '', + 'equiv' => '2261', + 'error' => '', + 'expansion' => '2192', + 'minus' => '2212', # in mathematical operators +# 'minus' => '002D', # in latin1 + 'point' => '2605', + 'print' => '22A3', + 'result' => '21D2', + 'today' => '', + 'aa' => '00E5', + 'AA' => '00C5', + 'ae' => '00E6', + 'oe' => '0153', + 'AE' => '00C6', + 'OE' => '0152', + 'o' => '00F8', + 'O' => '00D8', + 'ss' => '00DF', + 'l' => '0142', + 'L' => '0141', + 'exclamdown' => '00A1', + 'questiondown' => '00BF', + 'pounds' => '00A3', + 'ordf' => '00AA', + 'ordm' => '00BA', + 'comma' => '002C', + 'euro' => '20AC', + 'tie' => '', +# 'tie' => '0020', + ); + +%transliterate_map = ( + '00C5' => 'AA', + '00E5' => 'aa', + '00D8' => 'OE', + '00F8' => 'oe', + '00E6' => 'ae', + '0153' => 'oe', + '00C6' => 'AE', + '0152' => 'OE', + '00DF' => 'ss', + '0141' => 'L', + '0142' => 'l', + '00D0' => 'DH', + '0415' => 'E', + '0435' => 'e', + '0426' => 'C', + '042A' => 'W', + '044A' => 'w', + '042C' => 'X', + '044C' => 'x', + '042E' => 'yu', + '042F' => 'YA', + '044F' => 'ya', + '0433' => 'g', + '0446' => 'c', + '04D7' => 'IO', + '00DD' => 'Y', # unidecode gets this wrong ? + ); + +foreach my $symbol(keys(%unicode_map)) +{ + if ($unicode_map{$symbol} ne '' and !exists($transliterate_map{$symbol})) + { + $no_transliterate_map{$unicode_map{$symbol}} = 1; + } +} + +%ascii_character_map = ( + ' ' => '0020', + '!' => '0021', + '"' => '0022', + '#' => '0023', + '$' => '0024', + '%' => '0025', + '&' => '0026', + "'" => '0027', + '(' => '0028', + ')' => '0029', + '*' => '002A', + '+' => '002B', + ',' => '002C', + '-' => '002D', + '.' => '002E', + '/' => '002F', + ':' => '003A', + ';' => '003B', + '<' => '003C', + '=' => '003D', + '>' => '003E', + '?' => '003F', + '@' => '0040', + '[' => '005B', + '\\' => '005C', + ']' => '005D', + '^' => '005E', + '_' => '005F', + '`' => '0060', + '{' => '007B', + '|' => '007C', + '}' => '007D', + '~' => '007E', +); + +%perl_charset_to_html = ( + 'utf8' => 'utf-8', + 'utf-8-strict' => 'utf-8', + 'ascii' => 'us-ascii', +); + +# symbols used for the commands if $USE_ISO is true. +%iso_symbols = ( + 'equiv' => '≡', + 'dots' => '…', + 'bullet' => '•', + 'result' => '⇒', + 'expansion' => '→', + 'point' => '∗', + "'" => '’', + '`' => '‘', + ); + +# not used currently for html, but used in chm.init +%numeric_entity_map = (); + +foreach my $symbol (keys(%unicode_map)) +{ + if ($symbol ne '') + { + $numeric_entity_map{$symbol} = '&#' . hex($unicode_map{$symbol}) . ';'; + } +} + +# When the value begins with & the function with that name is used to do the +# html. The first argument is the text enclosed within {}, the second is the +# style name (which is also the key of the hash) +# +# Otherwithe the value is the html element used to enclose the text, and if +# there is a " the resulting text is also enclosed within `' +my %old_style_map = ( + 'acronym', '', + 'asis', '', + 'b', 'b', + 'cite', 'cite', + 'code', 'code', + 'command', 'code', + 'ctrl', '&default_ctrl', + 'dfn', 'em', + 'dmn', '', + 'email', '&default_email', + 'emph', 'em', + 'env', 'code', + 'file', '"tt', + 'i', 'i', + 'kbd', 'kbd', + 'key', 'kbd', + 'math', 'em', + 'option', '"samp', + 'r', '', + 'samp', '"samp', + 'sc', '&default_sc', + 'strong', 'strong', + 't', 'tt', + 'uref', '&default_uref', + 'url', '&default_url', + 'var', 'var', + 'verb', 'tt', + 'titlefont', '&default_titlefont', + 'w', '', + ); + +# default is {'args' => ['normal'], 'attribute' => ''}, +%style_map = ( + 'asis', {}, + 'b', {'attribute' => 'b'}, + 'cite', {'attribute' => 'cite'}, + 'code', {'args' => ['code'], 'attribute' => 'code'}, + 'command', {'args' => ['code'], 'attribute' => 'code'}, + 'ctrl', {'function' => \&t2h_default_ctrl,'type' => 'simple_type'}, + 'dfn', {'attribute' => 'em'}, + 'dmn', {}, + 'email', {'args' => ['code', 'normal'], + 'function' => \&t2h_default_email, + 'type' => 'simple_type'}, + #'email', {'args' => ['normal', 'normal'], + # 'function' => \&t2h_default_email}, + 'emph', {'attribute' => 'em'}, + 'env', {'args' => ['code'], 'attribute' => 'code'}, + 'file', {'args' => ['code'], 'attribute' => 'tt', 'quote' => '"'}, + 'i', {'attribute' => 'i'}, + 'slanted', {'attribute' => 'i'}, + 'sansserif', {'attribute' => 'span class="sansserif"'}, + 'kbd', {'args' => ['code'], 'attribute' => 'kbd'}, + 'key', {'begin' => '<', 'end' => '>'}, + 'math', {'attribute' => 'em'}, + 'option', {'args' => ['code'], 'attribute' => 'samp', 'quote' => '"'}, + 'r', {'attribute' => 'span class="roman"'}, + 'samp', {'args' => ['code'], 'attribute' => 'samp', 'quote' => '"'}, +# 'sc', {'function' => \&t2h_default_sc}, + 'sc', {'attribute' => 'small'}, + 'strong', {'attribute' => 'strong'}, + 't', {'attribute' => 'tt'}, + 'uref', {'function' => \&t2h_default_uref, + 'args' => ['code', 'normal', 'normal'], + 'type' => 'simple_type' }, + #'uref', {'function' => \&t2h_default_uref, + # 'args' => ['normal', 'normal', 'normal']}, + 'url', {'function' => \&t2h_default_uref, + 'args' => ['code', 'normal', 'normal'], + 'type' => 'simple_type'}, + 'indicateurl', {'args' => ['code'], 'begin' => '<<code>', 'end' => '</code>>','type' => 'simple_type'}, + 'var', {'attribute' => 'var'}, + 'verb', {'args' => ['code'], 'attribute' => 'tt'}, + 'titlefont', {'function' => \&t2h_default_titlefont, + 'type' => 'simple_type'}, + 'w', {'type' => 'simple_type'}, + ); + +%command_type = (); + +foreach my $style (keys(%style_map)) +{ + if (exists($style_map{$style}->{'type'})) + { + $command_type{$style} = $style_map{$style}->{'type'}; + } + else + { + $command_type{$style} = 'style'; + } +} + +%unicode_diacritical = ( + 'H' => '030B', + 'ringaccent' => '030A', + "'" => '0301', + 'v' => '030C', + ',' => '0327', + '^' => '0302', + 'dotaccent' => '0307', + '`' => '0300', + '=' => '0304', + '~' => '0303', + '"' => '0308', + 'udotaccent' => '0323', + 'ubaraccent' => '0332', + 'u' => '0306', + 'tieaccent' => '0361' +); + +%unicode_accents = ( + 'dotaccent' => { # dot above + 'A' => '0226', #C moz-1.2 + 'a' => '0227', #c moz-1.2 + 'B' => '1E02', + 'b' => '1E03', + 'C' => '010A', + 'c' => '010B', + 'D' => '1E0A', + 'd' => '1E0B', + 'E' => '0116', + 'e' => '0117', + 'F' => '1E1E', + 'f' => '1E1F', + 'G' => '0120', + 'g' => '0121', + 'H' => '1E22', + 'h' => '1E23', + 'i' => '0069', + 'I' => '0130', + 'N' => '1E44', + 'n' => '1E45', + 'O' => '022E', #Y moz-1.2 + 'o' => '022F', #v moz-1.2 + 'P' => '1E56', + 'p' => '1E57', + 'R' => '1E58', + 'r' => '1E59', + 'S' => '1E60', + 's' => '1E61', + 'T' => '1E6A', + 't' => '1E6B', + 'W' => '1E86', + 'w' => '1E87', + 'X' => '1E8A', + 'x' => '1E8B', + 'Y' => '1E8E', + 'y' => '1E8F', + 'Z' => '017B', + 'z' => '017C', + }, + 'udotaccent' => { # dot below + 'A' => '1EA0', + 'a' => '1EA1', + 'B' => '1E04', + 'b' => '1E05', + 'D' => '1E0C', + 'd' => '1E0D', + 'E' => '1EB8', + 'e' => '1EB9', + 'H' => '1E24', + 'h' => '1E25', + 'I' => '1ECA', + 'i' => '1ECB', + 'K' => '1E32', + 'k' => '1E33', + 'L' => '1E36', + 'l' => '1E37', + 'M' => '1E42', + 'm' => '1E43', + 'N' => '1E46', + 'n' => '1E47', + 'O' => '1ECC', + 'o' => '1ECD', + 'R' => '1E5A', + 'r' => '1E5B', + 'S' => '1E62', + 's' => '1E63', + 'T' => '1E6C', + 't' => '1E6D', + 'U' => '1EE4', + 'u' => '1EE5', + 'V' => '1E7E', + 'v' => '1E7F', + 'W' => '1E88', + 'w' => '1E89', + 'Y' => '1EF4', + 'y' => '1EF5', + 'Z' => '1E92', + 'z' => '1E93', + }, + 'ubaraccent' => { # line below + 'B' => '1E06', + 'b' => '1E07', + 'D' => '1E0E', + 'd' => '1E0F', + 'h' => '1E96', + 'K' => '1E34', + 'k' => '1E35', + 'L' => '1E3A', + 'l' => '1E3B', + 'N' => '1E48', + 'n' => '1E49', + 'R' => '1E5E', + 'r' => '1E5F', + 'T' => '1E6E', + 't' => '1E6F', + 'Z' => '1E94', + 'z' => '1E95', + }, + ',' => { # cedilla + 'C' => '00C7', + 'c' => '00E7', + 'D' => '1E10', + 'd' => '1E11', + 'E' => '0228', #C moz-1.2 + 'e' => '0229', #c moz-1.2 + 'G' => '0122', + 'g' => '0123', + 'H' => '1E28', + 'h' => '1E29', + 'K' => '0136', + 'k' => '0137', + 'L' => '013B', + 'l' => '013C', + 'N' => '0145', + 'n' => '0146', + 'R' => '0156', + 'r' => '0157', + 'S' => '015E', + 's' => '015F', + 'T' => '0162', + 't' => '0163', + }, + '=' => { # macron + 'A' => '0100', + 'a' => '0101', + 'E' => '0112', + 'e' => '0113', + 'I' => '012A', + 'i' => '012B', + 'G' => '1E20', + 'g' => '1E21', + 'O' => '014C', + 'o' => '014D', + 'U' => '016A', + 'u' => '016B', + 'Y' => '0232', #? moz-1.2 + 'y' => '0233', #? moz-1.2 + }, + '"' => { # diaeresis + 'A' => '00C4', + 'a' => '00E4', + 'E' => '00CB', + 'e' => '00EB', + 'H' => '1E26', + 'h' => '1E27', + 'I' => '00CF', + 'i' => '00EF', + 'O' => '00D6', + 'o' => '00F6', + 't' => '1E97', + 'U' => '00DC', + 'u' => '00FC', + 'W' => '1E84', + 'w' => '1E85', + 'X' => '1E8C', + 'x' => '1E8D', + 'y' => '00FF', + 'Y' => '0178', + }, + 'u' => { # breve + 'A' => '0102', + 'a' => '0103', + 'E' => '0114', + 'e' => '0115', + 'G' => '011E', + 'g' => '011F', + 'I' => '012C', + 'i' => '012D', + 'O' => '014E', + 'o' => '014F', + 'U' => '016C', + 'u' => '016D', + }, + "'" => { # acute + 'A' => '00C1', + 'a' => '00E1', + 'C' => '0106', + 'c' => '0107', + 'E' => '00C9', + 'e' => '00E9', + 'G' => '01F4', + 'g' => '01F5', + 'I' => '00CD', + 'i' => '00ED', + 'K' => '1E30', + 'k' => '1E31', + 'L' => '0139', + 'l' => '013A', + 'M' => '1E3E', + 'm' => '1E3F', + 'N' => '0143', + 'n' => '0144', + 'O' => '00D3', + 'o' => '00F3', + 'P' => '1E54', + 'p' => '1E55', + 'R' => '0154', + 'r' => '0155', + 'S' => '015A', + 's' => '015B', + 'U' => '00DA', + 'u' => '00FA', + 'W' => '1E82', + 'w' => '1E83', + 'Y' => '00DD', + 'y' => '00FD', + 'Z' => '0179', + 'z' => '018A', + }, + '~' => { # tilde + 'A' => '00C3', + 'a' => '00E3', + 'E' => '1EBC', + 'e' => '1EBD', + 'I' => '0128', + 'i' => '0129', + 'N' => '00D1', + 'n' => '00F1', + 'O' => '00D5', + 'o' => '00F5', + 'U' => '0168', + 'u' => '0169', + 'V' => '1E7C', + 'v' => '1E7D', + 'Y' => '1EF8', + 'y' => '1EF9', + }, + '`' => { # grave + 'A' => '00C0', + 'a' => '00E0', + 'E' => '00C8', + 'e' => '00E8', + 'I' => '00CC', + 'i' => '00EC', + 'N' => '01F8', + 'n' => '01F9', + 'O' => '00D2', + 'o' => '00F2', + 'U' => '00D9', + 'u' => '00F9', + 'W' => '1E80', + 'w' => '1E81', + 'Y' => '1EF2', + 'y' => '1EF3', + }, + '^' => { # circumflex + 'A' => '00C2', + 'a' => '00E2', + 'C' => '0108', + 'c' => '0109', + 'E' => '00CA', + 'e' => '00EA', + 'G' => '011C', + 'g' => '011D', + 'H' => '0124', + 'h' => '0125', + 'I' => '00CE', + 'i' => '00EE', + 'J' => '0134', + 'j' => '0135', + 'O' => '00D4', + 'o' => '00F4', + 'S' => '015C', + 's' => '015D', + 'U' => '00DB', + 'u' => '00FB', + 'W' => '0174', + 'w' => '0175', + 'Y' => '0176', + 'y' => '0177', + 'Z' => '1E90', + 'z' => '1E91', + }, + 'ringaccent' => { # ring + 'A' => '00C5', + 'a' => '00E5', + 'U' => '016E', + 'u' => '016F', + 'w' => '1E98', + 'y' => '1E99', + }, + 'v' => { # caron + 'A' => '01CD', + 'a' => '01CE', + 'C' => '010C', + 'c' => '010D', + 'D' => '010E', + 'd' => '010F', + 'E' => '011A', + 'e' => '011B', + 'G' => '01E6', + 'g' => '01E7', + 'H' => '021E', #K with moz-1.2 + 'h' => '021F', #k with moz-1.2 + 'I' => '01CF', + 'i' => '01D0', + 'K' => '01E8', + 'k' => '01E9', + 'L' => '013D', #L' with moz-1.2 + 'l' => '013E', #l' with moz-1.2 + 'N' => '0147', + 'n' => '0148', + 'O' => '01D1', + 'o' => '01D2', + 'R' => '0158', + 'r' => '0159', + 'S' => '0160', + 's' => '0161', + 'T' => '0164', + 't' => '0165', + 'U' => '01D3', + 'u' => '01D4', + 'Z' => '017D', + 'z' => '017E', + }, + 'H' => { # double acute + 'O' => '0150', + 'o' => '0151', + 'U' => '0170', + 'u' => '0171', + }, +); + +%transliterate_accent_map = (); +foreach my $command (keys(%unicode_accents)) +{ + foreach my $letter(keys (%{$unicode_accents{$command}})) + { + $transliterate_accent_map{$unicode_accents{$command}->{$letter}} + = $letter + unless (exists($transliterate_map{$unicode_accents{$command}->{$letter}})); + } +} + +%special_accents = ( + 'ringaccent' => 'aA', + "'" => 'aeiouyAEIOUY', + ',' => 'cC', + '^' => 'aeiouAEIOU', + '`' => 'aeiouAEIOU', + '~' => 'nNaoAO', + '"' => 'aeiouyAEIOU', +); + +foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents)) +{ + $style_map{$accent_command} = { 'function' => \&t2h_default_accent }; + $old_style_map{$accent_command} = '&default_accent'; + $style_map_texi{$accent_command} = { 'function' => \&t2h_default_ascii_accent }; +} + +sub default_accent($$) +{ + my $text = shift; + my $accent = shift; + return "&${text}$accent_map{$accent};" if (defined($accent_map{$accent}) and defined($special_accents{$accent}) and ($text =~ /^[$special_accents{$accent}]$/)); + return '&' . $text . 'ring;' if (($accent eq 'ringaccent') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/)); + return $text . '<' if ($accent eq 'v'); + return "&${text}cedil;" if (($accent eq ',') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/)); + return ascii_accents($text, $accent); +} + +sub t2h_default_accent($$) +{ + my $accent = shift; + my $args = shift; + + my $text = $args->[0]; + + return "&${text}$accent_map{$accent};" if (defined($accent_map{$accent}) and defined($special_accents{$accent}) and ($text =~ /^[$special_accents{$accent}]$/)); + return '&' . $text . 'ring;' if (($accent eq 'ringaccent') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/)); + return $text . '<' if ($accent eq 'v'); + return "&${text}cedil;" if (($accent eq ',') and (defined($special_accents{$accent})) and ($text =~ /^[$special_accents{$accent}]$/)); +# FIXME here there could be a conversion to the character in the right +# encoding, like +# if ($USE_UNICODE and defined($OUT_ENCODING) and $OUT_ENCODING ne '' +# and exists($unicode_accents{$accent}) and exists($unicode_accents{$accent}->{$text})) +# { +# my $encoded_char = Encode::encode($OUT_ENCODING, chr(hex($unicode_map{$thing})), Encode::FB_QUIET); +# return $encoded_char if ($encoded_char ne ''); +# } + if ($USE_NUMERIC_ENTITY) + { + if (exists($unicode_accents{$accent}) and exists($unicode_accents{$accent}->{$text})) + { + return ('&#' . hex($unicode_accents{$accent}->{$text}) . ';'); + } + } + return ascii_accents($text, $accent); +} + +sub ascii_accents($$) +{ + my $text = shift; + my $accent = shift; + return $text if ($accent eq 'dotless'); + return $text . $accent if (defined($accent_map{$accent})); + return $text . "''" if ($accent eq 'H'); + return $text . '.' if ($accent eq 'dotaccent'); + return $text . '*' if ($accent eq 'ringaccent'); + return $text . '[' if ($accent eq 'tieaccent'); + return $text . '(' if ($accent eq 'u'); + return $text . '_' if ($accent eq 'ubaraccent'); + return '.' . $text if ($accent eq 'udotaccent'); + return $text . '<' if ($accent eq 'v'); + return $text . ',' if ($accent eq ','); +} + +sub default_sc($$) +{ + return '<small>' . uc($_[0]) . '</small>'; +} + +# now unused, upcasing is done in normal_text +sub t2h_default_sc($$$) +{ + shift; + my $args = shift; + return '<small>' . uc($args->[0]) . '</small>'; +} + +sub default_ctrl($$) +{ + return "^$_[0]"; +} + +sub t2h_default_ctrl($$$) +{ + shift; + my $args = shift; + return "^$args->[0]"; +} + +sub default_sc_pre($$) +{ + return uc($_[0]); +} + +# now unused, upcasing is done in normal_text +sub t2h_default_sc_pre($$$) +{ + shift; + my $args = shift; + return uc($args->[0]); +} + +sub default_titlefont($$) +{ + return "<h1 class=\"titlefont\">$_[0]</h1>" if ($_[0] =~ /\S/); + return ''; +} + +# Avoid adding h1 if the text is empty +sub t2h_default_titlefont($$$) +{ + shift; + my $args = shift; + return "<h1 class=\"titlefont\">$args->[0]</h1>" if ($args->[0] =~ /\S/); + return ''; +} + +# At some point in time (before 4.7?) according to the texinfo +# manual, url shouldn't lead to a link but rather be formatted +# like text. It is now what indicateurl do, url is the same that +# uref with one arg. If we did like makeinfo did it would have been +#sub url($$) +#{ +# return '<<code>' . $_[0] . '</code>>'; +#} +# +# This is unused, t2h_default_uref is used instead +sub t2h_default_url ($$) +{ + shift; + my $args = shift; + my $url = shift @$args; + #$url =~ s/\s*$//; + #$url =~ s/^\s*//; + $url = main::normalise_space($url); + return '' unless ($url =~ /\S/); + return &$anchor('', $url, $url); +} + +sub default_url ($$) +{ + my $url = shift; + my $command = shift; + $url =~ s/\s*$//; + $url =~ s/^\s*//; + return '' unless ($url =~ /\S/); + return &$anchor('', $url, $url); +} + +sub default_uref($$) +{ + my $arg = shift; + my $command = shift; + my ($url, $text, $replacement); + ($url, $text, $replacement) = split /,\s*/, $arg; + $url =~ s/\s*$//; + $url =~ s/^\s*//; + $text = $replacement if (defined($replacement)); + $text = $url unless ($text); + return $text if ($url eq ''); + return &$anchor('', $url, $text); +} + +sub t2h_default_uref($$) +{ + shift; + my $args = shift; + my $url = shift @$args; + my $text = shift @$args; + my $replacement = shift @$args; + #$url =~ s/\s*$//; + #$url =~ s/^\s*//; + $url = main::normalise_space($url); + $replacement = '' if (!defined($replacement)); + $replacement = main::normalise_space($replacement); + $text = '' if (!defined($text)); + $text = main::normalise_space($text); + $text = $replacement if ($replacement ne ''); + $text = $url unless ($text ne ''); + return $text if ($url eq ''); + return &$anchor('', $url, $text); +} + +sub default_email($$) +{ + my $arg = shift; + my $command = shift; + my ($mail, $text); + ($mail, $text) = split /,\s*/, $arg; + $mail =~ s/\s*$//; + $mail =~ s/^\s*//; + $text = $mail unless ($text); + return $text if ($mail eq ''); + return &$anchor('', "mailto:$mail", $text); +} + +sub t2h_default_email($$) +{ + my $command = shift; + my $args = shift; + my $mail = shift @$args; + my $text = shift @$args; + $mail = main::normalise_space($mail); + #$mail =~ s/\s*$//; + #$mail =~ s/^\s*//; + $text = $mail unless (defined($text) and ($text ne '')); + $text = main::normalise_space($text); + return $text if ($mail eq ''); + return &$anchor('', "mailto:$mail", $text); +} + +sub t2h_default_ascii_accent($$$$) +{ + my $accent = shift; + my $args = shift; + + my $text = $args->[0]; + return ascii_accents($text, $accent); +} + +sub t2h_default_no_texi_email +{ + my $command = shift; + my $args = shift; + my $mail = shift @$args; + my $text = shift @$args; + $mail = main::normalise_space($mail); + #$mail =~ s/\s*$//; + #$mail =~ s/^\s*//; + return $text if (defined($text) and ($text ne '')); + return $mail; +} + +sub t2h_default_no_texi_image($$$$) +{ + my $command = shift; + my $args = shift; + my $text = $args->[0]; + $text = main::normalise_space($text); + my @args = split (/\s*,\s*/, $text); + return $args[0]; +} + +sub t2h_default_no_texi_acronym_like($$) +{ + my $command = shift; + my $args = shift; + my $acronym_texi = $args->[0]; + return (main::remove_texi($acronym_texi)); +} + +sub t2h_remove_command($$$$) +{ + return ''; +} + +# This is used for style in preformatted sections +my %old_style_map_pre = %old_style_map; +$old_style_map_pre{'sc'} = '&default_sc_pre'; +$old_style_map_pre{'titlefont'} = ''; + +foreach my $command (keys(%style_map)) +{ + $style_map_pre{$command} = {}; + $style_map_texi{$command} = {} if (!exists($style_map_texi{$command})); + $style_map_texi{$command}->{'args'} = $style_map{$command}->{'args'} + if (exists($style_map{$command}->{'args'})); + #print STDERR "COMMAND $command"; + + foreach my $key (keys(%{$style_map{$command}})) + { + $style_map_pre{$command}->{$key} = $style_map{$command}->{$key}; + } +} + +#$style_map_pre{'sc'}->{'function'} = \&t2h_default_sc_pre; +$style_map_pre{'sc'} = {}; +$style_map_pre{'titlefont'} = {}; + +#$style_map_texi{'sc'}->{'function'} = \&t2h_default_sc_pre; +$style_map_texi{'sc'} = {}; +$style_map_texi{'email'}->{'function'} = \&t2h_default_no_texi_email; + +####### special styles. You shouldn't need to change them +my %special_style = ( + #'xref' => ['keep','normal','normal','keep','normal'], + 'xref' => { 'args' => ['keep','keep','keep','keep','keep'], + 'function' => \&main::do_xref }, + 'ref' => { 'args' => ['keep','keep','keep','keep','keep'], + 'function' => \&main::do_xref }, + 'pxref' => { 'args' => ['keep','keep','keep','keep','keep'], + 'function' => \&main::do_xref }, + 'inforef' => { 'args' => ['keep','keep','keep'], + 'function' => \&main::do_xref }, + 'image' => { 'args' => ['keep'], 'function' => \&main::do_image }, + 'anchor' => { 'args' => ['keep'], 'function' => \&main::do_anchor_label }, + 'footnote' => { 'args' => ['keep'], 'function' => \&main::do_footnote }, + 'shortcaption' => { 'args' => ['keep'], 'function' => \&main::do_caption_shortcaption }, + 'caption' => { 'args' => ['keep'], 'function' => \&main::do_caption_shortcaption }, + 'acronym', {'args' => ['keep','keep'], 'function' => \&main::do_acronym_like}, + 'abbr', {'args' => ['keep','keep'], 'function' => \&main::do_acronym_like}, +); + +# @image is replaced by the first arg in strings +$style_map_texi{'image'} = { 'args' => ['keep'], + 'function' => \&t2h_default_no_texi_image }; + +$style_map_texi{'acronym'} = { 'args' => ['keep','keep'], + 'function' => \&t2h_default_no_texi_acronym_like }; +$style_map_texi{'abbr'} = { 'args' => ['keep','keep'], + 'function' => \&t2h_default_no_texi_acronym_like }; + +foreach my $special (keys(%special_style)) +{ + $style_map{$special} = $special_style{$special} + unless (defined($style_map{$special})); + $style_map_pre{$special} = $special_style{$special} + unless (defined($style_map_pre{$special})); + $style_map_texi{$special} = { 'args' => ['keep'], + 'function' => \&t2h_remove_command } + unless (defined($style_map_texi{$special})); +} +####### end special styles. + + +#foreach my $command (keys(%style_map)) +#{ +# print STDERR "STYLE_MAP_TEXI $command($style_map_texi{$command}) "; +# print STDERR "ARGS $style_map_texi{$command}->{'args'} " if (defined($style_map_texi{$command}->{'args'})); +# print STDERR "FUN $style_map_texi{$command}->{'function'} " if (defined($style_map_texi{$command}->{'function'})); +# print STDERR "\n"; +#} + +# uncomment to use the old interface +#%style_map = %old_style_map; +#%style_map_pre = %old_style_map_pre; + +%simple_format_simple_map_texi = %simple_map_pre; +%simple_format_texi_map = %pre_map; +%simple_format_style_map_texi = (); + +foreach my $command (keys(%style_map_texi)) +{ + #$simple_format_style_map_texi{$command} = {}; + foreach my $key (keys (%{$style_map_texi{$command}})) + { + #print STDERR "$command, $key, $style_map_texi{$command}->{$key}\n"; + $simple_format_style_map_texi{$command}->{$key} = + $style_map_texi{$command}->{$key}; + } + $simple_format_style_map_texi{$command} = {} if (!defined($simple_format_style_map_texi{$command})); +} + +foreach my $accent_command ('tieaccent', 'dotless', keys(%unicode_accents)) +{ +# $simple_format_style_map_texi{$accent_command}->{'args'} = ['normal']; + $simple_format_style_map_texi{$accent_command}->{'function'} = \&t2h_default_accent; +} + +%format_map = ( +# 'quotation' => 'blockquote', + # lists +# 'itemize' => 'ul', + 'enumerate' => 'ol', + 'multitable' => 'table', + 'table' => 'dl compact="compact"', + 'vtable' => 'dl compact="compact"', + 'ftable' => 'dl compact="compact"', + 'group' => '', + ); + +%special_list_commands = ( + 'table' => {}, + 'vtable' => {}, + 'ftable' => {}, + 'itemize' => { 'bullet' => '' } + ); +# +# texinfo format to align attribute of paragraphs +# + +%paragraph_style = ( + 'center' => 'center', + 'flushleft' => 'left', + 'flushright' => 'right', + ); + +# an eval of these $complex_format_map->{what}->{'begin'} yields beginning +# an eval of these $complex_format_map->{what}->{'end'} yields end +# $EXAMPLE_INDENT_CELL and SMALL_EXAMPLE_INDENT_CELL can be usefull here +$complex_format_map = +{ + 'example' => + { + 'begin' => q{"<table><tr>$EXAMPLE_INDENT_CELL<td>"}, + 'end' => q{"</td></tr></table>\n"}, + }, + 'smallexample' => + { + 'begin' => q{"<table><tr>$SMALL_EXAMPLE_INDENT_CELL<td>"}, + 'end' => q{"</td></tr></table>\n"}, + }, + 'display' => + { + 'begin' => q{"<table><tr>$EXAMPLE_INDENT_CELL<td>"}, + 'end' => q{"</td></tr></table>\n"}, + }, + 'smalldisplay' => + { + 'begin' => q{"<table><tr>$SMALL_EXAMPLE_INDENT_CELL<td>"}, + 'end' => q{"</td></tr></table>\n"}, + } +}; + +# format shouldn't narrow the margins + +$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'}; + +%def_map = ( + # basic commands + 'deffn', [ 'f', 'category', 'name', 'arg' ], + 'defvr', [ 'v', 'category', 'name' ], + 'deftypefn', [ 'f', 'category', 'type', 'name', 'arg' ], + 'deftypeop', [ 'f', 'category', 'class' , 'type', 'name', 'arg' ], + 'deftypevr', [ 'v', 'category', 'type', 'name' ], + 'defcv', [ 'v', 'category', 'class' , 'name' ], + 'deftypecv', [ 'v', 'category', 'class' , 'type', 'name' ], + 'defop', [ 'f', 'category', 'class' , 'name', 'arg' ], + 'deftp', [ 't', 'category', 'name', 'arg' ], + # shortcuts + # FIXME i18n + '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', 'deftypecv {Instance Variable}', + 'defmethod', 'defop Method', + 'deftypemethod', 'deftypeop Method', + ); + +# basic x commands +foreach my $key (keys(%def_map)) +{ + $def_map{$key . 'x'} = $def_map{$key}; +} + +# +# miscalleneous commands +# +# Depending on the value, the command arg or spaces following the command +# are handled differently: +# +# the value is a reference on a hash. +# the hash keys are +# 'arg' if the value is 'line' then the remaining of the line is the arg +# if it is a number it is the number of args (separated by spaces) +# 'skip' if the value is 'line' then the remaining of the line is skipped +# if the value is 'space' space but no newline is skipped +# if the value is 'whitespace' space is skipped +# if the value is 'linewhitespace' space is skipped if there are +# only spaces remaining on the line +# if the value is 'linespace' space but no newline is skipped if +# there are only spaces remaining on the line +# 'texi' if true it is some texinfo code and @value and @macros are expanded +# 'keep' if true the args and the macro are kept, otherwise the macro +# args and skipped stuffs are removed +%misc_command = ( + # not needed for formatting + 'raisesections' => {'skip' => 'line'}, # no arg + 'lowersections' => {'skip' => 'line'}, # no arg + 'contents' => {}, # no arg + 'shortcontents' => {}, # no arg + 'summarycontents'=> {}, # no arg + 'setcontentsaftertitlepage' => {}, # no arg + 'setshortcontentsaftertitlepage' => {}, # no arg + 'detailmenu' => {'skip' => 'whitespace'}, # no arg + 'end detailmenu' => {'skip' => 'space'}, # no arg + 'bye' => {'skip' => 'line'}, # no arg + # comments + 'comment' => {'arg' => 'line'}, + 'c' => {'arg' => 'line'}, + # in preamble + 'novalidate' => {}, # no arg + 'dircategory'=> {'skip' => 'line'}, # line. Position with regard + # with direntry is significant + 'pagesizes' => {'skip' => 'line', 'arg' => 2}, # can have 2 args + # or one? 200mm,150mm 11.5in + 'finalout' => {}, # no arg + 'paragraphindent' => {'skip' => 'line', 'arg' => 1}, # arg none asis + # or a number and forbids anything else on the line + 'firstparagraphindent' => {'skip' => 'line', 'arg' => 1}, # none insert + 'frenchspacing' => {'arg' => 1}, # on off + 'exampleindent' => {'skip' => 'line', 'arg' => 1}, # asis or a number + 'footnotestyle'=> {'skip' => 'line', 'arg' => 1}, # end and separate + # and nothing else on the line + 'afourpaper' => {'skip' => 'line'}, # no arg + 'afourlatex' => {'skip' => 'line'}, # no arg + 'afourwide' => {'skip' => 'line'}, # no arg + 'headings'=> {'skip' => 'line', 'arg' => 1}, + #off on single double singleafter doubleafter + # interacts with setchapternewpage + 'setchapternewpage' => {'skip' => 'line', 'arg' => 1}, # off on odd + 'everyheading' => {'arg' => 'line'}, + 'everyfooting' => {'arg' => 'line'}, + 'evenheading' => {'arg' => 'line'}, + 'evenfooting' => {'arg' => 'line'}, + 'oddheading' => {'arg' => 'line'}, + 'oddfooting' => {'arg' => 'line'}, + 'smallbook' => {'skip' => 'line'}, # no arg + 'setfilename' => {'arg' => 'line'}, + 'shorttitle' => {'arg' => 'line', 'texi' => 1}, + 'shorttitlepage' => {'arg' => 'line', 'texi' => 1}, + 'settitle' => {'arg' => 'line', 'texi' => 1}, + 'author' => {'arg' => 'line', 'texi' => 1}, + 'subtitle' => {'arg' => 'line', 'texi' => 1}, + 'title' => {'arg' => 'line', 'texi' => 1}, + 'syncodeindex' => {'skip' => 'linespace', 'arg' => 2}, + # args are index identifiers + 'synindex' => {'skip' => 'linespace', 'arg' => 2}, + 'defindex' => {'skip' => 'line', 'arg' => 1}, # one identifier arg + 'defcodeindex' => {'skip' => 'line', 'arg' => 1}, # one identifier arg + 'documentlanguage' => {'skip' => 'whitespace', 'arg' => 1}, + # language code arg + 'kbdinputstyle' => {'skip' => 'whitespace', 'arg' => 1}, # code + #example distinct + 'sp' => {'skip' => 'whitespace', 'arg' => 1}, # no arg + # at the end of line or a numerical arg + # formatting + 'page' => {}, # no arg (pagebreak) + 'refill' => {}, # no arg (obsolete, to be ignored) + 'noindent' => {'skip' => 'whitespace'}, # no arg + 'indent' => {'skip' => 'whitespace'}, + 'need' => {'skip' => 'line', 'arg' => 1}, # one numerical/real arg + 'exdent' => {'skip' => 'space'}, + # not valid for info (should be in @iftex) + 'vskip' => {'arg' => 'line'}, # arg line in TeX + 'cropmarks' => {}, # no arg + # miscalleneous + 'verbatiminclude'=> {'skip' => 'line'}, + 'documentencoding' => {'arg' => 1}, # makeinfo ignore the whole line + # ??? + 'filbreak' => {}, + # obsolete @-commands + 'quote-arg' => {}, + 'allow-recursion' => {}, + ); +my %misc_command_old = ( + # not needed for formatting + 'raisesections', 'line', # no arg + 'lowersections', 'line', # no arg + 'contents', 1, # no arg + 'shortcontents', 1, # no arg + 'summarycontents', 1, # no arg + 'detailmenu', 'whitespace', # no arg + 'end detailmenu', 'space', # no arg + #'end detailmenu', 1, # no arg + 'novalidate', 1, # no arg + 'bye', 'line', # no arg + # comments + 'comment', 'line', + 'c', 'line', + # in preamble + 'dircategory', 'line', # line. Position with regard with direntry is + # significant + 'pagesizes', 'line arg2', # can have 2 args + 'finalout', 1, # no arg + 'paragraphindent', 'line arg1', # in fact accepts only none asis + # or a number and forbids anything else on the line + 'firstparagraphindent', 'line arg1', # in fact accepts only none insert + 'exampleindent', 'line arg1', # in fact accepts only asis or a number + 'footnotestyle', 'line arg1', # in fact accepts only end and separate + # and nothing else on the line + 'afourpaper', 'line', # no arg + 'afourlatex', 'line', # no arg + 'afourwide', 'line', # no arg + 'headings', 'line', # one arg, possibilities are + #off on single double singleafter doubleafter + # interacts with setchapternewpage + 'setchapternewpage', 'line', # no arg + 'everyheading', 'line', + 'everyfooting', 'line', + 'evenheading', 'line', + 'evenfooting', 'line', + 'oddheading', 'line', + 'oddfooting', 'line', + 'smallbook', 'line', # no arg + 'setfilename', 'line', + 'shorttitle', 'linetexi', + 'shorttitlepage', 'linetexi', + 'settitle', 'linetexi', + 'author', 'linetexi', + 'subtitle', 'linetexi', + 'title','linetexi', + 'syncodeindex','linespace arg2', # args are + 'synindex','linespace arg2', + 'defindex', 'line arg1', # one identifier arg + 'defcodeindex', 'line arg1', # one identifier arg + 'documentlanguage', 'whitespace arg1', # one language code arg + 'kbdinputstyle', 'whitespace arg1', # one arg within + #code example distnct + 'sp', 'whitespace arg1', # no arg at the en of line or a numerical arg + # formatting + 'page', 1, # no arg (pagebreak) + 'refill', 1, # no arg (obsolete, to be ignored)) + 'noindent', 'space', # no arg + 'need', 'line arg1', # one numerical/real arg + 'exdent', 'space', + # not valid for info (should be in @iftex) + 'vskip', 'line', # arg line in TeX + 'cropmarks', 1, # no arg + # miscalleneous + 'verbatiminclude', 'line', + 'documentencoding', 'arg1', + # ??? + 'filbreak', 1, + ); + +%format_in_paragraph = ( + 'group' => 1, + 'html' => 1, +); +# map mapping css specification to style + +%css_map = + ( + 'ul.toc' => "$TOC_LIST_STYLE", + 'pre.menu-comment' => "$MENU_PRE_STYLE", + 'pre.menu-preformatted' => "$MENU_PRE_STYLE", + 'a.summary-letter' => 'text-decoration: none', + 'pre.display' => 'font-family: serif', + 'pre.smalldisplay' => 'font-family: serif; font-size: smaller', + 'pre.smallexample' => 'font-size: smaller', + 'span.sansserif' => 'font-family:sans-serif; font-weight:normal;', + 'span.roman' => 'font-family:serif; font-weight:normal;' + ); + +$css_map{'pre.format'} = $css_map{'pre.display'}; +$css_map{'pre.smallformat'} = $css_map{'pre.smalldisplay'}; +$css_map{'pre.smalllisp'} = $css_map{'pre.smallexample'}; + +# The command_handler arrays are for commands formatted externally. +# The function references in @command_handler_init are called +# before the second pass, before the @-commands text collection. +# Those in @command_handler_process are called between the second pass +# and the third pass, after collection of @-commands text and before their +# expansion. +# Those in @command_handler_process are called after the third pass, +# after the document generation. +@command_handler_init = (); +@command_handler_process = (); +@command_handler_finish = (); + +# the keys of %command_handler are @-command names and the value +# is a hash reference with the following keys: +# 'init' function reference used to collect the @-command text +# 'expand' function reference used when expanding the @-command text +%command_handler = (); + +# formatting functions + +$anchor = \&t2h_default_anchor; +$def_item = \&t2h_default_def_item; +$def = \&t2h_default_def; +$menu = \&t2h_default_menu; +$menu_link = \&t2h_default_menu_link; +$menu_comment = \&t2h_default_menu_comment; +$menu_description = \&t2h_default_menu_description; +$simple_menu_link = \&t2h_default_simple_menu_link; +$external_ref = \&t2h_default_external_ref; +$external_href = \&t2h_default_external_href; +$internal_ref = \&t2h_default_internal_ref; +$table_item = \&t2h_default_table_item; +$table_line = \&t2h_default_table_line; +$table_list = \&t2h_default_table_list; +$row = \&t2h_default_row; +$cell = \&t2h_default_cell; +$list_item = \&t2h_default_list_item; +$comment = \&t2h_default_comment; +$def_line = \&t2h_default_def_line; +$def_line_no_texi = \&t2h_default_def_line_no_texi; +$raw = \&t2h_default_raw; +$raw_no_texi = \&t2h_default_raw_no_texi; +$heading = \&t2h_default_heading; +$paragraph = \&t2h_default_paragraph; +$preformatted = \&t2h_default_preformatted; +$foot_line_and_ref = \&t2h_default_foot_line_and_ref; +$foot_section = \&t2h_default_foot_section; +$image_files = \&t2h_default_image_files; +$image = \&t2h_default_image; +$address = \&t2h_default_address; +$index_entry_label = \&t2h_default_index_entry_label; +$index_summary = \&t2h_default_index_summary; +$summary_letter = \&t2h_default_summary_letter; +$index_entry = \&t2h_default_index_entry; +$index_letter = \&t2h_default_index_letter; +$print_index = \&t2h_default_print_index; +$protect_text = \&t2h_default_protect_text; +$normal_text = \&t2h_default_normal_text; +$complex_format = \&t2h_default_complex_format; +$cartouche = \&t2h_default_cartouche; +$sp = \&t2h_default_sp; +$definition_category = \&t2h_default_definition_category; +$copying_comment = \&t2h_default_copying_comment; +$index_summary_file_entry = \&t2h_default_index_summary_file_entry; +$index_summary_file_end = \&t2h_default_index_summary_file_end; +$index_summary_file_begin = \&t2h_default_index_summary_file_begin; +$empty_line = \&t2h_default_empty_line; +$unknown = \&t2h_default_unknown; +$unknown_style = \&t2h_default_unknown_style; +$caption_shortcaption = \&t2h_caption_shortcaption; +$float = \&t2h_default_float; +$listoffloats = \&t2h_default_listoffloats; +$listoffloats_entry = \&t2h_default_listoffloats_entry; +$listoffloats_caption = \&t2h_default_listoffloats_caption; +$listoffloats_float_style = \&t2h_default_listoffloats_float_style; +$listoffloats_style = \&t2h_default_listoffloats_style; +$acronym_like = \&t2h_default_acronym_like; +$quotation = \&t2h_default_quotation; +$quotation_prepend_text = \&t2h_default_quotation_prepend_text; +$paragraph_style_command = \&t2h_default_paragraph_style_command; +$heading_texi = \&t2h_default_heading_texi; +$index_element_heading_texi = \&t2h_default_index_element_heading_texi; + +# This function is called whenever a complex format is processed +# +# arguments: +# name of the format +# text appearing inside the format +# +# an eval of $complex_format->{format name}->{'begin'} should lead to the +# beginning of the complex format, an eval of +# $complex_format->{format name}->{'end'} should lead to the end of the +# complex format. +sub t2h_default_complex_format($$) +{ + my $name = shift; + my $text = shift; + return '' if ($text eq ''); + my $beginning = eval "$complex_format_map->{$name}->{'begin'}"; + if ($@ ne '') + { + print STDERR "$ERROR Evaluation of $complex_format_map->{$name}->{'begin'}: $@"; + $beginning = ''; + + } + my $end = eval "$complex_format_map->{$name}->{'end'}"; + if ($@ ne '') + { + print STDERR "$ERROR Evaluation of $complex_format_map->{$name}->{'end'}: $@"; + $end = ''; + + } + return $beginning . $text . $end; +} + +sub t2h_default_empty_line($$) +{ + my $text = shift; + my $state = shift; + #ignore the line if it just follows a deff + return '' if ($state->{'deff_line'}); + return $text; +} + +sub t2h_default_unknown($$$$) +{ + my $macro = shift; + my $line = shift; + my $stack = shift; + my $state = shift; + + my ($result_line, $result, $result_text, $message); + return ($line, 0, undef, undef); +} + +sub t2h_default_unknown_style($$$$) +{ + my $command = shift; + my $text = shift; + my $state = shift; + + my ($result, $result_text, $message); + return (0, undef, undef); +} + +sub t2h_caption_shortcaption($) +{ + my $float = shift; + my $caption_lines; + my $shortcaption_lines; + my $style = $float->{'style_texi'}; + if (defined($float->{'nr'})) + { + my $nr = $float->{'nr'}; + if ($style ne '') + { + $style = &$I('%{style} %{number}', { 'style' => $style, 'number' => $nr}); + } + else + { + $style = $nr; + } + } + + if (defined($float->{'caption_texi'})) + { + @$caption_lines = @{$float->{'caption_texi'}}; + if (defined($style)) + { + $caption_lines->[0] = '@strong{' . &$I('%{style}: %{caption_first_line}', { 'style' => $style, 'caption_first_line' => $caption_lines->[0] }); + } + else + { + $caption_lines->[0] = '@strong{' . $caption_lines->[0]; + } + push @$caption_lines, "}\n"; + } + elsif (defined($style)) + { + $caption_lines->[0] = '@strong{' . $style . '}' . "\n"; + } + if (defined($float->{'shortcaption_texi'})) + { + @$shortcaption_lines = @{$float->{'shortcaption_texi'}}; + if (defined($style)) + { + $shortcaption_lines->[0] = '@strong{' . &$I('%{style}: %{shortcaption_first_line}', { 'style' => $style, 'shortcaption_first_line' => $shortcaption_lines->[0] }); + } + else + { + $shortcaption_lines->[0] = '@strong{' . $shortcaption_lines->[0]; + } + push @$shortcaption_lines, "}\n"; + } + elsif (defined($style)) + { + $shortcaption_lines->[0] = '@strong{' . $style . '}' . "\n"; + } + return ($caption_lines, $shortcaption_lines); +} + +sub t2h_default_float($$$$$) +{ + my $text = shift; + my $float = shift; + my $caption = shift; + my $shortcaption = shift; + + my $label = ''; + if (exists($float->{'id'})) + { + $label = &$anchor($float->{'id'}); + } + my $caption_text = ''; + + if (defined($float->{'caption_texi'})) + { + $caption_text = $caption; + } + elsif (defined($float->{'shortcaption_texi'})) + { + $caption_text = $shortcaption; + } + elsif (defined($caption)) + { + $caption_text = $caption; + } + + return '<div class="float">' . "$label\n" . $text . '</div>' . $caption_text; +} + +sub t2h_default_listoffloats_style($) +{ + my $style_texi = shift; + return ($style_texi); +} + +sub t2h_default_listoffloats_float_style($$) +{ + my $style_texi = shift; + my $float = shift; + + my $style = $float->{'style_texi'}; + if (defined($float->{'nr'})) + { + my $nr = $float->{'nr'}; + if ($style ne '') + { + $style = &$I('%{style} %{number}', { 'style' => $style, 'number' => $nr}); + } + else + { + $style = $nr; + } + } + return $style; +} + +sub t2h_default_listoffloats_caption($) +{ + my $float = shift; + if (defined($float->{'shortcaption_texi'})) + { + return [ @{$float->{'shortcaption_texi'}} ]; + } + elsif (defined($float->{'caption_texi'})) + { + return [ @{$float->{'caption_texi'}} ]; + } + return [ ]; +} + +sub t2h_default_listoffloats_entry($$$$) +{ + my $style_texi = shift; + my $float = shift; + my $float_style = shift; + my $caption = shift; + my $href = shift; + + return '<dt>' . &$anchor('', $href, $float_style) . '</dt><dd>' . $caption +. '</dd>' . "\n"; +} + +sub t2h_default_listoffloats($$$) +{ + my $style_texi = shift; + my $style = shift; + my $float_entries = shift; + + my $result = "<dl class=\"listoffloats\">\n" ; + foreach my $float_entry (@$float_entries) + { + $result .= $float_entry; + } + return $result . "</dl>\n"; +} + +# This function is used to protect characters which are special in html +# in inline text: &, ", <, and >. +# +# argument: +# text to be protected +sub t2h_default_protect_text($) +{ + my $text = shift; + $text =~ s/&/&/g; + $text =~ s/</</g; + $text =~ s/>/>/g; + $text =~ s/\"/"/g; + return $text; +} + + +sub in_small_caps($) +{ + my $style_stack = shift; + my $in_sc = 0; + if ($style_stack and scalar(@{$style_stack})) + { + my $level = $#$style_stack; + #print STDERR ":::$level ::@{$style_stack}\n"; + while ($level >= 0) + { + if ($style_stack->[$level] eq 'sc') + { + $in_sc = 1; + last; + } + $level--; + } + } + return $in_sc; +} +# +# +sub t2h_default_normal_text($$$$$) +{ + my $text = shift; + my $in_raw_text = shift; + my $in_preformatted = shift; + my $in_code = shift; + my $style_stack = shift; + $text = uc($text) if (in_small_caps($style_stack)); + $text = &$protect_text($text) unless($in_raw_text); + if (! $in_code and !$in_preformatted) + { + if ($USE_ISO and !$in_raw_text) + { + $text =~ s/---/\&mdash\;/g; + $text =~ s/--/\&ndash\;/g; + $text =~ s/``/\&ldquo\;/g; + $text =~ s/''/\&rdquo\;/g; + } + else + { + if ($in_raw_text) #FIXME really do that ? + { + $text =~ s/``/"/g; + $text =~ s/''/"/g; + } + else + { + $text =~ s/``/"/g; + $text =~ s/''/"/g; + } + # temporary reuse '' to store --- !.... + # FIXME won't '---' be handled wrongly? + # FIXME really do that in raw text? + $text =~ s/---/''/g; + $text =~ s/--/-/g; + $text =~ s/''/--/g; + } + } + return $text; +} + +# This function produces an anchor +# +# arguments: +# $name : anchor name +# $href : anchor href +# text : text displayed +# extra_attribs : added to anchor attributes list +sub t2h_default_anchor($;$$$) +{ + my $name = shift; + my $href = shift; + my $text = shift; + my $attributes = shift; +#print STDERR "!$name!$href!$text!$attributes!\n"; + if (!defined($attributes) or ($attributes !~ /\S/)) + { + $attributes = ''; + } + else + { + $attributes = ' ' . $attributes; + } + $name = '' if (!defined($name) or ($name !~ /\S/)); + $href = '' if (!defined($href) or ($href !~ /\S/)); + $text = '' if (!defined($text)); + return $text if (($name eq '') and ($href eq '')); + $name = "name=\"$name\"" if ($name ne ''); + $href = "href=\"$href\"" if ($href ne ''); + $href = ' ' . $href if (($name ne '') and ($href ne '')); +#print STDERR "!!!$name!$href!$text!$attributes!\n"; + return "<a ${name}${href}${attributes}>$text</a>"; +} + +# This function is used to format the text associated with a @deff/@end deff +# +# argument: +# text +# +# $DEF_TABLE should be used to distinguish between @def formatted as table +# and as definition lists. +sub t2h_default_def_item($) +{ + my $text = shift; + if ($text =~ /\S/) + { + if (! $DEF_TABLE) + { + return '<dd>' . $text . '</dd>'; + } + else + { + return '<tr><td colspan="2">' . $text . '</td></tr>'; + } + } + return ''; +} + +sub t2h_default_definition_category($$$) +{ + my $name = shift; + my $class = shift; + my $style = shift; + return ($name) if (!defined($class) or $class =~ /^\s*$/); + if ($style eq 'f') + { + return &$I('%{name} on %{class}', { 'name' => $name, 'class' => $class }); + } + elsif ($style eq 'v') + { + return &$I('%{name} of %{class}', { 'name' => $name, 'class' => $class }); + } + else + { + return $name; + } +} + +# format the container for the @deffn line and text +# +# argument +# text of the whole @def, line and associated text. +# +# $DEF_TABLE should be used. +sub t2h_default_def($) +{ + my $text = shift; + if ($text =~ /\S/) + { + if (! $DEF_TABLE) + { + return "<dl>\n" . $text . "</dl>\n"; + } + else + { + return "<table width=\"100%\">\n" . $text . "</table>\n"; + } + } + return ''; + +} + +# a whole menu +# +# argument: +# the whole menu text (entries and menu comments) +# +# argument: +# whole menu text. +sub t2h_default_menu($) +{ + my $text = shift; + if ($text =~ /\S/) + { + return "<table class=\"menu\" border=\"0\" cellspacing=\"0\">\n" + . $text . "</table>\n"; + } +} + +# a simple menu entry ref in case we aren't in a standard menu context +sub t2h_default_simple_menu_link($$$$$$) +{ + my $entry = shift; + my $preformatted = shift; + my $href = shift; + my $node = shift; + my $name = shift; + my $ending = shift; + $ending = '' if (!defined($ending)); + if (($entry eq '') or $NODE_NAME_IN_MENU or $preformatted) + { + $name .= ':' if ($name ne ''); + $entry = "$MENU_SYMBOL$name$node"; + } + $entry = &$anchor('', $href, $entry) if ($href); + $entry .= $ending if ($preformatted); + $entry .= ' ' unless $preformatted; + return $entry; +} + +# formats a menu entry link pointing to a node or section +# +# arguments: +# the entry text +# the state, a hash reference holding informations about the context, with a +# usefull entry, 'preformatted', true if we are in a preformatted format +# (a format keeping space between words). In that case a function +# of the main program, main::do_preformatted($text, $state) might +# be used to format the text with the current format style. +# href is optionnal. It is the reference to the section or the node anchor +# which should be used to make the link (typically it is the argument +# of a href= attribute in a <a> element). +sub t2h_default_menu_link($$$$$$) +{ + my $entry = shift; + my $state = shift; + my $href = shift; + my $node = shift; + my $name = shift; + my $ending = shift; +#print STDERR "MENU_LINK\n"; + if (($entry eq '') or $NODE_NAME_IN_MENU or $state->{'preformatted'}) + { + $name .= ':' if ($name ne ''); + $entry = "$MENU_SYMBOL$name$node"; + } + $entry = &$anchor ('', $href, $entry) if (defined($href)); + return $entry if ($SIMPLE_MENU); + if ($state->{'preformatted'}) + { + return '<tr><td>' . main::do_preformatted($entry . $ending, $state); + } + return "<tr><td align=\"left\" valign=\"top\">$entry</td><td> </td>"; +} + +sub simplify_text($) +{ + my $text = shift; + $text =~ s/[^\w]//og; + return $text; +} + +# formats a menu entry description, ie the text appearing after the node +# specification in a menu entry an spanning until there is another +# menu entry, an empty line or some text at the very beginning of the line +# (we consider that text at the beginning of the line begins a menu comment) +# +# arguments: +# the description text +# the state. See menu_entry. +# the heading of the element associated with the node. +sub t2h_default_menu_description($$$) +{ + my $text = shift; + my $state = shift; + my $element_text = shift; + return $text if ($SIMPLE_MENU); +#print STDERR "MENU_DESCRIPTION element_text!$element_text, text!$text\n"; + if ($state->{'preformatted'}) + { + return main::do_preformatted($text, $state) . '</td></tr>'; + } + elsif ($AVOID_MENU_REDUNDANCY) + { + $text = '' if (simplify_text($element_text) eq simplify_text($text)); + } + return "<td align=\"left\" valign=\"top\">$text</td></tr>\n"; +} + +# a menu comment (between menu lines) +# formats the container of a menu comment. A menu comment is any text +# appearing between menu lines, either separated by an empty line from +# the preceding menu entry, or a text beginning at the first character +# of the line (text not at the very beginning of the line is considered to +# be the continuation of a menu entry description text). +# +# The text itself is considered to be in a preformatted environment +# with name 'menu-commment' and with style $MENU_PRE_STYLE. +# +# argument +# text contained in the menu comment. +sub t2h_default_menu_comment($) +{ + my $text = shift; + return $text if ($SIMPLE_MENU); + if ($text =~ /\S/) + { + return "<tr><th colspan=\"3\" align=\"left\" valign=\"top\">$text</th></tr>"; + } + return ''; +} + +# Construct a href to an external source of information. +# node is the node with texinfo @-commands +# node_id is the node transliterated and transformed as explained in the +# texinfo manual +# node_xhtml_id is the node transformed such that it is unique and can +# be used to make an html cross ref as explained in the texinfo manual +# file is the file in '(file)node' +sub t2h_default_external_href($$$) +{ + my $node = shift; + my $node_id = shift; + my $node_xhtml_id = shift; + my $file = shift; + $file = '' if (!defined($file)); + my $default_target_split = $EXTERNAL_CROSSREF_SPLIT; + my $target_split; + my $target_mono; + my $href_split; + my $href_mono; + if ($file ne '') + { + if ($NEW_CROSSREF_STYLE) + { + $file =~ s/\.[^\.]*$//; + $file =~ s/^.*\///; + my $href; + if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file})) + { + if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'split'})) + { + $target_split = 1; + $href_split = $Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'split'}->{'href'}; + } + if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'mono'})) + { + $target_mono = 1; + $href_mono = $Texi2HTML::THISDOC{'htmlxref'}->{$file}->{'mono'}->{'href'}; + } + } + + if ((not $target_mono) and (not $target_split)) + { # nothing specified for that manual, use default + $target_split = $default_target_split; + } + elsif ($target_split and $target_mono) + { # depends on the splitting of the manual + $target_split = $SPLIT; + } + elsif ($target_mono) + { # only mono specified + $target_split = 0; + } + + if ($target_split) + { + if (defined($href_split)) + { + $file = "$href_split"; + } + elsif (defined($EXTERNAL_DIR)) + { + $file = "$EXTERNAL_DIR/$file"; + } + elsif ($SPLIT) + { + $file = "../$file"; + } + $file .= "/"; + } + else + {# target not split + if (defined($href_mono)) + { + $file = "$href_mono"; + } + else + { + if (defined($EXTERNAL_DIR)) + { + $file = "$EXTERNAL_DIR/$file"; + } + elsif ($SPLIT) + { + $file = "../$file"; + } + $file .= "." . $NODE_FILE_EXTENSION; + } + } + } + else + { + $file .= "/"; + if (defined($EXTERNAL_DIR)) + { + $file = $EXTERNAL_DIR . $file; + } + else + { + $file = '../' . $file; + } + } + } + else + { + $target_split = $default_target_split; + } + if ($node eq '') + { + if ($NEW_CROSSREF_STYLE) + { + if ($target_split) + { + return $file . $TOP_NODE_FILE . '.' . $NODE_FILE_EXTENSION . '#Top'; + # or ? + #return $file . '#Top'; + } + else + { + return $file . '#Top'; + } + } + else + { + return $file; + } + } + my $target; + if ($NEW_CROSSREF_STYLE) + { + $node = $node_id; + $target = $node_xhtml_id; + } + else + { + $node = main::remove_texi($node); + $node =~ s/[^\w\.\-]/-/g; + } + my $file_basename = $node; + $file_basename = $TOP_NODE_FILE if ($node =~ /^top$/i); + if ($NEW_CROSSREF_STYLE) + { + if ($target_split) + { + return $file . $file_basename . ".$NODE_FILE_EXTENSION" . '#' . $target; + } + else + { + return $file . '#' . $target; + } + } + else + { + return $file . $file_basename . ".$NODE_FILE_EXTENSION"; + } +} + +# format a reference external to the generated manual. This produces a full +# reference with introductive words and the reference itself. +# +# arguments: +# type of the reference: xref (reference at the beginning of a sentence), +# pxref (reference in a parenthesis), +# section in the book. This might be undef. +# book name. +# node and file name formatted according to the convention used in info +# '(file)node' and no node means the Top node. +# href linking to the html page containing the referenced node. A typical +# use for this href is a href attribute in an <a> element +# an optionnal cross reference name +sub t2h_default_external_ref($$$$$$) +{ + my $type = shift; + my $section = shift; + my $book = shift; + my $file_node = shift; + my $href = shift; + my $cross_ref = shift; + + $file_node = "$cross_ref: $file_node" if (($file_node ne '') and ($cross_ref ne '')); + $file_node = &$anchor('', $href, $file_node) if ($file_node ne ''); + + # Yes, this is ugly, but this helps internationalization + if ($type eq 'pxref') + { + if (($book ne '') and ($file_node ne '')) + { + return &$I('see %{node_file_href} section `%{section}\' in @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book, 'section' => $section }) if ($section ne ''); + return &$I('see %{node_file_href} @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book }); + } + elsif ($book ne '') + { + return &$I('see section `%{section}\' in @cite{%{book}}', { 'book' => $book, 'section' => $section }) if ($section ne ''); + return &$I('see @cite{%{book}}', { 'book' => $book }); + } + elsif ($file_node ne '') + { + return &$I('see %{node_file_href}', { 'node_file_href' => $file_node }); + } + } + if ($type eq 'xref') + { + if (($book ne '') and ($file_node ne '')) + { + return &$I('See %{node_file_href} section `%{section}\' in @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book, 'section' => $section }) if ($section ne ''); + return &$I('See %{node_file_href} @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book }); + } + elsif ($book ne '') + { + return &$I('See section `%{section}\' in @cite{%{book}}', { 'book' => $book, 'section' => $section }) if ($section ne ''); + return &$I('See @cite{%{book}}', { 'book' => $book }); + } + elsif ($file_node ne '') + { + return &$I('See %{node_file_href}', { 'node_file_href' => $file_node }); + } + } + if ($type eq 'ref') + { + if (($book ne '') and ($file_node ne '')) + { + return &$I('%{node_file_href} section `%{section}\' in @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book, 'section' => $section }) if ($section ne ''); + return &$I('%{node_file_href} @cite{%{book}}', { 'node_file_href' => $file_node, 'book' => $book }); + } + elsif ($book ne '') + { + return &$I('section `%{section}\' in @cite{%{book}}', { 'book' => $book, 'section' => $section }) if ($section ne ''); + return &$I('@cite{%{book}}', { 'book' => $book }); + } + elsif ($file_node ne '') + { + return &$I('%{node_file_href}', { 'node_file_href' => $file_node }); + } + } + return ''; +} + +# format a reference to a node or a section in the generated manual. This +# produces a full reference with introductive words and the reference itself. +# +# arguments: +# type of the reference: xref (reference at the beginning of a sentence), +# pxref (reference in a parenthesis), +# href linking to the html page containing the node or the section. A typical +# use for this href is a href attribute in an <a> element +# short name for this reference +# name for this reference +# boolean true if the reference is a reference to a section +# +# $SHORT_REF should be used. +sub t2h_default_internal_ref($$$$$) +{ + my $type = shift; + my $href = shift; + my $short_name = shift; + my $name = shift; + my $is_section = shift; + + if (! $SHORT_REF) + { + $name = &$anchor('', $href, $name); + if ($type eq 'pxref') + { + return &$I('see section %{reference_name}', { 'reference_name' => $name }) if ($is_section); + return &$I('see %{reference_name}', { 'reference_name' => $name }); + } + elsif ($type eq 'xref') + { + return &$I('See section %{reference_name}', { 'reference_name' => $name }) if ($is_section); + return &$I('See %{reference_name}', { 'reference_name' => $name }); + } + elsif ($type eq 'ref') + { + return &$I('%{reference_name}', { 'reference_name' => $name }); + } + } + else + { + $name = &$anchor('', $href, $short_name); + if ($type eq 'pxref') + { + return &$I('see %{reference_name}', { 'reference_name' => $name }); + } + elsif ($type eq 'xref') + { + return &$I('See %{reference_name}', { 'reference_name' => $name }); + } + elsif ($type eq 'ref') + { + return &$I('%{reference_name}', { 'reference_name' => $name }); + } + } + return ''; +} + +sub teletyped_in_stack($) +{ + my $stack = shift; + foreach my $element(reverse(@$stack)) + { + if ($complex_format_map->{$element}) + { + if (!$complex_format_map->{$element}->{'pre_style'}) + { + return 1; + } + else + { + return 0; + } + } + } + return 0; +} + +# text after @item in table, vtable and ftable +sub t2h_default_table_item($$$$$$) +{ + my $text = shift; + my $index_label = shift; + my $format = shift; + my $command = shift; + my $formatted_command = shift; + my $style_stack = shift; + #print STDERR "-> $format (@$style_stack)\n"; + $formatted_command = '' if (!defined($formatted_command) or + exists($special_list_commands{$format}->{$command})); + if (teletyped_in_stack($style_stack)) + { + $text .= '</tt>'; + $formatted_command = '<tt>' . $formatted_command; + } + $text .= "\n" . $index_label if (defined($index_label)); + return '<dt>' . $formatted_command . $text . '</dt>' . "\n"; +} + +# format text on the line following the @item line (in table, vtable and ftable) +sub t2h_default_table_line($) +{ + my $text = shift; + + if ($text =~ /\S/) + { + return '<dd>' . $text . '</dd>' . "\n"; + } + return ''; +} + +# row in multitable +sub t2h_default_row($$) +{ + my $text = shift; + my $macro = shift; + + if ($text =~ /\S/) + { + if ($macro eq 'headitem') + { + return '<thead><tr>' . $text . '</tr></thead>' . "\n"; + } + return '<tr>' . $text . '</tr>' . "\n"; + } + return ''; +} + +# cell in multitable +sub t2h_default_cell($$) +{ + my $text = shift; + my $row_macro = shift; + + if ($row_macro eq 'headitem') + { + return '<th>' . $text . '</th>'; + } + return '<td>' . $text . '</td>'; +} + +# format an item in a list +# +# argument: +# text of the item +# format of the list (itemize or enumerate) +# command passed as argument to the format +# formatted_command leading command formatted, if it is a thing command +sub t2h_default_list_item($$$$$$$) +{ + my $text = shift; + my $format = shift; + my $command = shift; + my $formatted_command = shift; + my $item_nr = shift; + my $enumerate_style = shift; + my $number = shift; + + $formatted_command = '' if (!defined($formatted_command) or + exists($special_list_commands{$format}->{$command})); + if ($text =~ /\S/) + { + return '<li>' . $formatted_command . $text . '</li>'; + } + return ''; +} + +sub t2h_default_table_list($$$$$$) +{ + my $format = shift; + my $text = shift; + my $command = shift; + my $formatted_command = shift; + my $item_nr = shift; + my $enumerate_style = shift; + my $number = shift; + $formatted_command = '' if (!defined($formatted_command) or + exists($special_list_commands{$format}->{$command})); + if ($format eq 'itemize') + { + return "<ul>\n" . $text . "</ul>\n" if ($command eq 'bullet'); + return "<ul$TOC_LIST_ATTRIBUTE>\n" . $text . "</ul>\n"; + } +} + +# an html comment +sub t2h_default_comment($) +{ + my $text = shift; + $text =~ s/--+/-/go; + return '<!-- ' . $text . ' -->' . "\n"; +} + +sub t2h_collect_styles($) +{ + my $stack = shift; + my @result = (); + foreach my $style (reverse(@$stack)) + { +# last unless (defined($command_type{$style}) and $command_type{$style} eq 'style'); + push @result, $style if (defined($command_type{$style}) and $command_type{$style} eq 'style'); + } + return @result; +} + +sub t2h_get_attribute($;$) +{ + my $command = shift; + my $map_ref = shift; + $map_ref = \%style_map if (!defined($map_ref)); + return '' unless (defined($map_ref->{$command})); + if ((ref($map_ref->{$command}) eq 'HASH') + and exists($map_ref->{$command}->{'attribute'})) + { + return $map_ref->{$command}->{'attribute'}; + } + elsif ($map_ref->{$command} !~ /^&/) + { + my $attribute = $map_ref->{$command}; + $attribute =~ s/^\"//; + return $attribute; + } + return ''; +} + +sub t2h_begin_style($$;$) +{ + my $command = shift; + my $text = shift; + my $map_ref = shift; + my $attribute = t2h_get_attribute($command,$map_ref); + $attribute = "<$attribute>" if ($attribute ne ''); + return $attribute.$text; +} + +sub t2h_end_style($$;$) +{ + my $command = shift; + my $text = shift; + my $map_ref = shift; + my $attribute = t2h_get_attribute($command,$map_ref); + if ($attribute =~ /^(\w+)/) + { + $attribute = $1; + } + $attribute = "</$attribute>" if ($attribute ne ''); + return $text.$attribute; +} + +# a paragraph +# arguments: +# $text of the paragraph +# $align for the alignement +# $indent for the indent style (indent or noindent) +# The following is usefull if the paragraph is in an itemize. +# $paragraph_command is the leading formatting command (like @minus) +# $paragraph_command_formatted is the leading formatting command formatted +# $paragraph_number is a reference on the number of paragraphs appearing +# in the format. The value should be increased if a paragraph is done +# $format is the format name (@itemize) +sub t2h_default_paragraph($$$$$$$$$$$$) +{ + my $text = shift; + my $align = shift; + my $indent = shift; + my $paragraph_command = shift; + my $paragraph_command_formatted = shift; + my $paragraph_number = shift; + my $format = shift; + my $item_nr = shift; + my $enumerate_style = shift; + my $number = shift; + my $command_stack_at_end = shift; + my $command_stack_at_begin = shift; +#print STDERR "format: $format\n" if (defined($format)); +#print STDERR "paragraph @$command_stack_at_end; @$command_stack_at_begin\n"; + $paragraph_command_formatted = '' if (!defined($paragraph_command_formatted) or + exists($special_list_commands{$format}->{$paragraph_command})); + return '' if ($text =~ /^\s*$/); + foreach my $style(t2h_collect_styles($command_stack_at_begin)) + { + $text = t2h_begin_style($style, $text); + } + foreach my $style(t2h_collect_styles($command_stack_at_end)) + { + $text = t2h_end_style($style, $text); + } + if (defined($paragraph_number) and defined($$paragraph_number)) + { + $$paragraph_number++; + return $text if (($format eq 'itemize' or $format eq 'enumerate') and + ($$paragraph_number == 1)); + } + my $open = '<p>'; + if ($align) + { + $open = "<p align=\"$paragraph_style{$align}\">"; + } + return $open.$text.'</p>'; +} + +# a preformatted region +# arguments: +# $text of the preformatted region +# $pre_style css style +# $class identifier for the preformatted region (example, menu-comment) +# The following is usefull if the preformatted is in an itemize. +# $leading_command is the leading formatting command (like @minus) +# $leading_command_formatted is the leading formatting command formatted +# $preformatted_number is a reference on the number of preformatteds appearing +# in the format. The value should be increased if a preformatted is done +sub t2h_default_preformatted($$$$$$$$$$$$) +{ + my $text = shift; + my $pre_style = shift; + my $class = shift; + my $leading_command = shift; + my $leading_command_formatted = shift; + my $preformatted_number = shift; + my $format = shift; + my $item_nr = shift; + my $enumerate_style = shift; + my $number = shift; + my $command_stack_at_end = shift; + my $command_stack_at_begin = shift; + +#print STDERR "preformatted @$command_stack_at_end; @$command_stack_at_begin\n"; + return '' if ($text eq ''); + $leading_command_formatted = '' if (!defined($leading_command_formatted) or + exists($special_list_commands{$format}->{$leading_command})); + if (defined($preformatted_number) and defined($$preformatted_number)) + { + $$preformatted_number++; + } + foreach my $style(t2h_collect_styles($command_stack_at_begin)) + { + $text = t2h_begin_style($style, $text, \%style_map_pre); + } + foreach my $style(t2h_collect_styles($command_stack_at_end)) + { + $text = t2h_end_style($style, $text, \%style_map_pre); + } + return "<pre class=\"$class\">".$text."</pre>"; +} + +# This function formats a heading for an element +# +# argument: +# an element. It is a hash reference for a node or a sectionning command. +# The interesting keys are: +# 'text': the heading text +# 'text_nonumber': the heading text without section number +# 'node': true if it is a node +# 'level': level of the element. 0 for @top, 1 for chapter, heading, +# appendix..., 2 for section and so on... +# 'tag_level': the sectionning element name, raisesections and lowersections +# taken into account +sub t2h_default_heading($) +{ + my $element = shift; + my $level = 3; + if (!$element->{'node'}) + { + $level = $element->{'level'}; + } + $level = 1 if ($level == 0); + my $text = $element->{'text'}; + return '' if ($text !~ /\S/); + my $class = $element->{'tag_level'}; + $class = 'unnumbered' if ($class eq 'top'); + if (defined($element->{'tocid'}) and $TOC_LINKS) + { + $text = &$anchor ('', "$Texi2HTML::THISDOC{'toc_file'}#$element->{'tocid'}", $text); + } + my $align = ''; + $align = ' align="center"' if ($element->{'tag'} eq 'centerchap'); + return "<h$level class=\"$class\"$align> $text </h$level>\n"; +} + +# formatting of raw regions +# if L2H is true another mechanism is used for tex +sub t2h_default_raw($$) +{ + my $style = shift; + my $text = shift; + if ($style eq 'verbatim' or $style eq 'tex') + { + return "<pre class=\"$style\">" . &$protect_text($text) . '</pre>'; + } + elsif ($style eq 'html') + { + return $text; + } + else + { + warn "$WARN (bug) unknown style $style\n"; + return &$protect_text($text); + } +} + +# raw environment when removing texi (in comments) +sub t2h_default_raw_no_texi($$) +{ + my $style = shift; + my $text = shift; + return $text; +} + +# This function formats a footnote reference and the footnote text associated +# with a given footnote. +# The footnote reference is the text appearing in the main document pointing +# to the footnote text. +# +# arguments: +# absolute number of the footnote (in the document) +# relative number of the footnote (in the page) +# identifier for the footnote +# identifier for the footnote reference in the main document +# main document file +# footnote text file +# array with the footnote text lines +# the state. See menu entry. +# +# returns: +# reference on an array containing the footnote text lines which should +# have been updated +# the text for the reference pointing on the footnote text +sub t2h_default_foot_line_and_ref($$$$$$$) +{ + my $number_in_doc = shift; + my $number_in_page = shift; + my $footnote_id = shift; + my $place_id = shift; + my $document_file = shift; + my $footnote_file = shift; + my $lines = shift; + my $state = shift; + + unshift (@$lines, '<h3>' . + &$anchor($footnote_id, $document_file . "#$place_id", + "($number_in_doc)") + . "</h3>\n"); + return ($lines, &$anchor($place_id, $footnote_file . "#$footnote_id", + "($number_in_doc)")); +} + +# formats a group of footnotes. +# +# argument: +# array reference on the footnotes texts lines +# +# returns an array reference on the group of footnotes lines +sub t2h_default_foot_section($) +{ + my $lines = shift; + unshift (@$lines, "<div class=\"footnote\">\n" ,"$DEFAULT_RULE\n", "<h3>" . &$I('Footnotes') . "</h3>\n"); + push (@$lines, "</div>\n"); + return $lines; +} + +sub t2h_default_image_files($$) +{ + my $base = shift; + my $extension = shift; + my @files = (); + return @files if (!defined($base) or ($base eq '')); + push @files,"$base.$extension" if (defined($extension) and ($extension ne '')); + foreach my $ext (@IMAGE_EXTENSIONS) + { + push @files, "$base.$ext"; + } + return @files; +} + +# format an image +# +# arguments: +# image file name with path +# image basename +# a boolean true if we are in a preformatted format +# image file name without path +# alt text +# width +# height +# raw alt +# extension +# path to working dir +# path to file relative from working dir +sub t2h_default_image($$$$$$$$$$$) +{ + my $file = shift; + my $base = shift; + my $preformatted = shift; + my $file_name = shift; + my $alt = shift; + my $width = shift; + my $height = shift; + my $raw_alt = shift; + my $extension = shift; + my $working_dir = shift; + my $file_path = shift; + + if (!defined($file_path) or $file_path eq '') + { + if (defined($extension) and $extension ne '') + { + $file = "$base.$extension"; + } + else + { + $file = "$base.jpg"; + } + main::echo_warn ("no image file for $base, (using $file)"); + } + $alt = &$protect_text($base) if (!defined($alt) or ($alt eq '')); + return "[ $alt ]" if ($preformatted); + # it is possible that $file_name is more correct as it allows the user + # to chose the relative path. + $file = &$protect_text($file); + return "<img src=\"$file\" alt=\"$alt\">"; +} + +# address put in footer describing when was generated and who did the manual +sub t2h_default_address($$) +{ + my $user = shift; + my $date = shift; + $user = '' if (!defined($user)); + $date = '' if (!defined($date)); + if (($user ne '') and ($date ne '')) + { + return &$I('by @emph{%{user}} on @emph{%{date}}', { 'user' => $user, + 'date' => $date }); + } + elsif ($user ne '') + { + return &$I('by @emph{%{user}}', { 'user' => $user }); + } + elsif ($date ne '') + { + return &$I('on @emph{%{date}}', { 'date' => $date }); + } + return ''; +} + +# format a target in the main document for an index entry. +# +# arguments: +# target identifier +# boolean true if in preformatted format +# FIXME document the remaining +sub t2h_default_index_entry_label($$) +{ + my $identifier = shift; + my $preformatted = shift; + + return '' if (!defined($identifier) or ($identifier !~ /\S/)); + my $label = &$anchor($identifier); + return $label . "\n" if (!$preformatted); + return $label; +} + +# process definition commands line @deffn for example +sub t2h_default_def_line($$$$$) +{ + my $category = shift; + my $name = shift; + my $type = shift; + my $arguments = shift; + my $index_label = shift; + $index_label = '' if (!defined($index_label)); + $category = '' if (!defined($category) or ($category =~ /^\s*$/)); + $name = '' if (!defined($name) or ($name =~ /^\s*$/)); + $type = '' if (!defined($type) or $type =~ /^\s*$/); + if (!defined($arguments) or $arguments =~ /^\s*$/) + { + $arguments = ''; + } + else + { + chomp ($arguments); + $arguments = '<i>' . $arguments . '</i>'; + } + my $type_name = ''; + $type_name = " $type" if ($type ne ''); + $type_name .= ' <b>' . $name . '</b>' if ($name ne ''); + $type_name .= $arguments . "\n"; + if (! $DEF_TABLE) + { + return '<dt>'. '<u>' . $category . ':</u>' . $type_name . $index_label . "</dt>\n"; + } + else + { + + return "<tr>\n<td align=\"left\">" . $type_name . + "</td>\n<td align=\"right\">" . $category . $index_label . "</td>\n" . "</tr>\n"; + } +} + +# process definition commands line @deffn for example while removing texi +# commands +sub t2h_default_def_line_no_texi($$$$$) +{ + my $category = shift; + my $name = shift; + my $type = shift; + my $arguments = shift; + $name = '' if (!defined($name) or ($name =~ /^\s*$/)); + $type = '' if (!defined($type) or $type =~ /^\s*$/); + if (!defined($arguments) or $arguments =~ /^\s*$/) + { + $arguments = ''; + } + my $type_name = ''; + $type_name = " $type" if ($type ne ''); + $type_name .= ' ' . $name if ($name ne ''); + $type_name .= $arguments; + if (! $DEF_TABLE) + { + return $category . ':' . $type_name . "\n"; + } + else + { + + return $type_name . " " . $category . "\n"; + } +} + +# a cartouche +sub t2h_default_cartouche($$) +{ + my $text = shift; + + if ($text =~ /\S/) + { + return "<table class=\"cartouche\" border=\"1\"><tr><td>\n" . $text . "</td></tr></table>\n"; + } + return ''; +} + +# key: +# origin_href: +# entry: +# texi entry: +# element_href: +# element_text: +sub t2h_default_index_summary_file_entry ($$$$$$$$) +{ + my $index_name = shift; + my $key = shift; + my $origin_href = shift; + my $entry = shift; + my $texi_entry = shift; + my $element_href = shift; + my $element_text = shift; + my $is_printed = shift; + print IDXFILE "key: $key\n origin_href: $origin_href\n entry: $entry\n" + . " texi_entry: $texi_entry\n" + . " element_href: $element_href\n element_text: $element_text\n"; +} + +sub t2h_default_index_summary_file_begin($$) +{ + my $name = shift; + my $is_printed = shift; + open(IDXFILE, ">$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'file_base_name'}" . "_$name.idx") + || die "Can't open >$Texi2HTML::THISDOC{'destination_directory'}$Texi2HTML::THISDOC{'file_base_name'}" . "_$name.idx for writing: $!\n"; +} + +sub t2h_default_index_summary_file_end($$) +{ + my $name = shift; + my $is_printed = shift; + close (IDXFILE); +} + +sub t2h_default_sp($$) +{ + my $number = shift; + my $preformatted = shift; + return "<br>\n" x $number if (!$preformatted); + return "\n" x $number; +} + +sub t2h_default_acronym_like($$$$$$) +{ + my $command = shift; + my $acronym_texi = shift; + my $acronym_text = shift; + my $with_explanation = shift; + my $explanation_lines = shift; + my $explanation_text = shift; + my $explanation_simply_formatted = shift; + + my $attribute = $command; + my $opening = "<$attribute>"; + if (defined($explanation_simply_formatted)) + { + $opening = "<$attribute title=\"$explanation_simply_formatted\">"; + } + if ($with_explanation) + { + return &$I('%{acronym_like} (%{explanation})', {'acronym_like' => $opening . $acronym_text . "</$attribute>", 'explanation' => $explanation_text}) + } + else + { + return $opening . $acronym_text . "</$attribute>"; + } +} + +sub t2h_default_quotation_prepend_text($) +{ + my $text = shift; + return undef if (!defined($text) or $text =~ /^$/); +# FIXME if there is a @ protecting the end of line the result is +# @b{some text @:} +# It is likely not to be what was intended + chomp($text); + return &$I('@b{%{quotation_arg}:} ', {'quotation_arg' => $text}, {'keep_texi' => 1}); +} + +sub t2h_default_quotation($$$) +{ + my $text = shift; + my $argument_text = shift; + my $argument_text_texi = shift; +# my $argument_style_texi = shift; +# my $argument_style_id = shift; +# if (defined($argument_text)) +# { +# return '<blockquote>' . &$I('%{style}:%{quotation}', +# {'style' => $argument_text, 'quotation' => $text}) . '</blockquote>' ; +# } + return '<blockquote>' . $text . "</blockquote>\n"; +} + +# format the text within a paragraph style format, +# +# argument: +# format name +# text within the format +sub t2h_default_paragraph_style_command($$) +{ + my $format = shift; + my $text = shift; + return $text; +} + +# format a whole index +# +# argument: +# index text +# index name +sub t2h_default_print_index($$) +{ + my $text = shift; + my $name = shift; + return "<table border=\"0\" class=\"index-$name\">\n" . + "<tr><td></td><th align=\"left\">" . &$I('Index Entry') . "</th><th align=\"left\"> " . &$I('Section') . "</th></tr>\n" + . "<tr><td colspan=\"3\"> $DEFAULT_RULE</td></tr>\n" . $text . + "</table>\n"; +} + +# format a letter entry in an index page. The letter entry contains +# the index entries for the words beginning with that letter. It is +# a target for links pointing from the summary of the index. +# +# arguments: +# the letter +# identifier for the letter entry. This should be used to make the target +# identifier +# text of the index entries +sub t2h_default_index_letter($$$) +{ + my $letter = shift; + my $id = shift; + my $text = shift; + return '<tr><th>' . &$anchor($id,'',&$protect_text($letter)) . + "</th><td></td><td></td></tr>\n" . $text . + "<tr><td colspan=\"3\"> $DEFAULT_RULE</td></tr>\n"; +} + +# format an index entry (in a letter entry). +# +# arguments: +# href to the main text, linking to the place where the index entry appears +# entry text +# href to the main text, linking to the section or node where the index +# entry appears +# section or node heading +sub t2h_default_index_entry($$$$) +{ + my $text_href = shift; + my $entry = shift; + my $element_href = shift; + my $element_text = shift; + + return '<tr><td></td><td valign="top">' . &$anchor('', $text_href, $entry) + . '</td><td valign="top">' . &$anchor('', $element_href, $element_text) + . "</td></tr>\n"; +} + + +sub t2h_default_copying_comment($) +{ + my $copying_lines = shift; + my $text = &$comment(main::remove_texi(@$copying_lines)); + return $text; +} +# format a letter appearing in a summary for an index. The letter links to +# the place where the index elements beginning with this letter are (called +# a letter entry). +# +# arguments: +# letter +# file where the target letter entry is +# identifier for the target letter entry +sub t2h_default_summary_letter($$$) +{ + my $letter = shift; + my $file = shift; + my $identifier = shift; + return &$anchor('', $file . '#' . $identifier, '<b>' . &$protect_text($letter) . '</b>', 'class="summary-letter"'); +} + +# format an index summary. This is a list of letters linking to the letter +# entries. +# +# arguments: +# array reference containing the formatted alphabetical letters +# array reference containing the formatted non lphabetical letters +sub t2h_default_index_summary($$) +{ + my $alpha = shift; + my $nonalpha = shift; + my $join = ''; + my $nonalpha_text = ''; + my $alpha_text = ''; + $join = " \n<br>\n" if (@$nonalpha and @$alpha); + if (@$nonalpha) + { + $nonalpha_text = join("\n \n", @$nonalpha) . "\n"; + } + if (@$alpha) + { + $alpha_text = join("\n \n", @$alpha) . "\n \n"; + } + return "<table><tr><th valign=\"top\">" . &$I('Jump to') .": </th><td>" . + $nonalpha_text . $join . $alpha_text . "</td></tr></table>\n"; +} + +# return the heading with number texinfo text +# also called for nodes. +sub t2h_default_heading_texi($$$) +{ + my $tag = shift; + my $texi = shift; + my $number = shift; + $texi =~ s/\s*$//; + $texi =~ s/^\s*//; + return "$number $texi" if ($NUMBER_SECTIONS and defined($number) and ($number !~ /^\s*$/)) ; + return $texi; +} + +# return the heading texinfo text for split index sections +sub t2h_default_index_element_heading_texi($$$) +{ # FIXME i18n + my $heading_texi = shift; + my $tag = shift; + my $texi = shift; + my $number = shift; + my $first_letter = shift; + my $last_letter = shift; + return "$heading_texi: $first_letter -- $last_letter" if ($last_letter ne $first_letter); + return "$heading_texi: $first_letter"; +} + +1; + +require "$ENV{T2H_HOME}/texi2html.init" + if ($0 =~ /\.pl$/ && + -e "$ENV{T2H_HOME}/texi2html.init" && -r "$ENV{T2H_HOME}/texi2html.init"); + +my $translation_file = 'translations.pl'; # file containing all the translations +my $T2H_OBSOLETE_STRINGS; + +# leave this within comments, and keep the require statement +# This way, you can directly run texi2html.pl, +# if $ENV{T2H_HOME}/translations.pl exists. +# +# @T2H_TRANSLATIONS_FILE@ +$LANGUAGES->{'de'} = { + ' The buttons in the navigation panels have the following meaning:' => '', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '', + ' Up ' => '', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '', + '%{name} of %{class}' => '', + '%{name} on %{class}' => '', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => '', + 'About (help)' => '', + 'About This Document' => '@"Uber dieses Dokument', + 'April' => 'April', + 'August' => 'August', + 'Back' => '', + 'Beginning of this chapter or previous chapter' => '', + 'Button' => '', + 'Contents' => '', + 'Cover (top) of document' => '', + 'Current Position' => '', + 'Current section' => '', + 'December' => 'Dezember', + 'FastBack' => '', + 'FastForward' => '', + 'February' => 'Februar', + 'First' => '', + 'First section in reading order' => '', + 'Following' => '', + 'Following node' => '', + 'Footnotes' => 'Fu@ss{}noten', + 'Forward' => '', + 'From 1.2.3 go to' => '', + 'Go to' => '', + 'Index' => 'Index', + 'Index Entry' => '', + 'January' => 'Januar', + 'July' => 'Juli', + 'Jump to' => '', + 'June' => 'Juni', + 'Last' => '', + 'Last section in reading order' => '', + 'March' => 'M@"arz', + 'May' => 'Mai', + 'Menu:' => '', + 'Name' => '', + 'Next' => '', + 'Next chapter' => '', + 'Next node' => '', + 'Next section in reading order' => '', + 'Next section on same level' => '', + 'Node following in node reading order' => '', + 'Node up' => '', + 'NodeNext' => '', + 'NodePrev' => '', + 'NodeUp' => '', + 'November' => 'November', + 'October' => 'Oktober', + 'Overview' => '', + 'Overview:' => '', + 'Prev' => '', + 'Previous node' => '', + 'Previous section in reading order' => '', + 'Previous section on same level' => '', + 'Section' => '', + 'Section One' => '', + 'See %{node_file_href}' => '', + 'See %{node_file_href} @cite{%{book}}' => '', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'See %{reference_name}' => '', + 'See @cite{%{book}}' => '', + 'See section %{reference_name}' => '', + 'See section `%{section}\' in @cite{%{book}}' => '', + 'September' => 'September', + 'Short Table of Contents' => 'Kurzes Inhaltsverzeichniss', + 'Short table of contents' => '', + 'Subsection One-Four' => '', + 'Subsection One-One' => '', + 'Subsection One-Three' => '', + 'Subsection One-Two' => '', + 'Subsubsection One-Two-Four' => '', + 'Subsubsection One-Two-One' => '', + 'Subsubsection One-Two-Three' => '', + 'Subsubsection One-Two-Two' => '', + 'T2H_today' => '', + 'Table of Contents' => 'Inhaltsverzeichniss', + 'Table of contents' => '', + 'The node you are looking for is at %{href}.' => '', + 'This' => '', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'Top' => '', + 'Untitled Document' => '', + 'Up' => '', + 'Up node' => '', + 'Up section' => '', + 'by @emph{%{user}}' => '', + 'by @emph{%{user}} on @emph{%{date}}' => '', + 'current' => '', + 'on @emph{%{date}}' => '', + 'section `%{section}\' in @cite{%{book}}' => '', + 'see %{node_file_href}' => '', + 'see %{node_file_href} @cite{%{book}}' => '', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'see %{reference_name}' => '', + 'see @cite{%{book}}' => '', + 'see section %{reference_name}' => '', + 'see section `%{section}\' in @cite{%{book}}' => '', + 'unknown' => '' + }; + +$T2H_OBSOLETE_STRINGS->{'de'} = { + 'See' => 'Siehe', + 'section' => 'Abschnitt', + 'see' => 'siehe' + }; + + +$LANGUAGES->{'en'} = { + ' The buttons in the navigation panels have the following meaning:' => '', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '', + ' Up ' => '', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '', + '%{name} of %{class}' => '', + '%{name} on %{class}' => '', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => '', + 'About (help)' => '', + 'About This Document' => '', + 'April' => '', + 'August' => '', + 'Back' => '', + 'Beginning of this chapter or previous chapter' => '', + 'Button' => '', + 'Contents' => '', + 'Cover (top) of document' => '', + 'Current Position' => '', + 'Current section' => '', + 'December' => '', + 'FastBack' => '', + 'FastForward' => '', + 'February' => '', + 'First' => '', + 'First section in reading order' => '', + 'Following' => '', + 'Following node' => '', + 'Footnotes' => '', + 'Forward' => '', + 'From 1.2.3 go to' => '', + 'Go to' => '', + 'Index' => '', + 'Index Entry' => '', + 'January' => '', + 'July' => '', + 'Jump to' => '', + 'June' => '', + 'Last' => '', + 'Last section in reading order' => '', + 'March' => '', + 'May' => '', + 'Menu:' => '', + 'Name' => '', + 'Next' => '', + 'Next chapter' => '', + 'Next node' => '', + 'Next section in reading order' => '', + 'Next section on same level' => '', + 'Node following in node reading order' => '', + 'Node up' => '', + 'NodeNext' => '', + 'NodePrev' => '', + 'NodeUp' => '', + 'November' => '', + 'October' => '', + 'Overview' => '', + 'Overview:' => '', + 'Prev' => '', + 'Previous node' => '', + 'Previous section in reading order' => '', + 'Previous section on same level' => '', + 'Section' => '', + 'Section One' => '', + 'See %{node_file_href}' => '', + 'See %{node_file_href} @cite{%{book}}' => '', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'See %{reference_name}' => '', + 'See @cite{%{book}}' => '', + 'See section %{reference_name}' => '', + 'See section `%{section}\' in @cite{%{book}}' => '', + 'September' => '', + 'Short Table of Contents' => '', + 'Short table of contents' => '', + 'Subsection One-Four' => '', + 'Subsection One-One' => '', + 'Subsection One-Three' => '', + 'Subsection One-Two' => '', + 'Subsubsection One-Two-Four' => '', + 'Subsubsection One-Two-One' => '', + 'Subsubsection One-Two-Three' => '', + 'Subsubsection One-Two-Two' => '', + 'T2H_today' => '%s, %d %d', + 'Table of Contents' => '', + 'Table of contents' => '', + 'The node you are looking for is at %{href}.' => '', + 'This' => '', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'Top' => '', + 'Untitled Document' => '', + 'Up' => '', + 'Up node' => '', + 'Up section' => '', + 'by @emph{%{user}}' => '', + 'by @emph{%{user}} on @emph{%{date}}' => '', + 'current' => '', + 'on @emph{%{date}}' => '', + 'section `%{section}\' in @cite{%{book}}' => '', + 'see %{node_file_href}' => '', + 'see %{node_file_href} @cite{%{book}}' => '', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'see %{reference_name}' => '', + 'see @cite{%{book}}' => '', + 'see section %{reference_name}' => '', + 'see section `%{section}\' in @cite{%{book}}' => '', + 'unknown' => '' + }; + +$T2H_OBSOLETE_STRINGS->{'en'} = {}; + + +$LANGUAGES->{'es'} = { + ' The buttons in the navigation panels have the following meaning:' => '', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '', + ' Up ' => '', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '', + '%{name} of %{class}' => '', + '%{name} on %{class}' => '', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => '', + 'About (help)' => '', + 'About This Document' => '', + 'April' => 'abril', + 'August' => 'agosto', + 'Back' => '', + 'Beginning of this chapter or previous chapter' => '', + 'Button' => '', + 'Contents' => '', + 'Cover (top) of document' => '', + 'Current Position' => '', + 'Current section' => '', + 'December' => 'diciembre', + 'FastBack' => '', + 'FastForward' => '', + 'February' => 'febrero', + 'First' => '', + 'First section in reading order' => '', + 'Following' => '', + 'Following node' => '', + 'Footnotes' => '', + 'Forward' => '', + 'From 1.2.3 go to' => '', + 'Go to' => '', + 'Index' => 'Index', + 'Index Entry' => '', + 'January' => 'enero', + 'July' => 'julio', + 'Jump to' => '', + 'June' => 'junio', + 'Last' => '', + 'Last section in reading order' => '', + 'March' => 'marzo', + 'May' => 'mayo', + 'Menu:' => '', + 'Name' => '', + 'Next' => '', + 'Next chapter' => '', + 'Next node' => '', + 'Next section in reading order' => '', + 'Next section on same level' => '', + 'Node following in node reading order' => '', + 'Node up' => '', + 'NodeNext' => '', + 'NodePrev' => '', + 'NodeUp' => '', + 'November' => 'noviembre', + 'October' => 'octubre', + 'Overview' => '', + 'Overview:' => '', + 'Prev' => '', + 'Previous node' => '', + 'Previous section in reading order' => '', + 'Previous section on same level' => '', + 'Section' => '', + 'Section One' => '', + 'See %{node_file_href}' => '', + 'See %{node_file_href} @cite{%{book}}' => '', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'See %{reference_name}' => '', + 'See @cite{%{book}}' => '', + 'See section %{reference_name}' => '', + 'See section `%{section}\' in @cite{%{book}}' => '', + 'September' => 'septiembre', + 'Short Table of Contents' => 'Resumen del Contenido', + 'Short table of contents' => '', + 'Subsection One-Four' => '', + 'Subsection One-One' => '', + 'Subsection One-Three' => '', + 'Subsection One-Two' => '', + 'Subsubsection One-Two-Four' => '', + 'Subsubsection One-Two-One' => '', + 'Subsubsection One-Two-Three' => '', + 'Subsubsection One-Two-Two' => '', + 'T2H_today' => '', + 'Table of Contents' => '@\'{@dotless{I}}ndice General', + 'Table of contents' => '', + 'The node you are looking for is at %{href}.' => '', + 'This' => '', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'Top' => '', + 'Untitled Document' => '', + 'Up' => '', + 'Up node' => '', + 'Up section' => '', + 'by @emph{%{user}}' => '', + 'by @emph{%{user}} on @emph{%{date}}' => '', + 'current' => '', + 'on @emph{%{date}}' => '', + 'section `%{section}\' in @cite{%{book}}' => '', + 'see %{node_file_href}' => '', + 'see %{node_file_href} @cite{%{book}}' => '', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'see %{reference_name}' => '', + 'see @cite{%{book}}' => '', + 'see section %{reference_name}' => '', + 'see section `%{section}\' in @cite{%{book}}' => '', + 'unknown' => '' + }; + +$T2H_OBSOLETE_STRINGS->{'es'} = { + 'See' => 'V@\'ease', + 'section' => 'secci@\'on', + 'see' => 'v@\'ase' + }; + + +$LANGUAGES->{'fr'} = { + ' The buttons in the navigation panels have the following meaning:' => ' Les boutons de navigation ont la signification suivante :', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => ' Dans cet exemple on est @`a @strong{ Sous section un-deux-trois } dans un document dont la structure est :', + ' Up ' => 'Plus haut', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => 'le %{day} %{month} %{year}', + '%{name} of %{class}' => '%{name} de %{class}', + '%{name} on %{class}' => '%{name} de %{class}', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '%{node_file_href} section `%{section}\' dans @cite{%{book}}', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => 'A propos', + 'About (help)' => 'A propos (page d\'aide)', + 'About This Document' => 'A propos de ce document', + 'April' => 'Avril', + 'August' => 'Ao@^ut', + 'Back' => 'Retour', + 'Beginning of this chapter or previous chapter' => 'D@\'ebut de ce chapitre ou chapitre pr@\'ec@\'edent', + 'Button' => 'Bouton', + 'Contents' => 'Table des mati@`eres', + 'Cover (top) of document' => 'Couverture (top) du document', + 'Current Position' => 'Position', + 'Current section' => 'Section actuelle', + 'December' => 'D@\'ecembre', + 'FastBack' => 'RetourRapide', + 'FastForward' => 'AvanceRapide', + 'February' => 'F@\'evrier', + 'First' => 'Premier', + 'First section in reading order' => 'Premi@`e section dans l\'ordre de lecture', + 'Following' => 'Suivant', + 'Following node' => 'N@oe{}ud suivant', + 'Footnotes' => 'Notes de bas de page', + 'Forward' => 'Avant', + 'From 1.2.3 go to' => 'Depuis 1.2.3 aller @`a', + 'Go to' => 'Aller @`a', + 'Index' => 'Index', + 'Index Entry' => 'Entr@\'ee d\'index', + 'January' => 'Janvier', + 'July' => 'Juillet', + 'Jump to' => 'Aller @`a', + 'June' => 'Juin', + 'Last' => 'Dernier', + 'Last section in reading order' => 'Derni@`ere section dans l\'ordre de lecture', + 'March' => 'Mars', + 'May' => 'Mai', + 'Menu:' => 'Menu@ :', + 'Name' => 'Nom', + 'Next' => 'Suivant', + 'Next chapter' => 'Chapitre suivant', + 'Next node' => 'N@oe{}ud suivant', + 'Next section in reading order' => 'Section suivante dans l\'ordre de lecture', + 'Next section on same level' => 'Section suivante au m@^eme niveau', + 'Node following in node reading order' => 'N@oe{}ud suivant dans l\'ordre de lecture', + 'Node up' => 'N@oe{}ud au dessus', + 'NodeNext' => 'N@oe{}udSuivant', + 'NodePrev' => 'N@oe{}udPr@\'ec@\'edent', + 'NodeUp' => 'N@oe{}udMonter', + 'November' => 'Novembre', + 'October' => 'Octobre', + 'Overview' => 'Vue d\'ensemble', + 'Overview:' => 'Vue d\'ensemble@ :', + 'Prev' => 'Pr@\'ec@\'edent', + 'Previous node' => 'N@oe{}ud pr@\'ec@\'edent', + 'Previous section in reading order' => 'Section pr@\'ec@\'edente dans l\'ordre de lecture', + 'Previous section on same level' => 'Section pr@\'ec@\'edente au m@^eme niveau', + 'Section' => '', + 'Section One' => 'Section un', + 'See %{node_file_href}' => 'Voir %{node_file_href}', + 'See %{node_file_href} @cite{%{book}}' => 'Voir %{node_file_href} @cite{%{book}}', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'Voir %{node_file_href} section `%{section}\' dans @cite{%{book}}', + 'See %{reference_name}' => 'Voir %{reference_name}', + 'See @cite{%{book}}' => 'Voir @cite{%{book}}', + 'See section %{reference_name}' => 'Voir la section %{reference_name}', + 'See section `%{section}\' in @cite{%{book}}' => 'Voir la section `%{section}\' dans @cite{%{book}}', + 'September' => 'Septembre', + 'Short Table of Contents' => 'R@\'esum@\'e du contenu', + 'Short table of contents' => 'R@\'esum@\'e du contenu', + 'Subsection One-Four' => 'Sous section un-quatre', + 'Subsection One-One' => 'Sous section un-un', + 'Subsection One-Three' => 'Sous section un-trois', + 'Subsection One-Two' => 'Sous section un-deux', + 'Subsubsection One-Two-Four' => 'Sous sous section un-deux-quatre', + 'Subsubsection One-Two-One' => 'Sous sous section un-deux-un', + 'Subsubsection One-Two-Three' => 'Sous sous section un-deux-trois', + 'Subsubsection One-Two-Two' => 'Sous sous section un-deux-deux', + 'T2H_today' => 'le %2$d %1$s %3$d', + 'Table of Contents' => 'Table des mati@`eres', + 'Table of contents' => 'Table des mati@`eres', + 'The node you are looking for is at %{href}.' => 'Le n@oe{}ud que vous recherchez est ici@ : %{href}.', + 'This' => 'Ici', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} @emph{%{date}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}.', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}.', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e @emph{%{date}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e en utilisant @uref{%{program_homepage}, @emph{%{program}}}.', + 'Top' => '', + 'Untitled Document' => 'Document sans titre', + 'Up' => 'Monter', + 'Up node' => 'N@oe{}ud au dessus', + 'Up section' => 'Section sup@\'erieure', + 'by @emph{%{user}}' => 'par @emph{%{user}}', + 'by @emph{%{user}} on @emph{%{date}}' => 'par @emph{%{user}} @emph{%{date}}', + 'current' => 'courante', + 'on @emph{%{date}}' => '@emph{%{date}}', + 'section `%{section}\' in @cite{%{book}}' => 'section `%{section}\' dans @cite{%{book}}', + 'see %{node_file_href}' => 'voir %{node_file_href}', + 'see %{node_file_href} @cite{%{book}}' => 'voir %{node_file_href} @cite{%{book}}', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'voir %{node_file_href} section `%{section}\' dans @cite{%{book}}', + 'see %{reference_name}' => 'voir %{reference_name}', + 'see @cite{%{book}}' => 'voir @cite{%{book}}', + 'see section %{reference_name}' => 'voir la section %{reference_name}', + 'see section `%{section}\' in @cite{%{book}}' => 'voir la section `%{section}\' dans @cite{{book}}', + 'unknown' => 'inconnu' + }; + +$T2H_OBSOLETE_STRINGS->{'fr'} = { + ' This document was generated %{who_and_when_generated} using %{program_homepage_href}.' => ' Ce document a été généré %{who_and_when_generated} en utilisant %{program_homepage_href}.', + ' where the <strong> Example </strong> assumes that the current position is at <strong> Subsubsection One-Two-Three </strong> of a document of the following structure:' => ' Dans cet exemple on est à <strong> Sous section un-deux-trois </strong> dans un document dont la structure est :', + '%{node_file_href} section `%{section}\' in <cite>%{book}</cite>' => '%{node_file_href} section `%{section}\' dans <cite>%{book}</cite>', + 'See' => 'Voir', + 'See %{node_file_href} <cite>%{book}</cite>' => 'Voir %{node_file_href} <cite>%{book}</cite>', + 'See %{node_file_href} section `%{section}\' in <cite>%{book}</cite>' => 'Voir %{node_file_href} section `%{section}\' dans <cite>%{book}</cite>', + 'See <cite>%{book}</cite>' => 'Voir <cite>%{book}</cite>', + 'See section `%{section}\' in <cite>%{book}</cite>' => 'Voir la section `%{section}\' dans <cite>%{book}</cite>', + 'This document was generated by <i>%{user}</i> on <i>%{date}</i> using %{program_homepage_href}.' => 'Ce document a été généré par <i>%{user}</i> <i>%{date}</i> en utilisant %{program_homepage_href}.', + 'This document was generated by <i>%{user}</i> using %{program_homepage_href}.' => 'Ce document a été généré par <i>%{user}</i> en utilisant %{program_homepage_href}.', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} @emph{%{date}} en utilisant %{program_homepage_href}.', + 'This document was generated by @emph{%{user}} using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e par @emph{%{user}} en utilisant %{program_homepage_href}.', + 'This document was generated on <i>%{date}</i> using %{program_homepage_href}.' => 'Ce document a été généré <i>%{date}</i> en utilisant %{program_homepage_href}.', + 'This document was generated on @emph{%{date}} using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e @emph{%{date}} en utilisant %{program_homepage_href}.', + 'This document was generated on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e @emph{%{date}} en utilisant @uref{%{program_homepage}, @emph{%{program}}}.', + 'This document was generated using %{program_homepage_href}.' => 'Ce document a @\'et@\'e g@\'en@\'er@\'e en utilisant %{program_homepage_href}.', + 'about (help)' => '@`a propos (page d\'aide)', + 'about (this page)' => 'a propos (cette page)', + 'beginning of this chapter or previous chapter' => 'd@\'ebut de ce chapitre ou chapitre pr@\'ec@\'edent', + 'by <i>%{user}</i>' => 'par <i>%{user}</i>', + 'by <i>%{user}</i> on <i>%{date}</i>' => 'par <i>%{user}</i> <i>%{date}</i>', + 'concept index' => 'index', + 'cover (top) of document' => 'couverture (top) du document', + 'current section' => 'section actuelle', + 'first section in reading order' => 'premi@`e section dans l\'ordre de lecture', + 'following node' => 'node suivant', + 'index' => 'index', + 'last section in reading order' => 'derni@`ere section dans l\'ordre de lecture', + 'next chapter' => 'chapitre suivant', + 'next node' => 'node suivant', + 'next section in reading order' => 'section suivante dans l\'ordre de lecture', + 'next section on same level' => 'section suivante au m@^eme niveau', + 'node following in node reading order' => 'node suivant dans l\'ordre des nodes', + 'node up' => 'node au dessus', + 'on <i>%{date}</i>' => '<i>%{date}</i>', + 'previous node' => 'node pr@\'ec@\'edent', + 'previous section in reading order' => 'section pr@\'ec@\'edente dans l\'ordre de lecture', + 'previous section on same level' => 'section pr@\'ec@\'edente au m@^eme niveau', + 'section' => 'section', + 'section `%{section}\' in <cite>%{book}</cite>' => 'section `%{section}\' dans <cite>%{book}</cite>', + 'see' => 'voir', + 'see %{node_file_href} <cite>%{book}</cite>' => 'voir %{node_file_href} <cite>%{book}</cite>', + 'see %{node_file_href} section `%{section}\' in <cite>%{book}</cite>' => 'voir %{node_file_href} section `%{section}\' dans <cite>%{book}</cite>', + 'see <cite>%{book}</cite>' => 'voir <cite>%{book}</cite>', + 'see section `%{section}\' in <cite>%{book}</cite>' => 'voir la section `%{section}\' dans <cite>%{book}</cite>', + 'short table of contents' => 'table des mati@`eres r@\'esum@\'ee', + 'table of contents' => 'table des mati@`eres', + 'up node' => 'node au dessus', + 'up section' => 'section sup@\'erieure' + }; + + +$LANGUAGES->{'ja'} = { + ' The buttons in the navigation panels have the following meaning:' => 'ナビゲーションパネル中のボタンには以下の意味があります。', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '@strong{例}では、以下に示す構造を持つ文書の@strong{1.2.3項}を現在位置に仮定しています。', + ' Up ' => '上', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '%{year}年%{month}月%{day}日', + '%{name} of %{class}' => '', + '%{name} on %{class}' => '', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => '', + 'About (help)' => '', + 'About This Document' => 'この文書について', + 'April' => '4月', + 'August' => '8月', + 'Back' => '', + 'Beginning of this chapter or previous chapter' => '', + 'Button' => 'ボタン', + 'Contents' => '目次', + 'Cover (top) of document' => '', + 'Current Position' => '現在位置', + 'Current section' => '', + 'December' => '12月', + 'FastBack' => '', + 'FastForward' => '', + 'February' => '2月', + 'First' => '', + 'First section in reading order' => '', + 'Following' => '', + 'Following node' => '', + 'Footnotes' => '脚注', + 'Forward' => '', + 'From 1.2.3 go to' => '1.2.3項からの移動先', + 'Go to' => '移動先', + 'Index' => '見出し', + 'Index Entry' => '見出し一覧', + 'January' => '1月', + 'July' => '7月', + 'Jump to' => '移動', + 'June' => '6月', + 'Last' => '', + 'Last section in reading order' => '', + 'March' => '3月', + 'May' => '5月', + 'Menu:' => 'メニュー', + 'Name' => '名称', + 'Next' => '次', + 'Next chapter' => '', + 'Next node' => '', + 'Next section in reading order' => '', + 'Next section on same level' => '', + 'Node following in node reading order' => '', + 'Node up' => '', + 'NodeNext' => '', + 'NodePrev' => '', + 'NodeUp' => '', + 'November' => '11月', + 'October' => '10月', + 'Overview' => '概要', + 'Overview:' => '概要:', + 'Prev' => '前', + 'Previous node' => '', + 'Previous section in reading order' => '', + 'Previous section on same level' => '', + 'Section' => '項', + 'Section One' => '第1項', + 'See %{node_file_href}' => '', + 'See %{node_file_href} @cite{%{book}}' => '', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'See %{reference_name}' => '', + 'See @cite{%{book}}' => '', + 'See section %{reference_name}' => '', + 'See section `%{section}\' in @cite{%{book}}' => '', + 'September' => '9月', + 'Short Table of Contents' => '簡略化した目次', + 'Short table of contents' => '', + 'Subsection One-Four' => '第1.4項', + 'Subsection One-One' => '第1.1項', + 'Subsection One-Three' => '第1.3項', + 'Subsection One-Two' => '第1.2項', + 'Subsubsection One-Two-Four' => '第1.2.4項', + 'Subsubsection One-Two-One' => '第1.2.1項', + 'Subsubsection One-Two-Three' => '第1.2.3項', + 'Subsubsection One-Two-Two' => '第1.2.2項', + 'T2H_today' => '%s, %d %d', + 'Table of Contents' => '目次', + 'Table of contents' => '', + 'The node you are looking for is at %{href}.' => '', + 'This' => '', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'この文書は@emph{%{user}}によって@emph{%{date}}に@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'この文書は@emph{%{user}}によって@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => 'この文書は@emph{%{date}}に@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => 'この文書は@uref{%{program_homepage}, @emph{%{program}}}を用いて生成されました。', + 'Top' => '冒頭', + 'Untitled Document' => '無題の文書', + 'Up' => '', + 'Up node' => '', + 'Up section' => '', + 'by @emph{%{user}}' => '@emph{%{user}}', + 'by @emph{%{user}} on @emph{%{date}}' => '@emph{%{user}}, @emph{%{date}', + 'current' => '現在位置', + 'on @emph{%{date}}' => '@emph{%{date}}', + 'section `%{section}\' in @cite{%{book}}' => '@cite{%{book}}の `%{section}\' ', + 'see %{node_file_href}' => '%{node_file_href}参照', + 'see %{node_file_href} @cite{%{book}}' => '%{node_file_href} @cite{%{book}}参照', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'see %{reference_name}' => '', + 'see @cite{%{book}}' => '', + 'see section %{reference_name}' => '', + 'see section `%{section}\' in @cite{%{book}}' => '', + 'unknown' => '不明' + }; + +$T2H_OBSOLETE_STRINGS->{'ja'} = { + 'about (help)' => '使用法 (ヘルプ)', + 'beginning of this chapter or previous chapter' => 'この章または前の章の冒頭', + 'cover (top) of document' => '文書の表紙 (トップ)', + 'current section' => '現在の節', + 'first section in reading order' => '文書順で前の項', + 'following node' => '次の節', + 'index' => '見出し', + 'last section in reading order' => '文書順で最後の項', + 'next chapter' => '次の章', + 'next node' => '次の節', + 'next section in reading order' => '文書順で次の項', + 'next section on same level' => '同じ階層にある次の項', + 'node following in node reading order' => '文書順で次の節', + 'node up' => '上の節へ', + 'previous node' => '前の節', + 'previous section in reading order' => '文書順で前の節', + 'previous section on same level' => '同じ階層にある前の項', + 'short table of contents' => '簡略化した目次', + 'table of contents' => '文書の目次', + 'up node' => '上の節', + 'up section' => '上の項' + }; + + +$LANGUAGES->{'nl'} = { + ' The buttons in the navigation panels have the following meaning:' => '', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '', + ' Up ' => '', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '', + '%{name} of %{class}' => '', + '%{name} on %{class}' => '', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => '', + 'About (help)' => '', + 'About This Document' => 'No translation available!', + 'April' => 'April', + 'August' => 'Augustus', + 'Back' => '', + 'Beginning of this chapter or previous chapter' => '', + 'Button' => '', + 'Contents' => '', + 'Cover (top) of document' => '', + 'Current Position' => '', + 'Current section' => '', + 'December' => 'December', + 'FastBack' => '', + 'FastForward' => '', + 'February' => 'Februari', + 'First' => '', + 'First section in reading order' => '', + 'Following' => '', + 'Following node' => '', + 'Footnotes' => 'No translation available!', + 'Forward' => '', + 'From 1.2.3 go to' => '', + 'Go to' => '', + 'Index' => 'Index', + 'Index Entry' => '', + 'January' => 'Januari', + 'July' => 'Juli', + 'Jump to' => '', + 'June' => 'Juni', + 'Last' => '', + 'Last section in reading order' => '', + 'March' => 'Maart', + 'May' => 'Mei', + 'Menu:' => '', + 'Name' => '', + 'Next' => '', + 'Next chapter' => '', + 'Next node' => '', + 'Next section in reading order' => '', + 'Next section on same level' => '', + 'Node following in node reading order' => '', + 'Node up' => '', + 'NodeNext' => '', + 'NodePrev' => '', + 'NodeUp' => '', + 'November' => 'November', + 'October' => 'Oktober', + 'Overview' => '', + 'Overview:' => '', + 'Prev' => '', + 'Previous node' => '', + 'Previous section in reading order' => '', + 'Previous section on same level' => '', + 'Section' => '', + 'Section One' => '', + 'See %{node_file_href}' => '', + 'See %{node_file_href} @cite{%{book}}' => '', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'See %{reference_name}' => '', + 'See @cite{%{book}}' => '', + 'See section %{reference_name}' => '', + 'See section `%{section}\' in @cite{%{book}}' => '', + 'September' => 'September', + 'Short Table of Contents' => 'Korte inhoudsopgave', + 'Short table of contents' => '', + 'Subsection One-Four' => '', + 'Subsection One-One' => '', + 'Subsection One-Three' => '', + 'Subsection One-Two' => '', + 'Subsubsection One-Two-Four' => '', + 'Subsubsection One-Two-One' => '', + 'Subsubsection One-Two-Three' => '', + 'Subsubsection One-Two-Two' => '', + 'T2H_today' => '', + 'Table of Contents' => 'Inhoudsopgave', + 'Table of contents' => '', + 'The node you are looking for is at %{href}.' => '', + 'This' => '', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'Top' => '', + 'Untitled Document' => '', + 'Up' => '', + 'Up node' => '', + 'Up section' => '', + 'by @emph{%{user}}' => '', + 'by @emph{%{user}} on @emph{%{date}}' => '', + 'current' => '', + 'on @emph{%{date}}' => '', + 'section `%{section}\' in @cite{%{book}}' => '', + 'see %{node_file_href}' => '', + 'see %{node_file_href} @cite{%{book}}' => '', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'see %{reference_name}' => '', + 'see @cite{%{book}}' => '', + 'see section %{reference_name}' => '', + 'see section `%{section}\' in @cite{%{book}}' => '', + 'unknown' => '' + }; + +$T2H_OBSOLETE_STRINGS->{'nl'} = { + 'See' => 'Zie', + 'section' => 'sectie', + 'see' => 'zie' + }; + + +$LANGUAGES->{'no'} = { + ' The buttons in the navigation panels have the following meaning:' => '', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => '', + ' Up ' => '', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '', + '%{name} of %{class}' => '', + '%{name} on %{class}' => '', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => '', + 'About (help)' => '', + 'About This Document' => 'No translation available!', + 'April' => 'april', + 'August' => 'august', + 'Back' => '', + 'Beginning of this chapter or previous chapter' => '', + 'Button' => '', + 'Contents' => '', + 'Cover (top) of document' => '', + 'Current Position' => '', + 'Current section' => '', + 'December' => 'desember', + 'FastBack' => '', + 'FastForward' => '', + 'February' => 'februar', + 'First' => '', + 'First section in reading order' => '', + 'Following' => '', + 'Following node' => '', + 'Footnotes' => 'No translation available!', + 'Forward' => '', + 'From 1.2.3 go to' => '', + 'Go to' => '', + 'Index' => 'Indeks', + 'Index Entry' => '', + 'January' => 'januar', + 'July' => 'juli', + 'Jump to' => '', + 'June' => 'juni', + 'Last' => '', + 'Last section in reading order' => '', + 'March' => 'mars', + 'May' => 'mai', + 'Menu:' => '', + 'Name' => '', + 'Next' => '', + 'Next chapter' => '', + 'Next node' => '', + 'Next section in reading order' => '', + 'Next section on same level' => '', + 'Node following in node reading order' => '', + 'Node up' => '', + 'NodeNext' => '', + 'NodePrev' => '', + 'NodeUp' => '', + 'November' => 'november', + 'October' => 'oktober', + 'Overview' => '', + 'Overview:' => '', + 'Prev' => '', + 'Previous node' => '', + 'Previous section in reading order' => '', + 'Previous section on same level' => '', + 'Section' => '', + 'Section One' => '', + 'See %{node_file_href}' => '', + 'See %{node_file_href} @cite{%{book}}' => '', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'See %{reference_name}' => '', + 'See @cite{%{book}}' => '', + 'See section %{reference_name}' => '', + 'See section `%{section}\' in @cite{%{book}}' => '', + 'September' => 'september', + 'Short Table of Contents' => 'Kort innholdsfortegnelse', + 'Short table of contents' => '', + 'Subsection One-Four' => '', + 'Subsection One-One' => '', + 'Subsection One-Three' => '', + 'Subsection One-Two' => '', + 'Subsubsection One-Two-Four' => '', + 'Subsubsection One-Two-One' => '', + 'Subsubsection One-Two-Three' => '', + 'Subsubsection One-Two-Two' => '', + 'T2H_today' => '', + 'Table of Contents' => 'Innholdsfortegnelse', + 'Table of contents' => '', + 'The node you are looking for is at %{href}.' => '', + 'This' => '', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => '', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => '', + 'Top' => '', + 'Untitled Document' => '', + 'Up' => '', + 'Up node' => '', + 'Up section' => '', + 'by @emph{%{user}}' => '', + 'by @emph{%{user}} on @emph{%{date}}' => '', + 'current' => '', + 'on @emph{%{date}}' => '', + 'section `%{section}\' in @cite{%{book}}' => '', + 'see %{node_file_href}' => '', + 'see %{node_file_href} @cite{%{book}}' => '', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => '', + 'see %{reference_name}' => '', + 'see @cite{%{book}}' => '', + 'see section %{reference_name}' => '', + 'see section `%{section}\' in @cite{%{book}}' => '', + 'unknown' => '' + }; + +$T2H_OBSOLETE_STRINGS->{'no'} = { + 'See' => 'Se', + 'section' => 'avsnitt', + 'see' => 'se' + }; + + +$LANGUAGES->{'pt'} = { + ' The buttons in the navigation panels have the following meaning:' => ' Os bot@~oes nos pain@\'eis de navega@,{c}@~ao possuem os seguintes significados:', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => ' onde o @strong{ Exemplo } assume que a posi@,{c}@~ao atual localiza-se em @strong{ Subsub@,{c}@~ao Um-Dois-Tr@^es } de um documento com a seguinte estrutura:', + ' Up ' => ' Acima ', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '%{day} de %{month} de %{year}', + '%{name} of %{class}' => '%{name} da %{class}', + '%{name} on %{class}' => '%{name} na %{class}', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '%{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => 'Sobre', + 'About (help)' => 'Sobre (ajuda)', + 'About This Document' => 'Sobre Esse Documento', + 'April' => 'Abril', + 'August' => 'Agosto', + 'Back' => 'Volta', + 'Beginning of this chapter or previous chapter' => 'Come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior', + 'Button' => 'Bot@~ao', + 'Contents' => 'Conte@\'udo', + 'Cover (top) of document' => 'In@\'icio (topo) do documento', + 'Current Position' => 'Posi@,{c}@~ao Atual', + 'Current section' => 'Se@,{c}@~ao atual', + 'December' => 'Dezembro', + 'FastBack' => 'Voltar R@\'apido', + 'FastForward' => 'Avan@,{c}ar R@\'apido', + 'February' => 'Fevereiro', + 'First' => 'Primeiro', + 'First section in reading order' => 'Primeira se@,{c}@~ao na ordem de leitura', + 'Following' => 'Seguinte', + 'Following node' => 'Nodo seguinte', + 'Footnotes' => 'Notas de Rodap@\'e', + 'Forward' => 'Avan@,{c}ar', + 'From 1.2.3 go to' => 'De 1.2.3 v@\'a para', + 'Go to' => 'V@\'a para', + 'Index' => '@\'Indice', + 'Index Entry' => 'Entrada de @\'Indice', + 'January' => 'Janeiro', + 'July' => 'Julho', + 'Jump to' => 'Pular para', + 'June' => 'Junho', + 'Last' => '@\'Ultimo', + 'Last section in reading order' => '@\'Ultima se@,{c}@~ao na ordem de leitura', + 'March' => 'Mar@,{c}o', + 'May' => 'Maio', + 'Menu:' => '', + 'Name' => 'Nome', + 'Next' => 'Pr@\'oximo', + 'Next chapter' => 'Pr@\'oximo cap@\'itulo', + 'Next node' => 'Pr@\'oximo nodo', + 'Next section in reading order' => 'Pr@\'oxima se@,{c}@~ao na ordem de leitura', + 'Next section on same level' => 'Pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel', + 'Node following in node reading order' => 'Nodo seguinte na ordem de leitura de nodos', + 'Node up' => 'Nodo acima', + 'NodeNext' => 'Pr@\'oximo Nodo', + 'NodePrev' => 'Nodo Anterior', + 'NodeUp' => 'Nodo Acima', + 'November' => 'Novembro', + 'October' => 'Outubro', + 'Overview' => 'Vis@~ao geral', + 'Overview:' => 'Vis@~ao geral:', + 'Prev' => 'Pr@\'evio', + 'Previous node' => 'Nodo anterior', + 'Previous section in reading order' => 'Se@,{c}@~ao anterior na ordem de leitura', + 'Previous section on same level' => 'Se@,{c}@~ao anterior no mesmo n@\'ivel', + 'Section' => 'Se@,{c}@~ao', + 'Section One' => 'Se@,{c}@~ao Um', + 'See %{node_file_href}' => 'Veja %{node_file_href}', + 'See %{node_file_href} @cite{%{book}}' => 'Veja %{node_file_href} @cite{%{book}}', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'Veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'See %{reference_name}' => 'Veja %{reference_name}', + 'See @cite{%{book}}' => 'Veja @cite{%{book}}', + 'See section %{reference_name}' => 'Veja se@,{c}@~ao %{reference_name}', + 'See section `%{section}\' in @cite{%{book}}' => 'Veja se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'September' => 'Setembro', + 'Short Table of Contents' => 'Breve Sum@\'ario', + 'Short table of contents' => 'Breve sum@\'ario', + 'Subsection One-Four' => 'Subse@,{c}@~ao Um-Quatro', + 'Subsection One-One' => 'Subse@,{c}@~ao Um-Um', + 'Subsection One-Three' => 'Subse@,{c}@~ao Um-Tr@^es', + 'Subsection One-Two' => 'Subse@,{c}@~ao Um-Dois', + 'Subsubsection One-Two-Four' => 'Subse@,{c}@~ao Um-Dois-Quatro', + 'Subsubsection One-Two-One' => 'Subse@,{c}@~ao Um-Dois-Um', + 'Subsubsection One-Two-Three' => 'Subse@,{c}@~ao Um-Dois-Tr@^es', + 'Subsubsection One-Two-Two' => 'Subse@,{c}@~ao Um-Dois-Dois', + 'T2H_today' => '', + 'Table of Contents' => 'Sum@\'ario', + 'Table of contents' => 'Sum@\'ario', + 'The node you are looking for is at %{href}.' => 'O nodo que vo@^e est@\'a olhando est@\'a em %{href}.', + 'This' => 'Esse', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gereado por @emph{%{user}} em @emph{%{date}} usando @uref{%{program_homepage}, @emph{%{program}}}.', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado por @emph{%{user}} usando @uref{%{program_homepage}, @emph{%{program}}}.', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => 'Esse documento foi gerado em @i{%{date}} usando @uref{%{program_homepage}, @i{%{program}}}.', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado usando @uref{%{program_homepage}, @emph{%{program}}}.', + 'Top' => 'Topo', + 'Untitled Document' => 'Documento Sem Nome', + 'Up' => 'Acima', + 'Up node' => 'Nodo acima', + 'Up section' => 'Se@,{c}@~ao acima', + 'by @emph{%{user}}' => 'por @emph{%{user}}', + 'by @emph{%{user}} on @emph{%{date}}' => 'por @emph{%{user}} em @emph{%{date}}', + 'current' => 'atual', + 'on @emph{%{date}}' => 'em @emph{%{date}}', + 'section `%{section}\' in @cite{%{book}}' => 'se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'see %{node_file_href}' => 'veja %{node_file_href}', + 'see %{node_file_href} @cite{%{book}}' => 'veja %{node_file_href} @cite{%{book}}', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'see %{reference_name}' => 'veja %{reference_name}', + 'see @cite{%{book}}' => 'veja @cite{%{book}}', + 'see section %{reference_name}' => 'veja se@,{c}@~ao %{reference_name}', + 'see section `%{section}\' in @cite{%{book}}' => 'veja se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'unknown' => 'desconhecido' + }; + +$T2H_OBSOLETE_STRINGS->{'pt'} = { + 'See' => 'Veja', + 'about (help)' => 'sobre (ajuda)', + 'beginning of this chapter or previous chapter' => 'come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior', + 'cover (top) of document' => 'in@\'icio (topo) do documento', + 'current section' => 'se@,{c}@~ao atual', + 'first section in reading order' => 'primeira se@,{c}@~ao na ordem de leitura', + 'following node' => 'nodo seguinte', + 'index' => '@\'indice', + 'last section in reading order' => '@\'ultima se@,{c}@~ao na ordem de leitura', + 'next chapter' => 'pr@\'oximo cap@\'itulo', + 'next node' => 'pr@\'oximo nodo', + 'next section in reading order' => 'pr@\'oxima se@,{c}@~ao na ordem de leitura', + 'next section on same level' => 'pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel', + 'node following in node reading order' => 'nodo seguinte na ordem de leitura de nodos', + 'node up' => 'nodo acima', + 'previous node' => 'nodo anterior', + 'previous section in reading order' => 'se@,{c}@~ao anterior na ordem de leitura', + 'previous section on same level' => 'se@,{c}@~ao anterior no mesmo n@\'ivel', + 'section' => 'Se@,{c}@~ao', + 'see' => 'veja', + 'short table of contents' => 'breve sum@\'ario', + 'table of contents' => 'sum@\'ario', + 'up node' => 'nodo acima', + 'up section' => 'se@,{c}@~ao acima' + }; + + +$LANGUAGES->{'pt_BR'} = { + ' The buttons in the navigation panels have the following meaning:' => ' Os bot@~oes nos pain@\'eis de navega@,{c}@~ao possuem os seguintes significados:', + ' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:' => ' onde o @strong{ Exemplo } assume que a posi@,{c}@~ao atual localiza-se em @strong{ Subsub@,{c}@~ao Um-Dois-Tr@^es } de um documento com a seguinte estrutura:', + ' Up ' => ' Acima ', + '%{acronym_like} (%{explanation})' => '', + '%{month}, %{day} %{year}' => '%{day} de %{month} de %{year}', + '%{name} of %{class}' => '%{name} da %{class}', + '%{name} on %{class}' => '%{name} na %{class}', + '%{node_file_href}' => '', + '%{node_file_href} @cite{%{book}}' => '', + '%{node_file_href} section `%{section}\' in @cite{%{book}}' => '%{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}', + '%{reference_name}' => '', + '%{style} %{number}' => '', + '%{style}: %{caption_first_line}' => '', + '%{style}: %{shortcaption_first_line}' => '', + '@b{%{quotation_arg}:} ' => '', + '@cite{%{book}}' => '', + 'About' => 'Sobre', + 'About (help)' => 'Sobre (ajuda)', + 'About This Document' => 'Sobre Esse Documento', + 'April' => 'Abril', + 'August' => 'Agosto', + 'Back' => 'Volta', + 'Beginning of this chapter or previous chapter' => 'Come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior', + 'Button' => 'Bot@~ao', + 'Contents' => 'Conte@\'udo', + 'Cover (top) of document' => 'In@\'icio (topo) do documento', + 'Current Position' => 'Posi@,{c}@~ao Atual', + 'Current section' => 'Se@,{c}@~ao atual', + 'December' => 'Dezembro', + 'FastBack' => 'Voltar R@\'apido', + 'FastForward' => 'Avan@,{c}ar R@\'apido', + 'February' => 'Fevereiro', + 'First' => 'Primeiro', + 'First section in reading order' => 'Primeira se@,{c}@~ao na ordem de leitura', + 'Following' => 'Seguinte', + 'Following node' => 'Nodo seguinte', + 'Footnotes' => 'Notas de Rodap@\'e', + 'Forward' => 'Avan@,{c}ar', + 'From 1.2.3 go to' => 'De 1.2.3 v@\'a para', + 'Go to' => 'V@\'a para', + 'Index' => '@\'Indice', + 'Index Entry' => 'Entrada de @\'Indice', + 'January' => 'Janeiro', + 'July' => 'Julho', + 'Jump to' => 'Pular para', + 'June' => 'Junho', + 'Last' => '@\'Ultimo', + 'Last section in reading order' => '@\'Ultima se@,{c}@~ao na ordem de leitura', + 'March' => 'Mar@,{c}o', + 'May' => 'Maio', + 'Menu:' => '', + 'Name' => 'Nome', + 'Next' => 'Pr@\'oximo', + 'Next chapter' => 'Pr@\'oximo cap@\'itulo', + 'Next node' => 'Pr@\'oximo nodo', + 'Next section in reading order' => 'Pr@\'oxima se@,{c}@~ao na ordem de leitura', + 'Next section on same level' => 'Pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel', + 'Node following in node reading order' => 'Nodo seguinte na ordem de leitura de nodos', + 'Node up' => 'Nodo acima', + 'NodeNext' => 'Pr@\'oximo Nodo', + 'NodePrev' => 'Nodo Anterior', + 'NodeUp' => 'Nodo Acima', + 'November' => 'Novembro', + 'October' => 'Outubro', + 'Overview' => 'Vis@~ao geral', + 'Overview:' => 'Vis@~ao geral:', + 'Prev' => 'Pr@\'evio', + 'Previous node' => 'Nodo anterior', + 'Previous section in reading order' => 'Se@,{c}@~ao anterior na ordem de leitura', + 'Previous section on same level' => 'Se@,{c}@~ao anterior no mesmo n@\'ivel', + 'Section' => 'Se@,{c}@~ao', + 'Section One' => 'Se@,{c}@~ao Um', + 'See %{node_file_href}' => 'Veja %{node_file_href}', + 'See %{node_file_href} @cite{%{book}}' => 'Veja %{node_file_href} @cite{%{book}}', + 'See %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'Veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'See %{reference_name}' => 'Veja %{reference_name}', + 'See @cite{%{book}}' => 'Veja @cite{%{book}}', + 'See section %{reference_name}' => 'Veja se@,{c}@~ao %{reference_name}', + 'See section `%{section}\' in @cite{%{book}}' => 'Veja se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'September' => 'Setembro', + 'Short Table of Contents' => 'Breve Sum@\'ario', + 'Short table of contents' => 'Breve sum@\'ario', + 'Subsection One-Four' => 'Subse@,{c}@~ao Um-Quatro', + 'Subsection One-One' => 'Subse@,{c}@~ao Um-Um', + 'Subsection One-Three' => 'Subse@,{c}@~ao Um-Tr@^es', + 'Subsection One-Two' => 'Subse@,{c}@~ao Um-Dois', + 'Subsubsection One-Two-Four' => 'Subse@,{c}@~ao Um-Dois-Quatro', + 'Subsubsection One-Two-One' => 'Subse@,{c}@~ao Um-Dois-Um', + 'Subsubsection One-Two-Three' => 'Subse@,{c}@~ao Um-Dois-Tr@^es', + 'Subsubsection One-Two-Two' => 'Subse@,{c}@~ao Um-Dois-Dois', + 'T2H_today' => '', + 'Table of Contents' => 'Sum@\'ario', + 'Table of contents' => 'Sum@\'ario', + 'The node you are looking for is at %{href}.' => 'O nodo que vo@^e est@\'a olhando est@\'a em %{href}.', + 'This' => 'Esse', + 'This document was generated by @emph{%{user}} on @emph{%{date}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gereado por @emph{%{user}} em @emph{%{date}} usando @uref{%{program_homepage}, @emph{%{program}}}.', + 'This document was generated by @emph{%{user}} using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado por @emph{%{user}} usando @uref{%{program_homepage}, @emph{%{program}}}.', + 'This document was generated on @i{%{date}} using @uref{%{program_homepage}, @i{%{program}}}.' => 'Esse documento foi gerado em @i{%{date}} usando @uref{%{program_homepage}, @i{%{program}}}.', + 'This document was generated using @uref{%{program_homepage}, @emph{%{program}}}.' => 'Esse documento foi gerado usando @uref{%{program_homepage}, @emph{%{program}}}.', + 'Top' => 'Topo', + 'Untitled Document' => 'Documento Sem Nome', + 'Up' => 'Acima', + 'Up node' => 'Nodo acima', + 'Up section' => 'Se@,{c}@~ao acima', + 'by @emph{%{user}}' => 'por @emph{%{user}}', + 'by @emph{%{user}} on @emph{%{date}}' => 'por @emph{%{user}} em @emph{%{date}}', + 'current' => 'atual', + 'on @emph{%{date}}' => 'em @emph{%{date}}', + 'section `%{section}\' in @cite{%{book}}' => 'se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'see %{node_file_href}' => 'veja %{node_file_href}', + 'see %{node_file_href} @cite{%{book}}' => 'veja %{node_file_href} @cite{%{book}}', + 'see %{node_file_href} section `%{section}\' in @cite{%{book}}' => 'veja %{node_file_href} se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'see %{reference_name}' => 'veja %{reference_name}', + 'see @cite{%{book}}' => 'veja @cite{%{book}}', + 'see section %{reference_name}' => 'veja se@,{c}@~ao %{reference_name}', + 'see section `%{section}\' in @cite{%{book}}' => 'veja se@,{c}@~ao `%{section}\' em @cite{%{book}}', + 'unknown' => 'desconhecido' + }; + +$T2H_OBSOLETE_STRINGS->{'pt_BR'} = { + 'See' => 'Veja', + 'about (help)' => 'sobre (ajuda)', + 'beginning of this chapter or previous chapter' => 'come@,{c}o desse cap@\'itulo ou cap@\'itulo anterior', + 'cover (top) of document' => 'in@\'icio (topo) do documento', + 'current section' => 'se@,{c}@~ao atual', + 'first section in reading order' => 'primeira se@,{c}@~ao na ordem de leitura', + 'following node' => 'nodo seguinte', + 'index' => '@\'indice', + 'last section in reading order' => '@\'ultima se@,{c}@~ao na ordem de leitura', + 'next chapter' => 'pr@\'oximo cap@\'itulo', + 'next node' => 'pr@\'oximo nodo', + 'next section in reading order' => 'pr@\'oxima se@,{c}@~ao na ordem de leitura', + 'next section on same level' => 'pr@\'oxima se@,{c}@~ao no mesmo n@\'ivel', + 'node following in node reading order' => 'nodo seguinte na ordem de leitura de nodos', + 'node up' => 'nodo acima', + 'previous node' => 'nodo anterior', + 'previous section in reading order' => 'se@,{c}@~ao anterior na ordem de leitura', + 'previous section on same level' => 'se@,{c}@~ao anterior no mesmo n@\'ivel', + 'section' => 'Se@,{c}@~ao', + 'see' => 'veja', + 'short table of contents' => 'breve sum@\'ario', + 'table of contents' => 'sum@\'ario', + 'up node' => 'nodo acima', + 'up section' => 'se@,{c}@~ao acima' + }; + + + +require "$ENV{T2H_HOME}/$translation_file" + if ($0 =~ /\.pl$/ && + -e "$ENV{T2H_HOME}/$translation_file" && -r "$ENV{T2H_HOME}/$translation_file"); + +# set the default 'args' entry to normal for each style hash (and each command +# within) +my $name_index = -1; +my @hash_names = ('style_map', 'style_map_pre', 'style_map_texi', 'simple_format_style_map_texi'); +foreach my $hash (\%style_map, \%style_map_pre, \%style_map_texi, \%simple_format_style_map_texi) +{ + $name_index++; + my $name = $hash_names[$name_index]; # name associated with hash ref + foreach my $style (keys(%{$hash})) + { + next unless (ref($hash->{$style}) eq 'HASH'); + $hash->{$style}->{'args'} = ['normal'] if (!exists($hash->{$style}->{'args'})); + die "Bug: args not defined, but existing, for $style in $name" if (!defined($hash->{$style}->{'args'})); +#print STDERR "DEFAULT($name, $hash) add normal as arg for $style ($hash->{$style}), $hash->{$style}->{'args'}\n"; + } +} + +# +# Some functions used to override normal formatting functions in specific +# cases. The user shouldn't want to change them, but can use them. +# + +# used to utf8 encode the result +sub t2h_utf8_accent($$$) +{ + my $accent = shift; + my $args = shift; + my $style_stack = shift; + + my $text = $args->[0]; + #print STDERR "$accent\[".scalar(@$style_stack) ."\] (@$style_stack)\n"; + + # special handling of @dotless{i} + if ($accent eq 'dotless') + { + if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent'))) + { + return "\x{0131}"; + } + #return "\x{}" if ($text eq 'j'); # not found ! + return $text; + } + + # FIXME \x{0131}\x{0308} for @dotless{i} @" doesn't lead to NFC 00ef. + return Unicode::Normalize::NFC($text . chr(hex($unicode_diacritical{$accent}))) + if (defined($unicode_diacritical{$accent})); + return ascii_accents($text, $accent); +} + +sub t2h_utf8_normal_text($$$$$) +{ + my $text = shift; + my $in_raw_text = shift; + my $in_preformatted = shift; + my $in_code =shift; + my $style_stack = shift; + $text = &$protect_text($text) unless($in_raw_text); + $text = uc($text) if (in_small_caps($style_stack)); + + if (!$in_code and !$in_preformatted) + { + $text =~ s/---/\x{2014}/g; + $text =~ s/--/\x{2013}/g; + $text =~ s/``/\x{201C}/g; + $text =~ s/''/\x{201D}/g; + } + return Unicode::Normalize::NFC($text); +} + +# these are unlikely to be used by users, as they are essentially +# used to follow the html external refs specification in texinfo +sub t2h_cross_manual_normal_text($$$$$) +{ + my $text = shift; + my $in_raw_text = shift; + my $in_preformatted = shift; + my $in_code =shift; + my $style_stack = shift; + + $text = uc($text) if (in_small_caps($style_stack)); + return $text if ($USE_UNICODE); + + # if there is no unicode support, we do all the transformations here + my $result = ''; + while ($text ne '') + { + if ($text =~ s/^([A-Za-z0-9]+)//o) + { + $result .= $1; + } + elsif ($text =~ s/^ //o) + { + $result .= '-'; + } + elsif ($text =~ s/^(.)//o) + { + if (exists($ascii_character_map{$1})) + { + $result .= '_' . lc($ascii_character_map{$1}); + } + else + { # wild guess that should work for latin1 + $result .= '_' . '00' . lc(sprintf("%02x",ord($1))); + } + } + else + { + print STDERR "Bug: unknown character in cross ref (likely in infinite loop)\n"; + sleep 1; + } + } + + return $result; +} + +sub t2h_nounicode_cross_manual_accent($$$) +{ + my $accent = shift; + my $args = shift; + my $style_stack = shift; + + my $text = $args->[0]; + + if ($accent eq 'dotless') + { + if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent'))) + { + return "_0131"; + } + #return "\x{}" if ($text eq 'j'); # not found ! + return $text; + } + return '_' . lc($unicode_accents{$accent}->{$text}) + if (defined($unicode_accents{$accent}->{$text})); + return ($text . '_' . lc($unicode_diacritical{$accent})) + if (defined($unicode_diacritical{$accent})); + return ascii_accents($text, $accent); +} + +sub t2h_transliterate_cross_manual_accent($$) +{ + my $accent = shift; + my $args = shift; + + my $text = $args->[0]; + + if (exists($unicode_accents{$accent}->{$text}) and + exists ($transliterate_map{$unicode_accents{$accent}->{$text}})) + { + return $transliterate_map{$unicode_accents{$accent}->{$text}}; + } + return $text; +} + + +} # end package Texi2HTML::Config + +use vars qw( +%value +); + +# variables which might be redefined by the user but aren't likely to be +# they seem to be in the main namespace +use vars qw( +%index_names +%predefined_index +%valid_index +%sec2level +%code_style_map +%region_lines +%forbidden_index_name +); + +# Some global variables are set in the script, and used in the subroutines +# they are in the Texi2HTML namespace, thus prefixed with Texi2HTML::. +# see texi2html.init for details. + +#+++############################################################################ +# # +# 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. + +# @MYSIMPLE@ +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: MySimple.pm,v 1.5 2006/04/17 23:11:09 pertusus 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]); sleep 5;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'} }) ) + { + next unless (ref(${$self -> {'default'} }{$_}) eq 'HASH'); + 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') and (defined($$val))) + { + $val = $$val; + } + else + { + $val = ''; + } + } + elsif (defined(${$self->{'default'} }{$_}{'default'})) + { + $val = ${$self->{'default'} }{$_}{'default'}; + } + else + { + $val = ''; + } + $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 <<EOT; +Note: 'Options' may be abbreviated. 'Type' specifications mean: + <none>| ! 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"); + +#+++######################################################################## +# # +# Initialization # +# Pasted content of File $(srcdir)/T2h_i18n.pm: Internationalisation # +# # +#---######################################################################## + +# leave this within comments, and keep the require statement +# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/T2h_i18n.pm +# exists. + +# @T2H_I18N@ +#+############################################################################## +# +# T2h_i18n.pm: Internationalization for texi2html +# +# Copyright (C) 1999-2005 Patrice Dumas <dumas@centre-cired.fr>, +# Derek Price <derek@ximbiot.com>, +# Adrian Aichner <adrian@xemacs.org>, +# & others. +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +#-############################################################################## + +# This requires perl version 5 or higher +require 5.0; + +package Texi2HTML::I18n; + +use strict; + +use vars qw( +@ISA +@EXPORT +); + +use Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(pretty_date); + +my $language; +my $i18n_dir = 'i18n'; # name of the directory containing the per language files +#my $translation_file = 'translations.pl'; # file containing all the translations +#my @known_languages = ('de', 'nl', 'es', 'no', 'pt', 'fr'); # The supported + # languages + +######################################################################## +# Language dependencies: +# To add a new language extend the WORDS hash and create $T2H_<...>_WORDS hash +# To redefine one word, simply do: +# $T2h_i18n::T2H_LANGUAGES->{<language>}->{<word>} = 'whatever' in your personal init file. +# + +# Those hashes are obsolete but retained here for reference + +my $T2H_WORDS_EN = +{ + # titles of pages + #'Table of Contents' => 'Table of Contents', + #'Short Table of Contents' => 'Short Table of Contents', + #'Index' => 'Index', + #'About This Document' => 'About This Document', + #'Footnotes' => 'Footnotes', + #'See' => 'See', + #'see' => 'see', + #'section' => 'section', + 'About This Document' => '', + 'Table of Contents' => '', + 'Short Table of Contents', => '', + 'Index' => '', + 'Footnotes' => '', + 'See' => '', + 'see' => '', + 'section' => '', + 'Top' => '', + 'Untitled Document' => '', + # 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' + 'January' => '', + 'February' => '', + 'March' => '', + 'April' => '', + 'May' => '', + 'June' => '', + 'July' => '', + 'August' => '', + 'September' => '', + 'October' => '', + 'November' => '', + 'December' => '', + 'T2H_today' => '%s, %d %d', +}; + +my $T2H_WORDS_DE = +{ + 'Table of Contents' => 'Inhaltsverzeichniss', + 'Short Table of Contents' => 'Kurzes Inhaltsverzeichniss', + 'Index' => 'Index', + 'About This Document' => 'Über dieses Dokument', + 'Footnotes' => 'Fußnoten', + 'See' => 'Siehe', + 'see' => 'siehe', + 'section' => 'Abschnitt', + 'January' => 'Januar', + 'February' => 'Februar', + 'March' => 'März', + 'April' => 'April', + 'May' => 'Mai', + 'June' => 'Juni', + 'July' => 'Juli', + 'August' => 'August', + 'September' => 'September', + 'October' => 'Oktober', + 'November' => 'November', + 'December' => 'Dezember', +}; + +my $T2H_WORDS_NL = +{ + 'Table of Contents' => 'Inhoudsopgave', + 'Short Table of Contents' => 'Korte inhoudsopgave', + 'Index' => 'Index', #Not sure ;-) + 'About This Document' => 'No translation available!', #No translation available! + 'Footnotes' => 'No translation available!', #No translation available! + 'See' => 'Zie', + 'see' => 'zie', + 'section' => 'sectie', + 'January' => 'Januari', + 'February' => 'Februari', + 'March' => 'Maart', + 'April' => 'April', + 'May' => 'Mei', + 'June' => 'Juni', + 'July' => 'Juli', + 'August' => 'Augustus', + 'September' => 'September', + 'October' => 'Oktober', + 'November' => 'November', + 'December' => 'December', +}; + +my $T2H_WORDS_ES = +{ + 'Table of Contents' => 'índice General', + 'Short Table of Contents' => 'Resumen del Contenido', + 'Index' => 'Index', #Not sure ;-) + 'About This Document' => 'No translation available!', #No translation available! + 'Footnotes' => 'Fußnoten', + 'See' => 'Véase', + 'see' => 'véase', + 'section' => 'sección', + 'January' => 'enero', + 'February' => 'febrero', + 'March' => 'marzo', + 'April' => 'abril', + 'May' => 'mayo', + 'June' => 'junio', + 'July' => 'julio', + 'August' => 'agosto', + 'September' => 'septiembre', + 'October' => 'octubre', + 'November' => 'noviembre', + 'December' => 'diciembre', +}; + +my $T2H_WORDS_NO = +{ + 'Table of Contents' => 'Innholdsfortegnelse', + 'Short Table of Contents' => 'Kort innholdsfortegnelse', + 'Index' => 'Indeks', #Not sure ;-) + 'About This Document' => 'No translation available!', #No translation available! + 'Footnotes' => 'No translation available!', + 'See' => 'Se', + 'see' => 'se', + 'section' => 'avsnitt', + 'January' => 'januar', + 'February' => 'februar', + 'March' => 'mars', + 'April' => 'april', + 'May' => 'mai', + 'June' => 'juni', + 'July' => 'juli', + 'August' => 'august', + 'September' => 'september', + 'October' => 'oktober', + 'November' => 'november', + 'December' => 'desember', +}; + +my $T2H_WORDS_PT = +{ + 'Table of Contents' => 'Sumário', + 'Short Table of Contents' => 'Breve Sumário', + 'Index' => 'Índice', #Not sure ;-) + 'About This Document' => 'No translation available!', #No translation available! + 'Footnotes' => 'No translation available!', + 'See' => 'Veja', + 'see' => 'veja', + 'section' => 'Seção', + 'January' => 'Janeiro', + 'February' => 'Fevereiro', + 'March' => 'Março', + 'April' => 'Abril', + 'May' => 'Maio', + 'June' => 'Junho', + 'July' => 'Julho', + 'August' => 'Agosto', + 'September' => 'Setembro', + 'October' => 'Outubro', + 'November' => 'Novembro', + 'December' => 'Dezembro', +}; + +my $T2H_WORDS_FR = +{ + 'Table of Contents' => 'Table des matières', + 'Short Table of Contents' => 'Résumée du contenu', + 'Index' => 'Index', + 'About This Document' => 'A propos de ce document', + 'Footnotes' => 'Notes de bas de page', + 'See' => 'Voir', + 'see' => 'voir', + 'section' => 'section', + 'January' => 'Janvier', + 'February' => 'Février', + 'March' => 'Mars', + 'April' => 'Avril', + 'May' => 'Mai', + 'June' => 'Juin', + 'July' => 'Juillet', + 'August' => 'Août', + 'September' => 'Septembre', + 'October' => 'Octobre', + 'November' => 'Novembre', + 'December' => 'Décembre', + 'T2H_today' => 'le %2$d %1$s %3$d' +}; + +#$T2H_LANGUAGES = +#{ +# '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, +#}; + +sub set_language($) +{ + my $lang = shift; + if (defined($lang) && exists($Texi2HTML::Config::LANGUAGES->{$lang}) && defined($Texi2HTML::Config::LANGUAGES->{$lang})) + { + $language = $lang; + return 1; + } + else + { + return 0; + } +} + + +my @MONTH_NAMES = + ( + 'January', 'February', 'March', 'April', 'May', + 'June', 'July', 'August', 'September', 'October', + 'November', 'December' + ); + +my $I = \&get_string; + +sub pretty_date($) +{ + my $lang = shift; + 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->{$lang}[$mon] . ", " . $mday . " " . $year); + #return(sprintf(&$I('T2H_today'), (get_string($MONTH_NAMES[$mon]), $mday, $year))); + return &$I('%{month}, %{day} %{year}', { 'month' => get_string($MONTH_NAMES[$mon]), + 'day' => $mday, 'year' => $year }); +} + +my $error_no_en = 0; +sub get_string($;$$) +{ + my $string = shift; + my $arguments = shift; + my $state = shift; + my $T2H_LANGUAGES = $Texi2HTML::Config::LANGUAGES; + if (! exists($T2H_LANGUAGES->{'en'})) + { + unless($error_no_en) + { + print STDERR "i18n: no LANGUAGES->{'en'} hash\n"; + $error_no_en = 1; + } + } + else + { + print STDERR "i18n: missing string $string\n" unless (exists ($T2H_LANGUAGES->{'en'}->{$string})); + if (defined ($T2H_LANGUAGES->{$language}->{$string}) and + ($T2H_LANGUAGES->{$language}->{$string} ne '')) + { + $string = $T2H_LANGUAGES->{$language}->{$string}; + } + elsif (defined ($T2H_LANGUAGES->{'en'}->{$string}) and + ($T2H_LANGUAGES->{'en'}->{$string} ne '')) + { + $string = $T2H_LANGUAGES->{'en'}->{$string}; + } + } + return main::substitute_line($string, $state) unless (defined($arguments) or !keys(%$arguments)); + # if there are arguments, we must protect the %{arg} constructs before + # doing substitute_line. So there is a first pass here to change %{arg} + # to %@{arg@} + my $result = ''; + if (!$state->{'keep_texi'}) + { + while ($string) + { + if ($string =~ s/^([^%]*)%//) + { + $result .= $1 if (defined($1)); + $result .= '%'; + if ($string =~ s/^%//) + { + $result .= '%'; + } + elsif ($string =~ /^\{(\w+)\}/ and exists($arguments->{$1})) + { + $string =~ s/^\{(\w+)\}//; + $result .= "\@\{$1\@\}"; + } + else + { + $result .= '%'; + } + next; + } + else + { + $result .= $string; + last; + } + } + $string = main::substitute_line($result, $state); + } + # now we substitute the arguments + $result = ''; + while ($string) + { + if ($string =~ s/^([^%]*)%//) + { + $result .= $1 if (defined($1)); + if ($string =~ s/^%//) + { + $result .= '%'; + } + elsif ($string =~ /^\{(\w+)\}/ and exists($arguments->{$1})) + { + $string =~ s/^\{(\w+)\}//; + $result .= $arguments->{$1}; + } + else + { + $result .= '%'; + } + next; + } + else + { + $result .= $string; + last; + } + } + return $result; +} + +1; +require "$ENV{T2H_HOME}/T2h_i18n.pm" + if ($0 =~ /\.pl$/ && + -e "$ENV{T2H_HOME}/T2h_i18n.pm" && -r "$ENV{T2H_HOME}/T2h_i18n.pm"); + + +######################################################################### +# +# latex2html stuff +# +#---###################################################################### + +{ +# leave this within comments, and keep the require statement +# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/T2h_l2h.pm +# exists. + +# @T2H_L2H@ +#+############################################################################## +# +# T2h_l2h.pm: interface to LaTeX2HTML +# +# Copyright (C) 1999-2005 Patrice Dumas <dumas@centre-cired.fr>, +# Derek Price <derek@ximbiot.com>, +# Adrian Aichner <adrian@xemacs.org>, +# & others. +# +# 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., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA +# +#-############################################################################## + +require 5.0; +use strict; + +package Texi2HTML::LaTeX2HTML; +use Cwd; + + +# 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 +# + +# init l2h defaults for files and names + +# global variable used for caching +use vars qw( + %l2h_cache + ); + +my ($l2h_name, $l2h_latex_file, $l2h_cache_file, $l2h_html_file, $l2h_prefix); + +# holds the status of latex2html operations. If 0 it means that there was +# an error +my $status = 0; + +my $debug; +my $verbose; +my $docu_rdir; +my $docu_name; +my $docu_ext; +my $ERROR = '***'; + +########################## +# +# First stage: Generation of Latex file +# Initialize with: init +# Add content with: to_latex ($text) --> HTML placeholder comment +# Finish with: finish_to_latex +# + +my $l2h_latex_preamble = <<EOT; +% This document was automatically generated by the l2h extenstion of texi2html +% DO NOT EDIT !!! +\\documentclass{article} +\\usepackage{html} +\\begin{document} +EOT + +my $l2h_latex_closing = <<EOT; +\\end{document} +EOT + +my %l2h_to_latex = (); # associate a latex text with the index in the + # html result array. +my @l2h_to_latex = (); # array used to associate the index with + # the original latex text. +my $latex_count = 0; # number of latex texts really stored +my $latex_converted_count = 0; # number of latex texts passed through latex2html +my $to_latex_count = 0; # total number of latex texts processed +my $cached_count = 0; # number of cached latex texts +%l2h_cache = (); # the cache hash. Associate latex text with + # html from the previous run +my @l2h_from_html; # array of resulting html + +my %global_count = (); # associate a command name and the + # corresponding counter to the index in the + # html result array + +# set $status to 1, if l2h could be initalized properly, to 0 otherwise +sub init() +{ + $docu_name = $Texi2HTML::THISDOC{'file_base_name'}; + $docu_rdir = $Texi2HTML::THISDOC{'out_dir'}; + $docu_ext = $Texi2HTML::THISDOC{'extension'}; + $l2h_name = "${docu_name}_l2h"; + $l2h_latex_file = "$docu_rdir${l2h_name}.tex"; + $l2h_cache_file = "${docu_rdir}${docu_name}-l2h_cache.pm"; + # 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}_"; + $debug = $Texi2HTML::THISDOC{'debug_l2h'}; + $verbose = $Texi2HTML::Config::VERBOSE; + + unless ($Texi2HTML::Config::L2H_SKIP) + { + unless (open(L2H_LATEX, ">$l2h_latex_file")) + { + warn "$ERROR l2h: Can't open latex file '$l2h_latex_file' for writing: $!\n"; + $status = 0; + return; + } + warn "# l2h: use ${l2h_latex_file} as latex file\n" if ($verbose); + print L2H_LATEX $l2h_latex_preamble; + } + # open the database that holds cached text + init_cache(); + $status = 1; +} + + +# print text (2nd arg) into latex file (if not already there nor in cache) +# which can be later on replaced by the latex2html generated text. +# +sub to_latex($$$) +{ + my $command = shift; + my $text = shift; + my $counter = shift; + if ($command eq 'tex') + { + $text .= ' '; + } + elsif ($command eq 'math') + { + $text = "\$".$text."\$"; + } + $to_latex_count++; + $text =~ s/(\s*)$//; + # try whether we have text already on things to do + my $count = $l2h_to_latex{$text}; + unless ($count) + { + $latex_count++; + $count = $latex_count; + # try whether we can get it from cache + my $cached_text = from_cache($text); + if (defined($cached_text)) + { + $cached_count++; + # put the cached result in the html result array + $l2h_from_html[$count] = $cached_text; + } + else + { + $latex_converted_count++; + unless ($Texi2HTML::Config::L2H_SKIP) + { + print L2H_LATEX "\\begin{rawhtml}\n"; + print L2H_LATEX "<!-- l2h_begin $l2h_name $count -->\n"; + print L2H_LATEX "\\end{rawhtml}\n"; + + print L2H_LATEX "$text\n"; + + print L2H_LATEX "\\begin{rawhtml}\n"; + print L2H_LATEX "<!-- l2h_end $l2h_name $count -->\n"; + print L2H_LATEX "\\end{rawhtml}\n"; + } + } + $l2h_to_latex[$count] = $text; + $l2h_to_latex{$text} = $count; + } + $global_count{"${command}_$counter"} = $count; + return 1; +} + +# print closing into latex file and close it +sub finish_to_latex() +{ + my $reused = $to_latex_count - $latex_converted_count - $cached_count; + unless ($Texi2HTML::Config::L2H_SKIP) + { + print L2H_LATEX $l2h_latex_closing; + close (L2H_LATEX); + } + warn "# l2h: finished to latex ($cached_count cached, $reused reused, $latex_converted_count to process)\n" if ($verbose); + unless ($latex_count) + { + # no @tex nor @math + finish(); + return 0; + } + return 1; +} + +################################### +# Second stage: Use latex2html to generate corresponding html code and images +# +# to_html([$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 to_html() +{ + my ($call, $dotbug); + # when there are no tex constructs to convert (happens in case everything + # comes from the cache), there is no latex2html run + if ($Texi2HTML::Config::L2H_SKIP or ($latex_converted_count == 0)) + { + warn "# l2h: skipping latex2html run\n" if ($verbose); + return 1; + } + # Check for dot in directory where dvips will work + if ($Texi2HTML::Config::L2H_TMP) + { + if ($Texi2HTML::Config::L2H_TMP =~ /\./) + { + warn "$ERROR Warning l2h: l2h_tmp dir contains a dot. Use /tmp, instead\n"; + $dotbug = 1; + } + } + else + { + if (cwd() =~ /\./) + { + 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 + $Texi2HTML::Config::L2H_TMP = "/tmp" if ($dotbug); + + $call = $Texi2HTML::Config::L2H_L2H; + # use init file, if specified + my $init_file = main::locate_init_file($Texi2HTML::Config::L2H_FILE); + $call = $call . " -init_file " . $init_file if ($init_file); + # set output dir + $call .= ($docu_rdir ? " -dir $docu_rdir" : " -no_subdir"); + # use l2h_tmp, if specified + $call .= " -tmp $Texi2HTML::Config::L2H_TMP" if ($Texi2HTML::Config::L2H_TMP); + # use a given html version if specified + $call .= " -html_version $Texi2HTML::Config::L2H_HTML_VERSION" if ($Texi2HTML::Config::L2H_HTML_VERSION); + # options we want to be sure of + $call .= " -address 0 -info 0 -split 0 -no_navigation -no_auto_link"; + $call .= " -prefix $l2h_prefix $l2h_latex_file"; + + warn "# l2h: executing '$call'\n" if ($verbose); + if (system($call)) + { + warn "$ERROR l2h: '${call}' did not succeed\n"; + return 0; + } + else + { + warn "# l2h: latex2html finished successfully\n" if ($verbose); + return 1; + } +} + +########################## +# Third stage: Extract generated contents from latex2html run +# Initialize with: init_from_html +# open $l2h_html_file for reading +# reads in contents into array indexed by numbers +# return 1, on success -- 0, otherwise +# Finish with: finish +# closes $l2h_html_dir/$l2h_name.".$docu_ext" + +# the images generated by latex2html have names like ${docu_name}_l2h_img?.png +# they are copied to ${docu_name}_?.png, and html is changed accordingly. +my %l2h_img; # associate src file to destination file + # such that files are not copied twice +my $image_count = 1; +sub change_image_file_names($) +{ + 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}_${image_count}$ext") + { + $image_count++; + } + $dest = "${docu_name}_${image_count}$ext"; +# FIXME this isn't portable. + error condition not checked. + system("cp -f $docu_rdir$src $docu_rdir$dest"); + $l2h_img{$src} = $dest; +# FIXME error condition not checked + unlink "$docu_rdir$src" unless ($debug); + } + $content =~ s/SRC="$src"/SRC="$dest"/g; + } + return $content; +} + +my $extract_error_count = 0; +my $invalid_counter_count = 0; + +sub init_from_html() +{ + # when there are no tex constructs to convert (happens in case everything + # comes from the cache), the html file that was generated by previous + # latex2html runs isn't reused. + if ($latex_converted_count == 0) + { + return 1; + } + + if (! open(L2H_HTML, "<$l2h_html_file")) + { + warn "$ERROR l2h: Can't open $l2h_html_file for reading\n"; + return 0; + } + warn "# l2h: use $l2h_html_file as html file\n" if ($verbose); + + my $html_converted_count = 0; # number of html resulting texts + # retrieved in the file + + my ($count, $h_line); + while ($h_line = <L2H_HTML>) + { + if ($h_line =~ /^<!-- l2h_begin $l2h_name ([0-9]+) -->/) + { + $count = $1; + my $h_content = ''; + my $h_end_found = 0; + while ($h_line = <L2H_HTML>) + { + if ($h_line =~ /^<!-- l2h_end $l2h_name $count -->/) + { + $h_end_found = 1; + chomp $h_content; + chomp $h_content; + $html_converted_count++; + # transform image file names and copy image files + $h_content = change_image_file_names($h_content); + # store result in the html result array + $l2h_from_html[$count] = $h_content; + # also add the result in cache hash + $l2h_cache{$l2h_to_latex[$count]} = $h_content; + last; + } + $h_content = $h_content.$h_line; + } + unless ($h_end_found) + { # couldn't found the closing comment. Certainly a bug. + warn "$ERROR l2h(BUG): l2h_end $l2h_name $count not found\n"; + close(L2H_HTML); + return 0; + } + } + } + + # Not the same number of converted elements and retrieved elements + if ($latex_converted_count != $html_converted_count) + { + warn "$ERROR l2h(BUG): waiting for $latex_converted_count elements found $html_converted_count\n"; + } + + warn "# l2h: Got $html_converted_count of $latex_count html contents\n" + if ($verbose); + + close(L2H_HTML); + return 1; +} + +my $html_output_count = 0; # html text outputed in html result file + +# called each time a construct handled by latex2html is encountered, should +# output the corresponding html +sub do_tex($$$$) +{ + my $style = shift; + my $counter = shift; + my $state = shift; + my $count = $global_count{"${style}_$counter"}; + ################################## begin debug section (incorrect counts) + if (!defined($count)) + { + # counter is undefined + $invalid_counter_count++; + warn "$ERROR l2h(BUG): undefined count for ${style}_$counter\n"; + return ("<!-- l2h: ". __LINE__ . " undef count for ${style}_$counter -->") + if ($debug); + return ''; + } + elsif(($count <= 0) or ($count > $latex_count)) + { + # counter out of range + $invalid_counter_count++; + warn "$ERROR l2h(BUG): Request of $count content which is out of valide range [0,$latex_count)\n"; + return ("<!-- l2h: ". __LINE__ . " out of range count $count -->") + if ($debug); + return ''; + } + ################################## end debug section (incorrect counts) + + # this seems to be a valid counter + my $result = ''; + $result = "<!-- l2h_begin $l2h_name $count -->" if ($debug); + if (defined($l2h_from_html[$count])) + { + $html_output_count++; + # maybe we could also have something if simple_format + # with Texi2HTML::Config::protect_text, once simple_format + # may happen for anything else than lines + if ($state->{'remove_texi'}) + {# don't protect anything + $result .= $l2h_to_latex[$count]; + } + else + { + $result .= $l2h_from_html[$count]; + } + } + else + { + # if the result is not in @l2h_from_html, there is an error somewhere. + $extract_error_count++; + warn "$ERROR l2h(BUG): can't extract content $count from html\n"; + # try simple (ordinary) substitution (without l2h) + $result .= "<!-- l2h: ". __LINE__ . " use texi2html -->" if ($debug); + $result .= main::substitute_text({}, $l2h_to_latex[$count]); + } + $result .= "<!-- l2h_end $l2h_name $count -->" if ($debug); + return $result; +} + +# store results in the cache and remove temporary files. +sub finish() +{ + return unless($status); + if ($verbose) + { + if ($extract_error_count + $invalid_counter_count) + { + warn "# l2h: finished from html ($extract_error_count extract and $invalid_counter_count invalid counter errors)\n"; + } + else + { + warn "# l2h: finished from html (no error)\n"; + } + if ($html_output_count != $latex_converted_count) + { # this may happen if @-commands are collected at some places + # but @-command at those places are not expanded later. For + # example @math on @multitable lines. + warn "# l2h: $html_output_count html outputed for $latex_converted_count converted\n"; + } + } + store_cache(); + if ($Texi2HTML::Config::L2H_CLEAN) + { + local ($_); + warn "# l2h: removing temporary files generated by l2h extension\n" + if $verbose; + while (<"$docu_rdir$l2h_name"*>) + { +# FIXME error condition not checked + unlink $_; + } + } + warn "# l2h: Finished\n" if $verbose; + return 1; +} + +# the driver of end of first pass, second pass and beginning of third pass +# +sub latex2html() +{ + return unless($status); + return unless ($status = finish_to_latex()); + return unless ($status = to_html()); + return unless ($status = init_from_html()); +} + + +############################## +# 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 init_cache +{ + 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); + } +} + +# store all the text obtained through latex2html +sub store_cache +{ + return unless $latex_count; + my ($key, $value); + unless (open(FH, ">$l2h_cache_file")) + { + warn "$ERROR l2h Error: could not open $docu_rdir$l2h_cache_file for writing: $!\n"; + return; + } + 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 from_cache($) +{ + my $text = shift; + my $cached = $l2h_cache{$text}; + if (defined($cached)) + { + while ($cached =~ m/SRC="(.*?)"/g) + { + unless (-e "$docu_rdir$1") + { + return undef; + } + } + return $cached; + } + return undef; +} + +1; + + +require "$ENV{T2H_HOME}/T2h_l2h.pm" + if ($0 =~ /\.pl$/ && + -e "$ENV{T2H_HOME}/T2h_l2h.pm" && -r "$ENV{T2H_HOME}/T2h_l2h.pm"); + +} + +{ +package Texi2HTML::LaTeX2HTML::Config; + +# latex2html variables +# These variables are not used. They are here for information only, and +# an example of config file for latex2html file is included. +my $ADDRESS; +my $ANTI_ALIAS; +my $ANTI_ALIAS_TEXT; +my $ASCII_MODE; +my $AUTO_LINK; +my $AUTO_PREFIX; +my $CHILDLINE; +my $DEBUG; +my $DESTDIR; +my $ERROR; +my $EXTERNAL_FILE; +my $EXTERNAL_IMAGES; +my $EXTERNAL_UP_LINK; +my $EXTERNAL_UP_TITLE; +my $FIGURE_SCALE_FACTOR; +my $HTML_VERSION; +my $IMAGES_ONLY; +my $INFO; +my $LINE_WIDTH; +my $LOCAL_ICONS; +my $LONG_TITLES; +my $MATH_SCALE_FACTOR; +my $MAX_LINK_DEPTH; +my $MAX_SPLIT_DEPTH; +my $NETSCAPE_HTML; +my $NOLATEX; +my $NO_FOOTNODE; +my $NO_IMAGES; +my $NO_NAVIGATION; +my $NO_SIMPLE_MATH; +my $NO_SUBDIR; +my $PAPERSIZE; +my $PREFIX; +my $PS_IMAGES; +my $REUSE; +my $SCALABLE_FONTS; +my $SHORTEXTN; +my $SHORT_INDEX; +my $SHOW_SECTION_NUMBERS; +my $SPLIT; +my $TEXDEFS; +my $TITLE; +my $TITLES_LANGUAGE; +my $TMP; +my $VERBOSE; +my $WORDS_IN_NAVIGATION_PANEL_TITLES; +my $WORDS_IN_PAGE; + +# @T2H_L2H_INIT@ + +###################################################################### +# 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 = ''; + +$NO_SUBDIR = 1; + +$PREFIX = ''; + +$AUTO_PREFIX = 0; + +$AUTO_LINK = 0; + +$SPLIT = 0; + +$MAX_LINK_DEPTH = 0; + +$TMP = ''; + +$DEBUG = 0; + +$VERBOSE = 1; + +# +# Options controlling Extensions and Special Features +# +#$HTML_VERSION = "3.2"; # set by command line + +$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; + +# 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 l2h.init +###################################################################### + +} + +package main; + +# +# pre-defined indices +# + +my %index_prefix_to_name = (); + +%index_names = +( + 'cp' => { 'prefix' => ['cp','c']}, + 'fn' => { 'prefix' => ['fn', 'f'], code => 1}, + 'vr' => { 'prefix' => ['vr', 'v'], code => 1}, + 'ky' => { 'prefix' => ['ky', 'k'], code => 1}, + 'pg' => { 'prefix' => ['pg', 'p'], code => 1}, + 'tp' => { 'prefix' => ['tp', 't'], code => 1} +); + +foreach my $name(keys(%index_names)) +{ + foreach my $prefix (@{$index_names{$name}->{'prefix'}}) + { + $forbidden_index_name{$prefix} = 1; + $index_prefix_to_name{$prefix} = $name; + } +} + +foreach my $other_forbidden_index_name ('info','ps','pdf','htm', + 'log','aux','dvi','texi','txi','texinfo','tex','bib') +{ + $forbidden_index_name{$other_forbidden_index_name} = 1; +} + +# commands with ---, -- '' and `` preserved +# usefull with the old interface + +%code_style_map = ( + 'code' => 1, + 'command' => 1, + 'env' => 1, + 'file' => 1, + 'kbd' => 1, + 'option' => 1, + 'samp' => 1, + 'verb' => 1, +); + +my @element_directions = ('Up', 'Forward', 'Back', 'Next', 'Prev', +'SectionNext', 'SectionPrev', 'SectionUp', 'FastForward', 'FastBack', +'This', 'NodeUp', 'NodePrev', 'NodeNext', 'Following' ); +$::simple_map_ref = \%Texi2HTML::Config::simple_map; +$::simple_map_pre_ref = \%Texi2HTML::Config::simple_map_pre; +$::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi; +$::style_map_ref = \%Texi2HTML::Config::style_map; +$::style_map_pre_ref = \%Texi2HTML::Config::style_map_pre; +$::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi; +$::things_map_ref = \%Texi2HTML::Config::things_map; +$::pre_map_ref = \%Texi2HTML::Config::pre_map; +$::texi_map_ref = \%Texi2HTML::Config::texi_map; + +# delete from hash if we are using the new interface +foreach my $code (keys(%code_style_map)) +{ + delete ($code_style_map{$code}) + if (ref($::style_map_ref->{$code}) eq 'HASH'); +} + +# no paragraph in these commands +my %no_paragraph_macro = ( + 'xref' => 1, + 'ref' => 1, + 'pxref' => 1, + 'inforef' => 1, + 'anchor' => 1, +); + + +# +# texinfo section names to level +# +%sec2level = ( + 'top', 0, + 'chapter', 1, + 'unnumbered', 1, + 'chapheading', 1, + 'appendix', 1, + 'section', 2, + 'unnumberedsec', 2, + 'heading', 2, + 'appendixsec', 2, + 'subsection', 3, + 'unnumberedsubsec', 3, + 'subheading', 3, + 'appendixsubsec', 3, + 'subsubsection', 4, + 'unnumberedsubsubsec', 4, + 'subsubheading', 4, + 'appendixsubsubsec', 4, + ); + +# the reverse mapping. There is an entry for each sectionning command. +# The value is a ref on an array containing at each index the corresponding +# sectionning command name. +my %level2sec; +{ + my $sections = [ ]; + my $appendices = [ ]; + my $unnumbered = [ ]; + my $headings = [ ]; + foreach my $command (keys (%sec2level)) + { + if ($command =~ /^appendix/) + { + $level2sec{$command} = $appendices; + } + elsif ($command =~ /^unnumbered/ or $command eq 'top') + { + $level2sec{$command} = $unnumbered; + } + elsif ($command =~ /section$/ or $command eq 'chapter') + { + $level2sec{$command} = $sections; + } + else + { + $level2sec{$command} = $headings; + } + $level2sec{$command}->[$sec2level{$command}] = $command; + } +} + +# this are synonyms +$sec2level{'appendixsection'} = 2; +# sec2level{'majorheading'} is also 1 and not 0 +$sec2level{'majorheading'} = 1; +$sec2level{'chapheading'} = 1; +$sec2level{'centerchap'} = 1; + +# sction to level hash not taking into account raise and lower sections +my %reference_sec2level = %sec2level; + +# regions treated especially. The text for these regions is collected in the +# corresponding array +%region_lines = ( + 'titlepage' => [ ], + 'documentdescription' => [ ], + 'copying' => [ ], +); + +# those macros aren't considered as beginning a paragraph +my %no_line_macros = ( + 'macro' => 1, + 'unmacro' => 1, + 'rmacro' => 1, + 'set' => 1, + 'clear' => 1, + 'titlefont' => 1, + 'include' => 1, + 'copying' => 1, + 'end copying' => 1, + 'tab' => 1, + 'item' => 1, + 'itemx' => 1, + '*' => 1, + 'float' => 1, + 'end float' => 1, + 'caption' => 1, + 'shortcaption' => 1, +); + +foreach my $key (keys(%Texi2HTML::Config::misc_command)) +{ + $no_line_macros{$key} = 1; +} + +# a hash associating a format @thing / @end thing with the type of the format +# 'complex_format' 'simple_format' 'deff' 'list' 'menu' 'paragraph_format' +my %format_type = (); + +foreach my $simple_format (keys(%Texi2HTML::Config::format_map)) +{ + $format_type{$simple_format} = 'simple_format'; +} +foreach my $paragraph_style (keys(%Texi2HTML::Config::paragraph_style)) +{ + $format_type{$paragraph_style} = 'paragraph_format'; +} +foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map)) +{ + $format_type{$complex_format} = 'complex_format'; +} +foreach my $table (('table', 'ftable', 'vtable', 'multitable')) +{ + $format_type{$table} = 'table'; +} +foreach my $def_format (keys(%Texi2HTML::Config::def_map)) +{ + $format_type{$def_format} = 'deff'; +} +$format_type{'itemize'} = 'list'; +$format_type{'enumerate'} = 'list'; + +$format_type{'menu'} = 'menu'; + +$format_type{'cartouche'} = 'cartouche'; + +$format_type{'float'} = 'float'; + +$format_type{'quotation'} = 'quotation'; + +$format_type{'group'} = 'group'; + +foreach my $key (keys(%format_type)) +{ + $no_line_macros{$key} = 1; + $no_line_macros{"end $key"} = 1; +} + +foreach my $macro (keys(%Texi2HTML::Config::format_in_paragraph)) +{ + $no_line_macros{$macro} = 1; + $no_line_macros{"end $macro"} = 1; +} + +# fake format at the bottom of the stack +$format_type{'noformat'} = ''; + +# fake formats are formats used internally within other formats +# we associate them with a real format, for the error messages +my %fake_format = ( + 'line' => 'table', + 'term' => 'table', + 'item' => 'list or table', + 'row' => 'multitable row', + 'cell' => 'multitable cell', + 'deff_item' => 'definition command', + 'menu_comment' => 'menu', + 'menu_description' => 'menu', + 'menu_preformatted' => 'menu', + ); + +foreach my $key (keys(%fake_format)) +{ + $format_type{$key} = 'fake'; +} + +# raw formats which are expanded especially +my @raw_regions = ('html', 'verbatim', 'tex', 'xml', 'docbook'); + +# regions expanded or not depending on the value of this hash +my %text_macros = ( + 'iftex' => 0, + 'ignore' => 0, + 'menu' => 0, + 'ifplaintext' => 0, + 'ifinfo' => 0, + 'ifxml' => 0, + 'ifhtml' => 0, + 'ifdocbook' => 0, + 'html' => 0, + 'tex' => 0, + 'xml' => 0, + 'titlepage' => 1, + 'documentdescription' => 1, + 'copying' => 1, + 'ifnothtml' => 1, + 'ifnottex' => 1, + 'ifnotplaintext' => 1, + 'ifnotinfo' => 1, + 'ifnotxml' => 1, + 'ifnotdocbook' => 1, + 'direntry' => 0, + 'verbatim' => 'raw', + 'ifclear' => 'value', + 'ifset' => 'value' , + ); + +foreach my $key (keys(%text_macros)) +{ + unless ($text_macros{$key} eq 'raw') + { + $no_line_macros{$key} = 1; + $no_line_macros{"end $key"} = 1; + } +} + +# The css formats are associated with complex format commands, and associated +# with the 'pre_style' key +foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map)) +{ + next if (defined($Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'})); + $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = ''; + $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = $Texi2HTML::Config::css_map{"pre.$complex_format"} if (exists($Texi2HTML::Config::css_map{"pre.$complex_format"})); +} + +#+++############################################################################ +# # +# Argument parsing, initialisation # +# # +#---############################################################################ + +# +# flush stdout and stderr after every write +# +select(STDERR); +$| = 1; +select(STDOUT); +$| = 1; + +my $I = \&Texi2HTML::I18n::get_string; + +my $T2H_USER; # user running the script +my $documentdescription; # text in @documentdescription + +# shorthand for Texi2HTML::Config::VERBOSE +my $T2H_VERBOSE; +my $T2H_DEBUG; + +sub echo_warn($;$); +#print STDERR "" . &$I('test i18n: \' , \a \\ %% %{unknown}a %known % %{known} \\', { 'known' => 'a known string', 'no' => 'nope'}); exit 0; + +# file: file name to locate. It can be a file path. +# all_files: if true collect all the files with that name, otherwise stop +# at first match. +# directories: a reference on a array containing a list of directories to +# search the file in. default is \@texi2html_config_dirs. +sub locate_init_file($;$$) +{ + my $file = shift; + my $all_files = shift; + my $directories = shift; + + $directories = \@texi2html_config_dirs if !defined($directories); + + if ($file =~ /^\//) + { + return $file if (-e $file and -r $file); + } + else + { + my @files; + foreach my $dir (@$directories) + { + next unless (-d "$dir"); + if ($all_files) + { + push (@files, "$dir/$file") if (-e "$dir/$file" and -r "$dir/$file"); + } + else + { + return "$dir/$file" if (-e "$dir/$file" and -r "$dir/$file"); + } + } + return @files if ($all_files); + } + return undef; +} + +# called on -init-file +sub load_init_file +{ + # First argument is option + shift; + # second argument is value of options + my $init_file = shift; + my $file; + if ($file = locate_init_file($init_file)) + { + print STDERR "# reading initialization file from $file\n" + if ($T2H_VERBOSE); + return (Texi2HTML::Config::load($file)); + } + else + { + print STDERR "$ERROR Error: can't read init file $init_file\n"; + return 0; + } +} + +my $cmd_line_lang = 0; # 1 if lang was succesfully set by the command line + # in that case @documentlanguage is ignored. +my $lang_set = 0; # 1 if lang was set + +# +# called on -lang +sub set_document_language ($;$$) +{ + my $lang = shift; + my $from_command_line = shift; + my $line_nr = shift; + my @files = locate_init_file("$i18n_dir/$lang", 1); + foreach my $file (@files) + { + Texi2HTML::Config::load($file); + } + if (Texi2HTML::I18n::set_language($lang)) + { + print STDERR "# using '$lang' as document language\n" if ($T2H_VERBOSE); + $Texi2HTML::Config::LANG = $lang; + $lang_set = 1; + $cmd_line_lang = 1 if ($from_command_line); + if (!$Texi2HTML::Config::TEST) + { + print STDERR "# Setting date in $Texi2HTML::Config::LANG\n" if ($T2H_DEBUG); + $Texi2HTML::THISDOC{'today'} = Texi2HTML::I18n::pretty_date($Texi2HTML::Config::LANG); # like "20 September 1993"; + } + else + { + $Texi2HTML::THISDOC{'today'} = 'a sunny day'; + } + $Texi2HTML::THISDOC{'today'} = $Texi2HTML::Config::DATE + if (defined($Texi2HTML::Config::DATE)); + $::things_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'}; + $::pre_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'}; + $::texi_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'}; + } + else + { + echo_error ("Language specs for '$lang' do not exists. Reverting to '$Texi2HTML::Config::LANG'", $line_nr); + } +} + +# used to manage expanded sections from the command line +sub set_expansion($$) +{ + my $region = shift; + my $set = shift; + $set = 1 if (!defined($set)); + if ($set) + { + push (@Texi2HTML::Config::EXPAND, $region) unless (grep {$_ eq $region} @Texi2HTML::Config::EXPAND); + } + else + { + @Texi2HTML::Config::EXPAND = grep {$_ ne $region} @Texi2HTML::Config::EXPAND; + } +} + + +# find the encoding alias. +# with encoding support (USE_UNICODE), may return undef if no alias was found +sub encoding_alias($) +{ + my $encoding = shift; + return $encoding if (!defined($encoding) or $encoding eq ''); + if ($Texi2HTML::Config::USE_UNICODE) + { + if (! Encode::resolve_alias($encoding)) + { + echo_warn("Encoding $encoding unknown"); + return undef; + } + print STDERR "# Using encoding " . Encode::resolve_alias($encoding) . "\n" + if ($T2H_VERBOSE); + return Encode::resolve_alias($encoding); + } + else + { + echo_warn("No alias searched for encoding"); + return $encoding; + } +} + +# setup hashes used for html manual cross references in texinfo +my %cross_ref_texi_map = %Texi2HTML::Config::texi_map; + +$cross_ref_texi_map{'enddots'} = '...'; + +my %cross_ref_simple_map_texi = %Texi2HTML::Config::simple_map_texi; +my %cross_ref_style_map_texi = (); +my %cross_transliterate_style_map_texi = (); + +my %cross_transliterate_texi_map = %cross_ref_texi_map; + +foreach my $command (keys(%Texi2HTML::Config::style_map_texi)) +{ + $cross_ref_style_map_texi{$command} = {}; + $cross_transliterate_style_map_texi{$command} = {}; + foreach my $key (keys (%{$Texi2HTML::Config::style_map_texi{$command}})) + { +#print STDERR "$command, $key, $style_map_texi{$command}->{$key}\n"; + $cross_ref_style_map_texi{$command}->{$key} = + $Texi2HTML::Config::style_map_texi{$command}->{$key}; + $cross_transliterate_style_map_texi{$command}->{$key} = + $Texi2HTML::Config::style_map_texi{$command}->{$key}; + } +} + +$cross_ref_simple_map_texi{"\n"} = ' '; +$cross_ref_simple_map_texi{"*"} = ' '; + +my %nodes = (); # nodes hash. The key is the texi node name +my %cross_reference_nodes = (); # normalized node names arrays + +# This function is used to construct link names from node names as +# specified for texinfo +sub cross_manual_links() +{ + print STDERR "# Doing ".scalar(keys(%nodes))." cross manual links\n" + if ($T2H_DEBUG); + my $normal_text_kept = $Texi2HTML::Config::normal_text; + $::simple_map_texi_ref = \%cross_ref_simple_map_texi; + $::style_map_texi_ref = \%cross_ref_style_map_texi; + $::texi_map_ref = \%cross_ref_texi_map; + $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text; + + foreach my $key (keys(%nodes)) + { + my $node = $nodes{$key}; + #print STDERR "CROSS_MANUAL:$key,$node\n"; + next if ($node->{'index_page'}); + if (!defined($node->{'texi'})) + { + ###################### debug section + foreach my $key (keys(%$node)) + { + #print STDERR "$key:$node->{$key}!!!\n"; + } + ###################### end debug section + } + else + { + $node->{'cross_manual_target'} = remove_texi($node->{'texi'}); + if ($Texi2HTML::Config::USE_UNICODE) + { + $node->{'cross_manual_target'} = Unicode::Normalize::NFC($node->{'cross_manual_target'}); + if ($Texi2HTML::Config::TRANSLITERATE_NODE and $Texi2HTML::Config::USE_UNIDECODE) + { + $node->{'cross_manual_file'} = + unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_target'})); + } + $node->{'cross_manual_target'} = + unicode_to_protected($node->{'cross_manual_target'}); + } +#print STDERR "CROSS_MANUAL_TARGET $node->{'cross_manual_target'}\n"; + unless ($node->{'external_node'}) + { + if (exists($cross_reference_nodes{$node->{'cross_manual_target'}})) + { + my $other_node_array = $cross_reference_nodes{$node->{'cross_manual_target'}}; + my $node_seen; + foreach my $other_node (@{$other_node_array}) + { + $node_seen = $other_node; + last if ($nodes{$other_node}->{'seen'}) + } + echo_error("Node equivalent with `$node->{'texi'}' allready used `$node_seen'"); + push @{$other_node_array}, $node->{'texi'}; + } + else + { + push @{$cross_reference_nodes{$node->{'cross_manual_target'}}}, $node->{'texi'}; + } + } + } + } + + + if ($Texi2HTML::Config::TRANSLITERATE_NODE and + (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE)) + { + $::style_map_texi_ref = \%cross_transliterate_style_map_texi; + $::texi_map_ref = \%cross_transliterate_texi_map; + + foreach my $key (keys(%nodes)) + { + my $node = $nodes{$key}; + next if ($node->{'index_page'}); + if (defined($node->{'texi'})) + { + $node->{'cross_manual_file'} = remove_texi($node->{'texi'}); + $node->{'cross_manual_file'} = unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_file'})) if ($Texi2HTML::Config::USE_UNICODE); + } + } + } + + $Texi2HTML::Config::normal_text = $normal_text_kept; + $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi; + $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi; + $::texi_map_ref = \%Texi2HTML::Config::texi_map; +} + +sub unicode_to_protected($) +{ + my $text = shift; + my $result = ''; + while ($text ne '') + { + if ($text =~ s/^([A-Za-z0-9]+)//o) + { + $result .= $1; + } + elsif ($text =~ s/^ //o) + { + $result .= '-'; + } + elsif ($text =~ s/^(.)//o) + { + if (exists($Texi2HTML::Config::ascii_character_map{$1})) + { + $result .= '_' . lc($Texi2HTML::Config::ascii_character_map{$1}); + } + else + { + $result .= '_' . lc(sprintf("%04x",ord($1))); + } + } + else + { + print STDERR "Bug: unknown character in a cross ref (likely in infinite loop)\n"; + print STDERR "Text: !!$text!!\n"; + sleep 1; + } + } + return $result; +} + +sub unicode_to_transliterate($) +{ + my $text = shift; + my $result = ''; + while ($text ne '') + { + if ($text =~ s/^([A-Za-z0-9 ]+)//o) + { + $result .= $1; + } + elsif ($text =~ s/^(.)//o) + { + if (exists($Texi2HTML::Config::ascii_character_map{$1})) + { + $result .= $1; + } + elsif (exists($Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($1)))})) + { + $result .= $Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($1)))}; + } + elsif (exists($Texi2HTML::Config::unicode_diacritical{uc(sprintf("%04x",ord($1)))})) + { + $result .= ''; + } + else + { + if ($Texi2HTML::Config::USE_UNIDECODE) + { + $result .= unidecode($1); + } + else + { + $result .= $1; + } + } + } + else + { + print STDERR "Bug: unknown character in cross ref transliteration (likely in infinite loop)\n"; + sleep 1; + } + } + return $result; +} + +# This function is used to construct a link name from a node name as +# specified for texinfo +sub cross_manual_line($;$) +{ + my $text = shift; + my $transliterate = shift; +#print STDERR "cross_manual_line $text\n"; +#print STDERR "remove_texi text ". remove_texi($text)."\n\n\n"; + $::simple_map_texi_ref = \%cross_ref_simple_map_texi; + $::style_map_texi_ref = \%cross_ref_style_map_texi; + $::texi_map_ref = \%cross_ref_texi_map; + my $normal_text_kept = $Texi2HTML::Config::normal_text; + $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text; + + my ($cross_ref_target, $cross_ref_file); + if ($Texi2HTML::Config::USE_UNICODE) + { + $cross_ref_target = Unicode::Normalize::NFC(remove_texi($text)); + if ($transliterate and $Texi2HTML::Config::USE_UNIDECODE) + { + $cross_ref_file = + unicode_to_protected(unicode_to_transliterate($cross_ref_target)); + } + $cross_ref_target = unicode_to_protected($cross_ref_target); + } + else + { + $cross_ref_target = remove_texi($text); + } + + if ($transliterate and + (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE)) + { + $::style_map_texi_ref = \%cross_transliterate_style_map_texi; + $::texi_map_ref = \%cross_transliterate_texi_map; + $cross_ref_file = remove_texi($text); + $cross_ref_file = unicode_to_protected(unicode_to_transliterate($cross_ref_file)) + if ($Texi2HTML::Config::USE_UNICODE); + } + + $Texi2HTML::Config::normal_text = $normal_text_kept; + $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi; + $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi; + $::texi_map_ref = \%Texi2HTML::Config::texi_map; +#print STDERR "\n\ncross_ref $cross_ref\n"; + unless ($transliterate) + { + return $cross_ref_target; + } +# print STDERR "$text|$cross_ref_target|$cross_ref_file\n"; + return ($cross_ref_target, $cross_ref_file); +} + +# 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_OPTIONS; +$T2H_OPTIONS -> {'debug'} = +{ + type => '=i', + linkage => \$Texi2HTML::Config::DEBUG, + verbose => 'output HTML with debuging information', +}; + +$T2H_OPTIONS -> {'doctype'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::DOCTYPE, + verbose => 'document type which is output in header of HTML files', + noHelp => 1 +}; + +$T2H_OPTIONS -> {'frameset-doctype'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE, + verbose => 'document type for HTML frameset documents', + noHelp => 1 +}; + +$T2H_OPTIONS -> {'test'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::TEST, + verbose => 'use predefined information to avoid differences with reference files', + noHelp => 1 +}; + +$T2H_OPTIONS -> {'dump-texi'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::DUMP_TEXI, + verbose => 'dump the output of first pass into a file with extension passfirst and exit', + noHelp => 1 +}; + +$T2H_OPTIONS -> {'macro-expand'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::MACRO_EXPAND, + verbose => 'output macro expanded source in <file>', +}; + +$T2H_OPTIONS -> {'expand'} = +{ + type => '=s', + linkage => sub {set_expansion($_[1], 1);}, + verbose => 'Expand info|tex|none section of texinfo source', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'no-expand'} = +{ + type => '=s', + linkage => sub {set_expansion ($_[1], 0);}, + verbose => 'Don\'t expand the given section of texinfo source', +}; + +$T2H_OPTIONS -> {'noexpand'} = +{ + type => '=s', + linkage => $T2H_OPTIONS->{'no-expand'}->{'linkage'}, + verbose => $T2H_OPTIONS->{'no-expand'}->{'verbose'}, + noHelp => 1, +}; + +$T2H_OPTIONS -> {'ifhtml'} = +{ + type => '!', + linkage => sub { set_expansion('html', $_[1]); }, + verbose => "expand ifhtml and html sections", +}; + +$T2H_OPTIONS -> {'ifinfo'} = +{ + type => '!', + linkage => sub { set_expansion('info', $_[1]); }, + verbose => "expand ifinfo", +}; + +$T2H_OPTIONS -> {'ifxml'} = +{ + type => '!', + linkage => sub { set_expansion('xml', $_[1]); }, + verbose => "expand ifxml and xml sections", +}; + +$T2H_OPTIONS -> {'ifdocbook'} = +{ + type => '!', + linkage => sub { set_expansion('docbook', $_[1]); }, + verbose => "expand ifdocbook and docbook sections", +}; + +$T2H_OPTIONS -> {'iftex'} = +{ + type => '!', + linkage => sub { set_expansion('tex', $_[1]); }, + verbose => "expand iftex and tex sections", +}; + +$T2H_OPTIONS -> {'ifplaintext'} = +{ + type => '!', + linkage => sub { set_expansion('plaintext', $_[1]); }, + verbose => "expand ifplaintext sections", +}; + +$T2H_OPTIONS -> {'invisible'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::INVISIBLE_MARK, + verbose => 'use text in invisble anchor', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'iso'} = +{ + type => 'iso', + linkage => \$Texi2HTML::Config::USE_ISO, + verbose => 'if set, ISO8859 characters are used for special symbols (like copyright, etc)', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'I'} = +{ + type => '=s', + linkage => \@Texi2HTML::Config::INCLUDE_DIRS, + verbose => 'append $s to the @include search path', +}; + +$T2H_OPTIONS -> {'conf-dir'} = +{ + type => '=s', + linkage => \@Texi2HTML::Config::CONF_DIRS, + verbose => 'append $s to the init file directories', +}; + +$T2H_OPTIONS -> {'P'} = +{ + type => '=s', + linkage => sub {unshift (@Texi2HTML::Config::PREPEND_DIRS, $_[1]);}, + verbose => 'prepend $s to the @include search path', +}; + +$T2H_OPTIONS -> {'top-file'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::TOP_FILE, + verbose => 'use $s as top file, instead of <docname>.html', +}; + +$T2H_OPTIONS -> {'toc-file'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::TOC_FILE, + verbose => 'use $s as ToC file, instead of <docname>_toc.html', +}; + +$T2H_OPTIONS -> {'frames'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::FRAMES, + verbose => 'output files which use HTML 4.0 frames (experimental)', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'menu'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SHOW_MENU, + verbose => 'output Texinfo menus', +}; + +$T2H_OPTIONS -> {'number'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::NUMBER_SECTIONS, + verbose => 'use numbered sections', +}; + +$T2H_OPTIONS -> {'use-nodes'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::USE_NODES, + verbose => 'use nodes for sectionning', +}; + +$T2H_OPTIONS -> {'node-files'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::NODE_FILES, + verbose => 'produce one file per node for cross references' +}; + +$T2H_OPTIONS -> {'separated-footnotes'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SEPARATED_FOOTNOTES, + verbose => 'footnotes on a separated page', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'toc-links'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::TOC_LINKS, + verbose => 'create links from headings to toc entries' +}; + +$T2H_OPTIONS -> {'split'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::SPLIT, + verbose => 'split document on section|chapter|node else no splitting', +}; + +$T2H_OPTIONS -> {'sec-nav'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SECTION_NAVIGATION, + verbose => 'output navigation panels for each section', +}; + +$T2H_OPTIONS -> {'subdir'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::SUBDIR, + verbose => 'put files in directory $s, not $cwd', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'short-ext'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SHORTEXTN, + verbose => 'use "htm" extension for output HTML files', +}; + +$T2H_OPTIONS -> {'prefix'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::PREFIX, + verbose => 'use as prefix for output files, instead of <docname>', +}; + +$T2H_OPTIONS -> {'output'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::OUT, + verbose => 'output goes to $s (directory if split)', +}; + +$T2H_OPTIONS -> {'no-validate'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::NOVALIDATE, + verbose => 'suppress node cross-reference validation', +}; + +$T2H_OPTIONS -> {'short-ref'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SHORT_REF, + verbose => 'if set, references are without section numbers', +}; + +$T2H_OPTIONS -> {'idx-sum'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::IDX_SUMMARY, + verbose => 'if set, also output index summary', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'def-table'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::DEF_TABLE, + verbose => 'if set, \@def.. are converted using tables.', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'Verbose'} = +{ + type => '!', + linkage=> \$Texi2HTML::Config::VERBOSE, + verbose => 'print progress info to stdout', +}; + +$T2H_OPTIONS -> {'lang'} = +{ + type => '=s', + linkage => sub {set_document_language($_[1], 1)}, + verbose => 'use $s as document language (ISO 639 encoding)', +}; + +$T2H_OPTIONS -> {'ignore-preamble-text'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::IGNORE_PREAMBLE_TEXT, + verbose => 'if set, ignore the text before @node and sectionning commands', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'html-xref-prefix'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::EXTERNAL_DIR, + verbose => '$s is the base dir for external manual references', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'l2h'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::L2H, + verbose => 'if set, uses latex2html for @math and @tex', +}; + +$T2H_OPTIONS -> {'l2h-l2h'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::L2H_L2H, + verbose => 'program to use for latex2html translation', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'l2h-skip'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::L2H_SKIP, + verbose => 'if set, tries to reuse previously latex2html output', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'l2h-tmp'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::L2H_TMP, + verbose => 'if set, uses $s as temporary latex2html directory', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'l2h-file'} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::L2H_FILE, + verbose => 'if set, uses $s as latex2html init file', + noHelp => 1, +}; + + +$T2H_OPTIONS -> {'l2h-clean'} = +{ + type => '!', + linkage => \$Texi2HTML::Config::L2H_CLEAN, + verbose => 'if set, do not keep intermediate latex2html files for later reuse', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'D'} = +{ + type => '=s', + linkage => sub {$value{$_[1]} = 1;}, + verbose => 'equivalent to Texinfo "@set $s 1"', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'U'} = +{ + type => '=s', + linkage => sub {delete $value{$_[1]};}, + verbose => 'equivalent to Texinfo "@clear $s"', + noHelp => 1, +}; + +$T2H_OPTIONS -> {'init-file'} = +{ + type => '=s', + linkage => \&load_init_file, + verbose => 'load init file $s' +}; + +$T2H_OPTIONS -> {'css-include'} = +{ + type => '=s', + linkage => \@Texi2HTML::Config::CSS_FILES, + verbose => 'use css file $s' +}; + +## +## obsolete cmd line options +## +my $T2H_OBSOLETE_OPTIONS; + +$T2H_OBSOLETE_OPTIONS -> {'out-file'} = +{ + type => '=s', + linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';}, + verbose => 'if set, all HTML output goes into file $s, obsoleted by "-output" with different semantics', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {init_file} = +{ + type => '=s', + linkage => \&load_init_file, + verbose => 'obsolete, use "-init-file" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {l2h_clean} = +{ + type => '!', + linkage => \$Texi2HTML::Config::L2H_CLEAN, + verbose => 'obsolete, use "-l2h-clean" instead', + noHelp => 2, +}; + +$T2H_OBSOLETE_OPTIONS -> {l2h_l2h} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::L2H_L2H, + verbose => 'obsolete, use "-l2h-l2h" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {l2h_skip} = +{ + type => '!', + linkage => \$Texi2HTML::Config::L2H_SKIP, + verbose => 'obsolete, use "-l2h-skip" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {l2h_tmp} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::L2H_TMP, + verbose => 'obsolete, use "-l2h-tmp" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {out_file} = +{ + type => '=s', + linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';}, + verbose => 'obsolete, use "-out-file" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {short_ref} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SHORT_REF, + verbose => 'obsolete, use "-short-ref" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {idx_sum} = +{ + type => '!', + linkage => \$Texi2HTML::Config::IDX_SUMMARY, + verbose => 'obsolete, use "-idx-sum" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {def_table} = +{ + type => '!', + linkage => \$Texi2HTML::Config::DEF_TABLE, + verbose => 'obsolete, use "-def-table" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {short_ext} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SHORTEXTN, + verbose => 'obsolete, use "-short-ext" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {sec_nav} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SECTION_NAVIGATION, + verbose => 'obsolete, use "-sec-nav" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {top_file} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::TOP_FILE, + verbose => 'obsolete, use "-top-file" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {toc_file} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::TOC_FILE, + verbose => 'obsolete, use "-toc-file" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {glossary} = +{ + type => '!', + linkage => \$Texi2HTML::Config::USE_GLOSSARY, + verbose => "this does nothing", + noHelp => 2, +}; + +$T2H_OBSOLETE_OPTIONS -> {check} = +{ + type => '!', + linkage => sub {exit 0;}, + verbose => "exit without doing anything", + noHelp => 2, +}; + +$T2H_OBSOLETE_OPTIONS -> {dump_texi} = +{ + type => '!', + linkage => \$Texi2HTML::Config::DUMP_TEXI, + verbose => 'obsolete, use "-dump-texi" instead', + noHelp => 1 +}; + +$T2H_OBSOLETE_OPTIONS -> {frameset_doctype} = +{ + type => '=s', + linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE, + verbose => 'obsolete, use "-frameset-doctype" instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {'no-section_navigation'} = +{ + type => '!', + linkage => sub {$Texi2HTML::Config::SECTION_NAVIGATION = 0;}, + verbose => 'obsolete, use -nosec_nav', + noHelp => 2, +}; +my $use_acc; # not used +$T2H_OBSOLETE_OPTIONS -> {use_acc} = +{ + type => '!', + linkage => \$use_acc, + verbose => 'obsolete, set to true unconditionnaly', + noHelp => 2 +}; +$T2H_OBSOLETE_OPTIONS -> {expandinfo} = +{ + type => '!', + linkage => sub {push @Texi2HTML::Config::EXPAND, 'info';}, + verbose => 'obsolete, use "-expand info" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {expandtex} = +{ + type => '!', + linkage => sub {push @Texi2HTML::Config::EXPAND, 'tex';}, + verbose => 'obsolete, use "-expand tex" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {monolithic} = +{ + type => '!', + linkage => sub {$Texi2HTML::Config::SPLIT = '';}, + verbose => 'obsolete, use "-split no" instead', + noHelp => 2 +}; +$T2H_OBSOLETE_OPTIONS -> {split_node} = +{ + type => '!', + linkage => sub{$Texi2HTML::Config::SPLIT = 'section';}, + verbose => 'obsolete, use "-split section" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {split_chapter} = +{ + type => '!', + linkage => sub{$Texi2HTML::Config::SPLIT = 'chapter';}, + verbose => 'obsolete, use "-split chapter" instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {no_verbose} = +{ + type => '!', + linkage => sub {$Texi2HTML::Config::VERBOSE = 0;}, + verbose => 'obsolete, use -noverbose instead', + noHelp => 2, +}; +$T2H_OBSOLETE_OPTIONS -> {output_file} = +{ + type => '=s', + linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';}, + verbose => 'obsolete, use --out-file instead', + noHelp => 2 +}; + +$T2H_OBSOLETE_OPTIONS -> {section_navigation} = +{ + type => '!', + linkage => \$Texi2HTML::Config::SECTION_NAVIGATION, + verbose => 'obsolete, use --sec-nav instead', + noHelp => 2, +}; + +$T2H_OBSOLETE_OPTIONS -> {verbose} = +{ + type => '!', + linkage=> \$Texi2HTML::Config::VERBOSE, + verbose => 'obsolete, use -Verbose instead', + noHelp => 2 +}; + +# read initialzation from $sysconfdir/texi2htmlrc or $HOME/.texi2htmlrc +# (this is obsolete) +my @rc_files = (); +push @rc_files, "$sysconfdir/texi2htmlrc" if defined($sysconfdir); +push @rc_files, "$ENV{'HOME'}/.texi2htmlrc" if (defined($ENV{HOME})); +foreach my $i (@rc_files) +{ + if (-e $i and -r $i) + { + print STDERR "# reading initialization file from $i\n" + if ($T2H_VERBOSE); + print STDERR "Reading config from $i is obsolete, use texi2html/$conf_file_name instead\n"; + Texi2HTML::Config::load($i); + } +} + +# read initialization files +foreach my $file (locate_init_file($conf_file_name, 1)) +{ + print STDERR "# reading initialization file from $file\n" if ($T2H_VERBOSE); + Texi2HTML::Config::load($file); +} + +# +# %value hold texinfo variables, see also -D, -U, @set and @clear. +# we predefine html (the output format) and texi2html (the translator) +%value = + ( + 'html' => 1, + 'texi2html' => $THISVERSION, + ); + +#+++############################################################################ +# # +# parse command-line options +# # +#---############################################################################ + + +my $T2H_USAGE_TEXT = <<EOT; +Usage: texi2html [OPTIONS] TEXINFO-FILE +Translates Texinfo source documentation to HTML. +EOT +my $T2H_FAILURE_TEXT = <<EOT; +Try 'texi2html --help' for usage instructions. +EOT + +my $options = new Getopt::MySimple; + +$T2H_OPTIONS -> {'help'} = +{ + type => ':i', + default => '', + linkage => sub {$options->helpOptions($_[1]); + print "\nSend bugs and suggestions to <texi2html-bug\@nongnu.org>\n"; + exit (0);}, + verbose => "print help and exit" +}; + +# this avoids getOptions defining twice 'help' and 'version'. +$T2H_OBSOLETE_OPTIONS -> {'help'} = 0; +$T2H_OBSOLETE_OPTIONS -> {'version'} = 0; + +# some older version of GetOpt::Long don't have +# Getopt::Long::Configure("pass_through") +eval {Getopt::Long::Configure("pass_through");}; +my $Configure_failed = $@ && <<EOT; +**WARNING: Parsing of obsolete command-line options could have failed. + Consider to use only documented command-line options (run + 'texi2html --help 2' for a complete list) or upgrade to perl + version 5.005 or higher. +EOT +if (! $options->getOptions($T2H_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n")) +{ + print STDERR "$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 STDERR "$Configure_failed" if $Configure_failed; + die $T2H_FAILURE_TEXT; + } +} + +# +# read texi2html extensions (if any) +# It is obsolete (obsoleted by -init-file). we keep it for backward +# compatibility. +my $extensions = 'texi2html.ext'; # extensions in working directory +if (-f $extensions) +{ + print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE; + require($extensions); +} +my $progdir; +($progdir = $0) =~ s/[^\/]+$//; +if ($progdir && ($progdir ne './')) +{ + $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory + if (-f $extensions) + { + print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE; + require($extensions); + } +} + +# $T2H_DEBUG and $T2H_VERBOSE are shorthands +$T2H_DEBUG = $Texi2HTML::Config::DEBUG; +$T2H_VERBOSE = $Texi2HTML::Config::VERBOSE; + +$Texi2HTML::THISDOC{'debug_l2h'} = 0; +$Texi2HTML::THISDOC{'debug_l2h'} = 1 if ($T2H_DEBUG & $DEBUG_L2H); + + +#+++############################################################################ +# # +# evaluation of cmd line options +# # +#---############################################################################ + +# Fill in the %style_type hash, a hash associating style @-comand with +# the type, 'accent', real 'style', simple' style, or 'special'. +# 'simple_style' styles don't extend accross lines. +my %style_type = (); +my @simple_styles = ('ctrl', 'w', 'url','uref','indicateurl','email', + 'titlefont'); +foreach my $style (keys(%Texi2HTML::Config::style_map)) +{ + if (exists $Texi2HTML::Config::command_type{$style}) + { + $style_type{$style} = $Texi2HTML::Config::command_type{$style}; + next; + } + if (ref($Texi2HTML::Config::style_map{$style} eq 'HASH')) + { + $style_type{$style} = $Texi2HTML::Config::style_map{$style}->{'type'} + if (exists($Texi2HTML::Config::style_map{$style}->{'type'})); + } + else + { + $style_type{$style} = 'simple_style' if (grep {$_ eq $style} @simple_styles); + } + $style_type{$style} = 'style' unless (defined($style_type{$style})); +} +foreach my $accent (keys(%Texi2HTML::Config::unicode_accents), 'tieaccent', 'dotless') +{ + if (exists $Texi2HTML::Config::command_type{$accent}) + { + $style_type{$accent} = $Texi2HTML::Config::command_type{$accent}; + next; + } + $style_type{$accent} = 'accent'; +} +#foreach my $simple ('ctrl', 'w', 'url','uref','indicateurl','email') +#{ +# $style_type{$simple} = 'simple_style'; +#} +foreach my $special ('footnote', 'ref', 'xref', 'pxref', 'inforef', 'anchor', 'image') +{ + if (exists $Texi2HTML::Config::command_type{$special}) + { + $style_type{$special} = $Texi2HTML::Config::command_type{$special}; + next; + } + $style_type{$special} = 'special'; +} + +# retro compatibility for $Texi2HTML::Config::EXPAND +push (@Texi2HTML::Config::EXPAND, $Texi2HTML::Config::EXPAND) if ($Texi2HTML::Config::EXPAND); + +unshift @texi2html_config_dirs, @Texi2HTML::Config::CONF_DIRS; +# correct %text_macros based on command line and init +# variables +$text_macros{'menu'} = 1 if ($Texi2HTML::Config::SHOW_MENU); + +foreach my $expanded (@Texi2HTML::Config::EXPAND) +{ + $text_macros{"if$expanded"} = 1 if (exists($text_macros{"if$expanded"})); + next unless (exists($text_macros{$expanded})); + if (grep {$_ eq $expanded} @raw_regions) + { + $text_macros{$expanded} = 'raw'; + } + else + { + $text_macros{$expanded} = 1; + } +} + +# handle ifnot regions +foreach my $region (keys (%text_macros)) +{ + next if ($region =~ /^ifnot/); + if ($text_macros{$region} and $region =~ /^if(\w+)$/) + { + $text_macros{"ifnot$1"} = 0; + } +} + +if ($T2H_VERBOSE) +{ + print STDERR "# Expanded: "; + foreach my $text_macro (keys(%text_macros)) + { + print STDERR "$text_macro " if ($text_macros{$text_macro}); + } + print STDERR "\n"; +} + +# This is kept in that file although it is html formatting as it seems to +# be rather obsolete +$Texi2HTML::Config::INVISIBLE_MARK = '<img src="invisible.xbm" alt="">' if $Texi2HTML::Config::INVISIBLE_MARK eq 'xbm'; + +$T2H_DEBUG |= $DEBUG_TEXI if ($Texi2HTML::Config::DUMP_TEXI); + +# no user provided USE_UNICODE, use configure provided +if (!defined($Texi2HTML::Config::USE_UNICODE)) +{ + $Texi2HTML::Config::USE_UNICODE = '1'; +} + +# no user provided nor configured, run time test +if ($Texi2HTML::Config::USE_UNICODE eq '@' .'USE_UNICODE@') +{ + $Texi2HTML::Config::USE_UNICODE = 1; + eval { + require Encode; + require Unicode::Normalize; + Encode->import('encode'); + }; + $Texi2HTML::Config::USE_UNICODE = 0 if ($@); +} +elsif ($Texi2HTML::Config::USE_UNICODE) +{# user provided or set by configure + require Encode; + require Unicode::Normalize; + Encode->import('encode'); +} + +# no user provided USE_UNIDECODE, use configure provided +if (!defined($Texi2HTML::Config::USE_UNIDECODE)) +{ + $Texi2HTML::Config::USE_UNIDECODE = '0'; +} + +# no user provided nor configured, run time test +if ($Texi2HTML::Config::USE_UNIDECODE eq '@' .'USE_UNIDECODE@') +{ + $Texi2HTML::Config::USE_UNIDECODE = 1; + eval { + require Text::Unidecode; + Text::Unidecode->import('unidecode'); + }; + $Texi2HTML::Config::USE_UNIDECODE = 0 if ($@); +} +elsif ($Texi2HTML::Config::USE_UNIDECODE) +{# user provided or set by configure + require Text::Unidecode; + Text::Unidecode->import('unidecode'); +} + +print STDERR "# USE_UNICODE $Texi2HTML::Config::USE_UNICODE, USE_UNIDECODE $Texi2HTML::Config::USE_UNIDECODE \n" + if ($T2H_VERBOSE); + +# Construct hashes used for cross references generation +# Do it now as the user may have changed $USE_UNICODE + +foreach my $key (keys(%Texi2HTML::Config::unicode_map)) +{ + if ($Texi2HTML::Config::unicode_map{$key} ne '') + { + if ($Texi2HTML::Config::USE_UNICODE) + { + $cross_ref_texi_map{$key} = chr(hex($Texi2HTML::Config::unicode_map{$key})); + if (($Texi2HTML::Config::TRANSLITERATE_NODE and !$Texi2HTML::Config::USE_UNIDECODE) + and (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))) + { + $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}; + + } + } + else + { + $cross_ref_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key}); + if ($Texi2HTML::Config::TRANSLITERATE_NODE) + { + if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}})) + { + $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}; + } + else + { + $cross_transliterate_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key}); + } + } + } + } +} +if ($Texi2HTML::Config::USE_UNICODE and $Texi2HTML::Config::TRANSLITERATE_NODE + and ! $Texi2HTML::Config::USE_UNIDECODE) +{ + foreach my $key (keys (%Texi2HTML::Config::transliterate_accent_map)) + { + $Texi2HTML::Config::transliterate_map{$key} = $Texi2HTML::Config::transliterate_accent_map{$key}; + } +} + +foreach my $key (keys(%cross_ref_style_map_texi)) +{ + if ($style_type{$key} eq 'accent' + and (ref($cross_ref_style_map_texi{$key}) eq 'HASH')) + { + if ($Texi2HTML::Config::USE_UNICODE) + { + $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_utf8_accent; + } + else + { + $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_nounicode_cross_manual_accent; + } + if ($Texi2HTML::Config::TRANSLITERATE_NODE and + !($Texi2HTML::Config::USE_UNICODE and $Texi2HTML::Config::USE_UNIDECODE)) + { + $cross_transliterate_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_transliterate_cross_manual_accent; + } + } +} + +# +# file name business +# + + +my $docu_dir; # directory of the document +my $docu_name; # basename of the document +my $docu_rdir; # directory for the output +my $docu_ext = $Texi2HTML::Config::EXTENSION; # extension +my $docu_toc; # document's table of contents +my $docu_stoc; # document's short toc +my $docu_foot; # document's footnotes +my $docu_about; # about this document +my $docu_top; # document top +my $docu_doc; # document (or document top of split) + +die "Need exactly one file to translate\n$T2H_FAILURE_TEXT" unless @ARGV == 1; +my $docu = shift(@ARGV); +if ($docu =~ /(.*\/)/) +{ + chop($docu_dir = $1); + $docu_name = $docu; + $docu_name =~ s/.*\///; +} +else +{ + $docu_dir = '.'; + $docu_name = $docu; +} +unshift(@Texi2HTML::Config::INCLUDE_DIRS, $docu_dir); +unshift(@Texi2HTML::Config::INCLUDE_DIRS, @Texi2HTML::Config::PREPEND_DIRS); +$docu_name =~ s/\.te?x(i|info)?$//; +$docu_name = $Texi2HTML::Config::PREFIX if $Texi2HTML::Config::PREFIX; + +# resulting files splitting +if ($Texi2HTML::Config::SPLIT =~ /section/i) +{ + $Texi2HTML::Config::SPLIT = 'section'; +} +elsif ($Texi2HTML::Config::SPLIT =~ /node/i) +{ + $Texi2HTML::Config::SPLIT = 'node'; +} +elsif ($Texi2HTML::Config::SPLIT =~ /chapter/i) +{ + $Texi2HTML::Config::SPLIT = 'chapter'; +} +else +{ + $Texi2HTML::Config::SPLIT = ''; +} + +# Something like backward compatibility +if ($Texi2HTML::Config::SPLIT and $Texi2HTML::Config::SUBDIR) +{ + $Texi2HTML::Config::OUT = $Texi2HTML::Config::SUBDIR; +} + +# subdir + +die "output to STDOUT and split or frames incompatible\n" + if (($Texi2HTML::Config::SPLIT or $Texi2HTML::Config::FRAMES) and ($Texi2HTML::Config::OUT eq '-')); + +if ($Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT eq '')) +{ + $Texi2HTML::Config::OUT = $docu_name; +} + +if ($Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT eq '.')) +{# This is to avoid trouble with latex2html + $Texi2HTML::Config::OUT = ''; +} + +$docu_rdir = ''; + +if ($Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT ne '')) +{ + $Texi2HTML::Config::OUT =~ s|/*$||; + $docu_rdir = "$Texi2HTML::Config::OUT/"; + unless (-d $Texi2HTML::Config::OUT) + { + if ( mkdir($Texi2HTML::Config::OUT, oct(755))) + { + print STDERR "# created directory $Texi2HTML::Config::OUT\n" if ($T2H_VERBOSE); + } + else + { + die "$ERROR can't create directory $Texi2HTML::Config::OUT\n"; + } + } + print STDERR "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE); +} +elsif (! $Texi2HTML::Config::SPLIT and ($Texi2HTML::Config::OUT ne '')) +{ + if ($Texi2HTML::Config::OUT =~ m|(.*)/|) + {# there is a leading directories + $docu_rdir = "$1/"; + unless (-d $docu_rdir) + { + if ( mkdir($docu_rdir, oct(755))) + { + print STDERR "# created directory $docu_rdir\n" if ($T2H_VERBOSE); + } + else + { + die "$ERROR can't create directory $docu_rdir\n"; + } + } + print STDERR "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE); + } + else + { + print STDERR "# putting result files into current directory \n" if ($T2H_VERBOSE); + $docu_rdir = ''; + } +} + +# We don't use "./" as $docu_rdir when $docu_rdir is the current directory +# because it is problematic for latex2html. To test writability with -w, +# however we need a real directory. +my $result_rdir = $docu_rdir; +$result_rdir = "." if ($docu_rdir eq ''); +unless (-w $result_rdir) +{ + $docu_rdir = 'current directory' if ($docu_rdir eq ''); + die "$ERROR $docu_rdir not writable\n"; +} + +# relative path leading to the working directory from the document directory +my $path_to_working_dir = $docu_rdir; +if ($docu_rdir ne '') +{ + my $cwd = cwd; + my $docu_path = $docu_rdir; + $docu_path = $cwd . '/' . $docu_path unless ($docu_path =~ /^\//); + my @result = (); + foreach my $element (split /\//, File::Spec->canonpath($docu_path)) + { + if ($element eq '') + { + push @result, ''; + } + elsif ($element eq '..') + { + if (@result and ($result[-1] eq '')) + { + print STDERR "Too much .. in absolute file name\n"; + } + elsif (@result and ($result[-1] ne '..')) + { + pop @result; + } + else + { + push @result, $element; + } + } + else + { + push @result, $element; + } + } + $path_to_working_dir = File::Spec->abs2rel($cwd, join ('/', @result)); + $path_to_working_dir =~ s|.*/||; + $path_to_working_dir .= '/' unless($path_to_working_dir eq ''); +} + +# extension +if ($Texi2HTML::Config::SHORTEXTN) +{ + $docu_ext = "htm"; +} + +$docu_doc = $docu_name . ($docu_ext ? ".$docu_ext" : ""); # document's contents +if ($Texi2HTML::Config::SPLIT) +{ + $docu_top = $Texi2HTML::Config::TOP_FILE || $docu_doc; + + if (defined $Texi2HTML::Config::element_file_name) + { + $docu_toc = &$Texi2HTML::Config::element_file_name + (undef, "toc", $docu_name); + $docu_stoc = &$Texi2HTML::Config::element_file_name + (undef, "stoc", $docu_name); + $docu_foot = &$Texi2HTML::Config::element_file_name + (undef, "foot", $docu_name); + $docu_about = &$Texi2HTML::Config::element_file_name + (undef, "about", $docu_name); + # $docu_top may be overwritten later. + } + if (!defined($docu_toc)) + { + my $default_toc = "${docu_name}_toc"; + $default_toc .= ".$docu_ext" if (defined($docu_ext)); + $docu_toc = $Texi2HTML::Config::TOC_FILE || $default_toc; + } + if (!defined($docu_stoc)) + { + $docu_stoc = "${docu_name}_ovr"; + $docu_stoc .= ".$docu_ext" if (defined($docu_ext)); + } + if (!defined($docu_foot)) + { + $docu_foot = "${docu_name}_fot"; + $docu_foot .= ".$docu_ext" if (defined($docu_ext)); + } + if (!defined($docu_about)) + { + $docu_about = "${docu_name}_abt"; + $docu_about .= ".$docu_ext" if (defined($docu_ext)); + } +} +else +{ + if ($Texi2HTML::Config::OUT) + { + $docu_doc = $Texi2HTML::Config::OUT; + $docu_doc =~ s|.*/||; + } + if (defined $Texi2HTML::Config::element_file_name) + { + my $docu_name = &$Texi2HTML::Config::element_file_name + (undef, "doc", $docu_name); + $docu_top = $docu_name if (defined($docu_name)); + } + $docu_toc = $docu_foot = $docu_stoc = $docu_about = $docu_top = $docu_doc; +} + +# Note that file extension has already been added here. + +# For use in init files +$Texi2HTML::THISDOC{'filename'}->{'top'} = $docu_top; +$Texi2HTML::THISDOC{'filename'}->{'foot'} = $docu_foot; +$Texi2HTML::THISDOC{'filename'}->{'stoc'} = $docu_stoc; +$Texi2HTML::THISDOC{'filename'}->{'about'} = $docu_about; +$Texi2HTML::THISDOC{'filename'}->{'toc'} = $docu_toc; +$Texi2HTML::THISDOC{'extension'} = $docu_ext; +# FIXME document that +$Texi2HTML::THISDOC{'out_dir'} = $docu_rdir; +$Texi2HTML::THISDOC{'file_base_name'} = $docu_name; + + +my $docu_doc_file = "$docu_rdir$docu_doc"; +my $docu_toc_file = "$docu_rdir$docu_toc"; +my $docu_stoc_file = "$docu_rdir$docu_stoc"; +my $docu_foot_file = "$docu_rdir$docu_foot"; +my $docu_about_file = "$docu_rdir$docu_about"; +my $docu_top_file = "$docu_rdir$docu_top"; + +my $docu_frame_file = "$docu_rdir${docu_name}_frame"; +$docu_frame_file .= ".$docu_ext" if $docu_ext; +my $docu_toc_frame_file = "$docu_rdir${docu_name}_toc_frame"; +$docu_toc_frame_file .= ".$docu_ext" if $docu_ext; + +# +# _foo: internal variables to track @foo +# +foreach my $key ('_author', '_title', '_subtitle', '_shorttitlepage', + '_settitle', '_setfilename', '_shorttitle', '_titlefont') +{ + $value{$key} = ''; # prevent -w warnings +} +my $index; # ref on a hash for the index entries +my %indices = (); # hash of indices names containing + #[ $pages, $entries ] (page indices and + # raw index entries) +my @index_labels = (); # array corresponding with @?index commands + # constructed during pass_texi, used to + # put labels in pass_text +# +# initial counters +# +my $foot_num = 0; +my $relative_foot_num = 0; +my $idx_num = 0; +my $sec_num = 0; +my $anchor_num = 0; + +# +# can I use ISO8859 characters? (HTML+) +# +if ($Texi2HTML::Config::USE_ISO) +{ + foreach my $thing (keys(%Texi2HTML::Config::iso_symbols)) + { + next unless exists ($::things_map_ref->{$thing}); + $::things_map_ref->{$thing} = $Texi2HTML::Config::iso_symbols{$thing}; + $::pre_map_ref->{$thing} = $Texi2HTML::Config::iso_symbols{$thing}; + $Texi2HTML::Config::simple_format_texi_map{$thing} = $Texi2HTML::Config::iso_symbols{$thing}; + } + # we don't override the user defined quote, but beware that this works + # only if the hardcoded defaults, '`' and "'" match with the defaults + # in the default init file + $Texi2HTML::Config::OPEN_QUOTE_SYMBOL = $Texi2HTML::Config::iso_symbols{'`'} + if (exists($Texi2HTML::Config::iso_symbols{'`'}) and ($Texi2HTML::Config::OPEN_QUOTE_SYMBOL eq '`')); + $Texi2HTML::Config::CLOSE_QUOTE_SYMBOL = $Texi2HTML::Config::iso_symbols{"'"} + if (exists($Texi2HTML::Config::iso_symbols{"'"}) and ($Texi2HTML::Config::CLOSE_QUOTE_SYMBOL eq "'")); +} + + + +# process a css file +sub process_css_file ($$) +{ + my $fh =shift; + my $file = shift; + my $in_rules = 0; + my $in_comment = 0; + my $in_import = 0; + my $in_string = 0; + my $rules = []; + my $imports = []; + while (<$fh>) + { + #print STDERR "Line: $_"; + if ($in_rules) + { + push @$rules, $_; + next; + } + my $text = ''; + while (1) + { + #sleep 1; + #print STDERR "${text}!in_comment $in_comment in_rules $in_rules in_import $in_import in_string $in_string: $_"; + if ($in_comment) + { + if (s/^(.*?\*\/)//) + { + $text .= $1; + $in_comment = 0; + } + else + { + push @$imports, $text . $_; + last; + } + } + elsif (!$in_string and s/^\///) + { # what do '\' do here ? + if (s/^\*//) + { + $text .= '/*'; + $in_comment = 1; + } + else + { + push (@$imports, $text. "\n") if ($text ne ''); + push (@$rules, '/' . $_); + $in_rules = 1; + last; + } + } + elsif (!$in_string and $in_import and s/^([\"\'])//) + { # strings outside of import start rules + $text .= "$1"; + $in_string = quotemeta("$1"); + } + elsif ($in_string and s/^(\\$in_string)//) + { + $text .= $1; + } + elsif ($in_string and s/^($in_string)//) + { + $text .= $1; + $in_string = 0; + } + elsif ((! $in_string and !$in_import) and (s/^([\\]?\@import)$// or s/^([\\]?\@import\s+)//)) + { + $text .= $1; + $in_import = 1; + } + elsif (!$in_string and $in_import and s/^\;//) + { + $text .= ';'; + $in_import = 0; + } + elsif (($in_import or $in_string) and s/^(.)//) + { + $text .= $1; + } + elsif (!$in_import and s/^([^\s])//) + { + push (@$imports, $text. "\n") if ($text ne ''); + push (@$rules, $1 . $_); + $in_rules = 1; + last; + } + elsif (s/^(\s)//) + { + $text .= $1; + } + elsif ($_ eq '') + { + push (@$imports, $text); + last; + } + } + } + warn "$WARN string not closed in css file $file\n" if ($in_string); + warn "$WARN comment not closed in css file $file\n" if ($in_comment); + warn "$WARN \@import not finished in css file $file\n" if ($in_import and !$in_comment and !$in_string); + return ($imports, $rules); +} + + + +# parse texinfo cnf file for external manual specifications. This was +# discussed on texinfo list but not in makeinfo for now. +my @texinfo_htmlxref_files = locate_init_file ($texinfo_htmlxref, 1, \@texinfo_config_dirs); +foreach my $file (@texinfo_htmlxref_files) +{ + print STDERR "html refs config file: $file\n" if ($T2H_DEBUG); + unless (open (HTMLXREF, $file)) + { + warn "Cannot open html refs config file ${file}: $!"; + next; + } + while (<HTMLXREF>) + { + my $line = $_; + s/[#]\s.*//; + s/^\s*//; + next if /^\s*$/; + my @htmlxref = split /\s+/; + my $manual = shift @htmlxref; + my $split_or_mono = shift @htmlxref; + if (!defined($split_or_mono) or ($split_or_mono ne 'split' and $split_or_mono ne 'mono')) + { + echo_warn("Bad line in $file: $line"); + next; + } + my $href = shift @htmlxref; + next if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono}) and exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'})); + + if (defined($href)) + { + $href =~ s/\/*$// if ($split_or_mono eq 'split'); + $Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'} = $href; + } + else + { + $Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono} = {}; + } + } + close (HTMLXREF); +} + +if ($T2H_DEBUG) +{ + foreach my $manual (keys(%{$Texi2HTML::THISDOC{'htmlxref'}})) + { + foreach my $split ('split', 'mono') + { + my $href = 'NO'; + next unless (exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split})); + $href = $Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split}->{'href'} if + exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split}->{'href'}); + print STDERR "$manual: $split, href: $href\n"; + } + } +} + +print STDERR "# reading from $docu\n" if $T2H_VERBOSE; + +#+++########################################################################### +# # +# Pass texi: read source, handle variable, ignored text, # +# # +#---########################################################################### + +my @fhs = (); # hold the file handles to read +my $input_spool; # spooled lines to read +my @lines = (); # whole document +my @lines_numbers = (); # line number, originating file associated with + # whole document +my $macros; # macros. reference on a hash +my %info_enclose; # macros defined with definfoenclose +my $texi_line_number = { 'file_name' => '', 'line_nr' => 0, 'macro' => '' }; +my @floats = (); # floats list +my %floats = (); # floats by style + +sub initialise_state_texi($) +{ + my $state = shift; + $state->{'texi'} = 1; # for substitute_text and close_stack: + # 1 if pass_texi/scan_texi is to be used + $state->{'macro_inside'} = 0 unless(defined($state->{'macro_inside'})); + $state->{'ifvalue_inside'} = 0 unless(defined($state->{'ifvalue_inside'})); + $state->{'arg_expansion'} = 0 unless(defined($state->{'arg_expansion'})); +} + +my @first_lines = (); + +sub pass_texi() +{ + my $first_lines = 1; # is it the first lines + my $state = {}; + # holds the informations about the context + # to pass it down to the functions + initialise_state_texi($state); + my @stack; + my $text; + INPUT_LINE: while (defined($_ = next_line($texi_line_number))) + { + # + # remove the lines preceding \input or an @-command + # + if ($first_lines) + { + if (/^\\input/) + { + push @first_lines, $_; + $first_lines = 0; + next; + } + if (/^\s*\@/) + { + $first_lines = 0; + } + else + { + push @first_lines, $_; + next; + } + } + #print STDERR "PASS_TEXI($texi_line_number->{'line_nr'})$_"; + my $chomped_line = $_; + if (scan_texi ($_, \$text, \@stack, $state, $texi_line_number) and chomp($chomped_line)) + { + #print STDERR "==> new page (line_nr $texi_line_number->{'line_nr'},$texi_line_number->{'file_name'},$texi_line_number->{'macro'})\n"; + push (@lines_numbers, { 'file_name' => $texi_line_number->{'file_name'}, + 'line_nr' => $texi_line_number->{'line_nr'}, + 'macro' => $texi_line_number->{'macro'} }); + } + #dump_stack (\$text, \@stack, $state); + if ($state->{'bye'}) + { + #dump_stack(\$text, \@stack, $state); + # close stack after bye + #print STDERR "close stack after bye\n"; + close_stack_texi_structure(\$text, \@stack, $state, $texi_line_number); + #dump_stack(\$text, \@stack, $state); + } + next if (@stack); + $_ = $text; + $text = ''; + if (!defined($_)) + {# FIXME: remove the error message if it is reported too often + print STDERR "# \$_ undefined after scan_texi. This may be a bug, or not.\n"; + print STDERR "# Report (with texinfo file) if you want, otherwise ignore that message.\n"; + next unless ($state->{'bye'}); + } + push @lines, split_lines($_); + last if ($state->{'bye'}); + } + # close stack at the end of pass texi + #print STDERR "close stack at the end of pass texi\n"; + close_stack_texi_structure(\$text, \@stack, $state, $texi_line_number); + push @lines, split_lines($text); + print STDERR "# end of pass texi\n" if $T2H_VERBOSE; +} + +# return the line after preserving things according to misc_command map. +sub preserve_command($$) +{ + my $line = shift; + my $macro = shift; + my $text = ''; + my $args = ''; + my $skip_spec = ''; + my $arg_spec = ''; + + $skip_spec = $Texi2HTML::Config::misc_command{$macro}->{'skip'} + if (defined($Texi2HTML::Config::misc_command{$macro}->{'skip'})); + $arg_spec = $Texi2HTML::Config::misc_command{$macro}->{'arg'} + if (defined($Texi2HTML::Config::misc_command{$macro}->{'arg'})); + + if ($arg_spec eq 'line') + { + $text .= $line; + $args .= $line; + $line = ''; + } + elsif ($arg_spec) + { + my $arg_nr = $Texi2HTML::Config::misc_command{$macro}->{'arg'}; + while ($arg_nr) + { + $line =~ s/(\s+\S*)//o; + $text .= $1 if defined($1); + $args .= $1 if defined($1); + $arg_nr--; + } + } + + if ($macro eq 'bye') + { + $line = ''; + $text = "\n"; + } + elsif ($skip_spec eq 'linespace') + { + if ($line =~ /^\s*$/o) + { + $line =~ s/([ \t]*)//o; + $text .= $1; + } + } + elsif ($skip_spec eq 'linewhitespace') + { + if ($line =~ /^\s*$/o) + { + $text .= $line; + $line = ''; + } + } + elsif ($skip_spec eq 'line') + { + $text .= $line; + $line = ''; + } + elsif ($skip_spec eq 'whitespace') + { + $line =~ s/(\s*)//o; + $text .= $1; + } + elsif ($skip_spec eq 'space') + { + $line =~ s/([ \t]*)//o; + $text .= $1; + } + $line = '' if (!defined($line)); + return ($line, $text, $args); +} + +#+++########################################################################### +# # +# Pass structure: parse document structure # +# # +#---########################################################################### + +# This is a virtual element for things appearing before @node and +# sectionning commands +my $element_before_anything = +{ + 'before_anything' => 1, + 'place' => [], + 'texi' => 'VIRTUAL ELEMENT BEFORE ANYTHING', +}; + +# This is a place for index entries, anchors and so on appearing in +# copying or documentdescription +my $region_place = []; + +sub initialise_state_structure($) +{ + my $state = shift; + $state->{'structure'} = 1; # for substitute_text and close_stack: + # 1 if pass_structure/scan_structure is + # to be used + $state->{'menu'} = 0; # number of opened menus + $state->{'detailmenu'} = 0; # number of opened detailed menus + $state->{'sectionning_base'} = 0; # current base sectionning level + $state->{'table_stack'} = [ "no table" ]; # a stack of opened tables/lists + if (exists($state->{'region_lines'}) and !defined($state->{'region_lines'})) + { + delete ($state->{'region_lines'}); + print STDERR "Bug: state->{'region_lines'} exists but undef.\n"; + } +} + +my @doc_lines = (); # whole document +my @doc_numbers = (); # whole document line numbers and file names +my @nodes_list = (); # nodes in document reading order + # each member is a reference on a hash +my @sections_list = (); # sections in reading order + # each member is a reference on a hash +my @all_elements = (); # sectionning elements (nodes and sections) + # in reading order. Each member is a reference + # on a hash which also appears in %nodes, + # @sections_list @nodes_list, @elements_list +my @elements_list; # all the resulting elements in document order +my %sections = (); # sections hash. The key is the section number + # headings are there, although they are not elements +my $section_top; # @top section +my $element_top; # Top element +my $node_top; # Top node +my $node_first; # First node +my $element_index; # element with first index +my $element_chapter_index; # chapter with first index +my $element_first; # first element +my $element_last; # last element +my %special_commands; # hash for the commands specially handled + # by the user + +# This is a virtual element used to have the right hrefs for index entries +# and anchors in footnotes +my $footnote_element = +{ + 'id' => 'SEC_Foot', + 'file' => $docu_foot, + 'footnote' => 1, + 'element' => 1, + 'place' => [], +}; + +my %content_element = +( + 'contents' => { 'id' => 'SEC_Contents', 'contents' => 1, 'texi' => '_contents' }, + 'shortcontents' => { 'id' => 'SEC_Overview', 'shortcontents' => 1, 'texi' => '_shortcontents' }, +); + +#my $do_contents; # do table of contents if true +#my $do_scontents; # do short table of contents if true +my $novalidate = $Texi2HTML::Config::NOVALIDATE; # @novalidate appeared + +sub pass_structure() +{ + my $state = {}; + # holds the informations about the context + # to pass it down to the functions + initialise_state_structure($state); + $state->{'element'} = $element_before_anything; + $state->{'place'} = $element_before_anything->{'place'}; + my @stack; + my $text; + my $line_nr; + + while (@lines) + { + $_ = shift @lines; + my $chomped_line = $_; + if (!chomp($chomped_line) and @lines) + { + $lines[0] = $_ . $lines[0]; + next; + } + $line_nr = shift (@lines_numbers); + #print STDERR "PASS_STRUCTURE: $_"; + if (!$state->{'raw'} and !$state->{'verb'}) + { + my $tag = ''; + if (/^\s*\@(\w+)\b/) + { + $tag = $1; + } + + # + # analyze the tag + # + if ($tag and $tag eq 'node' or defined($sec2level{$tag}) or $tag eq 'printindex') + { + $_ = substitute_texi_line($_); + if ($tag eq 'node' or defined($sec2level{$tag})) + {# in pass structure node shouldn't appear in formats + close_stack_texi_structure(\$text, \@stack, $state, $line_nr); + if (exists($state->{'region_lines'})) + { + push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($text); + close_region($state); + } + else + { + push @doc_lines, split_lines($text); + } + $text = ''; + } + if ($tag eq 'node') + { + my $node_ref; + my $auto_directions; + $auto_directions = 1 unless (/,/o); + my ($node, $node_next, $node_prev, $node_up) = split(/,/, $_); + $node =~ s/^\@node\s+// if ($node); + if ($node) + { + $node = normalise_space($node); + if (exists($nodes{$node}) and defined($nodes{$node}) + and $nodes{$node}->{'seen'}) + { + echo_error ("Duplicate node found: $node", $line_nr); + next; + } + else + { + if (exists($nodes{$node}) and defined($nodes{$node})) + { # node appeared in a menu + $node_ref = $nodes{$node}; + } + else + { + my $first; + $first = 1 if (!defined($node_ref)); + $node_ref = {}; + $node_first = $node_ref if ($first); + $nodes{$node} = $node_ref; + } + $node_ref->{'node'} = 1; + $node_ref->{'tag'} = 'node'; + $node_ref->{'tag_level'} = 'node'; + $node_ref->{'texi'} = $node; + $node_ref->{'seen'} = 1; + $node_ref->{'automatic_directions'} = $auto_directions; + $node_ref->{'place'} = []; + $node_ref->{'current_place'} = []; + merge_element_before_anything($node_ref); + $node_ref->{'index_names'} = []; + $state->{'place'} = $node_ref->{'current_place'}; + $state->{'element'} = $node_ref; + $state->{'after_element'} = 1; + $state->{'node_ref'} = $node_ref; + # makeinfo treats differently case variants of + # top in nodes and anchors and in refs commands and + # refs from nodes. + if ($node =~ /^top$/i) + { + if (!defined($node_top)) + { + $node_top = $node_ref; + $node_top->{'texi'} = 'Top'; + delete $nodes{$node}; + $nodes{$node_top->{'texi'}} = $node_ref; + } + else + { # All the refs are going to point to the first Top + echo_warn ("Top node allready exists", $line_nr); + #warn "$WARN Top node allready exists\n"; + } + } + unless (@nodes_list) + { + $node_ref->{'first'} = 1; + } + push (@nodes_list, $node_ref); + push @all_elements, $node_ref; + } + } + else + { + echo_error ("Node is undefined: $_ (eg. \@node NODE-NAME, NEXT, PREVIOUS, UP)", $line_nr); + next; + } + + if ($node_next) + { + $node_ref->{'node_next'} = normalise_node($node_next); + } + if ($node_prev) + { + $node_ref->{'node_prev'} = normalise_node($node_prev); + } + if ($node_up) + { + $node_ref->{'node_up'} = normalise_node($node_up); + } + } + elsif (defined($sec2level{$tag})) + { # section or heading + if (/^\@$tag\s*(.*)$/) + { + my $name = normalise_space($1); + $name = '' if (!defined($name)); + my $level = $sec2level{$tag}; + $state->{'after_element'} = 1; + my ($docid, $num); + if($tag ne 'top') + { + $sec_num++; + $num = $sec_num; + $docid = "SEC$sec_num"; + } + else + { + $num = 0; + $docid = "SEC_Top"; + } + if ($tag !~ /heading/) + { + my $section_ref = { 'texi' => $name, + 'level' => $level, + 'tag' => $tag, + 'sec_num' => $num, + 'section' => 1, + 'id' => $docid, + 'seen' => 1, + 'index_names' => [], + 'current_place' => [], + 'place' => [] + }; + + if ($tag eq 'top') + { + $section_ref->{'top'} = 1; + $section_ref->{'number'} = ''; + $sections{0} = $section_ref; + $section_top = $section_ref; + } + $sections{$num} = $section_ref; + merge_element_before_anything($section_ref); + if ($state->{'node_ref'} and !exists($state->{'node_ref'}->{'with_section'})) + { + my $node_ref = $state->{'node_ref'}; + $section_ref->{'node_ref'} = $node_ref; + $section_ref->{'titlefont'} = $node_ref->{'titlefont'}; + $node_ref->{'with_section'} = $section_ref; + $node_ref->{'top'} = 1 if ($tag eq 'top'); + } + if (! $name and $level) + { + echo_warn ("$tag without name", $line_nr); + } + push @sections_list, $section_ref; + push @all_elements, $section_ref; + $state->{'element'} = $section_ref; + $state->{'place'} = $section_ref->{'current_place'}; + my $node_ref = "NO NODE"; + my $node_texi =''; + if ($state->{'node_ref'}) + { + $node_ref = $state->{'node_ref'}; + $node_texi = $state->{'node_ref'}->{'texi'}; + } + print STDERR "# pass_structure node($node_ref)$node_texi, tag \@$tag($level) ref $section_ref, num,id $num,$docid\n $name\n" + if $T2H_DEBUG & $DEBUG_ELEMENTS; + } + else + { + my $section_ref = { 'texi' => $name, + 'level' => $level, + 'heading' => 1, + 'tag' => $tag, + 'tag_level' => $tag, + 'sec_num' => $sec_num, + 'id' => $docid, + 'number' => '' }; + $state->{'element'} = $section_ref; + push @{$state->{'place'}}, $section_ref; + $sections{$sec_num} = $section_ref; + } + } + } + elsif (/^\@printindex\s+(\w+)/) + { + unless (@all_elements) + { + echo_warn ("Printindex before document beginning: \@printindex $1", $line_nr); + next; + } + delete $state->{'after_element'}; + # $element_index is the first element with index + $element_index = $all_elements[-1] unless (defined($element_index)); + # associate the index to the element such that the page + # number is right + my $placed_elements = []; + push @{$all_elements[-1]->{'index_names'}}, { 'name' => $1, 'place' => $placed_elements }; + $state->{'place'} = $placed_elements; + } + if (exists($state->{'region_lines'})) + { + push @{$region_lines{$state->{'region_lines'}->{'format'}}}, $_; + } + else + { + push @doc_lines, $_; + push @doc_numbers, $line_nr; + } + next; + } + } + if (scan_structure ($_, \$text, \@stack, $state, $line_nr) and !(exists($state->{'region_lines'}))) + { + push (@doc_numbers, $line_nr); + } + next if (@stack); + $_ = $text; + $text = ''; + next if (!defined($_)); + if ($state->{'region_lines'}) + { + push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($_); + } + else + { + push @doc_lines, split_lines($_); + } + } + if (@stack) + {# close stack at the end of pass structure + close_stack_texi_structure(\$text, \@stack, $state, $line_nr); + if ($text) + { + if (exists($state->{'region_lines'})) + { + push @{$region_lines{$state->{'region_lines'}->{'format'}}}, + split_lines($text); + } + else + { + push @doc_lines, split_lines($text); + } + } + } + echo_warn ("At end of document, $state->{'region_lines'}->{'number'} $state->{'region_lines'}->{'format'} not closed") if (exists($state->{'region_lines'})); + print STDERR "# end of pass structure\n" if $T2H_VERBOSE; +} + +# split line at end of line and put each resulting line in an array +# FIXME there must be a more perlish way to do it... Not a big deal +# as long as it work +sub split_lines($) +{ + my $line = shift; + my @result = (); + my $i = 0; + while ($line) + { + $result[$i] = ''; + $line =~ s/^(.*)//; + $result[$i] .= $1; + $result[$i] .= "\n" if ($line =~ s/^\n//); + #print STDERR "$i: $result[$i]"; + $i++; + } + return @result; +} + +# handle misc commands and misc command args +sub misc_command_structure($$$$) +{ + my $line = shift; + my $macro = shift; + my $state = shift; + my $line_nr = shift; + my $text; + my $args; + + if ($macro eq 'lowersections') + { + my ($sec, $level); + while (($sec, $level) = each %sec2level) + { + $sec2level{$sec} = $level + 1; + } + $state->{'sectionning_base'}--; + } + elsif ($macro eq 'raisesections') + { + my ($sec, $level); + while (($sec, $level) = each %sec2level) + { + $sec2level{$sec} = $level - 1; + } + $state->{'sectionning_base'}++; + } + elsif (($macro eq 'contents') or ($macro eq 'summarycontents') or ($macro eq 'shortcontents')) + { + if ($macro eq 'contents') + { + $Texi2HTML::Config::DO_CONTENTS = 1; + } + else + { + $macro = 'shortcontents'; + $Texi2HTML::Config::DO_SCONTENTS = 1; + } + push @{$state->{'place'}}, $content_element{$macro}; + } + elsif ($macro eq 'detailmenu') + { + $state->{'detailmenu'}++; + } + elsif ($macro eq 'novalidate') + { + $novalidate = 1; + $Texi2HTML::THISDOC{$macro} = 1; + } + elsif (grep {$_ eq $macro} ('settitle','setfilename','shortitle','shorttitlepage') + and ($line =~ /^\s+(.*)$/)) + { + $value{"_$macro"} = substitute_texi_line($1); + } + elsif (grep {$_ eq $macro} ('author','subtitle','title') + and ($line =~ /^\s+(.*)$/)) + { + $value{"_$macro"} .= substitute_texi_line($1)."\n"; + push @{$Texi2HTML::THISDOC{"${macro}s"}}, substitute_texi_line($1); + } + elsif ($macro eq 'synindex' || $macro eq 'syncodeindex') + { + if ($line =~ /^\s+(\w+)\s+(\w+)/) + { + my $index_from = $1; + my $index_to = $2; + echo_error ("unknown from index name $index_from in \@$macro", $line_nr) + unless $index_names{$index_from}; + echo_error ("unknown to index name $index_to in \@$macro", $line_nr) + unless $index_names{$index_to}; + if ($index_names{$index_from} and $index_names{$index_to}) + { + if ($macro eq 'syncodeindex') + { + $index_names{$index_to}->{'associated_indices_code'}->{$index_from} = 1; + } + else + { + $index_names{$index_to}->{'associated_indices'}->{$index_from} = 1; + } + push @{$Texi2HTML::THISDOC{$macro}}, [$index_from,$index_to]; + } + } + else + { + echo_error ("Bad $macro line: $line", $line_nr); + } + } + elsif ($macro eq 'defindex' || $macro eq 'defcodeindex') + { + if ($line =~ /^\s+(\w+)\s*$/) + { + my $name = $1; + if ($forbidden_index_name{$name}) + { + echo_error("Reserved index name $name", $line_nr); + } + else + { + @{$index_names{$name}->{'prefix'}} = ($name); + $index_names{$name}->{'code'} = 1 if $macro eq 'defcodeindex'; + $index_prefix_to_name{$name} = $name; + push @{$Texi2HTML::THISDOC{$macro}}, $name; + } + } + else + {# makeinfo don't warn and even accepts index with empty name + # and index with numbers only. I reported it on the mailing list + # this should be fixed in future makeinfo versions. + echo_error ("Bad $macro line: $line", $line_nr); + } + } + elsif ($macro eq 'documentlanguage') + { + if ($line =~ /\s+(\w+)/) + { + my $lang = $1; + set_document_language($lang, 0, $line_nr) if (!$cmd_line_lang && $lang); + # warning, this is not the language of the document but the one that + # appear in the texinfo... + $Texi2HTML::THISDOC{$macro} = $lang; + } + } + elsif ($macro eq 'kbdinputstyle') + {# makeinfo ignores that with --html. I reported it and it should be + # fixed in future makeinfo releases + if ($line =~ /\s+([a-z]+)/) + { + if ($1 eq 'code') + { + $::style_map_ref->{'kbd'} = $::style_map_ref->{'code'}; + $::style_map_pre_ref->{'kbd'} = $::style_map_pre_ref->{'code'}; + $Texi2HTML::THISDOC{$macro} = $1; + } + elsif ($1 eq 'example') + { + $::style_map_pre_ref->{'kbd'} = $::style_map_pre_ref->{'code'}; + $Texi2HTML::THISDOC{$macro} = $1; + } + elsif ($1 ne 'distinct') + { + echo_error ("Unknown argument for \@$macro: $1", $line_nr); + } + } + else + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'paragraphindent') + { + if ($line =~ /\s+([0-9]+)/) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + elsif (($line =~ /\s+(none)[^\w\-]/) or ($line =~ /\s+(asis)[^\w\-]/)) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + else + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'firstparagraphindent') + { + if (($line =~ /\s+(none)[^\w\-]/) or ($line =~ /\s+(insert)[^\w\-]/)) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + else + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'exampleindent') + { + if ($line =~ /^\s+([0-9]+)/) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + elsif ($line =~ /^\s+(asis)[^\w\-]/) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + else + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'frenchspacing') + { + if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/)) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + else + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'footnotestyle') + { + if (($line =~ /^\s+(end)[^\w\-]/) or ($line =~ /^\s+(separate)[^\w\-]/)) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + else + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'headings') + { + my $valid_arg = 0; + foreach my $possible_arg (('off','on','single','double', + 'singleafter','doubleafter')) + { + if ($line =~ /^\s+($possible_arg)[^\w\-]/) + { + $valid_arg = 1; + $Texi2HTML::THISDOC{$macro} = $possible_arg; + last; + } + } + unless ($valid_arg) + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'setchapternewpage') + { + if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/) + or ($line =~ /^\s+(odd)[^\w\-]/)) + { + $Texi2HTML::THISDOC{$macro} = $1; + } + else + { + echo_error ("Bad \@$macro", $line_nr); + } + } + elsif ($macro eq 'setcontentsaftertitlepage' or $macro eq 'setshortcontentsaftertitlepage') + { + $Texi2HTML::THISDOC{$macro} = 1; + my $tag = 'contents'; + $tag = 'shortcontents' if ($macro ne 'setcontentsaftertitlepage'); + $content_element{$tag}->{'aftertitlepage'} = 1; + } + elsif (grep {$macro eq $_} ('everyheading', 'everyfooting', + 'evenheading', 'evenfooting', 'oddheading', 'oddfooting')) + { + my $arg = $line; + $arg =~ s/^\s+//; + $Texi2HTML::THISDOC{$macro} = $arg; + } + elsif ($macro eq 'need') + { + unless (($line =~ /^\s+([0-9]+(\.[0-9]*)?)[^\w\-]/) or + ($line =~ /^\s+(\.[0-9]+)[^\w\-]/)) + { + echo_warn ("Bad \@$macro", $line_nr); + } + } + + ($text, $line, $args) = preserve_command($line, $macro); + return ($text, $line); +} + +# return the line after removing things according to misc_command map. +# if the skipped macro has an effect it is done here +# this is used during pass_text +sub misc_command_text($$$$$$) +{ + my $line = shift; + my $macro = shift; + my $stack = shift; + my $state = shift; + my $text = shift; + my $line_nr = shift; + my ($skipped, $remaining, $args); + # if it is true the command args are kept so the user can modify how + # they are skipped and handle them as unknown @-commands + my $keep = $Texi2HTML::Config::misc_command{$macro}->{'keep'}; + + if ($macro eq 'detailmenu') + { + $state->{'detailmenu'}++; + } + elsif ($macro eq 'sp') + { + my $sp_number; + if ($line =~ /^\s+(\d+)\s/) + { + $sp_number = $1; + } + elsif ($line =~ /(\s*)$/) + { + $sp_number = ''; + } + else + { + echo_error ("\@$macro needs a numeric arg or no arg", $line_nr); + } + $sp_number = 1 if ($sp_number eq ''); + if (!$state->{'remove_texi'}) + { + add_prev($text, $stack, &$Texi2HTML::Config::sp($sp_number, $state->{'preformatted'})); + } + } + elsif($macro eq 'verbatiminclude' and !$keep) + { + if ($line =~ /\s+(.+)/) + { + my $arg = $1; + my $file = locate_include_file($arg); + if (defined($file)) + { + if (!open(VERBINCLUDE, $file)) + { + echo_warn ("Can't read file $file: $!",$line_nr); + } + else + { + my $verb_text = ''; + while (my $line = <VERBINCLUDE>) + { + $verb_text .= $line; + } + + if ($state->{'remove_texi'}) + { + add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi('verbatim', $verb_text)); + } + else + { + add_prev($text, $stack, &$Texi2HTML::Config::raw('verbatim', $verb_text)); + } + close VERBINCLUDE; + } + } + else + { + echo_error ("Can't find $arg, skipping", $line_nr); + } + } + else + { + echo_error ("Bad \@$macro line: $_", $line_nr); + } + } + elsif ($macro eq 'indent' or $macro eq 'noindent') + { + $state->{'paragraph_indent'} = $macro; + } + ($remaining, $skipped, $args) = preserve_command($line, $macro); + return ($skipped) if ($keep); + return $remaining if ($remaining ne ''); + return undef; +} + +# merge the things appearing before the first @node or sectionning command +# (held by element_before_anything) with the current element +# do that only once. +sub merge_element_before_anything($) +{ + my $element = shift; + if (exists($element_before_anything->{'place'})) + { + $element->{'current_place'} = $element_before_anything->{'place'}; + delete $element_before_anything->{'place'}; + foreach my $placed_thing (@{$element->{'current_place'}}) + { + $placed_thing->{'element'} = $element if (exists($placed_thing->{'element'})); + } + } + # this is certainly redundant with the above condition, but cleaner + # that way + if (exists($element_before_anything->{'titlefont'})) + { + $element->{'titlefont'} = $element_before_anything->{'titlefont'}; + delete $element_before_anything->{'titlefont'}; + } +} + +# find menu_prev, menu_up... for a node in menu +sub menu_entry_texi($$$) +{ + my $node = shift; + my $state = shift; + my $line_nr = shift; + my $node_menu_ref = {}; + if (exists($nodes{$node})) + { + $node_menu_ref = $nodes{$node}; + } + else + { + $nodes{$node} = $node_menu_ref; + $node_menu_ref->{'texi'} = $node; + $node_menu_ref->{'external_node'} = 1 if ($node =~ /\(.+\)/); + } + return if ($state->{'detailmenu'}); + if ($state->{'node_ref'}) + { + $node_menu_ref->{'menu_up'} = $state->{'node_ref'}; + $node_menu_ref->{'menu_up_hash'}->{$state->{'node_ref'}->{'texi'}} = 1; + } + else + { + echo_warn ("menu entry without previous node: $node", $line_nr) unless ($node =~ /\(.+\)/); + } + if ($state->{'prev_menu_node'}) + { + $node_menu_ref->{'menu_prev'} = $state->{'prev_menu_node'}; + $state->{'prev_menu_node'}->{'menu_next'} = $node_menu_ref; + } + elsif ($state->{'node_ref'}) + { + $state->{'node_ref'}->{'menu_child'} = $node_menu_ref; + } + $state->{'prev_menu_node'} = $node_menu_ref; +} + +sub equivalent_nodes($) +{ + my $name = shift; +#print STDERR "equivalent_nodes $name\n"; + my $node = normalise_node($name); + $name = cross_manual_line($node); + my @equivalent_nodes = (); + if (exists($cross_reference_nodes{$name})) + { + @equivalent_nodes = grep {$_ ne $node} @{$cross_reference_nodes{$name}}; + } + return @equivalent_nodes; +} + +my %files = (); # keys are files. This is used to avoid reusing an allready + # used file name +my %empty_indices = (); # value is true for an index name key if the index + # is empty +my %printed_indices = (); # value is true for an index name not empty and + # printed + +# find next, prev, up, back, forward, fastback, fastforward +# find element id and file +# split index pages +# associate placed items (items which have links to them) with the right +# file and id +# associate nodes with sections +sub rearrange_elements() +{ + print STDERR "# find sections levels and toplevel\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + + my $toplevel = 4; + # correct level if raisesections or lowersections overflowed + # and find toplevel level + # use %sections to modify also the headings + foreach my $section (values(%sections)) + { + my $level = $section->{'level'}; + if ($level > $MAX_LEVEL) + { + $section->{'level'} = $MAX_LEVEL; + } + elsif ($level < $MIN_LEVEL and !$section->{'top'}) + { + $section->{'level'} = $MIN_LEVEL; + } + else + { + $section->{'level'} = $level; + } + $section->{'toc_level'} = $section->{'level'}; + # This is for top + $section->{'toc_level'} = $MIN_LEVEL if ($section->{'level'} < $MIN_LEVEL); + # find the new tag corresponding with the level of the section + if ($section->{'tag'} !~ /heading/ and ($level ne $reference_sec2level{$section->{'tag'}})) + { + $section->{'tag_level'} = $level2sec{$section->{'tag'}}->[$section->{'level'}]; + } + else + { + $section->{'tag_level'} = $section->{'tag'}; + } + $toplevel = $section->{'level'} if (($section->{'level'} < $toplevel) and ($section->{'level'} > 0 and ($section->{'tag'} !~ /heading/))); + print STDERR "# section level $level: $section->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + } + + print STDERR "# find sections structure, construct section numbers (toplevel=$toplevel)\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + my $in_appendix = 0; + # these arrays have an element per sectionning level. + my @previous_numbers = (); # holds the number of the previous sections + # at the same and upper levels + my @previous_sections = (); # holds the ref of the previous sections + + foreach my $section (@sections_list) + { + ########################### debug + print STDERR "BUG: node or section_ref defined for section $section->{'texi'}\n" + if (exists($section->{'node'}) or exists($section->{'section_ref'})); + ########################### end debug + next if ($section->{'top'}); + print STDERR "Bug level undef for ($section) $section->{'texi'}\n" if (!defined($section->{'level'})); + $section->{'toplevel'} = 1 if ($section->{'level'} == $toplevel); + # undef things under that section level + for (my $level = $section->{'level'} + 1; $level < $MAX_LEVEL + 1 ; $level++) + { + $previous_numbers[$level] = undef; + $previous_sections[$level] = undef; + } + my $number_set; + # find number at the current level + if ($section->{'tag'} =~ /appendix/ and !$in_appendix) + { + $previous_numbers[$toplevel] = 'A'; + $in_appendix = 1; + $number_set = 1 if ($section->{'level'} == $toplevel); + } + if (!defined($previous_numbers[$section->{'level'}]) and !$number_set) + { + if ($section->{'tag'} =~ /unnumbered/) + { + $previous_numbers[$section->{'level'}] = undef; + } + else + { + $previous_numbers[$section->{'level'}] = 1; + } + } + elsif ($section->{'tag'} !~ /unnumbered/ and !$number_set) + { + $previous_numbers[$section->{'level'}]++; + } + # construct the section number + $section->{'number'} = ''; + + unless ($section->{'tag'} =~ /unnumbered/) + { + my $level = $section->{'level'}; + while ($level > $toplevel) + { + my $number = $previous_numbers[$level]; + $number = 0 if (!defined($number)); + if ($section->{'number'}) + { + $section->{'number'} = "$number.$section->{'number'}"; + } + else + { + $section->{'number'} = $number; + } + $level--; + } + my $toplevel_number = $previous_numbers[$toplevel]; + $toplevel_number = 0 if (!defined($toplevel_number)); + $section->{'number'} = "$toplevel_number.$section->{'number'}"; + } + # find the previous section + if (defined($previous_sections[$section->{'level'}])) + { + my $prev_section = $previous_sections[$section->{'level'}]; + $section->{'sectionprev'} = $prev_section; + $prev_section->{'sectionnext'} = $section; + } + # find the up section + if ($section->{'level'} == $toplevel) + { + $section->{'sectionup'} = undef; + } + else + { + my $level = $section->{'level'} - 1; + while (!defined($previous_sections[$level]) and ($level >= 0)) + { + $level--; + } + if ($level >= 0) + { + $section->{'sectionup'} = $previous_sections[$level]; + # 'child' is the first child + $section->{'sectionup'}->{'child'} = $section unless ($section->{'sectionprev'}); + push @{$section->{'sectionup'}->{'section_childs'}}, $section; + } + else + { + $section->{'sectionup'} = undef; + } + } + $previous_sections[$section->{'level'}] = $section; + # This is what is used in the .init file. + $section->{'up'} = $section->{'sectionup'}; + # Not used but documented. + $section->{'next'} = $section->{'sectionnext'}; + $section->{'prev'} = $section->{'sectionprev'}; + + ############################# debug + my $up = "NO_UP"; + $up = $section->{'sectionup'} if (defined($section->{'sectionup'})); + print STDERR "# numbering section ($section->{'level'}): $section->{'number'}: (up: $up) $section->{'texi'}\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + ############################# end debug + } + + # at that point there are still some node structures that are not + # in %nodes, (the external nodes, and unknown nodes in case + # novalidate is true) so we cannot find the id. The consequence is that + # some node equivalent with another node may not be catched during + # that pass. We mark the nodes that have directions for unreferenced + # nodes and make a second pass for these nodes afterwards. + my @nodes_with_unknown_directions = (); + + my @node_directions = ('node_prev', 'node_next', 'node_up'); + # handle nodes + # the node_prev... are texinfo strings, find the associated node references + print STDERR "# Resolve nodes directions\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + foreach my $node (@nodes_list) + { + foreach my $direction (@node_directions) + { + if (defined($node->{$direction}) and !ref($node->{$direction}) + and ($node->{$direction} ne '')) + { + if ($nodes{$node->{$direction}} and $nodes{$node->{$direction}}->{'seen'}) + { + $node->{$direction} = $nodes{$node->{$direction}}; + } + elsif (($node->{$direction} =~ /^\(.*\)/) or $novalidate) + { # ref to an external node + if (exists($nodes{$node->{$direction}})) + { + $node->{$direction} = $nodes{$node->{$direction}}; + } + else + { + # FIXME if {'seen'} this is a node appearing in the + # document and a node like `(file)node'. What to + # do then ? + my $node_ref = { 'texi' => $node->{$direction} }; + $node_ref->{'external_node'} = 1 if ($node->{$direction} =~ /^\(.*\)/); + $nodes{$node->{$direction}} = $node_ref; + $node->{$direction} = $node_ref; + } + } + else + { + push @nodes_with_unknown_directions, $node; + } + } + } + } + + # Find cross manual links as explained on the texinfo mailing list + # The specification is such that cross manual links formatting should + # be insensitive to the manual split + cross_manual_links(); + + # Now it is possible to find the unknown directions that are equivalent + # (have same node id) than an existing node + foreach my $node (@nodes_with_unknown_directions) + { + foreach my $direction (@node_directions) + { + if (defined($node->{$direction}) and !ref($node->{$direction}) + and ($node->{$direction} ne '')) + { + echo_warn ("$direction `$node->{$direction}' for `$node->{'texi'}' not found"); + my @equivalent_nodes = equivalent_nodes($node->{$direction}); + my $node_seen; + foreach my $equivalent_node (@equivalent_nodes) + { + if ($nodes{$equivalent_node}->{'seen'}) + { + $node_seen = $equivalent_node; + last; + } + } + if (defined($node_seen)) + { + echo_warn (" ---> but equivalent node `$node_seen' found"); + $node->{$direction} = $nodes{$node_seen}; + } + else + { + delete $node->{$direction}; + } + } + } + } + + # find section preceding and following top + my $section_before_top; # section preceding the top node + my $section_after_top; # section following the top node + if ($node_top) + { + my $previous_is_top = 0; + foreach my $element (@all_elements) + { + if ($element eq $node_top) + { + $previous_is_top = 1; + next; + } + if ($previous_is_top) + { + if ($element->{'section'}) + { + $section_after_top = $element; + last; + } + next; + } + $section_before_top = $element if ($element->{'section'}); + } + } + print STDERR "# section before Top: $section_before_top->{'texi'}\n" + if ($section_before_top and ($T2H_DEBUG & $DEBUG_ELEMENTS)); + print STDERR "# section after Top: $section_after_top->{'texi'}\n" + if ($section_after_top and ($T2H_DEBUG & $DEBUG_ELEMENTS)); + + print STDERR "# Build the elements list\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + if (!$Texi2HTML::Config::USE_NODES) + { + #the only sectionning elements are sections + @elements_list = @sections_list; + # if there is no section we use nodes... + if (!@elements_list) + { + print STDERR "# no section\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + @elements_list = @all_elements; + } + elsif (!$section_top and $node_top and !$node_top->{'with_section'}) + { # special case for the top node if it isn't associated with + # a section. The top node element is inserted between the + # $section_before_top and the $section_after_top + print STDERR "# Top not associated with a section\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + $node_top->{'top_as_section'} = 1; + $node_top->{'section_ref'} = $node_top; + my @old_element_lists = @elements_list; + @elements_list = (); + while (@old_element_lists) + { + my $section = shift @old_element_lists; + if ($section_before_top and ($section eq $section_before_top)) + { + push @elements_list, $section; + push @elements_list, $node_top; + last; + } + elsif ($section_after_top and ($section eq $section_after_top)) + { + push @elements_list, $node_top; + push @elements_list, $section; + last; + } + push @elements_list, $section; + } + push @elements_list, @old_element_lists; + } + + foreach my $element (@elements_list) + { + print STDERR "# new section element $element->{'texi'}\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + } + } + else + { + # elements are sections if possible, and node if no section associated + foreach my $element(@all_elements) + { + if ($element->{'node'}) + { + if (!defined($element->{'with_section'})) + { + $element->{'toc_level'} = $MIN_LEVEL if (!defined($element->{'toc_level'})); + print STDERR "# new node element ($element) $element->{'texi'}\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + push @elements_list, $element; + } + } + else + { + print STDERR "# new section element ($element) $element->{'texi'}\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + push @elements_list, $element; + } + } + } + + # nodes are attached to the section preceding them if not allready + # associated with a section + # here we don't set @{$element->{'nodes'}} since it may be changed + # below if split by indices. Therefore we only set + # @{$element->{'all_elements'}} with all the elements associated + # with an element output, in the right order + print STDERR "# Find the section associated with each node\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + my $current_section = $sections_list[0]; + $current_section = $node_top if ($node_top and $node_top->{'top_as_section'} and !$section_before_top); + foreach my $element (@all_elements) + { + if ($element->{'node'} and !$element->{'top_as_section'}) + { + if ($element->{'with_section'}) + { # the node is associated with a section + $element->{'section_ref'} = $element->{'with_section'}; + push @{$element->{'section_ref'}->{'all_elements'}}, $element, $element->{'section_ref'}; + # first index is section if the first index is associated with that node + $element_index = $element->{'section_ref'} if ($element_index and ($element_index eq $element)); + } + elsif (defined($current_section)) + {# node appearing after a section, but not before another section, + # or appearing before any section + $element->{'section_ref'} = $current_section; + $element->{'toc_level'} = $current_section->{'toc_level'}; + push @{$current_section->{'node_childs'}}, $element; + if ($Texi2HTML::Config::USE_NODES) + { # the node is an element itself + push @{$element->{'all_elements'}}, $element; + } + else + { + push @{$current_section->{'all_elements'}}, $element; + # first index is section if the first index is associated with that node + $element_index = $current_section if ($element_index and ($element_index eq $element)); + } + } + else + { # seems like there are only nodes in the documents + $element->{'toc_level'} = $MIN_LEVEL; + push @{$element->{'all_elements'}}, $element; + } + } + else + { + $current_section = $element; + if ($element->{'node'}) + { # Top node not associated with a section + $element->{'toc_level'} = $MIN_LEVEL; + push @{$element->{'section_ref'}->{'all_elements'}}, $element; + } + elsif (!$element->{'node_ref'}) + { # a section not preceded by a node + push @{$element->{'all_elements'}}, $element; + } + } + } + + # find first, last and top elements + $element_first = $elements_list[0]; + print STDERR "# element first: $element_first->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + print STDERR "# top node: $node_top->{'texi'}\n" if (defined($node_top) and + ($T2H_DEBUG & $DEBUG_ELEMENTS)); + # element top is the element with @top. + $element_top = $section_top; + # If the top node is associated with a section it is the top_element + # otherwise element top may be the top node + $element_top = $node_top if (!defined($element_top) and defined($node_top)); + # If there is no @top section no top node the first node is the top element + $element_top = $element_first unless (defined($element_top)); + $element_top->{'top'} = 1 if ($element_top->{'node'}); + print STDERR "# element top: $element_top->{'texi'}\n" if ($element_top and + ($T2H_DEBUG & $DEBUG_ELEMENTS)); + + # It is the last element before indices split, which may add new + # elements + $element_last = $elements_list[-1]; + + print STDERR "# Complete nodes next prev and up based on menus and sections\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + # set the default id based on the node number + my $node_nr = 1; + # find the node* directions + # find the directions corresponding with sections + # and set 'up' for the node + foreach my $node (@nodes_list) + { + # first a warning if the node and the equivalent nodes don't + # appear in menus + if (!$node->{'first'} and !$node->{'top'} and !$node->{'menu_up'} and ($node->{'texi'} !~ /^top$/i) and $Texi2HTML::Config::SHOW_MENU) + { + my @equivalent_nodes = equivalent_nodes($node->{'texi'}); + my $found = 0; + foreach my $equivalent_node (@equivalent_nodes) + { + if ($nodes{$equivalent_node}->{'first'} or $nodes{$equivalent_node}->{'menu_up'}) + { + $found = 1; + last; + } + } + unless ($found) + { + warn "$WARN `$node->{'texi'}' doesn't appear in menus\n"; + } + } + + # use values deduced from menus to complete missing up, next, prev + # or from sectionning commands if automatic sectionning + if ($node->{'node_up'}) + { + $node->{'nodeup'} = $node->{'node_up'}; + } + elsif ($node->{'automatic_directions'} and $node->{'section_ref'}) + { + if (defined($node_top) and ($node eq $node_top)) + { # Top node has a special up, which is (dir) by default + my $top_nodeup = $Texi2HTML::Config::TOP_NODE_UP; + if (exists($nodes{$top_nodeup})) + { + $node->{'nodeup'} = $nodes{$top_nodeup}; + } + else + { + my $node_ref = { 'texi' => $top_nodeup }; + $node_ref->{'external_node'} = 1; + $nodes{$top_nodeup} = $node_ref; + $node->{'nodeup'} = $node_ref; + } + } + elsif (defined($node->{'section_ref'}->{'sectionup'})) + { + $node->{'nodeup'} = get_node($node->{'section_ref'}->{'sectionup'}); + } + elsif ($node->{'section_ref'}->{'toplevel'} and ($node->{'section_ref'} ne $element_top)) + { + $node->{'nodeup'} = get_node($element_top); + } + print STDERR "# Deducing from section node_up $node->{'nodeup'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS and defined($node->{'nodeup'})); + } + + if (!$node->{'nodeup'} and $node->{'menu_up'} and $Texi2HTML::Config::USE_MENU_DIRECTIONS) + { # makeinfo don't do that + $node->{'nodeup'} = $node->{'menu_up'}; + print STDERR "# Deducing from menu node_up $node->{'menu_up'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + } + + if ($node->{'nodeup'} and !$node->{'nodeup'}->{'external_node'}) + { + # We detect when the up node has no menu entry for that node, as + # there may be infinite loops when finding following node (see below) + unless (defined($node->{'menu_up_hash'}) and ($node->{'menu_up_hash'}->{$node->{'nodeup'}->{'texi'}})) + { + print STDERR "$WARN `$node->{'nodeup'}->{'texi'}' is up for `$node->{'texi'}', but has no menu entry for this node\n" if ($Texi2HTML::Config::SHOW_MENU); + push @{$node->{'up_not_in_menu'}}, $node->{'nodeup'}->{'texi'}; + } + } + + # Find next node + if ($node->{'node_next'}) + { + $node->{'nodenext'} = $node->{'node_next'}; + } + elsif ($node->{'texi'} eq 'Top') + { # special case as said in the texinfo manual + $node->{'nodenext'} = $node->{'menu_child'} if ($node->{'menu_child'}); + } + elsif ($node->{'automatic_directions'}) + { + if (defined($node->{'section_ref'})) + { + my $next; + my $section = $node->{'section_ref'}; + if (defined($section->{'sectionnext'})) + { + $next = get_node($section->{'sectionnext'}) + } + else + { + while (defined($section->{'sectionup'}) and !defined($section->{'sectionnext'})) + { + $section = $section->{'sectionup'}; + } + if (defined($section->{'sectionnext'})) + { + $next = get_node($section->{'sectionnext'}); + } + } + $node->{'nodenext'} = $next; + } + } + # next we try menus. makeinfo don't do that + if (!defined($node->{'nodenext'}) and $node->{'menu_next'} + and $Texi2HTML::Config::USE_MENU_DIRECTIONS) + { + $node->{'nodenext'} = $node->{'menu_next'}; + } + # Find prev node + if ($node->{'node_prev'}) + { + $node->{'nodeprev'} = $node->{'node_prev'}; + } + elsif ($node->{'automatic_directions'}) + { + if (defined($node->{'section_ref'})) + { + my $section = $node->{'section_ref'}; + if (defined($section->{'sectionprev'})) + { + $node->{'nodeprev'} = get_node($section->{'sectionprev'}); + } + elsif (defined($section->{'sectionup'})) + { + $node->{'nodeprev'} = get_node($section->{'sectionup'}); + } + } + } + # next we try menus. makeinfo don't do that + if (!defined($node->{'nodeprev'}) and $node->{'menu_prev'} and $Texi2HTML::Config::USE_MENU_DIRECTIONS) + { + $node->{'nodeprev'} = $node->{'menu_prev'}; + } + # the prev node is the parent node + elsif (!defined($node->{'nodeprev'}) and $node->{'menu_up'} and $Texi2HTML::Config::USE_MENU_DIRECTIONS) + { + $node->{'nodeprev'} = $node->{'menu_up'}; + } + + # the following node is the node following in node reading order + # it is thus first the child, else the next, else the next following + # the up + if ($node->{'menu_child'}) + { + $node->{'following'} = $node->{'menu_child'}; + } + elsif ($node->{'automatic_directions'} and defined($node->{'section_ref'}) and defined($node->{'section_ref'}->{'child'})) + { + $node->{'following'} = get_node($node->{'section_ref'}->{'child'}); + } + elsif (defined($node->{'nodenext'})) + { + $node->{'following'} = $node->{'nodenext'}; + } + else + { + my $up = $node->{'nodeup'}; + # in order to avoid infinite recursion in case the up node is the + # node itself we use the up node as following when there isn't + # a correct menu structure, here and also below. + $node->{'following'} = $up if (defined($up) and grep {$_ eq $up->{'texi'}} @{$node->{'up_not_in_menu'}}); + while ((!defined($node->{'following'})) and (defined($up))) + { + if (($node_top) and ($up eq $node_top)) + { # if we are at Top, Top is following + $node->{'following'} = $node_top; + $up = undef; + } + if (defined($up->{'nodenext'})) + { + $node->{'following'} = $up->{'nodenext'}; + } + elsif (defined($up->{'nodeup'})) + { + if (! grep { $_ eq $up->{'nodeup'}->{'texi'} } @{$node->{'up_not_in_menu'}}) + { + $up = $up->{'nodeup'}; + } + else + { # in that case we can go into a infinite loop + $node->{'following'} = $up->{'nodeup'}; + } + } + else + { + $up = undef; + } + } + } + + if (defined($node->{'section_ref'})) + { + my $section = $node->{'section_ref'}; + foreach my $direction ('sectionnext', 'sectionprev', 'sectionup') + { + $node->{$direction} = $section->{$direction} + if (defined($section->{$direction})); + } + # this is a node appearing within a section but not associated + # with that section. We consider that it is below that section. + $node->{'sectionup'} = $section + if (grep {$node eq $_} @{$section->{'node_childs'}}); + } + # 'up' is used in .init files. Maybe should go away. + if (defined($node->{'sectionup'})) + { + $node->{'up'} = $node->{'sectionup'}; + } + elsif (defined($node->{'nodeup'}) and + (!$node_top or ($node ne $node_top))) + { + $node->{'up'} = $node->{'nodeup'}; + } + # 'next' not used but documented. + if (defined($node->{'sectionnext'})) + { + $node->{'next'} = $node->{'sectionnext'}; + } + if (defined($node->{'sectionprev'})) + { + $node->{'prev'} = $node->{'sectionprev'}; + } + + # default id for nodes. Should be overriden later. + $node->{'id'} = 'NOD' . $node_nr; + $node_nr++; + } + + print STDERR "# find forward and back\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + my $prev; + foreach my $element (@elements_list) + { + $element->{'element'} = 1; + # complete the up for toplevel elements now that element_top is defined + print STDERR "# fwd and back for $element->{'texi'}\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + # at that point no node may be toplevel, only sections. + if ($element->{'toplevel'} and ($element ne $element_top)) + { + $element->{'sectionup'} = $element_top; + $element->{'up'} = $element_top; + } + if ($prev) + { + $element->{'back'} = $prev; + $prev->{'forward'} = $element; + $prev = $element; + } + else + { + $prev = $element; + } + # If the element is not a node, then all the node directions are copied + # if there is an associated node + if (defined($element->{'node_ref'})) + { + $element->{'nodenext'} = $element->{'node_ref'}->{'nodenext'}; + $element->{'nodeprev'} = $element->{'node_ref'}->{'nodeprev'}; + $element->{'menu_next'} = $element->{'node_ref'}->{'menu_next'}; + $element->{'menu_prev'} = $element->{'node_ref'}->{'menu_prev'}; + $element->{'menu_child'} = $element->{'node_ref'}->{'menu_child'}; + $element->{'menu_up'} = $element->{'node_ref'}->{'menu_up'}; + $element->{'nodeup'} = $element->{'node_ref'}->{'nodeup'}; + $element->{'following'} = $element->{'node_ref'}->{'following'}; + } + elsif (! $element->{'node'}) + { # the section has no node associated. Find the node directions using + # sections + if (defined($element->{'sectionnext'})) + { + $element->{'nodenext'} = get_node($element->{'sectionnext'}); + } + if (defined($element->{'sectionprev'})) + { + $element->{'nodeprev'} = get_node($element->{'sectionprev'}); + } + if (defined($element->{'up'})) + { + $element->{'nodeup'} = get_node($element->{'up'}); + } + if ($element->{'child'}) + { + $element->{'following'} = get_node($element->{'child'}); + } + elsif ($element->{'sectionnext'}) + { + $element->{'following'} = get_node($element->{'sectionnext'}); + } + elsif ($element->{'up'}) + { + my $up = $element; + while ($up->{'up'} and !$element->{'following'}) + { + print STDERR "# Going up, searching next section from $up->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + $up = $up->{'up'}; + if ($up->{'sectionnext'}) + { + $element->{'following'} = get_node ($up->{'sectionnext'}); + } + # avoid infinite loop if the top is up for itself + last if ($up->{'toplevel'} or $up->{'top'}); + } + } + } + } + + my @new_elements = (); + print STDERR "# preparing indices\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + + while(@elements_list) + { + my $element = shift @elements_list; + # current_element is the last element which can hold text. It is + # initialized to a fake element + my $current_element = { 'holder' => 1, 'texi' => 'HOLDER', + 'place' => [], 'indices' => [] }; + # $back, $forward and $sectionnext are kept because $element + # is in @{$element->{'all_elements'}}, so it is possible that + # those directions get changed. + # back is set to find back and forward + my $back = $element->{'back'} if defined($element->{'back'}); + my $forward = $element->{'forward'}; + my $sectionnext = $element->{'sectionnext'}; + my $index_num = 0; + my @waiting_elements = (); # elements (nodes) not used for sectionning + # waiting to be associated with an element + foreach my $checked_element(@{$element->{'all_elements'}}) + { + if ($checked_element->{'element'}) + { # this is the element, we must add it + push @new_elements, $checked_element; + if ($current_element->{'holder'}) + { # no previous element added + push @{$checked_element->{'place'}}, @{$current_element->{'place'}}; + foreach my $index(@{$current_element->{'indices'}}) + { + push @{$checked_element->{'indices'}}, [ { 'element' => $checked_element, 'page' => $index->[0]->{'page'}, 'name' => $index->[0]->{'name'} } ] ; + } + } + else + { + $current_element->{'sectionnext'} = $checked_element; + $current_element->{'following'} = $checked_element; + $checked_element->{'sectionprev'} = $current_element; + } + $current_element = $checked_element; + $checked_element->{'back'} = $back; + $back->{'forward'} = $checked_element if (defined($back)); + $back = $checked_element; + push @{$checked_element->{'nodes'}}, @waiting_elements; + @waiting_elements = (); + } + elsif ($current_element->{'holder'}) + { + push @waiting_elements, $checked_element; + } + else + { + push @{$current_element->{'nodes'}}, $checked_element; + $checked_element->{'section_ref'} = $current_element; + } + push @{$current_element->{'place'}}, @{$checked_element->{'current_place'}}; + foreach my $index (@{$checked_element->{'index_names'}}) + { + print STDERR "# Index in `$checked_element->{'texi'}': $index->{'name'}. Current is `$current_element->{'texi'}'\n" + if ($T2H_DEBUG & $DEBUG_INDEX); + my ($pages, $entries) = get_index($index->{'name'}); + if (defined($pages)) + { + my @pages = @$pages; + my $first_page = shift @pages; + ############################## begin debug section + my $back_texi = 'NO_BACK'; + $back_texi = $back->{'texi'} if (defined($back)); + print STDERR "# Index first page (back `$back_texi', in `$current_element->{'texi'}')\n" if ($T2H_DEBUG & $DEBUG_INDEX); + ############################## end debug section + push @{$current_element->{'indices'}}, [ {'element' => $current_element, 'page' => $first_page, 'name' => $index->{'name'} } ]; + if (@pages) + {# index is split accross more than one page + if ($current_element->{'holder'}) + { # the current element isn't an element which is + # normally outputted. We add a real element. + # we are in a node of a section but the element + # is split by the index, thus we must add + # a new element which will contain the text + # between the beginning of the element and the index + # WARNING the added element is like a section, and + # indeed it is a 'section_ref' and 'sectionup' + # for other nodes, it has 'nodes' + # (see below and above). + # But it is also a node. It may have a 'with_section' + # and have a 'section_ref' + # it may be considered 'node_ref' for a section. + # and the Texi2HTML::NODE is relative to this + # added element. + + push @new_elements, $checked_element; + print STDERR "# Add `$checked_element->{'texi'}' before index page for `$element->{'texi'}'\n" + if ($T2H_DEBUG & $DEBUG_INDEX); + echo_warn("Add `$checked_element->{'texi'}' for indicing"); + $checked_element->{'element'} = 1; + $checked_element->{'level'} = $element->{'level'}; + $checked_element->{'toc_level'} = $element->{'toc_level'}; + $checked_element->{'toplevel'} = $element->{'toplevel'}; + if ($element->{'top'}) + { + $checked_element->{'toplevel'} = 1; + $checked_element->{'top'} = 1; + } + $checked_element->{'up'} = $element->{'up'}; + $checked_element->{'sectionup'} = $element->{'sectionup'}; + $checked_element->{'element_added'} = 1; + print STDERR "Bug: checked element wasn't seen" if + (!$checked_element->{'seen'}); + $element->{'sectionprev'}->{'sectionnext'} = $checked_element if (exists($element->{'sectionprev'})); + push @{$checked_element->{'place'}}, @{$current_element->{'place'}}; + foreach my $index(@{$current_element->{'indices'}}) + { + push @{$checked_element->{'indices'}}, [ { 'element' => $checked_element, 'page' => $index->[0]->{'page'}, 'name' => $index->[0]->{'name'} } ] ; + } + foreach my $waiting_element (@waiting_elements) + { + next if ($waiting_element eq $checked_element); + $waiting_element->{'section_ref'} = $checked_element; + $waiting_element->{'sectionup'} = $checked_element; + push @{$checked_element->{'nodes'}}, $waiting_element; + } + @waiting_elements = (); + $checked_element->{'back'} = $back; + $back->{'forward'} = $checked_element if (defined($back)); + $current_element = $checked_element; + $back = $checked_element; + } + my $index_page; + while(@pages) + { + print STDERR "# New page (back `$back->{'texi'}', current `$current_element->{'texi'}')\n" if ($T2H_DEBUG & $DEBUG_INDEX); + $index_num++; + my $page = shift @pages; + $index_page = { 'index_page' => 1, + 'texi' => "NOT REALLY USED: $current_element->{'texi'}' index $index->{'name'} page $index_num", + 'level' => $element->{'level'}, + 'tag' => $element->{'tag'}, + 'tag_level' => $element->{'tag_level'}, + 'toplevel' => $element->{'toplevel'}, + 'top' => $element->{'top'}, + 'up' => $element->{'up'}, + 'sectionup' => $element->{'sectionup'}, + 'back' => $back, + 'prev' => $back, + 'sectionnext' => $sectionnext, + 'following' => $current_element->{'following'}, + 'nodeup' => $current_element->{'nodeup'}, + 'nodenext' => $current_element->{'nodenext'}, + 'nodeprev' => $back, + 'place' => [], + 'seen' => 1, + 'page' => $page + }; + # the index page is associated with the new element + # if there is one, the element otherwise + if ($checked_element->{'element_added'}) + { + $index_page->{'original_index_element'} = $checked_element; + } + else + { + $index_page->{'original_index_element'} = $element; + } + $index_page->{'node'} = 1 if ($element->{'node'}); + while ($nodes{$index_page->{'texi'}}) + { + $nodes{$index_page->{'texi'}} .= ' '; + } + $nodes{$index_page->{'texi'}} = $index_page; + push @{$current_element->{'indices'}->[-1]}, {'element' => $index_page, 'page' => $page, 'name' => $index->{'name'} }; + push @new_elements, $index_page; + $back->{'forward'} = $index_page; + $back->{'nodenext'} = $index_page; + $back->{'sectionnext'} = $index_page unless ($back->{'top'}); + $back->{'following'} = $index_page; + $back = $index_page; + $index_page->{'toplevel'} = 1 if ($element->{'top'}); + } + $current_element = $index_page; + } + } + else + { + print STDERR "# Empty index: $index->{'name'}\n" + if ($T2H_DEBUG & $DEBUG_INDEX); + $empty_indices{$index->{'name'}} = 1; + } + push @{$current_element->{'place'}}, @{$index->{'place'}}; + } + } + if ($forward and ($current_element ne $element)) + { + $current_element->{'forward'} = $forward; + $forward->{'back'} = $current_element; + } + next if ($current_element eq $element or !$element->{'toplevel'}); + # reparent the elements below $element to the last index page + print STDERR "# Reparent for `$element->{'texi'}':\n" if ($T2H_DEBUG & $DEBUG_INDEX); + foreach my $reparented(@{$element->{'section_childs'}},@{$element->{'node_childs'}}) + { + $reparented->{'sectionup'} = $current_element; + print STDERR " reparented: $reparented->{'texi'}\n" + if ($T2H_DEBUG & $DEBUG_INDEX); + } + } + @elements_list = @new_elements; + + print STDERR "# find fastback and fastforward\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + foreach my $element (@elements_list) + { + my $up = get_top($element); + next unless (defined($up)); + $element_chapter_index = $up if ($element_index and ($element_index eq $element)); + # fastforward is the next element on same level than the upper parent + # element + $element->{'fastforward'} = $up->{'sectionnext'} if (exists ($up->{'sectionnext'})); + # if the element isn't at the highest level, fastback is the + # highest parent element + if ($up and ($up ne $element)) + { + $element->{'fastback'} = $up; + } + elsif ($element->{'toplevel'}) + { + # the element is a top level element, we adjust the next + # toplevel element fastback + $element->{'fastforward'}->{'fastback'} = $element if ($element->{'fastforward'}); + } + } + + # set 'reference_element' which is used each time there is a cross ref + # to that node. + # It is the section associated with the node except if USE_NODES + unless ($Texi2HTML::Config::USE_NODES) + { + foreach my $node(@nodes_list) + { + if ($node->{'with_section'}) + { + $node->{'reference_element'} = $node->{'with_section'}; + } + } + } + + my $index_nr = 0; + # convert directions in direction with first letter in all caps, to be + # consistent with the convention used in the .init file. + # find id for nodes and indices + foreach my $element (@elements_list) + { + $element->{'this'} = $element; + foreach my $direction (@element_directions) + { + my $direction_no_caps = $direction; + $direction_no_caps =~ tr/A-Z/a-z/; + $element->{$direction} = $element->{$direction_no_caps}; + } + if ($element->{'index_page'}) + { + $element->{'id'} = "INDEX" . $index_nr; + $index_nr++; + } + } + + print STDERR "# find float id\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + foreach my $float (@floats) + { + $float->{'style_id'} = cross_manual_line(normalise_space($float->{'style_texi'})); + my $float_style = { }; + if (exists($floats{$float->{'style_id'}})) + { + $float_style = $floats{$float->{'style_id'}}; + } + else + { + $floats{$float->{'style_id'}} = $float_style; + } + push @{$float_style->{'floats'}}, $float; + $float->{'absolute_nr'} = scalar(@{$float_style->{'floats'}}); + my $up = get_top($float->{'element'}); + if (defined($up) and (!defined($float_style->{'current_chapter'}) or ($up->{'texi'} ne $float_style->{'current_chapter'}))) + { + $float_style->{'current_chapter'} = $up->{'texi'}; + $float_style->{'nr_in_chapter'} = 1; + } + else + { + $float_style->{'nr_in_chapter'}++; + } + if (defined($up) and $up->{'number'} ne '') + { + $float->{'chapter_nr'} = $up->{'number'}; + $float->{'nr'} = $float->{'chapter_nr'} . $float_style->{'nr_in_chapter'}; + } + else + { + $float->{'nr'} = $float->{'absolute_nr'}; + } + } + + if ($Texi2HTML::Config::NEW_CROSSREF_STYLE) + { + foreach my $key (keys(%nodes)) + { + my $node = $nodes{$key}; + next if ($node->{'external_node'} or $node->{'index_page'}); + $node->{'id'} = node_to_id($node->{'cross_manual_target'}); + } + } + + # Find node file names and file names for nodes considered as elements + my $node_as_top; + if ($node_top) + { + $node_as_top = $node_top; + } + elsif ($element_top->{'node_ref'}) + { + $node_as_top = $element_top->{'node_ref'}; + } + else + { + $node_as_top = $node_first; + } + if ($node_as_top) + { + my $node_file; + $node_file = &$Texi2HTML::Config::node_file_name($node_as_top,'top'); + $node_as_top->{'node_file'} = $node_file if (defined($node_file)); + } + foreach my $key (keys(%nodes)) + { + my $node = $nodes{$key}; + next if (defined($node_as_top) and ($node eq $node_as_top)); + my $node_file = &$Texi2HTML::Config::node_file_name($node,''); + $node->{'node_file'} = $node_file if (defined($node_file)); + } + + print STDERR "# split and set files\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + # find document nr and document file for sections and nodes. + # Split according to Texi2HTML::Config::SPLIT. + # find file and id for placed elements (anchors, index entries, headings) + if ($Texi2HTML::Config::SPLIT) + { + my $cut_section = $toplevel; + my $doc_nr = -1; + if ($Texi2HTML::Config::SPLIT eq 'section') + { + $cut_section = 2 if ($toplevel <= 2); + } + my $previous_file; + foreach my $element (@elements_list) + { + print STDERR "# Splitting ($Texi2HTML::Config::SPLIT:$cut_section) $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + my $new_file = 0; + if ( + ($Texi2HTML::Config::SPLIT eq 'node') or + ( + defined($element->{'level'}) and ($element->{'level'} <= $cut_section) + ) + ) + { + $new_file = 1; + $doc_nr++; + } + $doc_nr = 0 if ($doc_nr < 0); # happens if first elements are nodes + $element->{'doc_nr'} = $doc_nr; + my $is_top = ''; + $element->{'file'} = "${docu_name}_$doc_nr" + . ($docu_ext ? ".$docu_ext" : ""); + if ($element->{'top'} or (defined($element->{'node_ref'}) and $element->{'node_ref'} eq $element_top)) + { # the top elements + $is_top = "top"; + $element->{'file'} = $docu_top; + } + elsif ($Texi2HTML::Config::NODE_FILES) + { + if ($new_file) + { + my $node = get_node($element) unless(exists($element->{'node_ref'}) + and $element->{'node_ref'}->{'element_added'}); + if ($node and defined($node->{'node_file'})) + { + $element->{'file'} = $node->{'node_file'}; + } + $previous_file = $element->{'file'}; + } + elsif($previous_file) + { + $element->{'file'} = $previous_file; + } + } + if (defined($Texi2HTML::Config::element_file_name)) + { + my $filename = + &$Texi2HTML::Config::element_file_name ($element, $is_top, $docu_name); + $element->{'file'} = $filename if (defined($filename)); + } + print STDERR "# add_file $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + add_file($element->{'file'}); + foreach my $place(@{$element->{'place'}}) + { + $place->{'file'} = $element->{'file'}; + $place->{'id'} = $element->{'id'} unless defined($place->{'id'}); + } + if ($element->{'nodes'}) + { + foreach my $node (@{$element->{'nodes'}}) + { + $node->{'doc_nr'} = $element->{'doc_nr'}; + $node->{'file'} = $element->{'file'}; + } + } + } + } + else + { # not split + add_file($docu_doc); + foreach my $element(@elements_list) + { + $element->{'file'} = $docu_doc; + $element->{'doc_nr'} = 0; + foreach my $place(@{$element->{'place'}}) + { + $place->{'file'} = $element->{'file'}; + $place->{'id'} = $element->{'id'} unless defined($place->{'id'}); + } + } + foreach my $node(@nodes_list) + { + $node->{'file'} = $docu_doc; + $node->{'doc_nr'} = 0; + } + } + # correct the id and file for the things placed in footnotes + foreach my $place(@{$footnote_element->{'place'}}) + { + $place->{'file'} = $footnote_element->{'file'}; + $place->{'id'} = $footnote_element->{'id'} unless defined($place->{'id'}); + } + # if setcontentsaftertitlepage is set, the contents should be associated + # with the titlepage. That's wat is done there. + push @$region_place, $content_element{'contents'} + if ($Texi2HTML::Config::DO_CONTENTS and $Texi2HTML::THISDOC{'setcontentsaftertitlepage'}); + push @$region_place, $content_element{'shortcontents'} + if ($Texi2HTML::Config::DO_SCONTENTS and $Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'}); + # correct the id and file for the things placed in regions (copying...) + foreach my $place(@$region_place) + { +#print STDERR "entry $place->{'entry'} texi $place->{'texi'}\n"; + $place->{'file'} = $element_top->{'file'}; + $place->{'id'} = $element_top->{'id'} unless defined($place->{'id'}); + $place->{'element'} = $element_top if (exists($place->{'element'})); + } + foreach my $content_type(keys(%content_element)) + { + if (!defined($content_element{$content_type}->{'file'})) + { + print STDERR "# No content $content_type\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + $content_element{$content_type} = undef; + } + } + + ########################### debug prints + foreach my $file (keys(%files)) + { + last unless ($T2H_DEBUG & $DEBUG_ELEMENTS); + print STDERR "$file: counter $files{$file}->{'counter'}\n"; + } + foreach my $element ((@elements_list, $footnote_element)) + { + last unless ($T2H_DEBUG & $DEBUG_ELEMENTS); + my $is_toplevel = 'not toplevel'; + $is_toplevel = 'toplevel' if ($element->{'toplevel'}); + print STDERR "$element "; + if ($element->{'index_page'}) + { + print STDERR "index($element->{'id'}, $is_toplevel, doc_nr $element->{'doc_nr'}($element->{'file'})): $element->{'texi'}\n"; + } + elsif ($element->{'node'}) + { + print STDERR "node($element->{'id'}, toc_level $element->{'toc_level'}, $is_toplevel, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n"; + print STDERR " section_ref: $element->{'section_ref'}->{'texi'}\n" if (defined($element->{'section_ref'})); + } + elsif ($element->{'footnote'}) + { + print STDERR "footnotes($element->{'id'}, file $element->{'file'})\n"; + } + else + { + my $number = "UNNUMBERED"; + $number = $element->{'number'} if ($element->{'number'}); + print STDERR "$number ($element->{'id'}, $is_toplevel, level $element->{'level'}-$element->{'toc_level'}, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n"; + print STDERR " node_ref: $element->{'node_ref'}->{'texi'}\n" if (defined($element->{'node_ref'})); + } + + if (!$element->{'footnote'}) + { + if (!defined($files{$element->{'file'}})) + { + die "Bug: files{\$element->{'file'}} undef element $element->{'texi'}, file $element->{'file'}."; + } + print STDERR " file: $element->{'file'} $files{$element->{'file'}}, counter $files{$element->{'file'}}->{'counter'}\n"; + } + print STDERR " TOP($toplevel) " if ($element->{'top'}); + print STDERR " u: $element->{'up'}->{'texi'}\n" if (defined($element->{'up'})); + print STDERR " ch: $element->{'child'}->{'texi'}\n" if (defined($element->{'child'})); + print STDERR " fb: $element->{'fastback'}->{'texi'}\n" if (defined($element->{'fastback'})); + print STDERR " b: $element->{'back'}->{'texi'}\n" if (defined($element->{'back'})); + print STDERR " p: $element->{'prev'}->{'texi'}\n" if (defined($element->{'prev'})); + print STDERR " n: $element->{'sectionnext'}->{'texi'}\n" if (defined($element->{'sectionnext'})); + print STDERR " n_u: $element->{'nodeup'}->{'texi'}\n" if (defined($element->{'nodeup'})); + print STDERR " f: $element->{'forward'}->{'texi'}\n" if (defined($element->{'forward'})); + print STDERR " follow: $element->{'following'}->{'texi'}\n" if (defined($element->{'following'})); + print STDERR " m_p: $element->{'menu_prev'}->{'texi'}\n" if (defined($element->{'menu_prev'})); + print STDERR " m_n: $element->{'menu_next'}->{'texi'}\n" if (defined($element->{'menu_next'})); + print STDERR " m_u: $element->{'menu_up'}->{'texi'}\n" if (defined($element->{'menu_up'})); + print STDERR " m_ch: $element->{'menu_child'}->{'texi'}\n" if (defined($element->{'menu_child'})); + print STDERR " ff: $element->{'fastforward'}->{'texi'}\n" if (defined($element->{'fastforward'})); + if (defined($element->{'menu_up_hash'})) + { + print STDERR " parent nodes:\n"; + foreach my $menu_up (keys%{$element->{'menu_up_hash'}}) + { + print STDERR " $menu_up ($element->{'menu_up_hash'}->{$menu_up})\n"; + } + } + if (defined($element->{'nodes'})) + { + print STDERR " nodes: $element->{'nodes'} (@{$element->{'nodes'}})\n"; + foreach my $node (@{$element->{'nodes'}}) + { + my $beginning = " "; + $beginning = " *" if ($node->{'with_section'}); + my $file = $node->{'file'}; + $file = "file undef" if (! defined($node->{'file'})); + print STDERR "${beginning}$node->{'texi'} $file\n"; + } + } + print STDERR " places: $element->{'place'}\n"; + foreach my $place(@{$element->{'place'}}) + { + if (!$place->{'entry'} and !$place->{'float'} and !$place->{'texi'} and !$place->{'contents'} and !$place->{'shortcontents'}) + { + print STDERR "BUG: unknown placed stuff ========\n"; + foreach my $key (keys(%$place)) + { + print STDERR "$key: $place->{$key}\n"; + } + print STDERR "==================================\n"; + } + elsif ($place->{'entry'}) + { + print STDERR " index($place): $place->{'entry'}\n"; + } + elsif ($place->{'anchor'}) + { + print STDERR " anchor: $place->{'texi'}\n"; + } + elsif ($place->{'float'}) + { + if (defined($place->{'texi'})) + { + print STDERR " float($place): $place->{'texi'}\n"; + } + else + { + print STDERR " float($place): NO LABEL\n"; + } + } + elsif ($place->{'contents'}) + { + print STDERR " contents\n"; + } + elsif ($place->{'shortcontents'}) + { + print STDERR " shortcontents\n"; + } + else + { + print STDERR " heading: $place->{'texi'}\n"; + } + } + if ($element->{'indices'}) + { + print STDERR " indices: $element->{'indices'}\n"; + foreach my $index(@{$element->{'indices'}}) + { + print STDERR " $index: "; + foreach my $page (@$index) + { + print STDERR "'$page->{'element'}->{'texi'}'($page->{'name'}): $page->{'page'} "; + } + print STDERR "\n"; + } + } + } + ########################### end debug prints +} + +sub add_file($) +{ + my $file = shift; + if ($files{$file}) + { + $files{$file}->{'counter'}++; + } + else + { + $files{$file} = { + #'type' => 'section', + 'counter' => 1, + 'relative_foot_num' => 1, + 'foot_lines' => [] + }; + } +} + +# find parent element which is a top element, or a node within the top section +sub get_top($) +{ + my $element = shift; + my $up = $element; + while (!$up->{'toplevel'} and !$up->{'top'}) + { + $up = $up->{'sectionup'}; + if (!defined($up)) + { + # If there is no section, it is normal not to have toplevel element, + # and it is also the case if there is a low level element before + # a top level element + return undef; + } + } + return $up; +} + +sub get_node($) +{ + my $element = shift; + return undef if (!defined($element)); + return $element if ($element->{'node'}); + return $element->{'node_ref'} if ($element->{'node_ref'}); + return $element; +} +# get the html names from the texi for all elements +sub do_names() +{ + print STDERR "# Doing ". scalar(keys(%nodes)) . " nodes, ". + scalar(keys(%sections)) . " sections in ". $#elements_list . + " elements\n" if ($T2H_DEBUG); + # for nodes and anchors we haven't any state defined + # This seems right, however, as we don't want @refs or @footnotes + # or @anchors within nodes, section commands or anchors. + foreach my $node (keys(%nodes)) + { + next if ($nodes{$node}->{'index_page'}); # some nodes are index pages. + my $texi = &$Texi2HTML::Config::heading_texi($nodes{$node}->{'tag'}, + $nodes{$node}->{'texi'}, undef); + $nodes{$node}->{'text'} = substitute_line ($texi); + $nodes{$node}->{'text_nonumber'} = $nodes{$node}->{'text'}; + # backward compatibility + $nodes{$node}->{'name'} = $nodes{$node}->{'text_nonumber'}; + $nodes{$node}->{'no_texi'} = remove_texi($texi); + $nodes{$node}->{'simple_format'} = simple_format(undef, $texi); + $nodes{$node}->{'heading_texi'} = $texi; + # FIXME : what to do if $nodes{$node}->{'external_node'} and + # $nodes{$node}->{'seen'} + } + foreach my $number (keys(%sections)) + { + my $section = $sections{$number}; + #$section->{'name'} = substitute_line($section->{'texi'}); + my $texi = &$Texi2HTML::Config::heading_texi($section->{'tag'}, $section->{'texi'}, $section->{'number'}); + $section->{'text'} = substitute_line($texi); + $section->{'text_nonumber'} = substitute_line($section->{'texi'}); + # backward compatibility + $section->{'name'} = $section->{'text_nonumber'}; + $section->{'no_texi'} = remove_texi($texi); + $section->{'simple_format'} = simple_format(undef,$texi); + $section->{'heading_texi'} = $texi; + } + my $tocnr = 1; + foreach my $element (@elements_list) + { + if (!$element->{'top'} and !$element->{'index_page'}) + { # for link back to table of contents + # FIXME do it for top too? + $element->{'tocid'} = 'TOC' . $tocnr; + $tocnr++; + } + next if (defined($element->{'text'})); + if ($element->{'index_page'}) + { + my $page = $element->{'page'}; + my $original_element = $element->{'original_index_element'}; + my $texi = &$Texi2HTML::Config::index_element_heading_texi( + $original_element->{'heading_texi'}, + $original_element->{'tag'}, + $original_element->{'texi'}, + $original_element->{'number'}, + $page->{'first_letter'}, $page->{'last_letter'}); + $element->{'heading_texi'} = $texi; + $element->{'text'} = substitute_line($texi); + $element->{'no_texi'} = remove_texi($texi); + $element->{'simple_format'} = simple_format(undef,$texi); + } + } + print STDERR "# Names done\n" if ($T2H_DEBUG); +} + +@{$Texi2HTML::TOC_LINES} = (); # table of contents +@{$Texi2HTML::OVERVIEW} = (); # short table of contents + + + +#+++############################################################################ +# # +# Stuff related to Index generation # +# # +#---############################################################################ + +# called during pass_structure +sub enter_index_entry($$$$$$$) +{ + my $prefix = shift; + my $line_nr = shift; + my $key = shift; + my $place = shift; + my $element = shift; + my $use_section_id = shift; + my $command = shift; + unless ($index_prefix_to_name{$prefix}) + { + echo_error ("Undefined index command: ${prefix}index", $line_nr); + $key = ''; + } + if (!exists($element->{'tag'}) and !$element->{'footnote'}) + { + echo_warn ("Index entry before document: \@${prefix}index $key", $line_nr); + } + $key =~ s/\s+$//; + $key =~ s/^\s*//; + my $entry = $key; + # The $key is mostly usefull for alphabetical sorting + $key = remove_texi($key); + my $id = ''; + # don't add a specific index target if after a section or the index + # entry is in @copying or the like + unless ($use_section_id or ($place eq $region_place)) + { + $id = 'IDX' . ++$idx_num; + } + my $index_entry = { + 'entry' => $entry, + 'element' => $element, + 'prefix' => $prefix, + 'label' => $id, + 'command' => $command + }; + + print STDERR "# enter \@$command ${prefix}index '$key' with id $id ($index_entry)\n" + if ($T2H_DEBUG & $DEBUG_INDEX); + if ($key =~ /^\s*$/) + { + echo_warn("Empty index entry for \@$command",$line_nr); + # don't add the index entry to the list of index entries used for index + # entry formatting,if the index entry appears in a region like copying + push @index_labels, $index_entry unless ($place eq $region_place); + return; + } + while (exists $index->{$prefix}->{$key}) + { + $key .= ' '; + } + $index->{$prefix}->{$key} = $index_entry; + push @$place, $index_entry; + # don't add the index entry to the list of index entries used for index + # entry formatting,if the index entry appears in a region like copying + push @index_labels, $index_entry unless ($place eq $region_place); +} + +# sort according to cmp if both $a and $b are alphabetical or non alphabetical, +# otherwise the alphabetical is ranked first +sub by_alpha +{ + 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); + } +} + +# returns an array of index entries pages splitted by letters +# each page has the following members: +# 'first_letter' first letter on that page +# 'last_letter' last letter on that page +# 'letters' ref on an array with all the letters for that page +# 'entries_by_letter' ref on a hash. Each key is a letter, with value a ref +# on arrays of index entries beginning with this letter +sub get_index_pages($) +{ + my $entries = shift; + my (@letters); + my ($entries_by_letter, $pages, $page) = ({}, [], {}); + my @keys = sort by_alpha keys %$entries; + + # each index entry is placed according to its first letter in + # entries_by_letter + for my $key (@keys) + { + push @{$entries_by_letter->{uc(substr($key,0, 1))}} , $entries->{$key}; + } + @letters = sort by_alpha keys %$entries_by_letter; + $Texi2HTML::Config::SPLIT_INDEX = 0 unless $Texi2HTML::Config::SPLIT; + + if ($Texi2HTML::Config::SPLIT_INDEX and $Texi2HTML::Config::SPLIT_INDEX =~ /^\d+$/) + { + my $i = 0; + my ($prev_letter); + foreach my $letter (@letters) + { + if ($i > $Texi2HTML::Config::SPLIT_INDEX) + { + $page->{'last_letter'} = $prev_letter; + push @$pages, $page; + $i=0; + } + if ($i == 0) + { + $page = {}; + $page->{'letters'} = []; + $page->{'entries_by_letter'} = {}; + $page->{'first_letter'} = $letter; + } + push @{$page->{'letters'}}, $letter; + $page->{'entries_by_letter'}->{$letter} = [@{$entries_by_letter->{$letter}}]; + $i += scalar(@{$entries_by_letter->{$letter}}); + $prev_letter = $letter; + } + $page->{'last_letter'} = $letters[$#letters]; + push @$pages, $page; + } + else + { + warn "$WARN Bad Texi2HTML::Config::SPLIT_INDEX: $Texi2HTML::Config::SPLIT_INDEX\n" if ($Texi2HTML::Config::SPLIT_INDEX); + $page->{'first_letter'} = $letters[0]; + $page->{'last_letter'} = $letters[$#letters]; + $page->{'letters'} = \@letters; + $page->{'entries_by_letter'} = $entries_by_letter; + push @$pages, $page; + return $pages; + } + return $pages; +} + +# return the page and the entries. Cache the result in %indices. +sub get_index($;$) +{ + my $index_name = shift; + my $line_nr = shift; + + return (@{$indices{$index_name}}) if ($indices{$index_name}); + + unless (exists($index_names{$index_name})) + { + echo_error ("Bad index name: $index_name", $line_nr); + return; + } + # add the index name itself to the index names searched for index + # prefixes. Only those found associated by synindex or syncodeindex are + # allready there (unless this code has allready been called). + if ($index_names{$index_name}->{'code'}) + { + $index_names{$index_name}->{'associated_indices_code'}->{$index_name} = 1; + } + else + { + $index_names{$index_name}->{'associated_indices'}->{$index_name} = 1; + } + + # find all the index names associated with the prefixes and then + # all the entries associated with each prefix + my $entries = {}; + foreach my $associated_indice(keys %{$index_names{$index_name}->{'associated_indices'}}) + { + foreach my $prefix(@{$index_names{$associated_indice}->{'prefix'}}) + { + foreach my $key (keys %{$index->{$prefix}}) + { + $entries->{$key} = $index->{$prefix}->{$key}; + } + } + } + + foreach my $associated_indice (keys %{$index_names{$index_name}->{'associated_indices_code'}}) + { + unless (exists ($index_names{$index_name}->{'associated_indices'}->{$associated_indice})) + { + foreach my $prefix (@{$index_names{$associated_indice}->{'prefix'}}) + { + foreach my $key (keys (%{$index->{$prefix}})) + { + $entries->{$key} = $index->{$prefix}->{$key}; + # use @code for code style index entry + $entries->{$key}->{'entry'} = "\@code{$entries->{$key}->{entry}}"; + } + } + } + } + + return unless %$entries; + my $pages = get_index_pages($entries); + $indices{$index_name} = [ $pages, $entries ]; + return ($pages, $entries); +} + +my @foot_lines = (); # footnotes +my $copying_comment = ''; # comment constructed from text between + # @copying and @end copying with licence +my $to_encoding; # out file encoding +my %acronyms_like = (); # acronyms or similar commands associated texts + # the key are the commands, the values are + # hash references associating shorthands to + # texts. + +sub initialise_state($) +{ + my $state = shift; + $state->{'preformatted'} = 0 unless exists($state->{'preformatted'}); + $state->{'code_style'} = 0 unless exists($state->{'code_style'}); + $state->{'keep_texi'} = 0 unless exists($state->{'keep_texi'}); + $state->{'keep_nr'} = 0 unless exists($state->{'keep_nr'}); + $state->{'detailmenu'} = 0 unless exists($state->{'detailmenu'}); # number of opened detailed menus + $state->{'table_list_stack'} = [ {'format' => "noformat"} ] unless exists($state->{'table_list_stack'}); + $state->{'paragraph_style'} = [ '' ] unless exists($state->{'paragraph_style'}); + $state->{'preformatted_stack'} = [ '' ] unless exists($state->{'preformatted_stack'}); + $state->{'menu'} = 0 unless exists($state->{'menu'}); + $state->{'command_stack'} = [] unless exists($state->{'command_stack'}); + $state->{'quotation_stack'} = [] unless exists($state->{'quotation_stack'}); + # if there is no $state->{'element'} the first element is used + $state->{'element'} = $elements_list[0] unless (exists($state->{'element'}) and !$state->{'element'}->{'before_anything'}); +} + +sub pass_text() +{ + my %state; + initialise_state(\%state); + my @stack; + my $text; + my $doc_nr; + my $in_doc = 0; + my $element; + my @text =(); + my @section_lines = (); + my @head_lines = (); + my $one_section = 1 if (@elements_list == 1); + + if (@elements_list == 0) + { + warn "$WARN empty document\n"; + exit (0); + } + + # We set titlefont only if the titlefont appeared in the top element + if (defined($element_top->{'titlefont'})) + { + $value{'_titlefont'} = $element_top->{'titlefont'}; + } + + # prepare %Texi2HTML::THISDOC +# $Texi2HTML::THISDOC{'settitle_texi'} = $value{'_settitle'}; + $Texi2HTML::THISDOC{'fulltitle_texi'} = ''; + $Texi2HTML::THISDOC{'title_texi'} = ''; + foreach my $possible_fulltitle (('_title', '_settitle', '_shorttitlepage', '_titlefont')) + { + if ($value{$possible_fulltitle} ne '') + { + $Texi2HTML::THISDOC{'fulltitle_texi'} = $value{$possible_fulltitle}; + last; + } + } + foreach my $possible_title_texi ($value{'_settitle'}, $Texi2HTML::THISDOC{'fulltitle_texi'}) + { + if ($possible_title_texi ne '') + { + $Texi2HTML::THISDOC{'title_texi'} = $possible_title_texi; + last; + } + } +# $Texi2HTML::THISDOC{'fulltitle_texi'} = $value{'_title'} || $value{'_settitle'} || $value{'_shorttitlepage'} || $value{'_titlefont'}; +# $Texi2HTML::THISDOC{'title_texi'} = $value{'_title'} || $value{'_settitle'} || $value{'_shorttitlepage'} || $value{'_titlefont'}; + foreach my $texi_cmd (('shorttitlepage', 'settitle', 'author', + 'titlefont', 'subtitle', 'shorttitle')) + { + $Texi2HTML::THISDOC{$texi_cmd . '_texi'} = $value{'_' . $texi_cmd}; + } + foreach my $doc_thing (('shorttitlepage', 'settitle', 'author', + 'titlefont', 'subtitle', 'shorttitle', 'fulltitle', 'title')) + { + my $thing_texi = $Texi2HTML::THISDOC{$doc_thing . '_texi'}; + $Texi2HTML::THISDOC{$doc_thing} = substitute_line($thing_texi); + $Texi2HTML::THISDOC{$doc_thing . '_no_texi'} = + remove_texi($thing_texi); + $Texi2HTML::THISDOC{$doc_thing . '_simple_format'} = + simple_format(undef, $thing_texi); + } + + # find Top name + my $element_top_text = ''; + my $top_no_texi = ''; + my $top_simple_format = ''; + my $top_name; + if ($element_top and $element_top->{'text'} and (!$node_top or ($element_top ne $node_top))) + { + $element_top_text = $element_top->{'text'}; + $top_no_texi = $element_top->{'no_texi'}; + $top_simple_format = $element_top->{'simple_format'}; + } + foreach my $possible_top_name ($Texi2HTML::Config::TOP_HEADING, + $element_top_text, $Texi2HTML::THISDOC{'title'}, + $Texi2HTML::THISDOC{'shorttitle'}, &$I('Top')) + { + if (defined($possible_top_name) and $possible_top_name ne '') + { + $top_name = $possible_top_name; + last; + } + } + foreach my $possible_top_no_texi ($Texi2HTML::Config::TOP_HEADING, + $top_no_texi, $Texi2HTML::THISDOC{'title_no_texi'}, + $Texi2HTML::THISDOC{'shorttitle_no_texi'}, + &$I('Top',{},{'remove_texi' => 1})) + { + if (defined($possible_top_no_texi) and $possible_top_no_texi ne '') + { + $top_no_texi = $possible_top_no_texi; + last; + } + } + + foreach my $possible_top_simple_format ($top_simple_format, + $Texi2HTML::THISDOC{'title_simple_format'}, + $Texi2HTML::THISDOC{'shorttitle_simple_format'}, + &$I('Top',{}, {'simple_format' => 1})) + { + if (defined($possible_top_simple_format) and $possible_top_simple_format ne '') + { + $top_simple_format = $possible_top_simple_format; + last; + } + } + + +# my $top_name = $Texi2HTML::Config::TOP_HEADING || $element_top_text || $Texi2HTML::THISDOC{'title'} || $Texi2HTML::THISDOC{'shorttitle'} || &$I('Top'); + + if ($Texi2HTML::THISDOC{'fulltitle_texi'} eq '') + { + $Texi2HTML::THISDOC{'fulltitle_texi'} = &$I('Untitled Document',{}, + {'keep_texi' => 1}); + } + $Texi2HTML::THISDOC{'title_texi'} = $Texi2HTML::THISDOC{'settitle_texi'}; + $Texi2HTML::THISDOC{'title_texi'} = $Texi2HTML::THISDOC{'fulltitle_texi'} + if ($Texi2HTML::THISDOC{'title_texi'} eq ''); + + foreach my $doc_thing (('fulltitle', 'title')) + { + my $thing_texi = $Texi2HTML::THISDOC{$doc_thing . '_texi'}; + $Texi2HTML::THISDOC{$doc_thing} = substitute_line($thing_texi); + $Texi2HTML::THISDOC{$doc_thing . '_no_texi'} = + remove_texi($thing_texi); + $Texi2HTML::THISDOC{$doc_thing . '_simple_format'} = + simple_format(undef, $thing_texi); + } + + for my $key (keys %Texi2HTML::THISDOC) + { + next if (ref($Texi2HTML::THISDOC{$key})); +print STDERR "!!$key\n" if (!defined($Texi2HTML::THISDOC{$key})); + $Texi2HTML::THISDOC{$key} =~ s/\s*$//; + } + $Texi2HTML::THISDOC{'program'} = $THISPROG; + $Texi2HTML::THISDOC{'program_homepage'} = $T2H_HOMEPAGE; + $Texi2HTML::THISDOC{'program_authors'} = $T2H_AUTHORS; + $Texi2HTML::THISDOC{'user'} = $T2H_USER; + $Texi2HTML::THISDOC{'user'} = $Texi2HTML::Config::USER if (defined($Texi2HTML::Config::USER)); +# $Texi2HTML::THISDOC{'documentdescription'} = $documentdescription; + $Texi2HTML::THISDOC{'copying'} = $copying_comment; + $Texi2HTML::THISDOC{'destination_directory'} = $docu_rdir; + $Texi2HTML::THISDOC{'authors'} = [] if (!defined($Texi2HTML::THISDOC{'authors'})); + $Texi2HTML::THISDOC{'subtitles'} = [] if (!defined($Texi2HTML::THISDOC{'subtitles'})); + $Texi2HTML::THISDOC{'titles'} = [] if (!defined($Texi2HTML::THISDOC{'titles'})); + foreach my $element (('authors', 'subtitles', 'titles')) + { + my $i; + for ($i = 0; $i < $#{$Texi2HTML::THISDOC{$element}} + 1; $i++) + { + chomp ($Texi2HTML::THISDOC{$element}->[$i]); + $Texi2HTML::THISDOC{$element}->[$i] = substitute_line($Texi2HTML::THISDOC{$element}->[$i]); + #print STDERR "$element:$i: $Texi2HTML::THISDOC{$element}->[$i]\n"; + } + } + # prepare TOC, OVERVIEW... + my ($toc_file, $stoc_file, $foot_file, $about_file); + # if not split the references are to the same file + $toc_file = $stoc_file = $foot_file = $about_file = ''; + if ($Texi2HTML::Config::SPLIT) + { + $toc_file = $docu_toc; + $stoc_file = $docu_stoc; + if ($Texi2HTML::Config::INLINE_CONTENTS) + { + $toc_file = $content_element{'contents'}->{'file'} if (defined($content_element{'contents'})); + $stoc_file = $content_element{'shortcontents'}->{'file'} if (defined($content_element{'shortcontents'})); + } + $foot_file = $docu_foot; + $about_file = $docu_about; + } + $Texi2HTML::THISDOC{'toc_file'} = $toc_file; + $Texi2HTML::HREF{'Contents'} = $toc_file.'#'.$content_element{'contents'}->{'id'} if @{$Texi2HTML::TOC_LINES}; + $Texi2HTML::HREF{'Overview'} = $stoc_file.'#'.$content_element{'shortcontents'}->{'id'} if @{$Texi2HTML::OVERVIEW}; + $Texi2HTML::HREF{'Footnotes'} = $foot_file. '#SEC_Foot'; + $Texi2HTML::HREF{'About'} = $about_file . '#SEC_About' unless ($one_section or (not $Texi2HTML::Config::SPLIT and not $Texi2HTML::Config::SECTION_NAVIGATION)); + + $Texi2HTML::NAME{'First'} = $element_first->{'text'}; + $Texi2HTML::NAME{'Last'} = $element_last->{'text'}; + $Texi2HTML::NAME{'About'} = &$I('About This Document'); + $Texi2HTML::NAME{'Contents'} = &$I('Table of Contents'); + $Texi2HTML::NAME{'Overview'} = &$I('Short Table of Contents'); + $Texi2HTML::NAME{'Top'} = $top_name; + $Texi2HTML::NAME{'Footnotes'} = &$I('Footnotes'); + $Texi2HTML::NAME{'Index'} = $element_chapter_index->{'text'} if (defined($element_chapter_index)); + $Texi2HTML::NAME{'Index'} = $Texi2HTML::Config::INDEX_CHAPTER if ($Texi2HTML::Config::INDEX_CHAPTER ne ''); + + $Texi2HTML::NO_TEXI{'First'} = $element_first->{'no_texi'}; + $Texi2HTML::NO_TEXI{'Last'} = $element_last->{'no_texi'}; + $Texi2HTML::NO_TEXI{'About'} = &$I('About This Document', {}, {'remove_texi' => 1} ); + $Texi2HTML::NO_TEXI{'Contents'} = &$I('Table of Contents', {}, {'remove_texi' => 1} ); + $Texi2HTML::NO_TEXI{'Overview'} = &$I('Short Table of Contents', {}, {'remove_texi' => 1} ); + $Texi2HTML::NO_TEXI{'Top'} = $top_no_texi; + $Texi2HTML::NO_TEXI{'Footnotes'} = &$I('Footnotes', {}, {'remove_texi' => 1} ); + $Texi2HTML::NO_TEXI{'Index'} = $element_chapter_index->{'no_texi'} if (defined($element_chapter_index)); + + $Texi2HTML::SIMPLE_TEXT{'First'} = $element_first->{'simple_format'}; + $Texi2HTML::SIMPLE_TEXT{'Last'} = $element_last->{'simple_format'}; + $Texi2HTML::SIMPLE_TEXT{'About'} = &$I('About This Document', {}, {'simple_format' => 1}); + $Texi2HTML::SIMPLE_TEXT{'Contents'} = &$I('Table of Contents',{}, {'simple_format' => 1}); + $Texi2HTML::SIMPLE_TEXT{'Overview'} = &$I('Short Table of Contents', {}, {'simple_format' => 1}); + $Texi2HTML::SIMPLE_TEXT{'Top'} = $top_simple_format; + $Texi2HTML::SIMPLE_TEXT{'Footnotes'} = &$I('Footnotes', {},{'simple_format' => 1}); + + $Texi2HTML::SIMPLE_TEXT{'Index'} = $element_chapter_index->{'simple_format'} if (defined($element_chapter_index)); + # must be after toc_body, but before titlepage + for my $element_tag ('contents', 'shortcontents') + { + my $toc_lines = &$Texi2HTML::Config::inline_contents(undef, $element_tag, $content_element{$element_tag}); + @{$Texi2HTML::THISDOC{'inline_contents'}->{$element_tag}} = @$toc_lines if (defined($toc_lines)); + } + $Texi2HTML::TITLEPAGE = ''; + $Texi2HTML::TITLEPAGE = substitute_text({}, @{$region_lines{'titlepage'}}) + if (@{$region_lines{'titlepage'}}); + &$Texi2HTML::Config::titlepage(); + + &$Texi2HTML::Config::init_out(); + $to_encoding = $Texi2HTML::Config::OUT_ENCODING; + + ############################################################################ + # print frame and frame toc file + # + if ( $Texi2HTML::Config::FRAMES ) + { + my $FH = open_out($docu_frame_file); + print STDERR "# Creating frame in $docu_frame_file ...\n" if $T2H_VERBOSE; + &$Texi2HTML::Config::print_frame($FH, $docu_toc_frame_file, $docu_top_file); + close_out($FH, $docu_frame_file); + + $FH = open_out($docu_toc_frame_file); + print STDERR "# Creating toc frame in $docu_frame_file ...\n" if $T2H_VERBOSE; + &$Texi2HTML::Config::print_toc_frame($FH, $Texi2HTML::OVERVIEW); + close_out($FH, $docu_toc_frame_file); + } + + ############################################################################ + # + # + + my $FH; + my $index_pages; + my $index_pages_nr; + my $index_nr = 0; + my $line_nr; + my $first_section = 0; # 1 if it is the first section of a page + while (@doc_lines) + { + unless ($index_pages) + { # not in a index split over sections + $_ = shift @doc_lines; + my $chomped_line = $_; + if (!chomp($chomped_line) and @doc_lines) + { # if the line has no end of line it is concatenated with the next + $doc_lines[0] = $_ . $doc_lines[0]; + next; + } + $line_nr = shift (@doc_numbers); + #print STDERR "$line_nr->{'file_name'}($line_nr->{'macro'},$line_nr->{'line_nr'}) $_" if ($line_nr); + } + #print STDERR "PASS_TEXT: $_"; + #dump_stack(\$text, \@stack, \%state); + if (!$state{'raw'} and !$state{'verb'}) + { + my $tag = ''; + $tag = $1 if (/^\@(\w+)/ and !$index_pages); + + if (($tag eq 'node') or defined($sec2level{$tag}) or $index_pages) + { + if (@stack or (defined($text) and $text ne '')) + {# in pass text node and section shouldn't appear in formats + #print STDERR "close_stack before \@$tag\n"; + #print STDERR "text!$text%" if (! @stack); + close_stack(\$text, \@stack, \%state, $line_nr); + push @section_lines, $text; + $text = ''; + } + $sec_num++ if ($sec2level{$tag}); + my $new_element; + my $current_element; + if ($tag =~ /heading/) + {# handle headings, they are not in element lists + $current_element = $sections{$sec_num}; + #print STDERR "HEADING $_"; + if (! $element) + { + $new_element = shift @elements_list; + } + else + { + push (@section_lines, &$Texi2HTML::Config::anchor($current_element->{'id'}) . "\n"); + push @section_lines, &$Texi2HTML::Config::heading($current_element); + next; + } + } + elsif (!$index_pages) + {# handle node and structuring elements + $current_element = shift (@all_elements); + ########################## begin debug section + if ($current_element->{'node'}) + { + print STDERR 'NODE ' . "$current_element->{'texi'}($current_element->{'file'})" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + print STDERR "($current_element->{'section_ref'}->{'texi'})" if ($current_element->{'section_ref'} and ($T2H_DEBUG & $DEBUG_ELEMENTS)); + } + else + { + print STDERR 'SECTION ' . $current_element->{'texi'} if ($T2H_DEBUG & $DEBUG_ELEMENTS); + } + print STDERR ": $_" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + ########################## end debug section + + # The element begins a new section if there is no previous + # or it is an element and not the current one or the + # associated section (in case of node) is not the current + # one + if (!$element + or ($current_element->{'element'} and ($current_element ne $element)) + or ($current_element->{'section_ref'} and ($current_element->{'section_ref'} ne $element))) + { + $new_element = shift @elements_list; + } + ########################### begin debug + my $section_element = $new_element; + $section_element = $element unless ($section_element); + if (!$current_element->{'node'} and !$current_element->{'index_page'} and ($section_element ne $current_element)) + { + print STDERR "NODE: $element->{'texi'}\n" if ($element->{'node'}); + warn "elements_list and all_elements not in sync (elements $section_element->{'texi'}, all $current_element->{'texi'}): $_"; + } + ########################### end debug + } + else + { # this is a new index section + $new_element = $index_pages->[$index_pages_nr]->{'element'}; + $current_element = $index_pages->[$index_pages_nr]->{'element'}; + print STDERR "New index page '$new_element->{'texi'}' nr: $index_pages_nr\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + my $list_element = shift @elements_list; + die "element in index_pages $new_element->{'texi'} and in list $list_element->{'texi'} differs\n" unless ($list_element eq $new_element); + } + if ($new_element) + { + $index_nr = 0; + my $old = 'NO_OLD'; + $old = $element->{'texi'} if (defined($element)); + print STDERR "NEW: $new_element->{'texi'}, OLD: $old\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS); + # print the element that just finished + $Texi2HTML::THIS_SECTION = \@section_lines; + $Texi2HTML::THIS_HEADER = \@head_lines; + if ($element) + { + finish_element($FH, $element, $new_element, $first_section); + $first_section = 0; + @section_lines = (); + @head_lines = (); + } + else + { + print STDERR "# Writing elements:" if ($T2H_VERBOSE); + if ($Texi2HTML::Config::IGNORE_PREAMBLE_TEXT) + { + @section_lines = (); + @head_lines = (); + } + # remove empty line at the beginning of @section_lines + shift @section_lines while (@section_lines and ($section_lines[0] =~ /^\s*$/)); + } + # begin new element + my $previous_file; + $previous_file = $element->{'file'} if (defined($element)); + $element = $new_element; + $state{'element'} = $element; + $Texi2HTML::THIS_ELEMENT = $element; + #print STDERR "Doing hrefs for $element->{'texi'} First "; + $Texi2HTML::HREF{'First'} = href($element_first, $element->{'file'}); + #print STDERR "Last "; + $Texi2HTML::HREF{'Last'} = href($element_last, $element->{'file'}); + #print STDERR "Index "; + $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $element->{'file'}) if (defined($element_chapter_index)); + #print STDERR "Top "; + $Texi2HTML::HREF{'Top'} = href($element_top, $element->{'file'}); + if ($Texi2HTML::Config::INLINE_CONTENTS) + { + $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $element->{'file'}); + $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $element->{'file'}); + } + foreach my $direction (@element_directions) + { + my $elem = $element->{$direction}; + $Texi2HTML::NODE{$direction} = undef; + $Texi2HTML::HREF{$direction} = undef; + next unless (defined($elem)); + #print STDERR "$direction "; + if ($elem->{'node'} or $elem->{'external_node'} or $elem->{'index_page'} or !$elem->{'seen'}) + { + $Texi2HTML::NODE{$direction} = $elem->{'text'}; + } + elsif ($elem->{'node_ref'}) + { + $Texi2HTML::NODE{$direction} = $elem->{'node_ref'}->{'text'}; + } + if (!$elem->{'seen'}) + { + $Texi2HTML::HREF{$direction} = do_external_href($elem->{'texi'}); + } + else + { + $Texi2HTML::HREF{$direction} = href($elem, $element->{'file'}); + } + $Texi2HTML::NAME{$direction} = $elem->{'text'}; + $Texi2HTML::NO_TEXI{$direction} = $elem->{'no_texi'}; + $Texi2HTML::SIMPLE_TEXT{$direction} = $elem->{'simple_format'}; + #print STDERR "$direction ($element->{'texi'}): \n NO_TEXI: $Texi2HTML::NO_TEXI{$direction}\n NAME $Texi2HTML::NAME{$direction}\n NODE $Texi2HTML::NODE{$direction}\n HREF $Texi2HTML::HREF{$direction}\n\n"; + } + #print STDERR "\nDone hrefs for $element->{'texi'}\n"; + $files{$element->{'file'}}->{'counter'}--; + if (!defined($previous_file) or ($element->{'file'} ne $previous_file)) + { + my $file = $element->{'file'}; + print STDERR "\n" if ($T2H_VERBOSE and !$T2H_DEBUG); + print STDERR "# Writing to $docu_rdir$file " if $T2H_VERBOSE; + my $do_page_head = 0; + if ($files{$file}->{'filehandle'}) + { + $FH = $files{$file}->{'filehandle'}; + } + else + { + $FH = open_out("$docu_rdir$file"); +#print STDERR "OPEN $docu_rdir$file, $FH". scalar($FH)."\n"; + $files{$file}->{'filehandle'} = $FH; + $do_page_head = 1; + } + if ($element->{'top'}) + { + &$Texi2HTML::Config::print_Top_header($FH, $do_page_head); + } + else + { + &$Texi2HTML::Config::print_page_head($FH) if ($do_page_head); + &$Texi2HTML::Config::print_chapter_header($FH) if $Texi2HTML::Config::SPLIT eq 'chapter'; + &$Texi2HTML::Config::print_section_header($FH) if $Texi2HTML::Config::SPLIT eq 'section'; + } + $first_section = 1; + } + print STDERR "." if ($T2H_VERBOSE); + print STDERR "\n" if ($T2H_DEBUG); + } + my $label = &$Texi2HTML::Config::anchor($current_element->{'id'}) . "\n"; + if (@section_lines) + { + push (@section_lines, $label); + } + else + { + push @head_lines, $label; + } + if ($index_pages) + { + push @section_lines, &$Texi2HTML::Config::heading($element); + #print STDERR "Do index page $index_pages_nr\n"; + my $page = do_index_page($index_pages, $index_pages_nr); + push @section_lines, $page; + if (defined ($index_pages->[$index_pages_nr + 1])) + { + $index_pages_nr++; + } + else + { + $index_pages = undef; + } + next; + } + push @section_lines, &$Texi2HTML::Config::heading($current_element) if ($current_element->{'element'} and !$current_element->{'top'}); + next; + } + elsif ($tag eq 'printindex') + { + s/\s+(\w+)\s*//; + my $name = $1; + close_paragraph(\$text, \@stack, \%state); + next if (!$index_names{$name} or $empty_indices{$name}); + $printed_indices{$name} = 1; + print STDERR "print index $name($index_nr) in `$element->{'texi'}', element->{'indices'}: $element->{'indices'},\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS or $T2H_DEBUG & $DEBUG_INDEX); + print STDERR "element->{'indices'}->[index_nr]: $element->{'indices'}->[$index_nr] (@{$element->{'indices'}->[$index_nr]})\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS or $T2H_DEBUG & $DEBUG_INDEX); + $index_pages = $element->{'indices'}->[$index_nr] if (@{$element->{'indices'}->[$index_nr]} > 1); + $index_pages_nr = 0; + add_prev(\$text, \@stack, do_index_page($element->{'indices'}->[$index_nr], 0)); + $index_pages_nr++; + $index_nr++; + begin_paragraph (\@stack, \%state) if ($state{'preformatted'}); + next if (@stack); + push @section_lines, $text; + $text = ''; + next; + } + elsif (($tag eq 'contents') or ($tag eq 'summarycontents') or ($tag eq 'shortcontents')) + { + my $element_tag = $tag; + $element_tag = 'shortcontents' if ($element_tag ne 'contents'); + if ($Texi2HTML::Config::INLINE_CONTENTS and !$content_element{$element_tag}->{'aftertitlepage'}) + { + if (@stack or (defined($text) and $text ne '')) + {# in pass text contents shouldn't appear in formats + close_stack(\$text, \@stack, \%state, $line_nr); + push @section_lines, $text; + $text = ''; + } + my $toc_lines = &$Texi2HTML::Config::inline_contents($FH, $tag, $content_element{$element_tag}); + push (@section_lines, @$toc_lines) if (defined($toc_lines)) ; + } + next; + } + } + scan_line($_, \$text, \@stack, \%state, $line_nr); + #print STDERR "after scan_line: $_"; + #dump_stack(\$text, \@stack, \%state); + next if (@stack); + if ($text ne '' ) + { + push @section_lines, $text; + $text = ''; + } + } + if (@stack) + {# close stack at the end of pass text + close_stack(\$text, \@stack, \%state, $line_nr); + } + if (defined($text)) + { + push @section_lines, $text; + } + print STDERR "\n" if ($T2H_VERBOSE); + + $Texi2HTML::THIS_SECTION = \@section_lines; + # if no sections, then simply print document as is + if ($one_section) + { + if (@foot_lines) + { + &$Texi2HTML::Config::foot_section (\@foot_lines); + push @section_lines, @foot_lines; + } + $Texi2HTML::THIS_HEADER = \@head_lines; + if ($element->{'top'}) + { + print STDERR "Bug: `$element->{'texi'}' level undef\n" if (!$element->{'node'} and !defined($element->{'level'})); + $element->{'level'} = 1 if (!defined($element->{'level'})); + $element->{'node'} = 0; # otherwise Texi2HTML::Config::heading may uses the node level + $element->{'text'} = $Texi2HTML::NAME{'Top'}; + print STDERR "[Top]" if ($T2H_VERBOSE); + unless ($element->{'titlefont'} or $element->{'index_page'}) + { + unshift @section_lines, &$Texi2HTML::Config::heading($element); + } + } + print STDERR "# Write the section $element->{'texi'}\n" if ($T2H_VERBOSE); + &$Texi2HTML::Config::one_section($FH); + close_out($FH); + return; + } + + finish_element ($FH, $element, undef, $first_section); + + ############################################################################ + # Print ToC, Overview, Footnotes + # + foreach my $direction (@element_directions) + { + $Texi2HTML::HREF{$direction} = undef; + delete $Texi2HTML::HREF{$direction}; + # it is better to undef in case the references to these hash entries + # are used, as if deleted, the + # references are still refering to the old, undeleted element + # (we could do both) + $Texi2HTML::NAME{$direction} = undef; + $Texi2HTML::NO_TEXI{$direction} = undef; + $Texi2HTML::SIMPLE_TEXT{$direction} = undef; + $Texi2HTML::NODE{$direction} = undef; + + $Texi2HTML::THIS_ELEMENT = undef; + } + if (@foot_lines) + { + print STDERR "# writing Footnotes in $docu_foot_file\n" if $T2H_VERBOSE; + $FH = open_out ($docu_foot_file) + if $Texi2HTML::Config::SPLIT; + $Texi2HTML::HREF{'This'} = $Texi2HTML::HREF{'Footnotes'}; + $Texi2HTML::HREF{'Footnotes'} = '#' . $footnote_element->{'id'}; + $Texi2HTML::NAME{'This'} = $Texi2HTML::NAME{'Footnotes'}; + $Texi2HTML::NO_TEXI{'This'} = $Texi2HTML::NO_TEXI{'Footnotes'}; + $Texi2HTML::SIMPLE_TEXT{'This'} = $Texi2HTML::SIMPLE_TEXT{'Footnotes'}; + $Texi2HTML::THIS_SECTION = \@foot_lines; + $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor($footnote_element->{'id'}) . "\n" ]; + &$Texi2HTML::Config::print_Footnotes($FH); + close_out($FH, $docu_foot_file) + if ($Texi2HTML::Config::SPLIT); + $Texi2HTML::HREF{'Footnotes'} = $Texi2HTML::HREF{'This'}; + } + + if (@{$Texi2HTML::TOC_LINES} and !$Texi2HTML::Config::INLINE_CONTENTS) + { + print STDERR "# writing Toc in $docu_toc_file\n" if $T2H_VERBOSE; + $FH = open_out ($docu_toc_file) + if $Texi2HTML::Config::SPLIT; + $Texi2HTML::HREF{'This'} = $Texi2HTML::HREF{'Contents'}; + $Texi2HTML::HREF{'Contents'} = "#SEC_Contents"; + $Texi2HTML::NAME{'This'} = $Texi2HTML::NAME{'Contents'}; + $Texi2HTML::NO_TEXI{'This'} = $Texi2HTML::NO_TEXI{'Contents'}; + $Texi2HTML::SIMPLE_TEXT{'This'} = $Texi2HTML::SIMPLE_TEXT{'Contents'}; + $Texi2HTML::THIS_SECTION = $Texi2HTML::TOC_LINES; + $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor("SEC_Contents") . "\n" ]; + &$Texi2HTML::Config::print_Toc($FH); + close_out($FH, $docu_toc_file) + if ($Texi2HTML::Config::SPLIT); + $Texi2HTML::HREF{'Contents'} = $Texi2HTML::HREF{'This'}; + } + + if (@{$Texi2HTML::OVERVIEW} and !$Texi2HTML::Config::INLINE_CONTENTS) + { + print STDERR "# writing Overview in $docu_stoc_file\n" if $T2H_VERBOSE; + $FH = open_out ($docu_stoc_file) + if $Texi2HTML::Config::SPLIT; + $Texi2HTML::HREF{This} = $Texi2HTML::HREF{Overview}; + $Texi2HTML::HREF{Overview} = "#SEC_Overview"; + $Texi2HTML::NAME{This} = $Texi2HTML::NAME{Overview}; + $Texi2HTML::NO_TEXI{This} = $Texi2HTML::NO_TEXI{Overview}; + $Texi2HTML::SIMPLE_TEXT{This} = $Texi2HTML::SIMPLE_TEXT{Overview}; + $Texi2HTML::THIS_SECTION = $Texi2HTML::OVERVIEW; + $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor("SEC_Overview") . "\n" ]; + &$Texi2HTML::Config::print_Overview($FH); + close_out($FH,$docu_stoc_file) + if ($Texi2HTML::Config::SPLIT); + $Texi2HTML::HREF{Overview} = $Texi2HTML::HREF{This}; + } + my $about_body; + if ($about_body = &$Texi2HTML::Config::about_body()) + { + print STDERR "# writing About in $docu_about_file\n" if $T2H_VERBOSE; + $FH = open_out ($docu_about_file) + if $Texi2HTML::Config::SPLIT; + + $Texi2HTML::HREF{This} = $Texi2HTML::HREF{About}; + $Texi2HTML::HREF{About} = "#SEC_About"; + $Texi2HTML::NAME{This} = $Texi2HTML::NAME{About}; + $Texi2HTML::NO_TEXI{This} = $Texi2HTML::NO_TEXI{About}; + $Texi2HTML::SIMPLE_TEXT{This} = $Texi2HTML::SIMPLE_TEXT{About}; + $Texi2HTML::THIS_SECTION = [$about_body]; + $Texi2HTML::THIS_HEADER = [ &$Texi2HTML::Config::anchor("SEC_About") . "\n" ]; + &$Texi2HTML::Config::print_About($FH); + close_out($FH, $docu_stoc_file) + if ($Texi2HTML::Config::SPLIT); + $Texi2HTML::HREF{About} = $Texi2HTML::HREF{This}; + } + + unless ($Texi2HTML::Config::SPLIT) + { + &$Texi2HTML::Config::print_page_foot($FH); + close_out ($FH); + } +} + +# print section, close file if needed. +sub finish_element($$$$) +{ + my $FH = shift; + my $element = shift; + my $new_element = shift; + my $first_section = shift; +#print STDERR "FINISH_ELEMENT($FH)($element->{'texi'})[$element->{'file'}] counter $files{$element->{'file'}}->{'counter'}\n"; + + # handle foot notes + if ($Texi2HTML::Config::SPLIT and scalar(@foot_lines) + and !$Texi2HTML::Config::SEPARATED_FOOTNOTES + and (! $new_element or + ($element and ($new_element->{'file'} ne $element->{'file'}))) + ) + { + if ($files{$element->{'file'}}->{'counter'}) + {# there are other elements in that page we are not on its foot + $files{$element->{'file'}}->{'relative_foot_num'} + = $relative_foot_num; + push @{$files{$element->{'file'}}->{'foot_lines'}}, + @foot_lines; + } + else + {# we output the footnotes as we are at the file end + unshift @foot_lines, @{$files{$element->{'file'}}->{'foot_lines'}}; + &$Texi2HTML::Config::foot_section (\@foot_lines); + push @{$Texi2HTML::THIS_SECTION}, @foot_lines; + } + if ($new_element) + { + $relative_foot_num = + $files{$new_element->{'file'}}->{'relative_foot_num'}; + } + @foot_lines = (); + } + if ($element->{'top'}) + { + my $top_file = $docu_top_file; + #print STDERR "TOP $element->{'texi'}, @section_lines\n"; + print STDERR "[Top]" if ($T2H_VERBOSE); + $Texi2HTML::HREF{'Top'} = href($element_top, $element->{'file'}); + &$Texi2HTML::Config::print_Top($FH, ($element->{'titlefont'} or $element->{'index_page'})); + my $end_page = 0; + if ($Texi2HTML::Config::SPLIT) + { + if (!$files{$element->{'file'}}->{'counter'}) + { + $end_page = 1; + } + } + &$Texi2HTML::Config::print_Top_footer($FH, $end_page); + close_out($FH, $top_file) if ($end_page); + } + else + { + print STDERR "# do element $element->{'texi'}\n" + if ($T2H_DEBUG & $DEBUG_ELEMENTS); + &$Texi2HTML::Config::print_section($FH, $first_section); + if (defined($new_element) and ($new_element->{'file'} ne $element->{'file'})) + { + if (!$files{$element->{'file'}}->{'counter'}) + { + &$Texi2HTML::Config::print_chapter_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'chapter'); + &$Texi2HTML::Config::print_section_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'section'); + #print STDERR "Close file after $element->{'texi'}\n"; + &$Texi2HTML::Config::print_page_foot($FH); + close_out($FH); + } + else + { + print STDERR "counter $files{$element->{'file'}}->{'counter'} ne 0, file $element->{'file'}\n" if ($T2H_DEBUG); + } + } + elsif (!defined($new_element)) + { + if ($Texi2HTML::Config::SPLIT) + { # end of last splitted section + &$Texi2HTML::Config::print_chapter_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'chapter'); + &$Texi2HTML::Config::print_section_footer($FH) if ($Texi2HTML::Config::SPLIT eq 'section'); + &$Texi2HTML::Config::print_page_foot($FH); + close_out($FH); + } + else + { + &$Texi2HTML::Config::end_section($FH, 1); + } + } + elsif ($new_element->{'top'}) + { + &$Texi2HTML::Config::end_section($FH, 1); + } + else + { + &$Texi2HTML::Config::end_section($FH); + } + } +} + +# write to files with name the node name for cross manual references. +sub do_node_files() +{ + foreach my $key (keys(%nodes)) + { + my $node = $nodes{$key}; + next unless ($node->{'node_file'}); + my $redirection_file = $docu_doc; + $redirection_file = $node->{'file'} if ($Texi2HTML::Config::SPLIT); + if (!$redirection_file) + { + print STDERR "Bug: file for redirection for `$node->{'texi'}' don't exist\n" unless ($novalidate); + next; + } + next if ($redirection_file eq $node->{'node_file'}); + my $file = "${docu_rdir}$node->{'node_file'}"; + $Texi2HTML::NODE{'This'} = $node->{'text'}; + $Texi2HTML::NO_TEXI{'This'} = $node->{'no_texi'}; + $Texi2HTML::SIMPLE_TEXT{'This'} = $node->{'simple_format'}; + $Texi2HTML::NAME{'This'} = $node->{'text'}; + $Texi2HTML::HREF{'This'} = "$node->{'file'}#$node->{'id'}"; + my $NODEFILE = open_out ($file); + &$Texi2HTML::Config::print_redirection_page ($NODEFILE); + close $NODEFILE || die "$ERROR: Can't close $file: $!\n"; + } +} + +#+++############################################################################ +# # +# Low level functions # +# # +#---############################################################################ + +sub locate_include_file($) +{ + my $file = shift; + + # APA: Don't implicitely search ., to conform with the docs! + # return $file if (-e $file && -r $file); + foreach my $dir (@Texi2HTML::Config::INCLUDE_DIRS) + { + return "$dir/$file" if (-e "$dir/$file" && -r "$dir/$file"); + } + return undef; +} + +sub open_file($$) +{ + my $name = shift; + my $line_number = shift; + local *FH; + if (open(*FH, "<$name")) + { + if (defined($Texi2HTML::Config::IN_ENCODING) and $Texi2HTML::Config::USE_UNICODE) + { + binmode(*FH, ":encoding($Texi2HTML::Config::IN_ENCODING)"); + } + my $file = { 'fh' => *FH, + 'input_spool' => { 'spool' => [], + 'macro' => '' }, + 'name' => $name, + 'line_nr' => 0 }; + unshift(@fhs, $file); + $input_spool = $file->{'input_spool'}; + $line_number->{'file_name'} = $name; + $line_number->{'line_nr'} = 1; + } + else + { + warn "$ERROR Can't read file $name: $!\n"; + } +} + +sub open_out($) +{ + my $file = shift; + local *FILE; + if ($file eq '-') + { + binmode(STDOUT, ":encoding($to_encoding)") if (defined($to_encoding) and $Texi2HTML::Config::USE_UNICODE); + return \*STDOUT; + } + + unless (open(FILE, ">$file")) + { + die "$ERROR Can't open $file for writing: $!\n"; + } + if (defined($to_encoding) and $Texi2HTML::Config::USE_UNICODE) + { + if ($to_encoding eq 'utf8' or $to_encoding eq 'utf-8-strict') + { + binmode(FILE, ':utf8'); + } + else + { + binmode(FILE, ':bytes'); + } + binmode(FILE, ":encoding($to_encoding)"); + } + return *FILE; +} + +# FIXME not used when split +sub close_out($;$) +{ + my $FH = shift; + my $file = shift; + $file = '' if (!defined($file)); + return if ($Texi2HTML::Config::OUT eq ''); + close ($FH) || die "$ERROR: Error occurred when closing $file: $!\n"; +} + +sub next_line($) +{ + my $line_number = shift; + while (@fhs) + { + my $file = $fhs[0]; + $line_number->{'file_name'} = $file->{'name'}; + $input_spool = $file->{'input_spool'}; + if (@{$input_spool->{'spool'}}) + { + $line_number->{'macro'} = $file->{'input_spool'}->{'macro'}; + $line_number->{'line_nr'} = $file->{'line_nr'}; + my $line = shift(@{$input_spool->{'spool'}}); + print STDERR "# unspooling $line" if ($T2H_DEBUG & $DEBUG_MACROS); + return($line); + } + else + { + $file->{'input_spool'}->{'macro'} = ''; + $line_number->{'macro'} = ''; + } + my $fh = $file->{'fh'}; + no strict "refs"; + my $line = <$fh>; + use strict "refs"; + my $chomped_line = $line; + $file->{'line_nr'}++ if (defined($line) and chomp($chomped_line)); + $line_number->{'line_nr'} = $file->{'line_nr'}; + return($line) if (defined($line)); + no strict "refs"; + close($fh); + use strict "refs"; + shift(@fhs); + } + return(undef); +} + +# echo a warning +sub echo_warn($;$) +{ + my $text = shift; + chomp ($text); + my $line_number = shift; + warn "$WARN $text " . format_line_number($line_number) . "\n"; +} + +sub echo_error($;$) +{ + my $text = shift; + chomp ($text); + my $line_number = shift; + warn "$ERROR $text " . format_line_number($line_number) . "\n"; +} + +sub format_line_number($) +{ + my $line_number = shift; + my $macro_text = ''; + #$line_number = undef; + return '' unless (defined($line_number)); + $macro_text = " in $line_number->{'macro'}" if ($line_number->{'macro'} ne ''); + my $file_text = '('; + $file_text = "(in $line_number->{'file_name'} " if ($line_number->{'file_name'} ne $docu); + return "${file_text}l. $line_number->{'line_nr'}" . $macro_text . ')'; +} + +# to debug, dump the result of pass_texi and pass_structure in a file +sub dump_texi($$;$$) +{ + my $lines = shift; + my $pass = shift; + my $numbers = shift; + my $file = shift; + $file = "$docu_rdir$docu_name" . ".pass$pass" if (!defined($file)); + unless (open(DMPTEXI, ">$file")) + { + warn "Can't open $file for writing: $!\n"; + } + print STDERR "# Dump texi\n" if ($T2H_VERBOSE); + my $index = 0; + foreach my $line (@$lines) + { + my $number_information = ''; + my $chomped_line = $line; + $number_information = "$numbers->[$index]->{'file_name'}($numbers->[$index]->{'macro'},$numbers->[$index]->{'line_nr'}) " if (defined($numbers)); + print DMPTEXI "${number_information}$line"; + $index++ if (chomp($chomped_line)); + } + close DMPTEXI; +} + +# return next tag on the line +sub next_tag($) +{ + my $line = shift; + # macro_regexp + if ($line =~ /^\s*\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])/o or $line =~ /^\s*\@([a-zA-Z][\w-]*)([\s\{\}\@])/ or $line =~ /^\s*\@([a-zA-Z][\w-]*)$/) + { + return ($1); + } + return ''; +} + +sub top_stack($) +{ + my $stack = shift; + return undef unless(@$stack); + return $stack->[-1]; +} + +# return the next element with balanced {} +sub next_bracketed($$) +{ + my $line = shift; + my $line_nr = shift; + my $opened_braces = 0; + my $result = ''; + my $spaces; + if ($line =~ /^(\s*)$/) + { + return ('','',$1); + } + while ($line !~ /^\s*$/) + { +#print STDERR "next_bracketed($opened_braces): $result !!! $line"; + if (!$opened_braces) + { # beginning of item + $line =~ s/^(\s*)//; + $spaces = $1; + #if ($line =~ s/^([^\{\}\s]+)//) + if ($line =~ s/^([^\{\}]+?)(\s+)/$2/ or $line =~ s/^([^\{\}]+?)$//) + { + $result = $1; + $result =~ s/\s*$//; + return ($result, $line, $spaces); + } + elsif ($line =~ s/^([^\{\}]+?)([\{\}])/$2/) + { + $result = $1; + } + } + elsif($line =~ s/^([^\{\}]+)//) + { + $result .= $1; + } + if ($line =~ s/^([\{\}])//) + { + my $brace = $1; + $opened_braces++ if ($brace eq '{'); + $opened_braces-- if ($brace eq '}'); + + if ($opened_braces < 0) + { + echo_error("too much '}' in specification", $line_nr); + $opened_braces = 0; + next; + } + $result .= $brace; + return ($result, $line, $spaces) if ($opened_braces == 0); + } + } + if ($opened_braces) + { + echo_error("'{' not closed in specification", $line_nr); + return ($result . ( '}' x $opened_braces), '', $spaces); + } + print STDERR "BUG: at the end of next_bracketed\n"; + return undef; +} + +# do a href using file and id and taking care of ommitting file if it is +# the same +# element: structuring element to point to +# file: current file +sub href($$) +{ + my $element = shift; + my $file = shift; + return '' unless defined($element); + my $href = ''; + print STDERR "Bug: $element->{'texi'}, id undef\n" if (!defined($element->{'id'})); + print STDERR "Bug: $element->{'texi'}, file undef\n" if (!defined($element->{'file'})); +#foreach my $key (keys(%{$element})) +#{ +# my $value = 'UNDEF'; $value = $element->{$key} if defined($element->{$key}); +# print STDERR "$key: $value\n"; +#}print STDERR "\n"; + $href .= $element->{'file'} if (defined($element->{'file'}) and $file ne $element->{'file'}); + $href .= "#$element->{'id'}" if (defined($element->{'id'})); + return $href; +} + +sub normalise_space($) +{ + return undef unless (defined ($_[0])); + my $text = shift; + $text =~ s/\s+/ /go; + $text =~ s/ $//; + $text =~ s/^ //; + return $text; +} + +sub normalise_node($) +{ + return undef unless (defined ($_[0])); + my $text = shift; + $text = normalise_space($text); + $text =~ s/^top$/Top/i; + return $text; +} + +sub do_anchor_label($$$$) +{ + my $command = shift; + #my $anchor = shift; + my $args = shift; + my $anchor = $args->[0]; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + + return '' if ($state->{'multiple_pass'}); + $anchor = normalise_node($anchor); + if (!exists($nodes{$anchor}) or !defined($nodes{$anchor}->{'id'})) + { + print STDERR "Bug: unknown anchor `$anchor'\n"; + } + return &$Texi2HTML::Config::anchor($nodes{$anchor}->{'id'}); +} + +sub get_format_command($) +{ + my $format = shift; + my $command = ''; + my $format_name = ''; + my $term = 0; + my $item_nr; + my $paragraph_number; + my $enumerate_type; + my $number; + + $command = $format->{'command'} if (defined($format->{'command'})); + $format_name = $format->{'format'} if (defined($format->{'format'})); + $term = 1 if ($format->{'term'}); #This should never happen + + return ($format_name,$command,\$format->{'paragraph_number'},$term, + $format->{'item_nr'}, $format->{'spec'}, $format->{'number'}, + $format->{'stack_at_beginning'}); +} + +sub do_paragraph($$) +{ + my $text = shift; + my $state = shift; + my ($format, $paragraph_command, $paragraph_number, $term, $item_nr, + $enumerate_type, $number,$stack_at_beginning) + = get_format_command ($state->{'paragraph_context'}); + delete $state->{'paragraph_context'}; + + my $indent_style = ''; + if (exists($state->{'paragraph_indent'})) + { + $indent_style = $state->{'paragraph_indent'}; + $state->{'paragraph_indent'} = undef; + delete $state->{'paragraph_indent'}; + } + my $paragraph_command_formatted; + $state->{'paragraph_nr'}--; + (print STDERR "Bug text undef in do_paragraph", return '') unless defined($text); + my $align = ''; + $align = $state->{'paragraph_style'}->[-1] if ($state->{'paragraph_style'}->[-1]); + + if (exists($::style_map_ref->{$paragraph_command}) and + !exists($Texi2HTML::Config::special_list_commands{$format}->{$paragraph_command})) + { + if ($format eq 'itemize') + { + chomp ($text); + $text = do_simple($paragraph_command, $text, $state, [$text]); + $text = $text . "\n"; + } + } + elsif (exists($::things_map_ref->{$paragraph_command})) + { + $paragraph_command_formatted = do_simple($paragraph_command, '', $state); + } + return &$Texi2HTML::Config::paragraph($text, $align, $indent_style, $paragraph_command, $paragraph_command_formatted, $paragraph_number, $format, $item_nr, $enumerate_type, $number,$state->{'command_stack'},$stack_at_beginning); +} + +sub do_preformatted($$) +{ + my $text = shift; + my $state = shift; + my ($format, $leading_command, $preformatted_number, $term, $item_nr, + $enumerate_type, $number,$stack_at_beginning) + = get_format_command($state->{'preformatted_context'}); + delete ($state->{'preformatted_context'}); + my $leading_command_formatted; + my $pre_style = ''; + my $class = ''; + $pre_style = $state->{'preformatted_stack'}->[-1]->{'pre_style'} if ($state->{'preformatted_stack'}->[-1]->{'pre_style'}); + $class = $state->{'preformatted_stack'}->[-1]->{'class'}; + print STDERR "BUG: !state->{'preformatted_stack'}->[-1]->{'class'}\n" unless ($class); + if (exists($::style_map_ref->{$leading_command}) and + !exists($Texi2HTML::Config::special_list_commands{$format}->{$leading_command}) and ($style_type{$leading_command} eq 'style')) + { + $text = do_simple($leading_command, $text, $state,[$text]) if ($format eq 'itemize'); + } + elsif (exists($::things_map_ref->{$leading_command})) + { + $leading_command_formatted = do_simple($leading_command, '', $state); + } + return &$Texi2HTML::Config::preformatted($text, $pre_style, $class, $leading_command, $leading_command_formatted, $preformatted_number, $format, $item_nr, $enumerate_type, $number,$state->{'command_stack'},$stack_at_beginning); +} + +sub do_external_href($) +{ + # node_id is a unique node identifier with only letters, digits, - and _ + # node_xhtml_id is almost the same, but xhtml id can only begin with + # letters, so a prefix has to be appended + my $texi_node = shift; + my $file = ''; + my $node_file = ''; + my $node_id = ''; + my $node_xhtml_id = ''; + +#print STDERR "do_external_href $texi_node\n"; + + if ($texi_node =~ s/^\((.+?)\)//) + { + $file = $1; + } + $texi_node = normalise_node($texi_node); + if ($texi_node ne '') + { + if (exists($nodes{$texi_node}) and ($nodes{$texi_node}->{'cross_manual_target'})) + { + $node_id = $nodes{$texi_node}->{'cross_manual_target'}; + if ($Texi2HTML::Config::TRANSLITERATE_NODE) + { + $node_file = $nodes{$texi_node}->{'cross_manual_file'}; + } + } + else + { + if ($Texi2HTML::Config::TRANSLITERATE_NODE) + { + ($node_id, $node_file) = cross_manual_line($texi_node,1); + } + else + { + $node_id = cross_manual_line($texi_node); + } + } + $node_xhtml_id = node_to_id($node_id); + $node_file = $node_id unless ($Texi2HTML::Config::TRANSLITERATE_NODE); + } + return &$Texi2HTML::Config::external_href($texi_node, $node_file, + $node_xhtml_id, $file); +} + +# transform node for cross ref name to id suitable for xhtml: an xhtml id +# must begin with a letter. +sub node_to_id($) +{ + my $cross_ref_node_name = shift; + $cross_ref_node_name =~ s/^([0-9_])/g_t$1/; + return $cross_ref_node_name; +} + +# return 1 if the following tag shouldn't begin a line +sub no_line($) +{ + my $line = shift; + my $next_tag = next_tag($line); + return 1 if (($line =~ /^\s*$/) or $no_line_macros{$next_tag} or + (($next_tag =~ /^(\w+?)index$/) and ($1 ne 'print')) or + (($line =~ /^\@end\s+(\w+)/) and $no_line_macros{"end $1"})); + return 0; +} + +sub no_paragraph($$) +{ + my $state = shift; + my $line = shift; + return ($state->{'paragraph_context'} or $state->{'preformatted'} or $state->{'remove_texi'} or no_line($line) or $state->{'no_paragraph'}); +} + +# We restart the preformatted format which was stopped +# by the format if in preformatted, and start a paragraph +# for the text following the end of the format, if needed +sub begin_paragraph_after_command($$$$) +{ + my $state = shift; + my $stack = shift; + my $command = shift; + my $text_following = shift; + + if (($state->{'preformatted'} + and !$Texi2HTML::Config::format_in_paragraph{$command}) + or (!no_paragraph($state,$text_following))) + { + begin_paragraph($stack, $state); + } +} + +# handle raw formatting, ignored regions... +sub do_text_macro($$$$$) +{ + my $type = shift; + my $line = shift; + my $state = shift; + my $stack = shift; + my $line_nr = shift; + my $value; + #print STDERR "do_text_macro $type\n"; + + if ($text_macros{$type} eq 'raw') + { + $state->{'raw'} = $type; + #print STDERR "RAW\n"; + if ($state->{'raw'}) + { + push @$stack, { 'style' => $type, 'text' => '' }; + } + } + elsif ($text_macros{$type} eq 'value') + { + if (($line =~ s/(\s+)($VARRE)$//) or ($line =~ s/(\s+)($VARRE)(\s)//)) + { + $value = $1 . $2; + $value .= $3 if defined($3); + if ($state->{'ignored'}) + { + if ($type eq $state->{'ignored'}) + { + $state->{'ifvalue_inside'}++; + } + # if 'ignored' we don't care about the command as long as + # the nesting is correct + return ($line,''); + } + my $open_ifvalue = 0; + if ($type eq 'ifclear') + { + if (defined($value{$2})) + { + $open_ifvalue = 1; + } + else + { + push @{$state->{'text_macro_stack'}}, $type; + } + } + elsif ($type eq 'ifset') + { + unless (defined($value{$2})) + { + $open_ifvalue = 1; + } + else + { + push @{$state->{'text_macro_stack'}}, $type; + } + } + if ($open_ifvalue) + { + $state->{'ignored'} = $type; + $state->{'ifvalue'} = $type; + $state->{'ifvalue_inside'} = 1; + # We add at the top of the stack to be able to close all + # opened comands when closing the ifset/ifclear (and ignore + # everything that is in those commands) + push @$stack, { 'style' => 'ifvalue', 'text' => '' }; + } + + } + else + { # we accept a lone @ifset or @ifclear if it is inside an + if ($type eq $state->{'ifvalue'}) + { + $state->{'ifvalue_inside'}++; + return ($line,''); + } + echo_error ("Bad $type line: $line", $line_nr) unless ($state->{'ignored'}); + } + } + elsif (not $text_macros{$type}) + { # ignored text + $state->{'ignored'} = $type; + #print STDERR "IGNORED\n"; + } + else + { + push @{$state->{'text_macro_stack'}}, $type unless($state->{'ignored'}) ; + } + my $text = "\@$type"; + $text .= $value if defined($value); + return ($line, $text); +} + +# do regions handled specially, currently only tex, going through latex2html +sub init_special($$) +{ + my $style = shift; + my $text = shift; + if (defined($Texi2HTML::Config::command_handler{$style}) and + defined($Texi2HTML::Config::command_handler{$style}->{'init'})) + { + $special_commands{$style}->{'count'} = 0 if (!defined($special_commands{$style})); + if ($Texi2HTML::Config::command_handler{$style}->{'init'}($style,$text, + $special_commands{$style}->{'count'} +1)) + { + $special_commands{$style}->{'count'}++; + return "\@special_${style}_".$special_commands{$style}->{'count'}."{}"; + } + return ''; + } +} + +sub do_insertcopying($) +{ + my $state = shift; + return '' unless @{$region_lines{'copying'}}; + my $insert_copying_state = duplicate_state($state); + $insert_copying_state->{'multiple_pass'} = 1; + return substitute_text($insert_copying_state, @{$region_lines{'copying'}}); +} + +sub get_deff_index($$$) +{ + my $tag = shift; + my $line = shift; + my $line_nr = shift; + + $tag =~ s/x$//; + my ($style, $category, $name, $type, $class, $arguments); + ($style, $category, $name, $type, $class, $arguments) = parse_def($tag, $line, $line_nr); + $name = &$Texi2HTML::Config::definition_category($name, $class, $style); + return ($style, '') if (!defined($name) or ($name =~ /^\s*$/)); + return ($style, $name, $arguments); +} + +sub parse_def($$$) +{ + my $command = shift; + my $line = shift; + my $line_nr = shift; + + my $tag = $command; + + if (!ref ($Texi2HTML::Config::def_map{$tag})) + { + # substitute shortcuts for definition commands + my $substituted = $Texi2HTML::Config::def_map{$tag}; + $substituted =~ s/(\w+)//; + $tag = $1; + $line = $substituted . $line; + } +#print STDERR "PARSE_DEF($command,$tag) $line"; + my ($category, $name, $type, $class, $arguments); + my @args = @{$Texi2HTML::Config::def_map{$tag}}; + my $style = shift @args; + while (@args) + { + my $arg = shift @args; + if (defined($arg)) + { + # backward compatibility, it was possible to have a { in front. + $arg =~ s/^\{//; + my $item; + my $spaces; + ($item, $line,$spaces) = next_bracketed($line, $line_nr); + last if (!defined($item)); + $item =~ s/^\{(.*)\}$/$1/ if ($item =~ /^\{/); + if ($arg eq 'category') + { + $category = $item; + } + elsif ($arg eq 'name') + { + $name = $item; + } + elsif ($arg eq 'type') + { + $type = $item; + } + elsif ($arg eq 'class') + { + $class = $item; + } + elsif ($arg eq 'arg') + { + $line = $spaces . $item . $line; + } + } + else + { + last; + } + } +#print STDERR "PARSE_DEF (style $style, category $category, name $name, type $type, class $class, line $line)\n"; + return ($style, $category, $name, $type, $class, $line); +} + +sub begin_deff_item($$;$) +{ + my $stack = shift; + my $state = shift; + my $no_paragraph = shift; + #print STDERR "DEF push deff_item for $state->{'deff'}\n"; + push @$stack, { 'format' => 'deff_item', 'text' => '', 'deff_line' => $state->{'deff_line'}}; + # there is no paragraph when a new deff just follows the deff we are + # opening + begin_paragraph($stack, $state) + if ($state->{'preformatted'} and !$no_paragraph); + delete($state->{'deff_line'}); + #dump_stack(undef, $stack, $state); +} + +sub begin_paragraph($$) +{ + my $stack = shift; + my $state = shift; + + my $command = 1; + my $top_format = top_format($stack); + if (defined($top_format)) + { + $command = $top_format; + } + else + { + $command = { }; + } + $command->{'stack_at_beginning'} = [ @{$state->{'command_stack'}} ]; + if ($state->{'preformatted'}) + { + push @$stack, {'format' => 'preformatted', 'text' => '' }; + $state->{'preformatted_context'} = $command; + push @$stack, @{$state->{'paragraph_macros'}} if $state->{'paragraph_macros'}; + delete $state->{'paragraph_macros'}; + return; + } + $state->{'paragraph_context'} = $command; + $state->{'paragraph_nr'}++; + push @$stack, {'format' => 'paragraph', 'text' => '' }; + # if there are macros which weren't closed when the previous + # paragraph was closed we reopen them here + push @$stack, @{$state->{'paragraph_macros'}} if $state->{'paragraph_macros'}; + delete $state->{'paragraph_macros'}; +} + +sub parse_format_command($$) +{ + my $line = shift; + my $tag = shift; + my $command = 'asis'; + # macro_regexp + if (($line =~ /^\s*\@([A-Za-z][\w-]*)(\{\})?$/ or $line =~ /^\s*\@([A-Za-z][\w-]*)(\{\})?\s/) and ($::things_map_ref->{$1} or defined($::style_map_ref->{$1}))) + { + # macro_regexp + $line =~ s/^\s*\@([A-Za-z][\w-]*)(\{\})?\s*//; + $command = $1; + } + return ('', $command) if ($line =~ /^\s*$/); + chomp $line; + $line = substitute_text ({'keep_nr' => 1, 'keep_texi' => 1, 'check_item' => $tag}, $line); + return ($line, $command); +} + +sub parse_enumerate($) +{ + my $line = shift; + my $spec; + if ($line =~ /^\s*(\w)\b/ and ($1 ne '_')) + { + $spec = $1; + $line =~ s/^\s*(\w)\s*//; + } + return ($line, $spec); +} + +sub parse_multitable($$) +{ + my $line = shift; + my $line_nr = shift; + # first find the table width + my $table_width = 0; + if ($line =~ s/^\s+\@columnfractions\s+//) + { + my @fractions = split /\s+/, $line; + $table_width = $#fractions + 1; + while (@fractions) + { + my $fraction = shift @fractions; + unless ($fraction =~ /^(\d*\.\d+)|(\d+)\.?$/) + { + echo_error ("column fraction not a number: $fraction", $line_nr); + #warn "$ERROR column fraction not a number: $fraction"; + } + } + } + else + { + my $element; + my $line_orig = $line; + while ($line !~ /^\s*$/) + { + my $spaces; + ($element, $line, $spaces) = next_bracketed($line, $line_nr); + if ($element =~ /^\{/) + { + $table_width++; + } + else + { + echo_error ("garbage in multitable specification: $element", $line_nr); + } + } + } + return ($table_width); +} + +sub end_format($$$$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $format = shift; + my $line_nr = shift; + #print STDERR "END FORMAT $format\n"; + #dump_stack($text, $stack, $state); + #sleep 1; + if ($format_type{$format} eq 'menu') + { + $state->{'menu'}--; + close_menu($text, $stack, $state, $line_nr); + } + if (($format_type{$format} eq 'list') or ($format_type{$format} eq 'table')) + { # those functions return if they detect an inapropriate context + add_item($text, $stack, $state, $line_nr, '', 1); # handle lists + add_term($text, $stack, $state, $line_nr, 1); # handle table + add_line($text, $stack, $state, $line_nr, 1); # handle table + add_row($text, $stack, $state, $line_nr); # handle multitable + } + + #print STDERR "END_FORMAT\n"; + #dump_stack($text, $stack, $state); + + # set to 1 if there is a mismatch between the closed format and format + # opened before + my $format_mismatch = 0; + + my $format_ref = pop @$stack; + + ######################### debug + if (!defined($format_ref->{'text'})) + { + push @$stack, $format_ref; + print STDERR "Bug: text undef in end_format $format\n"; + dump_stack($text, $stack, $state); + pop @$stack; + } + ######################### end debug + + if (defined($Texi2HTML::Config::def_map{$format})) + { + close_stack($text, $stack, $state, $line_nr, undef, 'deff_item') + unless ($format_ref->{'format'} eq 'deff_item'); + add_prev($text, $stack, &$Texi2HTML::Config::def_item($format_ref->{'text'})); + $format_ref = pop @$stack; # pop deff + ######################################### debug + if (!defined($format_ref->{'format'}) or !defined($Texi2HTML::Config::def_map{$format_ref->{'format'}})) + { + print STDERR "Bug: not a def* under deff_item\n"; + push (@$stack, $format_ref); + dump_stack($text, $stack, $state); + pop @$stack; + } + ######################################### end debug + elsif ($format_ref->{'format'} ne $format) + { + $format_mismatch = 1; + echo_warn ("Waiting for \@end $format_ref->{'format'}, found \@end $format", $line_nr); + } + add_prev($text, $stack, &$Texi2HTML::Config::def($format_ref->{'text'})); + } + elsif ($format_type{$format} eq 'cartouche') + { + add_prev($text, $stack, &$Texi2HTML::Config::cartouche($format_ref->{'text'},$state->{'command_stack'})); + } + elsif ($format eq 'float') + { + unless (defined($state->{'float'})) + { + print STDERR "Bug: state->{'float'} not defined in float\n"; + next; + } + my ($caption_lines, $shortcaption_lines) = &$Texi2HTML::Config::caption_shortcaption($state->{'float'}); + my ($caption_text, $shortcaption_text); + $caption_text = substitute_text(duplicate_state($state), @$caption_lines) if (defined($caption_lines)); + $shortcaption_text = substitute_text(duplicate_state($state), @$shortcaption_lines) if (defined($shortcaption_lines)); + add_prev($text, $stack, &$Texi2HTML::Config::float($format_ref->{'text'}, $state->{'float'}, $caption_text, $shortcaption_text)); + delete $state->{'float'}; + } + elsif (exists ($Texi2HTML::Config::complex_format_map->{$format})) + { + $state->{'preformatted'}--; + pop @{$state->{'preformatted_stack'}}; + # debug + if (!defined($Texi2HTML::Config::complex_format_map->{$format_ref->{'format'}}->{'begin'})) + { + print STDERR "Bug undef $format_ref->{'format'}" . "->{'begin'} (for $format...)\n"; + dump_stack ($text, $stack, $state); + } + #print STDERR "before $format\n"; + #dump_stack ($text, $stack, $state); + add_prev($text, $stack, &$Texi2HTML::Config::complex_format($format_ref->{'format'}, $format_ref->{'text'})); + #print STDERR "after $format\n"; + #dump_stack ($text, $stack, $state); + } + elsif (($format_type{$format} eq 'table') or ($format_type{$format} eq 'list')) + { + #print STDERR "CLOSE $format ($format_ref->{'format'})\n$format_ref->{'text'}\n"; + pop @{$state->{'table_list_stack'}}; + #dump_stack($text, $stack, $state); + if ($format_ref->{'format'} ne $format) + { # for example vtable closing a table. Cannot be known + # before if in a cell + $format_mismatch = 1; + echo_warn ("Waiting for \@end $format_ref->{'format'}, found \@end $format ", $line_nr); + } + if ($Texi2HTML::Config::format_map{$format}) + { # table or list has a simple format + add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'})); + } + else + { # table or list handler defined by the user + add_prev($text, $stack, &$Texi2HTML::Config::table_list($format_ref->{'format'}, $format_ref->{'text'}, $format_ref->{'command'})); + } + } + elsif ($format_type{$format} eq 'menu') + { + # it should be short-circuited if $Texi2HTML::Config::SIMPLE_MENU + if ($state->{'preformatted'}) + { + # end the fake complex format + $state->{'preformatted'}--; + pop @{$state->{'preformatted_stack'}}; + pop @$stack; + } + add_prev($text, $stack, &$Texi2HTML::Config::menu($format_ref->{'text'})); + } + elsif ($format eq 'quotation') + { + my $quotation_args = pop @{$state->{'quotation_stack'}}; + #add_prev($text, $stack, &$Texi2HTML::Config::quotation($format_ref->{'text'}, $quotation_args->{'text'}, $quotation_args->{'style_texi'}, $quotation_args->{'style_id'})); + add_prev($text, $stack, &$Texi2HTML::Config::quotation($format_ref->{'text'}, $quotation_args->{'text'}, $quotation_args->{'text_texi'})); + } + elsif ($Texi2HTML::Config::paragraph_style{$format}) + { + if ($state->{'paragraph_style'}->[-1] eq $format) + { + pop @{$state->{'paragraph_style'}}; + } + add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command($format_ref->{'format'},$format_ref->{'text'})); + } + elsif (exists($Texi2HTML::Config::format_map{$format})) + { + add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'})); + } + else + { + echo_warn("Unknown format $format", $line_nr); + } + # special case for center as it is at the bottom of the stack + my $removed_from_stack; + if ($format eq 'center') + { + $removed_from_stack = shift @{$state->{'command_stack'}}; + } + else + { + $removed_from_stack = pop @{$state->{'command_stack'}}; + } + if ($removed_from_stack ne $format and !$format_mismatch) + { + print STDERR "Bug: removed_from_stack $removed_from_stack ne format $format\n"; + } +} + +sub do_text($;$) +{ + my $text = shift; + my $state = shift; + return $text if ($state->{'keep_texi'}); + my $remove_texi = 1 if ($state->{'remove_texi'} and !$state->{'simple_format'}); + return (&$Texi2HTML::Config::normal_text($text, $remove_texi, $state->{'preformatted'}, $state->{'code_style'},$state->{'command_stack'})); +} + +sub end_simple_format($$) +{ + my $tag = shift; + my $text = shift; + + my $element = $Texi2HTML::Config::format_map{$tag}; + return &$Texi2HTML::Config::format($tag, $element, $text); +} + +sub close_menu($$$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + if ($state->{'menu_comment'}) + { + #print STDERR "close MENU_COMMENT\n"; + #dump_stack($text, $stack, $state); + close_stack($text, $stack, $state, $line_nr, undef, 'menu_comment'); + # close_paragraph isn't needed in most cases, but a preformatted may + # appear after close_stack if we closed a format, as formats reopen + # preformatted. However it is empty and close_paragraph will remove it + close_paragraph($text, $stack, $state); + my $menu_comment = pop @$stack; + if (!$menu_comment->{'format'} or $menu_comment->{'format'} ne 'menu_comment') + { + warn "Bug waiting for menu_comment, got $menu_comment->{'format'}\n"; + dump_stack($text, $stack, $state); + } + add_prev($text, $stack, &$Texi2HTML::Config::menu_comment($menu_comment->{'text'})); + unless ($Texi2HTML::Config::SIMPLE_MENU) + { + pop @{$state->{'preformatted_stack'}}; + $state->{'preformatted'}--; + } + $state->{'menu_comment'}--; + } + if ($state->{'menu_entry'}) + { + close_stack($text, $stack,$state, $line_nr, undef, 'menu_description'); + my $descr = pop(@$stack); + print STDERR "# close_menu: close description\n" if ($T2H_DEBUG & $DEBUG_MENU); + add_prev($text, $stack, do_menu_description($descr->{'text'}, $state)); + delete $state->{'menu_entry'}; + } +} + +# Format menu link +sub do_menu_link($$;$) +{ + my $state = shift; + my $line_nr = shift; + my $simple = shift; + my $menu_entry = $state->{'menu_entry'}; + my $file = $state->{'element'}->{'file'}; + my $node_name = normalise_node($menu_entry->{'node'}); + + my $substitution_state = duplicate_state($state); + my $name = substitute_line($menu_entry->{'name'}, $substitution_state); + my $node_formatted = substitute_line($menu_entry->{'node'}, $substitution_state); + + my $entry = ''; + my $href; + my $element = $nodes{$node_name}; + + # menu points to an unknown node + if (!$element->{'seen'}) + { + if ($menu_entry->{'node'} =~ /^\s*\(.*\)/o or $novalidate) + { + # menu entry points to another info manual or invalid nodes + # and novalidate is set + #$href = $nodes{$node_name}->{'file'}; + $href = do_external_href($node_name); + } + else + { + echo_error ("Unknown node in menu entry `$node_name'", $line_nr); + # try to find an equivalent node + my @equivalent_nodes = equivalent_nodes($node_name); + my $node_seen; + foreach my $equivalent_node (@equivalent_nodes) + { + if ($nodes{$equivalent_node}->{'seen'}) + { + $node_seen = $equivalent_node; + last; + } + } + if (defined($node_seen)) + { + echo_warn (" ---> but equivalent node `$node_seen' found"); + $element = $nodes{$node_seen}; + } + } + } + + # the original node or an equivalent node was seen + if ($element->{'seen'}) + { + if ($element->{'reference_element'}) + { + $element = $element->{'reference_element'}; + } + + #print STDERR "SUBHREF in menu for `$element->{'texi'}'\n"; + $href = href($element, $file); + if (! $element->{'node'}) + { + $entry = $element->{'text'}; # this is the section/node name + $entry = "$Texi2HTML::Config::MENU_SYMBOL $entry" if (($entry ne '') and (!defined($element->{'number'}) or ($element->{'number'} =~ /^\s*$/)) and $Texi2HTML::Config::UNNUMBERED_SYMBOL_IN_MENU); + } + } + # save the element used for the href for the description + $menu_entry->{'menu_reference_element'} = $element; + + return &$Texi2HTML::Config::menu_link($entry, $substitution_state, $href, $node_formatted, $name, $menu_entry->{'ending'}) unless ($simple); + return &$Texi2HTML::Config::simple_menu_link($entry, $state->{'preformatted'}, $href, $node_formatted, $name, $menu_entry->{'ending'}); +} + +sub do_menu_description($$) +{ + my $descr = shift; + my $state = shift; + my $menu_entry = $state->{'menu_entry'}; + + my $element = $menu_entry->{'menu_reference_element'}; + + return &$Texi2HTML::Config::menu_description($descr, duplicate_state($state),$element->{'text_nonumber'}); +} + +sub do_xref($$$$) +{ + my $macro = shift; + my $args = shift; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + + my $result = ''; + my @args = @$args; + #print STDERR "DO_XREF: $macro\n"; + my $j = 0; + for ($j = 0; $j <= $#$args; $j++) + { + $args[$j] = normalise_space($args[$j]); + # print STDERR " ($j)$args[$j]\n"; + } + $args[0] = '' if (!defined($args[0])); + my $node_texi = normalise_node($args[0]); + # a ref to a node in an info manual + if ($args[0] =~ s/^\(([^\)]+)\)\s*//) + { + if ($macro eq 'inforef') + { + $args[2] = $1 unless ($args[2]); + } + else + { + $args[3] = $1 unless ($args[3]); + } + } + if (($macro ne 'inforef') and $args[3]) + { + $node_texi = "($args[3])" . normalise_node($args[0]); + } + + if ($macro eq 'inforef') + { + if ((@args < 1) or ($args[0] eq '')) + { + echo_error ("Need a node name for \@$macro", $line_nr); + return ''; + } + if (@args > 3) + { + echo_warn ("Too much arguments for \@$macro", $line_nr); + } + $args[2] = '' if (!defined($args[2])); + $args[1] = '' if (!defined($args[1])); + $node_texi = "($args[2])$args[0]"; + } + + my $i; + my $new_state = duplicate_state($state); + $new_state->{'keep_texi'} = 0; + $new_state->{'keep_nr'} = 0; + for ($i = 0; $i < 5; $i++) + { + $args[$i] = substitute_line($args[$i], $new_state); + } + #print STDERR "(@args)\n"; + + if (($macro eq 'inforef') or ($args[3] ne '') or ($args[4] ne '')) + {# external ref + if ($macro eq 'inforef') + { + $macro = 'xref'; + $args[3] = $args[2]; + } + my $href = ''; + my $node_file = ''; + if ($args[3] ne '') + { + $href = do_external_href($node_texi); + $node_file = "($args[3])$args[0]"; + } + my $section = ''; + if ($args[4] ne '') + { + $section = $args[0]; + if ($args[2] ne '') + { + $section = $args[2]; + } + } + $result = &$Texi2HTML::Config::external_ref($macro, $section, $args[4], $node_file, $href, $args[1]); + } + else + { + my $element = $nodes{$node_texi}; + if ($element and $element->{'seen'}) + { + if ($element->{'reference_element'}) + { + $element = $element->{'reference_element'}; + } + my $file = ''; + if (defined($state->{'element'})) + { + $file = $state->{'element'}->{'file'}; + } + else + { + echo_warn ("\@$macro not in text (in anchor, node, section...)", $line_nr); + # if Texi2HTML::Config::SPLIT the file is '' which ensures + # a href with the file name. if ! Texi2HTML::Config::SPLIT + # the 2 file will be the same thus there won't be the file name + $file = $element->{'file'} unless ($Texi2HTML::Config::SPLIT); + } + #print STDERR "SUBHREF in ref to node `$node_texi': $_"; + my $href = href($element, $file); + my $section = $args[2]; + $section = $args[1] if ($section eq ''); + my $name = $section; + my $short_name = $section; + if ($section eq '') + { + # FIXME maybe one should use 'text' instead of 'text_nonumber' + # However the real fix would be to have an internal_ref call + # with more informations + $name = $element->{'text_nonumber'}; + $short_name = $args[0]; + } + $result = &$Texi2HTML::Config::internal_ref ($macro, $href, $short_name, $name, $element->{'section'}); + } + else + { + if (($node_texi eq '') or !$novalidate) + { + echo_error ("Undefined node `$node_texi' in \@$macro", $line_nr); + my $text = ''; + for (my $i = 0; $i < @$args -1; $i++) + { + $text .= $args->[$i] .','; + } + $text .= $args->[-1]; + $result = "\@$macro"."{${text}}"; + } + else + { + $result = &$Texi2HTML::Config::external_ref($macro, '', '', $args[0], do_external_href($node_texi), $args[1]); + } + } + } + return $result; +} + +sub do_acronym_like($$$$$) +{ + my $command = shift; + my $args = shift; + my $acronym_texi = shift @$args; + my $explanation = shift @$args; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + + my $explanation_lines; + my $explanation_text; + my $explanation_simple_format; + + if (defined($explanation)) + { + $explanation =~ s/^\s*//; + $explanation =~ s/\s*$//; + $explanation = undef if ($explanation eq ''); + } + $acronym_texi =~ s/^\s*//; + $acronym_texi =~ s/\s*$//; + + return '' if ($acronym_texi eq ''); + + my $with_explanation = 0; + my $normalized_text = cross_manual_line(normalise_node($acronym_texi)); + if (defined($explanation)) + { + $with_explanation = 1; + $acronyms_like{$command}->{$normalized_text} = $explanation; + } + elsif (exists($acronyms_like{$command}->{$normalized_text})) + { + $explanation = $acronyms_like{$command}->{$normalized_text}; + } + + if (defined($explanation)) + { + @$explanation_lines = map {$_ = $_."\n"} split (/\n/, $explanation); + my $text = ''; + foreach my $line(@$explanation_lines) + { + $line .= ' ' if (chomp ($line)); + $text .= $line + } + $text =~ s/ $//; + my $simple_format_state = duplicate_state($state); + $explanation_simple_format = simple_format($simple_format_state,$text); + $explanation_text = substitute_line($text, duplicate_state($state)); + } + return &$Texi2HTML::Config::acronym_like($command, $acronym_texi, substitute_line($acronym_texi, duplicate_state($state)), + $with_explanation, $explanation_lines, $explanation_text, $explanation_simple_format); +} + +sub do_caption_shortcaption($$$$$) +{ + my $command = shift; + my $args = shift; + my $text = $args->[0]; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + + if (!exists($state->{'float'})) + { +#dump_stack(\"", [], $state); + echo_error("\@$command outside of float", $line_nr); + return ''; + } + my $float = $state->{'float'}; + my @texi_lines = map {$_ = $_."\n"} split (/\n/, $text); + $float->{"${command}_texi"} = \@texi_lines; + return ''; +} + +# function called when a @float is encountered. Don't do any output +# but prepare $state->{'float'} +sub do_float_line($$$$$) +{ + my $command = shift; + my $args = shift; + my @args = @$args; + my $style_texi = shift @args; + my $label_texi = shift @args; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + + $style_texi = undef if (defined($style_texi) and $style_texi=~/^\s*$/); + $label_texi = undef if (defined($label_texi) and $label_texi=~/^\s*$/); + if (defined($label_texi)) + { # the float is considered as a node as it may be a target for refs. + # it was entered as a node in the pass_structure and the float + # line was parsed at that time + $state->{'float'} = $nodes{normalise_node($label_texi)}; + #print STDERR "float: $state->{'float'}, $state->{'float'}->{'texi'}\n"; + } + else + { # a float without label. It can't be the target for refs. + $state->{'float'} = { 'float' => 1 }; + if (defined($style_texi)) + { + $state->{'float'}->{'style_texi'} = normalise_space($style_texi); + $state->{'float'}->{'style_id'} = + cross_manual_line($state->{'float'}->{'style_texi'}); + $state->{'float'}->{'style'} = substitute_line($style_texi); + } + #print STDERR "float: (no label) $state->{'float'}\n"; + } + return ''; +} + +sub do_quotation_line($$$$$) +{ + my $command = shift; + my $args = shift; + my @args = @$args; + my $text_texi = shift @args; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + my $text; + + $text_texi = undef if (defined($text_texi) and $text_texi=~/^\s*$/); + if (defined($text_texi)) + { + $text = substitute_line($text_texi, duplicate_state($state)); + $text =~ s/\s*$//; + } + my $quotation_args = { 'text' => $text, 'text_texi' => $text_texi }; + push @{$state->{'quotation_stack'}}, $quotation_args; + $state->{'prepend_text'} = &$Texi2HTML::Config::quotation_prepend_text($text_texi); + return ''; +} + +sub do_def_line($$$$$) +{ + my $command = shift; + my $args = shift; + my @args = @$args; + my $arguments = shift @args; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + + $state->{'deff_line'}->{'arguments'} = $arguments; + return ''; +} + +sub do_footnote($$$$) +{ + my $command = shift; + my $args = shift; + my $text = $args->[0]; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + + $text .= "\n"; + $foot_num++; + $relative_foot_num++; + my $docid = "DOCF$foot_num"; + my $footid = "FOOT$foot_num"; + my $from_file = ''; + if ($state->{'element'} and $Texi2HTML::Config::SPLIT and $Texi2HTML::Config::SEPARATED_FOOTNOTES) + { + $from_file = $state->{'element'}->{'file'}; + } + my %state; + initialise_state(\%state); + if ($Texi2HTML::Config::SEPARATED_FOOTNOTES) + { + $state{'element'} = $footnote_element; + } + else + { + $state{'element'} = $state->{'element'}; + } + my $file = ''; + $file = $docu_foot if ($Texi2HTML::Config::SPLIT and $Texi2HTML::Config::SEPARATED_FOOTNOTES); + + # FIXME use split_lines ? It seems to work like it is now ? + my @lines = substitute_text(\%state, map {$_ = $_."\n"} split (/\n/, $text)); + my ($foot_lines, $foot_label) = &$Texi2HTML::Config::foot_line_and_ref ($foot_num, + $relative_foot_num, $footid, $docid, $from_file, $file, \@lines, $state); + push(@foot_lines, @{$foot_lines}); + return $foot_label; +} + +sub do_image($$$$) +{ + # replace images + my $command = shift; + my $args = shift; + my $text = $args->[0]; + my $style_stack = shift; + my $state = shift; + my $line_nr = shift; + $text =~ s/\s+/ /gos; # remove useless spaces and newlines + my @args = split (/\s*,\s*/, $text); + my $base = $args[0]; + if ($base eq '') + { + echo_error ("no file argument for \@image", $line_nr); + #warn "$ERROR no file argument for \@image\n"; + return ''; + } + $args[4] = '' if (!defined($args[4])); + $args[3] = '' if (!defined($args[3])); + my $image; + my $file_name; + my @file_names = &$Texi2HTML::Config::image_files($base,$args[4]); +# $image = locate_include_file("$base.$args[4]") if ($args[4] ne ''); + foreach my $file (@file_names) + { + if ($image = locate_include_file($file)) + { + $file_name = $file; + last; + } + } + $image = '' if (!defined($image)); + + my $alt; + if ($args[3] =~ /\S/) + { + # makeinfo don't do that. Maybe it should be remove_texi or + # simple_format... The raw alt is also given in argument + $alt = do_text($args[3]); + $alt = $alt if ($alt =~ /\S/); + } + return &$Texi2HTML::Config::image($path_to_working_dir . $image, $base, + $state->{'preformatted'}, $file_name, $alt, $args[1], $args[2], + $args[3], $args[4], $path_to_working_dir, $image); +} + +sub duplicate_state($) +{ + my $state = shift; + my $new_state = { 'element' => $state->{'element'}, + 'preformatted' => $state->{'preformatted'}, + 'code_style' => $state->{'code_style'}, + 'keep_texi' => $state->{'keep_texi'}, + 'keep_nr' => $state->{'keep_nr'}, + 'preformatted_stack' => $state->{'preformatted_stack'}, + 'multiple_pass' => $state->{'multiple_pass'}, +# this is needed for preformatted + 'command_stack' => [ @{$state->{'command_stack'}} ], + 'preformatted_context' => + {'stack_at_beginning' => [ @{$state->{'command_stack'}} ] } + }; + return $new_state; +} + +sub expand_macro($$$$$) +{ + my $name = shift; + my $args = shift; + my $end_line = shift; + my $line_nr = shift; + my $state = shift; + + # we dont expand macros when in ignored environment. + return if ($state->{'ignored'}); + my $index = 0; + foreach my $arg (@$args) + { # expand @macros in arguments. It is complicated because we must be + # carefull not to expand macros in @ignore section or the like, and + # still keep every single piece of text (including the @ignore macros). + $args->[$index] = substitute_text({'texi' => 1, 'arg_expansion' => 1}, split_lines($arg)); + $index++; + } + # retrieve the macro definition + my $macrobody = $macros->{$name}->{'body'}; + my $formal_args = $macros->{$name}->{'args'}; + my $args_index = $macros->{$name}->{'args_index'}; + my $i; + + die "Bug end_line not defined" if (!defined($end_line)); + + for ($i=0; $i<=$#$formal_args; $i++) + { + $args->[$i] = "" unless (defined($args->[$i])); + print STDERR "# arg($i): $args->[$i]\n" if ($T2H_DEBUG & $DEBUG_MACROS); + } + echo_error ("too much arguments for macro $name", $line_nr) if (defined($args->[$i + 1])); + my $result = ''; + while ($macrobody) + { + if ($macrobody =~ s/^([^\\]*)\\//o) + { + $result .= $1 if defined($1); + if ($macrobody =~ s/^\\//) + { + $result .= '\\'; + } + elsif ($macrobody =~ s/^(\@end\sr?macro)$// or $macrobody =~ s/^(\@end\sr?macro\s)// or $macrobody =~ s/^(\@r?macro\s+\w+\s*.*)//) + { # \ protect @end macro + $result .= $1; + } + elsif ($macrobody =~ s/^([^\\]*)\\//) + { + my $arg = $1; + if (defined($args_index->{$arg})) + { + $result .= $args->[$args_index->{$arg}]; + } + else + { + warn "$ERROR \\ not followed by \\ or an arg but by $arg in macro\n"; + $result .= '\\' . $arg; + } + } + next; + } + $result .= $macrobody; + last; + } + my @result = split(/^/m, $result); + # Add the result of the macro expansion back to the input_spool. + # Set the macro name if in the outer macro + if ($state->{'arg_expansion'}) + { + unshift @{$state->{'spool'}}, (@result, $end_line); + } + else + { + unshift @{$input_spool->{'spool'}}, (@result, $end_line); + $input_spool->{'macro'} = $name if ($input_spool->{'macro'} eq ''); + } + if ($T2H_DEBUG & $DEBUG_MACROS) + { + print STDERR "# macro expansion result:\n"; + #print STDERR "$first_line"; + foreach my $line (@result) + { + print STDERR "$line"; + } + print STDERR "# macro expansion result end\n"; + } +} + +sub do_index_summary_file($) +{ + my $name = shift; + my ($pages, $entries) = get_index($name); + &$Texi2HTML::Config::index_summary_file_begin ($name, $printed_indices{$name}); + print STDERR "# writing $name index summary\n" if $T2H_VERBOSE; + + foreach my $key (sort keys %$entries) + { + my $entry = $entries->{$key}; + my $indexed_element = $entry->{'element'}; + my $entry_element = $indexed_element; + # notice that we use the section associated with a node even when + # there is no with_section, i.e. when there is another node preceding + # the sectionning command. + # However when it is the Top node, we use the node instead. + # (for the Top node, 'top_as_section' is true) + $entry_element = $entry_element->{'section_ref'} if ($entry_element->{'section_ref'} and !$entry_element->{'top_as_section'}); + my $origin_href = $entry->{'file'}; + #print STDERR "$entry $entry->{'entry'}, real elem $indexed_element->{'texi'}, section $entry_element->{'texi'}, real $indexed_element->{'file'}, entry file $entry->{'file'}\n"; + if ($entry->{'label'}) + { + $origin_href .= '#' . $entry->{'label'}; + } + else + { + # If the $indexed_element element and the $index entry are on + # the same + # file the real element is prefered. If they aren't on the same file + # the entry id is choosed as it means that the real element + # and the index entry are separated by a printindex. + print STDERR "id undef ($entry) entry: $entry->{'entry'}, label: $indexed_element->{'text'}\n" if (!defined($entry->{'id'})); + if ($entry->{'file'} eq $indexed_element->{'file'}) + { + $origin_href .= '#' . $indexed_element->{'id'}; + } + else + { + $origin_href .= '#' . $entry->{'id'} ; + } + } + &$Texi2HTML::Config::index_summary_file_entry ($name, + $key, $origin_href, + substitute_line($entry->{'entry'}), $entry->{'entry'}, + href($entry_element, ''), + $entry_element->{'text'}, + $printed_indices{$name}); + } + &$Texi2HTML::Config::index_summary_file_end ($name, $printed_indices{$name}); +} + +sub do_index_page($$;$) +{ + my $index_elements = shift; + my $nr = shift; + my $page = shift; + my $index_element = $index_elements->[$nr]; + my $summary = do_index_summary($index_element->{'element'}, $index_elements); + my $entries = do_index_entries($index_element->{'element'}, $index_element->{'page'}, $index_element->{'name'}); + return $summary . $entries . $summary; +} + +sub do_index_summary($$) +{ + my $element = shift; + my $index_elements = shift; + + my @letters; + my @symbols; + + for my $index_element_item (@$index_elements) + { + my $index_element = $index_element_item->{'element'}; + my $file = ''; + $file .= $index_element->{'file'} if ($index_element->{'file'} ne $element->{'file'}); + my $index = 0; + for my $letter (@{$index_element_item->{'page'}->{'letters'}}) + { + if ($letter =~ /^[A-Za-z]/) + { + push @letters, &$Texi2HTML::Config::summary_letter($letter, $file, "$index_element->{'id'}" . "_$index"); + } + else + { + push @symbols, &$Texi2HTML::Config::summary_letter($letter, $file, "$index_element->{'id'}" . "_$index"); + } + $index++; + } + } + return &$Texi2HTML::Config::index_summary(\@letters, \@symbols); +} + +sub do_index_entries($$$) +{ + my $element = shift; + my $page = shift; + my $name = shift; + + my $letters = ''; + my $index = 0; + foreach my $letter (@{$page->{'letters'}}) + { + my $entries = ''; + foreach my $entry (@{$page->{'entries_by_letter'}->{$letter}}) + { + my $indexed_element = $entry->{'element'}; + my $entry_element = $indexed_element; + # notice that we use the section associated with a node even when + # there is no with_section, i.e. when there is another node preceding + # the sectionning command. + # However when it is the Top node, we use the node instead. + # (for the Top node, 'top_as_section' is true) + $entry_element = $entry_element->{'section_ref'} if ($entry_element->{'section_ref'} and !$entry_element->{'top_as_section'}); + my $origin_href = ''; + $origin_href = $entry->{'file'} if ($Texi2HTML::Config::SPLIT and $entry->{'file'} ne $element->{'file'}); + #print STDERR "$entry $entry->{'entry'}, real elem $indexed_element->{'texi'}, section $entry_element->{'texi'}, real $indexed_element->{'file'}, entry file $entry->{'file'}\n"; + if ($entry->{'label'}) + { + $origin_href .= '#' . $entry->{'label'}; + } + else + { + # If the $indexed_element element and the $index entry are + # in the same file the indexed_element is prefered. If they + # aren't in the same file the entry id is choosed as it means + # that the indexed_element element and the index entry are + # separated by a printindex. + print STDERR "id undef ($entry) entry: $entry->{'entry'}, label: $indexed_element->{'text'}\n" if (!defined($entry->{'id'})); + if ($entry->{'file'} eq $indexed_element->{'file'}) + { + $origin_href .= '#' . $indexed_element->{'id'}; + } + else + { + $origin_href .= '#' . $entry->{'id'} ; + } + } + #print STDERR "SUBHREF in index entry `$entry->{'entry'}' for `$entry_element->{'texi'}'\n"; + $entries .= &$Texi2HTML::Config::index_entry ($origin_href, + substitute_line($entry->{'entry'}), + href($entry_element, $element->{'file'}), + $entry_element->{'text'}); + } + $letters .= &$Texi2HTML::Config::index_letter ($letter, "$element->{'id'}" . "_$index", $entries); + $index++; + } + return &$Texi2HTML::Config::print_index($letters, $name); +} + +# remove texi commands, replacing with what seems adequate. see simple_map_texi +# and texi_map. +# Doesn't protect html +sub remove_texi(@) +{ + return substitute_text ({ 'remove_texi' => 1}, @_); +} + +# Same as remove texi but protect text and use special maps for @-commands +sub simple_format($@) +{ + my $state = shift; + $state = {} if (!defined($state)); + $state->{'remove_texi'} = 1; + $state->{'simple_format'} = 1; + # WARNING currently it is only used for lines. It may change in the future. + $state->{'no_paragraph'} = 1; + $::simple_map_texi_ref = \%Texi2HTML::Config::simple_format_simple_map_texi; + $::style_map_texi_ref = \%Texi2HTML::Config::simple_format_style_map_texi; + $::texi_map_ref = \%Texi2HTML::Config::simple_format_texi_map; + my $text = substitute_text($state, @_); + $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi; + $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi; + $::texi_map_ref = \%Texi2HTML::Config::texi_map; + return $text; +} + +sub enter_table_index_entry($$$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + if ($state->{'item'} and ($state->{'table_stack'}->[-1] =~ /^(v|f)table$/)) + { + my $index = $1; + my $macro = $state->{'item'}; + delete $state->{'item'}; + close_stack($text, $stack, $state, $line_nr, undef, 'index_item'); + my $item = pop @$stack; + my $element = $state->{'element'}; + $element = $state->{'node_ref'} unless ($element); + enter_index_entry($index, $line_nr, $item->{'text'}, + $state->{'place'}, $element, 0, $state->{'table_stack'}->[-1]); + add_prev($text, $stack, "\@$macro" . $item->{'text'}); + } +} + +sub scan_texi($$$$;$) +{ + my $line = shift; + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + + die "stack not an array ref" unless (ref($stack) eq "ARRAY"); + local $_ = $line; + + while(1) + { + # scan_texi + #print STDERR "WHILE:$_"; + #print STDERR "ARG_EXPANSION: $state->{'arg_expansion'}\n" if ($state->{'arg_expansion'}); + #dump_stack($text, $stack, $state); + #print STDERR "ifvalue_inside $state->{'ifvalue_inside'}\n"; + + + # first we handle special cases: + # macro definition: $state->{'macro_inside'} + # macro arguments: $state->{'macro_name'} + # raw format: $state->{'raw'} + # @verb: $state->{'verb'} + # ignored: $state->{'ignored'} + # and then the remaining text/macros. + + # in macro definition + if ($state->{'macro_inside'}) + { + if (s/^([^\\\@]*\\)//) + {# protected character or @end macro + $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'}); + if (s/^\\//) + { + $state->{'macro'}->{'body'} .= '\\' unless ($state->{'ignored'}); + next; + } + # I believe it is correct, although makeinfo don't do that. + elsif (s/^(\@end\sr?macro)$//o or s/^(\@end\sr?macro\s)//o + or s/^(\@r?macro\s+\w+\s*.*)//o) + { + $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'}); + next; + } + } + #if (s/^(.*?)\@end\sr?macro$//o or s/^(.*?)\@end\sr?macro\s+//o) + if (s/^(\@end\sr?macro)$//o or s/^(\@end\sr?macro\s+)//o) + { + $state->{'macro_inside'}--; + next if ($state->{'ignored'}); + if ($state->{'macro_inside'}) + { + $state->{'macro'}->{'body'} .= $1; + next; + } + chomp $state->{'macro'}->{'body'}; + print STDERR "# end macro def. Body:\n$state->{'macro'}->{'body'}" + if ($T2H_DEBUG & $DEBUG_MACROS); + delete $state->{'macro'}; + return if (/^\s*$/); + next; + } + elsif(/^(\@r?macro\s+\w+\s*.*)/) + { + $state->{'macro'}->{'body'} .= $_ unless ($state->{'ignored'}); + $state->{'macro_inside'}++; + return; + } + elsif (s/^\@(.)//) + { + $state->{'macro'}->{'body'} .= '@' . $1 unless ($state->{'ignored'}); + next; + } + elsif (s/^\@//) + { + $state->{'macro'}->{'body'} .= '@' unless ($state->{'ignored'}); + next; + } + else + { + s/([^\@\\]*)//; + if ($state->{'ignored'}) + { + return if (/^$/); + next; + } + $state->{'macro'}->{'body'} .= $1 if (defined($1)); + if (/^$/) + { + $state->{'macro'}->{'body'} .= $_; + return; + } + next; + } + } + # in macro arguments parsing/expansion. Here \ { } and , if this is a + # multi args macro have a signification, the remaining is passed + # unmodified + if (defined($state->{'macro_name'})) + { + my $special_chars = quotemeta ('\{}'); + my $multi_args = 0; + my $formal_args = $macros->{$state->{'macro_name'}}->{'args'}; + $multi_args = 1 if ($#$formal_args >= 1); + $special_chars .= quotemeta(',') if ($multi_args); + if ($state->{'macro_args'}->[-1] eq '') + {# remove space at the very beginning + s/^\s*//o; + } + if (s/^([^$special_chars]*)([$special_chars])//) + { + $state->{'macro_args'}->[-1] .= $1 if defined($1); + # \ protects any character in macro arguments + if ($2 eq '\\') + { + print STDERR "# macro call: protected char\n" if ($T2H_DEBUG & $DEBUG_MACROS); + if (s/^(.)//) + { + $state->{'macro_args'}->[-1] .= $1; + } + else + { + $state->{'macro_args'}->[-1] .= '\\'; + } + } + elsif ($2 eq ',') + { # in texinfo 4.8.90 a comma in braces is protected + if ($state->{'macro_depth'} > 1) + { + $state->{'macro_args'}->[-1] .= ','; + } + else + { # separate args + print STDERR "# macro call: new arg\n" if ($T2H_DEBUG & $DEBUG_MACROS); + s/^\s*//o; + push @{$state->{'macro_args'}}, ''; + } + } + elsif ($2 eq '}') + { # balanced } ends the macro call, otherwise it is in the arg + $state->{'macro_depth'}--; + if ($state->{'macro_depth'} == 0) + { + print STDERR "# expanding macro $state->{'macro_name'}\n" if ($T2H_DEBUG & $DEBUG_MACROS); + $_ = expand_macro($state->{'macro_name'}, $state->{'macro_args'}, $_, $line_nr, $state); + delete $state->{'macro_name'}; + delete $state->{'macro_depth'}; + delete $state->{'macro_args'}; + return; + } + else + { + print STDERR "# macro call: closing }\n" if ($T2H_DEBUG & $DEBUG_MACROS); + add_text('}', \$state->{'macro_args'}->[-1]); + } + } + elsif ($2 eq '{') + { + print STDERR "# macro call: opening {\n" if ($T2H_DEBUG & $DEBUG_MACROS); + $state->{'macro_depth'}++; + add_text('{', \$state->{'macro_args'}->[-1]); + } + next; + } + print STDERR "# macro call: end of line\n" if ($T2H_DEBUG & $DEBUG_MACROS); + $state->{'macro_args'}->[-1] .= $_; + return; + } + # in a raw format, verbatim, tex or html + if ($state->{'raw'}) + { + my $tag = $state->{'raw'}; + + # debugging + if (! @$stack or ($stack->[-1]->{'style'} ne $tag)) + { + print STDERR "Bug: raw or special: $tag but not on top of stack\n"; + print STDERR "line: $_"; + dump_stack($text, $stack, $state); + exit 1; + } + + if (s/^(.*?)(\@end\s$tag)$// or s/^(.*?)(\@end\s$tag\s)//) + {# we add it even if 'ignored', it'll be discarded when there is + # the @end + add_prev ($text, $stack, $1); + my $end = $2; + my $style = pop @$stack; + if ($style->{'text'} !~ /^\s*$/ or $state->{'arg_expansion'}) + # FIXME if 'arg_expansion' and also 'ignored' is true, + # theoretically we should keep + # what is in the raw format however + # it will be removed later anyway + {# ARG_EXPANSION + my $after_macro = ''; + $after_macro = ' ' unless (/^\s*$/); + add_prev ($text, $stack, $style->{'text'} . $end . $after_macro) unless ($state->{'ignored'}); + delete $state->{'raw'}; + } + next; + } + else + {# we add it even if 'ignored', it'll be discarded when there is + # the @end + add_prev ($text, $stack, $_); + last; + } + } + + # in a @verb{ .. } macro + if (defined($state->{'verb'})) + { + #dump_stack($text, $stack, $state); + my $char = quotemeta($state->{'verb'}); + #print STDERR "VERB $char\n"; + if (s/^(.*?)$char\}/\}/) + {# we add it even if 'ignored', it'll be discarded when closing + add_prev($text, $stack, $1 . $state->{'verb'}); + $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'}; + delete $state->{'verb'}; + next; + } + else + {# we add it even if 'ignored', it'll be discarded when closing + add_prev($text, $stack, $_); + last; + } + } + # In ignored region + if ($state->{'ignored'}) + { + #print STDERR "IGNORED(ifvalue($state->{'ifvalue_inside'})): $state->{'ignored'}\n"; + if (/^.*?\@end(\s+)([a-zA-Z]\w+)/) + { + if ($2 eq $state->{'ignored'}) + { + s/^(.*?\@end)(\s+)([a-zA-Z]\w+)//; + my $end_ignore = $1.$2.$3; + if (($state->{'ifvalue_inside'}) and $state->{'ignored'} eq $state->{'ifvalue'}) + { + if ($state->{'ifvalue_inside'} == 1) + {# closing still opened @-commands with braces + pop (@$stack) while (@$stack and $stack->[-1]->{'style'} ne 'ifvalue') + } + pop (@$stack); + $state->{'ifvalue_inside'}--; + } + $state->{'ignored'} = undef; + delete $state->{'ignored'}; + # We are stil in the ignored ifset or ifclear section + $state->{'ignored'} = $state->{'ifvalue'} if ($state->{'ifvalue_inside'}); + #dump_stack($text, $stack, $state); + # MACRO_ARG => keep ignored text + if ($state->{'arg_expansion'}) + {# this may not be very usefull as it'll be remove later + add_prev ($text, $stack, $end_ignore); + next; + } + return if /^\s*$/o; + next; + } + } + add_prev ($text, $stack, $_) if ($state->{'arg_expansion'}); + # we could theoretically continue for ignored commands other + # than ifset or ifclear, however it isn't usefull. + return unless ($state->{'ifvalue_inside'} and ($state->{'ignored'} eq $state->{'ifvalue'})); + } + + + # an @end tag + # macro_regexp + if (s/^([^{}@]*)\@end(\s+)([a-zA-Z][\w-]*)//) + { + my $leading_text = $1; + my $space = $2; + my $end_tag = $3; + # when 'ignored' we don't open environments that aren't associated + # with ignored regions, so we don't need to close them. + next if ($state->{'ignored'});# ARG_EXPANSION + add_prev($text, $stack, $leading_text); + if (defined($state->{'text_macro_stack'}) + and @{$state->{'text_macro_stack'}} + and ($end_tag eq $state->{'text_macro_stack'}->[-1])) + { + pop @{$state->{'text_macro_stack'}}; + # we keep menu and titlepage for the following pass + if ((($end_tag eq 'menu') and $text_macros{'menu'}) or ($region_lines{$end_tag}) or $state->{'arg_expansion'}) + { + add_prev($text, $stack, "\@end${space}$end_tag"); + } + else + { + #print STDERR "End $end_tag\n"; + #dump_stack($text, $stack, $state); + return if (/^\s*$/); + } + } + elsif ($text_macros{$end_tag}) + { + echo_error ("\@end $end_tag without corresponding element", $line_nr); + } + else + {# ARG_EXPANSION + add_prev($text, $stack, "\@end${space}$end_tag"); + } + next; + } + # macro_regexp + elsif (s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])//o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)([\s\{\}\@])/$3/o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)$//o) + {# ARG_EXPANSION + add_prev($text, $stack, $1) unless $state->{'ignored'}; + my $macro = $2; + #print STDERR "MACRO $macro\n"; + # handle skipped @-commands + $state->{'bye'} = 1 if ($macro eq 'bye' and !$state->{'ignored'} and !$state->{'arg_expansion'}); + if (defined($Texi2HTML::Config::misc_command{$macro}) and + !$Texi2HTML::Config::misc_command{$macro}->{'texi'} + and $macro ne 'documentencoding') + {# ARG_EXPANSION + my ($line, $args); + ($_, $line, $args) = preserve_command($_, $macro); + add_prev ($text, $stack, "\@$macro" . $line) unless $state->{'ignored'}; + } + # pertusus: it seems that value substitution are performed after + # macro argument expansions: if we have + # @set comma , + # and a call to a macro @macro {arg1 @value{comma} arg2} + # the macro arg is arg1 , arg2 and the comma don't separate + # args. Likewise it seems that the @value are not expanded + # in macro definitions + + # track variables + elsif($macro eq 'set' or $macro eq 'clear') + { + if ($macro eq 'set') + { + if (s/^(\s+)($VARRE)(\s+)(.*)$//o) + { + if ($state->{'arg_expansion'}) + { + my $line = "\@$macro" . $1.$2.$3; + $line .= $4 if (defined($4)); + add_prev($text, $stack, $line); + next; + } + next if $state->{'ignored'}; + $value{$2} = $4; + } + else + { + echo_warn ("Missing argument for \@$macro", $line_nr); + } + } + elsif ($macro eq 'clear') + { + if (s/^(\s+)($VARRE)//o) + { + if ($state->{'arg_expansion'}) + { + add_prev($text, $stack, "\@$macro" . $1 . $2); + next; + } + next if $state->{'ignored'}; + delete $value{$2}; + } + else + { + echo_warn ("Missing argument for \@$macro", $line_nr); + } + } + return if (/^\s*$/); + } + elsif ($macro =~ /^r?macro$/) + { #FIXME what to do if 'arg_expansion' is true (ie within another + # macro call arguments? + if (/^\s+(\w[\w-]*)\s*(.*)/) + { + my $name = $1; + unless ($state->{'ignored'}) + { + if (exists($macros->{$name})) + { + echo_warn ("macro `$name' allready defined " . + format_line_number($macros->{$name}->{'line_nr'}) . " redefined", $line_nr); + } + + } + $state->{'macro_inside'} = 1; + next if ($state->{'ignored'}); + # if in 'arg_expansion' we really want to take into account + # that we are in an ignored ifclear. + my @args = (); + @args = split(/\s*,\s*/ , $1) + if ($2 =~ /^\s*{\s*(.*?)\s*}\s*/); + # keep the context information of the definition + $macros->{$name}->{'line_nr'} = { 'file_name' => $line_nr->{'file_name'}, + 'line_nr' => $line_nr->{'line_nr'}, 'macro' => $line_nr->{'macro'} } if (defined($line_nr)); + $macros->{$name}->{'args'} = \@args; + my $arg_index = 0; + my $debug_msg = ''; + foreach my $arg (@args) + { # when expanding macros, the argument index is retrieved + # with args_index + $macros->{$name}->{'args_index'}->{$arg} = $arg_index; + $debug_msg .= "$arg($arg_index) "; + $arg_index++; + } + $macros->{$name}->{'body'} = ''; + $state->{'macro'} = $macros->{$name}; + print STDERR "# macro def $name: $debug_msg\n" + if ($T2H_DEBUG & $DEBUG_MACROS); + } + else + {# it means we have a macro without a name + echo_error ("Macro definition without macro name $_", $line_nr) + unless ($state->{'ignored'}); + } + return; + } + elsif (defined($text_macros{$macro})) + { + my $tag; + ($_, $tag) = do_text_macro($macro, $_, $state, $stack, $line_nr); + # if it is a raw formatting command or a menu command + # we must keep it for later, unless we are in an 'ignored'. + # if in 'arg_expansion' we keep everything. + my $macro_kept; + if ((($state->{'raw'} or (($macro eq 'menu') and $text_macros{'menu'}) or (exists($region_lines{$macro}))) and !$state->{'ignored'}) or $state->{'arg_expansion'}) + { + add_prev($text, $stack, $tag); + $macro_kept = 1; + } + #dump_stack ($text, $stack, $state); + next if $macro_kept; + return if (/^\s*$/); + } + elsif ($macro eq 'documentencoding') + { + my $spaces = ''; + my $encoding = ''; + if (s/(\s+)([0-9\w\-]+)//) + { + $spaces = $1; + $encoding = $2; + next if ($state->{'ignored'}); + if (!$state->{'arg_expansion'} and !$state->{'ignored'}) + { + $Texi2HTML::Config::DOCUMENT_ENCODING = $encoding; + my $from_encoding = encoding_alias($encoding); + $Texi2HTML::Config::IN_ENCODING = $from_encoding if + defined($from_encoding); + if (defined($from_encoding) and $Texi2HTML::Config::USE_UNICODE) + { + foreach my $file (@fhs) + { + binmode($file->{'fh'}, ":encoding($from_encoding)"); + } + } + } + }# ARG_EXPANSION + add_prev($text, $stack, "\@$macro" . $spaces . $encoding) unless ($state->{'ignored'}); + } + elsif ($macro eq 'definfoenclose') + { + # FIXME if 'ignored' or 'arg_expansion' maybe we could parse + # the args anyway and don't take away the whole line? + + # as in the makeinfo doc 'definfoenclose' may override + # texinfo @-commands like @i. It is what we do here. + if ($state->{'arg_expansion'}) + { + add_prev($text, $stack, "\@$macro" . $_); + return; + } + return if ($state->{'ignored'}); + if (s/^\s+([a-z]+)\s*,\s*([^\s]+)\s*,\s*([^\s]+)//) + { + $info_enclose{$1} = [ $2, $3 ]; + } + else + { + echo_error("Bad \@$macro", $line_nr); + } + return if (/^\s*$/); + s/^\s*//; + } + elsif ($macro eq 'include') + { + if ($state->{'arg_expansion'}) + { + add_prev($text, $stack, "\@$macro" . $_); + return; + } + return if ($state->{'ignored'}); + #if (s/^\s+([\/\w.+-]+)//o) + if (s/^(\s+)(.*)//o) + { + my $file_name = $2; + $file_name =~ s/\s*$//; + my $file = locate_include_file($file_name); + if (defined($file)) + { + open_file($file, $line_nr); + print STDERR "# including $file\n" if $T2H_VERBOSE; + } + else + { + echo_error ("Can't find $file_name, skipping", $line_nr); + } + } + else + { + echo_error ("Bad include line: $_", $line_nr); + return; + } + return; + } + elsif ($macro eq 'value') + { + if (s/^{($VARRE)}//) + { + my $value = $1; + if ($state->{'arg_expansion'}) + { + add_prev($text, $stack, "\@$macro" .'{'. $value .'}'); + next; + } + next if ($state->{'ignored'}); + my $expansion = "No value for $value"; + $expansion = $value{$value} if (defined($value{$value})); + $_ = $expansion . $_; + } + else + { + if ($state->{'arg_expansion'}) + { + add_prev($text, $stack, "\@$macro"); + next; + } + next if ($state->{'ignored'}); + echo_error ("bad \@value macro", $line_nr); + } + } + elsif ($macro eq 'unmacro') + { #FIXME with 'arg_expansion' should it be passed unmodified ? + if ($state->{'ignored'}) + { + s/^\s+(\w+)//; + } + else + { + delete $macros->{$1} if (s/^\s+(\w+)//); + } + return if (/^\s*$/); + s/^\s*//; + } + elsif (exists($macros->{$macro})) + {# it must be before the handling of {, otherwise it is considered + # to be regular texinfo @-command. Maybe it could be placed higher + # if we want user defined macros to override texinfo @-commands + + # in 'ignored' we parse macro defined args anyway as it removes + # some text, but we don't expand the macro + + my $ref = $macros->{$macro}->{'args'}; + # we remove any space/new line before the argument + if (s/^\s*{\s*//) + { # the macro has args + $state->{'macro_args'} = [ "" ]; + $state->{'macro_name'} = $macro; + $state->{'macro_depth'} = 1; + } + elsif (($#$ref >= 1) or ($#$ref <0)) + { # no brace -> no arg + $_ = expand_macro ($macro, [], $_, $line_nr, $state); + return; + } + else + { # macro with one arg on the line + chomp $_; + $_ = expand_macro ($macro, [$_], "\n", $line_nr, $state); + return; + } + } + elsif ($macro eq ',') + {# the @, causes problems when `,' separates things (in @node, @ref) + $_ = "\@m_cedilla" . $_; + } # handling of @, must be done before handling of { + elsif (s/^{//) + {# we add nested commands in a stack. verb is also on the stack + # but handled specifically. + # we add it the comands even in 'ignored' as their result is + # discarded when the closing brace appear, or the ifset or + # iclear is closed. + if ($macro eq 'verb') + { + if (/^$/) + { + echo_error ("without associated character", $line_nr); + #warn "$ERROR verb at end of line"; + } + else + { + s/^(.)//; + $state->{'verb'} = $1; + } + } + push (@$stack, { 'style' => $macro, 'text' => '' }); + } + else + { + add_prev($text, $stack, "\@$macro") unless($state->{'ignored'}); + } + next; + } + #elsif(s/^([^{}@]*)\@(.)//o) + elsif(s/^([^{}@]*)\@([^\s\}\{\@]*)//o) + {# ARG_EXPANSION + # No need to warn here for @ followed by a character that + # is not in any @-command and it is done later + add_prev($text, $stack, $1 . "\@$2") unless($state->{'ignored'}); + next; + } + elsif (s/^([^{}]*)([{}])//o) + { + # in ignored section we cannot be sure that there is an @-command + # allready opened so we must discard the text. + # ARG_EXPANSION + add_prev($text, $stack, $1) unless($state->{'ignored'}); + if ($2 eq '{') + { + # this empty style is for a lone brace. + # we add it even in 'ignored' as it is discarded when the closing + # brace appear, or the ifset or iclear is closed. + push @$stack, { 'style' => '', 'text' => '' }; + } + else + { + if (@$stack) + { + my $style = pop @$stack; + my $result; + if (($style->{'style'} ne '') and exists($info_enclose{$style->{'style'}}) and !$state->{'arg_expansion'}) + { + $result = $info_enclose{$style->{'style'}}->[0] . $style->{'text'} . $info_enclose{$style->{'style'}}->[1]; + } + elsif ($style->{'style'} ne '') + { + $result = '@' . $style->{'style'} . '{' . $style->{'text'} . '}'; + } + else + { + $result = '{' . $style->{'text'}; + # don't close { if we are closing stack as we are not + # sure this is a { ... } construct. i.e. we are + # not sure that the user properly closed the matching + # brace, so we don't close it ourselves + $result .= '}' unless ($state->{'close_stack'} or $state->{'arg_expansion'}); + } + if ($state->{'ignored'}) + {# ARG_EXPANSION + print STDERR "# Popped `$style->{'style'}' in ifset/ifclear\n" if ($T2H_DEBUG); + next; + } + add_prev ($text, $stack, $result); + #print STDERR "MACRO end $style->{'style'} remaining: $_"; + next; + } + else + {# ARG_EXPANSION + # we warn in the last pass that there is a } without open + add_prev ($text, $stack, '}') unless($state->{'ignored'}); + } + } + } + else + {# ARG_EXPANSION + #print STDERR "END_LINE $_"; + add_prev($text, $stack, $_) unless($state->{'ignored'}); + last; + } + } + return undef if ($state->{'ignored'}); + return 1; +} + +sub close_structure_command($$$$) +{ + my $cmd_ref = shift; + my $state = shift; + my $unclosed_commands = shift; + my $line_nr = shift; + my $result; + + if ($cmd_ref->{'style'} eq 'anchor') + { + my $anchor = $cmd_ref->{'text'}; + $anchor = normalise_node($anchor); + if ($nodes{$anchor}) + { + echo_error ("Duplicate node for anchor found: $anchor", $line_nr); + return ''; + } + $anchor_num++; + $nodes{$anchor} = { 'anchor' => 1, 'seen' => 1, 'texi' => $anchor, 'id' => 'ANC' . $anchor_num}; + push @{$state->{'place'}}, $nodes{$anchor}; + } + elsif ($cmd_ref->{'style'} eq 'footnote') + { + if ($Texi2HTML::Config::SEPARATED_FOOTNOTES) + { + $state->{'element'} = $state->{'footnote_element'}; + $state->{'place'} = $state->{'footnote_place'}; + } + } + elsif ($cmd_ref->{'style'} eq 'caption' or $cmd_ref->{'style'} + eq 'shortcaption' and $state->{'float'}) + { + my @texi_lines = map {$_ = $_."\n"} split (/\n/, $cmd_ref->{'text'}); + $state->{'float'}->{$cmd_ref->{'style'} . "_texi"} = \@texi_lines; + } + if (($cmd_ref->{'style'} eq 'titlefont') and ($cmd_ref->{'text'} =~ /\S/)) + { + $state->{'element'}->{'titlefont'} = $cmd_ref->{'text'} unless ((exists($state->{'region_lines'}) and ($state->{'region_lines'}->{'format'} eq 'titlepage')) or defined($state->{'element'}->{'titlefont'})) ; + } + if (defined($Texi2HTML::Config::command_handler{$cmd_ref->{'style'}})) + { + $result = init_special($cmd_ref->{'style'},$cmd_ref->{'text'}); + if ($unclosed_commands) + { + $result .= "\n"; # the end of line is eaten by init_special + echo_error("Closing specially handled \@-command $cmd_ref->{'style'}",$line_nr); + } + } + elsif ($cmd_ref->{'style'}) + { + $result = '@' . $cmd_ref->{'style'} . '{' . $cmd_ref->{'text'}; + $result .= '}' unless ($unclosed_commands); + } + else + { + $result = '{' . $cmd_ref->{'text'}; + # don't close { if we are closing stack as we are not + # sure this is a licit { ... } construct. + $result .= '}' unless ($unclosed_commands); + } + return $result; +} + +sub scan_structure($$$$;$) +{ + my $line = shift; + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + + die "stack not an array ref" unless (ref($stack) eq "ARRAY"); + local $_ = $line; + #print STDERR "SCAN_STRUCTURE: $line"; + #dump_stack ($text, $stack, $state); + if (!$state->{'raw'} and (!exists($state->{'region_lines'}))) + { + if (!$state->{'verb'} and $state->{'menu'} and /^\*/o) + { + # new menu entry + delete ($state->{'after_element'}); + my $menu_line = $_; + my $node; + if (/^\*\s+($NODERE)::/) + { + $node = $1; + } + elsif (/^\*\s+([^:]+):\s*([^\t,\.\n]+)[\t,\.\n]/) + { + #$name = $1; + $node = $2; + } + if ($node) + { + menu_entry_texi(normalise_node($node), $state, $line_nr); + } + } + unless (no_line($_)) + { + delete $state->{'after_element'}; + } + } + + while(1) + { + # scan structure + #print STDERR "WHILE (s):$_"; + #dump_stack($text, $stack, $state); + + # as texinfo 4.5 + # verbatim might begin at another position than beginning + # of line, and end verbatim might too. To end a verbatim section + # @end verbatim must have exactly one space between end and verbatim + # things following end verbatim are not ignored. + # + # html might begin at another position than beginning + # of line, but @end html must begin the line, and have + # exactly one space. Things following end html are ignored. + # tex and ignore works like html + # + # ifnothtml might begin at another position than beginning + # of line, and @end ifnothtml might too, there might be more + # than one space between @end and ifnothtml but nothing more on + # the line. + # @end itemize, @end ftable works like @end ifnothtml. + # except that @item on the same line than @end vtable doesn't work + # + # text right after the itemize before an item is displayed. + # @item might be somewhere in a line. + # strangely @item on the same line than @end vtable doesn't work + # there should be nothing else than a command following @itemize... + # + # see more examples in formatting directory + + if ($state->{'raw'}) + { + my $tag = $state->{'raw'}; + ################# debug + if (! @$stack or ($stack->[-1]->{'style'} ne $tag)) + { + print STDERR "Bug: raw or special: $tag but not on top of stack\n"; + print STDERR "line: $_"; + dump_stack($text, $stack, $state); + exit 1; + } + ################# end debug + if (s/^(.*?)\@end\s$tag$// or s/^(.*?)\@end\s$tag\s//) + { + add_prev ($text, $stack, $1); + delete $state->{'raw'}; + my $style = pop @$stack; + if (defined($Texi2HTML::Config::command_handler{$tag})) + { # replace the special region by what init_special give + if ($style->{'text'} !~ /^\s*$/) + { + add_prev ($text, $stack, init_special($style->{'style'}, $style->{'text'})); + } + + } + else + { + my $after_macro = ''; + $after_macro = ' ' unless (/^\s*$/); + add_prev ($text, $stack, $style->{'text'} . "\@end $tag" . $after_macro); + } + unless (no_line($_)) + { + delete ($state->{'after_element'}); + } + next; + } + else + { + add_prev ($text, $stack, $_); + return if (defined($Texi2HTML::Config::command_handler{$tag})); + last; + } + } + + if (defined($state->{'verb'})) + { + my $char = quotemeta($state->{'verb'}); + if (s/^(.*?)$char\}/\}/) + { + add_prev($text, $stack, $1 . $state->{'verb'}); + $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'}; + delete $state->{'verb'}; + next; + } + else + { + add_prev($text, $stack, $_); + last; + } + } + + unless (no_line($_)) + { + delete $state->{'after_element'}; + } + # macro_regexp + if (s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//) + { + add_prev($text, $stack, $1); + my $end_tag = $2; + #print STDERR "END STRUCTURE $end_tag\n"; + $state->{'detailmenu'}-- if ($end_tag eq 'detailmenu' and $state->{'detailmenu'}); + if (defined($state->{'text_macro_stack'}) + and @{$state->{'text_macro_stack'}} + and ($end_tag eq $state->{'text_macro_stack'}->[-1])) + { + pop @{$state->{'text_macro_stack'}}; + if (exists($region_lines{$end_tag})) + { # end a region_line macro, like documentdescription, copying + print STDERR "Bug: end_tag $end_tag ne $state->{'region_lines'}->{'format'}" + if ( $end_tag ne $state->{'region_lines'}->{'format'}); + $state->{'region_lines'}->{'number'}--; + if ($state->{'region_lines'}->{'number'} == 0) + { + close_region($state); + } + #dump_stack($text, $stack, $state); + } + if ($end_tag eq 'menu') + { + add_prev($text, $stack, "\@end $end_tag"); + $state->{'menu'}--; + } + else + { + #print STDERR "End $end_tag\n"; + #dump_stack($text, $stack, $state); + return if (/^\s*$/); + } + } + elsif ($text_macros{$end_tag}) + { + echo_error ("\@end $end_tag without corresponding element", $line_nr); + #dump_stack($text, $stack, $state); + } + else + { + if ($end_tag eq 'float' and $state->{'float'}) + { + delete $state->{'float'}; + } + elsif ($end_tag eq $state->{'table_stack'}->[-1]) + { + enter_table_index_entry($text, $stack, $state, $line_nr); + pop @{$state->{'table_stack'}}; + } + #add end tag + add_prev($text, $stack, "\@end $end_tag"); + } + next; + } + #elsif (s/^([^{}@]*)\@([a-zA-Z]\w*|["'~\@\}\{,\.!\?\s\*\-\^`=:\/])//o) + # macro_regexp + elsif (s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])//o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)([\s\{\}\@])/$3/o or s/^([^{}@]*)\@([a-zA-Z][\w-]*)$//o) + { + add_prev($text, $stack, $1); + my $macro = $2; + #print STDERR "MACRO $macro\n"; + if (defined($Texi2HTML::Config::misc_command{$macro})) + { + my $line; + ($_, $line) = misc_command_structure($_, $macro, $state, + $line_nr); + add_prev ($text, $stack, "\@$macro".$line); + next; + } + + if ($macro =~ /^(\w+?)index/ and ($1 ne 'print') and ($1 ne 'syncode') and ($1 ne 'syn') and ($1 ne 'def') and ($1 ne 'defcode')) + { + my $index_prefix = $1; + my $key = $_; + $key =~ s/^\s*//; + $_ = substitute_texi_line($_); + enter_index_entry($index_prefix, $line_nr, $key, $state->{'place'}, $state->{'element'}, $state->{'after_element'}, $macro); + add_prev ($text, $stack, "\@$macro" . $_); + last; + } + elsif (defined($text_macros{$macro})) + { + #print STDERR "TEXT_MACRO: $macro\n"; + if ($text_macros{$macro} eq 'raw') + { + $state->{'raw'} = $macro; + #print STDERR "RAW\n"; + } + elsif ($format_type{$macro} and $format_type{$macro} eq 'menu') + { + $state->{'menu'}++; + delete ($state->{'prev_menu_node'}); + push @{$state->{'text_macro_stack'}}, $macro; + #print STDERR "MENU (text_macro_stack: @{$state->{'text_macro_stack'}})\n"; + } + elsif (exists($region_lines{$macro})) + { + if (exists($state->{'region_lines'}) and ($state->{'region_lines'}->{'format'} ne $macro)) + { + echo_error("\@$macro not allowed within $state->{'region_lines'}->{'format'}", $line_nr); + next; + } + if (!exists($state->{'region_lines'})) + { + $state->{'region_lines'}->{'format'} = $macro; + $state->{'region_lines'}->{'number'} = 1; + $state->{'region_lines'}->{'after_element'} = 1 if ($state->{'after_element'}); + $state->{'region_lines'}->{'kept_place'} = $state->{'place'}; + $state->{'place'} = $region_place; + } + else + { + $state->{'region_lines'}->{'number'}++; + } + push @{$state->{'text_macro_stack'}}, $macro; + } + # if it is a raw formatting command or a menu command + # we must keep it for later + my $macro_kept; + if (($state->{'raw'} and (!defined($Texi2HTML::Config::command_handler{$macro}))) or ($macro eq 'menu')) + { + add_prev($text, $stack, "\@$macro"); + $macro_kept = 1; + } + if ($state->{'raw'}) + { + push @$stack, { 'style' => $macro, 'text' => '' }; + } + next if $macro_kept; + #dump_stack ($text, $stack, $state); + return if (/^\s*$/); + } + elsif ($macro eq 'float') + { + my ($style_texi, $label_texi) = split(/,/, $_); + $style_texi = normalise_space($style_texi); + $label_texi = undef if (defined($label_texi) and ($label_texi =~ /^\s*$/)); + if (defined($label_texi)) + { # The float may be a target for refs if it has a label + $label_texi = normalise_node($label_texi); + if (exists($nodes{$label_texi}) and defined($nodes{$label_texi}) + and $nodes{$label_texi}->{'seen'}) + { + echo_error ("Duplicate label found: $label_texi", $line_nr); + while ($_ =~ /,/) + { + $_ =~ s/,.*$//; + } + } + else + { + my $float = { }; + if (exists($nodes{$label_texi}) and defined($nodes{$label_texi})) + { # float appeared in a menu + $float = $nodes{$label_texi}; + } + else + { + $nodes{$label_texi} = $float; + } + $float->{'float'} = 1; + $float->{'tag'} = 'float'; + $float->{'texi'} = $label_texi; + $float->{'seen'} = 1; + $float->{'id'} = $label_texi; +#print STDERR "FLOAT: $float $float->{'texi'}, place $state->{'place'}\n"; + push @{$state->{'place'}}, $float; + $float->{'element'} = $state->{'element'}; + $state->{'float'} = $float; + $float->{'style_texi'} = $style_texi; + push @floats, $float; + } + } + add_prev($text, $stack, "\@$macro" . $_); + last; + } + elsif (defined($Texi2HTML::Config::def_map{$macro})) + { + #We must enter the index entries + my ($prefix, $entry, $argument) = get_deff_index($macro, $_, $line_nr); + # use deffn instead of deffnx for @-command record + # associated with index entry + my $idx_macro = $macro; + $idx_macro =~ s/x$//; + enter_index_entry($prefix, $line_nr, $entry, $state->{'place'}, + $state->{'element'}, 0, $idx_macro) if ($prefix); + s/(.*)//; + add_prev($text, $stack, "\@$macro" . $1); + # the text is discarded but we must handle correctly bad + # texinfo with 2 @def-like commands on the same line + substitute_text({'structure' => 1, 'place' => $state->{'place'} },($argument)); + } + elsif ($macro =~ /^itemx?$/) + { + enter_table_index_entry($text, $stack, $state, $line_nr); + if ($state->{'table_stack'}->[-1] =~ /^(v|f)table$/) + { + $state->{'item'} = $macro; + push @$stack, { 'format' => 'index_item', 'text' => "" }; + } + else + { + add_prev($text, $stack, "\@$macro"); + } + } + elsif ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'list')) + { # We must enter the index entries of (v|f)table thus we track + # in which table we are + push @{$state->{'table_stack'}}, $macro; + add_prev($text, $stack, "\@$macro"); + } + elsif (s/^{//) + { + if ($macro eq 'verb') + { + if (/^$/) + { + # We allready warned in pass texi + #warn "$ERROR verb at end of line"; + } + else + { + s/^(.)//; + $state->{'verb'} = $1; + } + } + elsif ($macro eq 'footnote' and $Texi2HTML::Config::SEPARATED_FOOTNOTES) + { + $state->{'footnote_element'} = $state->{'element'}; + $state->{'footnote_place'} = $state->{'place'}; + $state->{'element'} = $footnote_element; + $state->{'place'} = $footnote_element->{'place'}; + } + push (@$stack, { 'style' => $macro, 'text' => '' }); + } + else + { + add_prev($text, $stack, "\@$macro"); + } + next; + } + #elsif(s/^([^{}@]*)\@(.)//o) + elsif(s/^([^{}@]*)\@([^\s\}\{\@]*)//o) + { + add_prev($text, $stack, $1 . "\@$2"); + next; + } + elsif (s/^([^{}]*)([{}])//o) + { + add_prev($text, $stack, $1); + if ($2 eq '{') + { + push @$stack, { 'style' => '', 'text' => '' }; + } + else + { + if (@$stack) + { + my $style = pop @$stack; + my $result; + add_prev ($text, $stack, close_structure_command($style, + $state, 0, $line_nr)); + next; + } + else + { + # We warn in the last pass + #warn "$ERROR '}' without opening '{' line: $line"; + #echo_error ("'}' without opening '{' line: $line", $line_nr); + add_prev ($text, $stack, '}'); + } + } + } + else + { + #print STDERR "END_LINE $_"; + add_prev($text, $stack, $_); + enter_table_index_entry($text, $stack, $state, $line_nr); + last; + } + } + return 1; +} + +sub scan_line($$$$;$) +{ + my $line = shift; + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + + die "stack not an array ref" unless (ref($stack) eq "ARRAY"); + local $_ = $line; + #print STDERR "SCAN_LINE (@{$state->{'command_stack'}}): $line"; + #dump_stack($text, $stack, $state ); + my $new_menu_entry; # true if there is a new menu entry + my $menu_description_in_format; # true if we are in a menu description + # but in another format section (@table....) + if (defined($state->{'prepend_text'})) + { + $_ = $state->{'prepend_text'} . $_; + $state->{'prepend_text'} = undef; + delete $state->{'prepend_text'}; + } + + unless ($state->{'end_of_line_protected'} and $state->{'deff_line'}) + { # end of lines are really protected only for @def* + if (!$state->{'raw'} and !$state->{'verb'} and $state->{'menu'}) + { # new menu entry + my ($node, $name, $ending); + if (s/^\*(\s+$NODERE)(::)//o) + { + $node = $1; + $ending = $2; + } + elsif (s/^\*(\s+[^:]+):(\s*[^\t,\.\n]+)([\t,\.\n])//o) + { + $name = $1; + $node = $2; + $ending = $3; + } + if ($node) + { + my $top_stack = top_stack($stack); + if ($top_stack and $top_stack->{'format'} and + ( + ($top_stack->{'format'} eq 'menu_description') or + ($top_stack->{'format'} eq 'menu') or + (($top_stack->{'format'} eq 'preformatted') and (stack_order($stack, 'preformatted', 'menu_comment'))) or + ($top_stack->{'format'} eq 'menu_preformatted') or + ($top_stack->{'format'} eq 'menu_comment') + ) + ) + { # we are in a normal menu state. + close_menu($text, $stack, $state, $line_nr); + $new_menu_entry = 1; + $state->{'menu_entry'} = { 'name' => $name, 'node' => $node, + 'ending' => $ending }; + add_prev ($text, $stack, do_menu_link($state, $line_nr)); + print STDERR "# New menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU); + push @$stack, {'format' => 'menu_description', 'text' => ''}; + } + else + { # we are within a macro or a format. In that case we use + # a simplified formatting of menu which should be right whatever + # the context + my $menu_entry = $state->{'menu_entry'}; + $state->{'menu_entry'} = { 'name' => $name, 'node' => $node, + 'ending' => $ending }; + add_prev ($text, $stack, do_menu_link($state, $line_nr, 1)); + $state->{'menu_entry'} = $menu_entry; + } + } + } + # we're in a menu entry description + if ($state->{'menu_entry'} and !$new_menu_entry) + { + my $top_stack = top_stack($stack); + if (/^\s+\S.*$/ or (!$top_stack->{'format'} or ($top_stack->{'format'} ne 'menu_description'))) + { # description continues + $menu_description_in_format = 1 if ($top_stack->{'format'} and ($top_stack->{'format'} ne 'menu_description')); + print STDERR "# Description continues\n" if ($T2H_DEBUG & $DEBUG_MENU); + } + else + { # enter menu comment after menu entry + ################################ begin debug + if (!$top_stack->{'format'} or ($top_stack->{'format'} ne 'menu_description')) + { + print STDERR "Bug: begin menu comment but previous isn't menu_description\n"; + dump_stack ($text, $stack, $state); + } + print STDERR "# Menu comment begins\n" if ($T2H_DEBUG & $DEBUG_MENU); + ################################ end debug + my $descr = pop(@$stack); + + add_prev ($text, $stack, do_menu_description($descr->{'text'}, $state)); + delete $state->{'menu_entry'}; + unless (/^\s*\@end\s+menu\b/) + { + $state->{'menu_comment'}++; + push @$stack, {'format' => 'menu_comment', 'text' => ''}; + unless ($Texi2HTML::Config::SIMPLE_MENU) + { + push @{$state->{'preformatted_stack'}}, {'pre_style' => $Texi2HTML::Config::MENU_PRE_STYLE, 'class' => 'menu-comment' }; + $state->{'preformatted'}++; + begin_paragraph($stack, $state); + } + } + } + } + if (($state->{'menu_entry'} and !$menu_description_in_format) or $state->{'raw'} or $state->{'preformatted'} or $state->{'no_paragraph'} or $state->{'keep_texi'} or $state->{'remove_texi'}) + { # empty lines are left unmodified + if (/^\s*$/) + { + add_prev($text, $stack, $_); + return; + } + elsif (!$state->{'raw'}) + { + my $next_tag = next_tag($_); + if ($state->{'deff_line'} and !defined($Texi2HTML::Config::def_map{$next_tag})) + { + begin_deff_item($stack, $state); + } + } + } + else + { + if (/^\s*$/) + { + if ($state->{'paragraph_context'}) + { # An empty line ends a paragraph + close_paragraph($text, $stack, $state, $line_nr); + } + add_prev($text, $stack, &$Texi2HTML::Config::empty_line($_,$state)); + return 1; + } + else + { + #print STDERR "a line not empty and not in no paragraph format\n"; + my $next_tag = next_tag($_); + if ($state->{'deff_line'} and !defined($Texi2HTML::Config::def_map{$next_tag})) + { # finish opening the deff, as this is not a deff tag, it can't be + # a deff macro with x + begin_deff_item($stack, $state); + } + if (!no_paragraph($state,$_)) + { # open a paragraph, unless the line begins with a macro that + # shouldn't trigger a paragraph opening + begin_paragraph($stack, $state); + } + } + } + } + delete $state->{'end_of_line_protected'} + if ($state->{'end_of_line_protected'}); + + while(1) + { + # scan_line + #print STDERR "WHILE (l): $_|"; + #dump_stack($text, $stack, $state); + # we're in a raw format (html, tex if !L2H, verbatim) + if (defined($state->{'raw'})) + { + (dump_stack($text, $stack, $state), die "Bug for raw ($state->{'raw'})") if (! @$stack or ! ($stack->[-1]->{'style'} eq $state->{'raw'})); + if (s/^(.*?)\@end\s$state->{'raw'}$// or s/^(.*?)\@end\s$state->{'raw'}\s+//) + # don't protect html, it is done by Texi2HTML::Config::raw if needed + { + print STDERR "# end raw $state->{'raw'}\n" if ($T2H_DEBUG & $DEBUG_FORMATS); + add_prev ($text, $stack, $1); + my $style = pop @$stack; + if ($style->{'text'} !~ /^\s*$/) + { + if ($state->{'keep_texi'}) + { + add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}"); + } + elsif ($state->{'remove_texi'}) + { + add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi($style->{'style'}, $style->{'text'})); + } + else + { + add_prev($text, $stack, &$Texi2HTML::Config::raw($style->{'style'}, $style->{'text'})); + } + } + if (!$state->{'keep_texi'} and !$state->{'remove_texi'}) + { + # reopen preformatted if it was interrupted by the raw format + # if raw format is html the preformatted wasn't interrupted + begin_paragraph($stack, $state) if ($state->{'preformatted'} and (!$Texi2HTML::Config::format_in_paragraph{$state->{'raw'}})); + delete $state->{'raw'}; + return if (/^\s*$/); + } + delete $state->{'raw'}; + next; + } + else + { + print STDERR "#within raw $state->{'raw'}:$_" if ($T2H_DEBUG & $DEBUG_FORMATS); + add_prev ($text, $stack, $_); + last; + } + } + + # we are within a @verb + if (defined($state->{'verb'})) + { + my $char = quotemeta($state->{'verb'}); + if (s/^(.*?)$char\}/\}/) + { + if ($state->{'keep_texi'}) + { + add_prev($text, $stack, $1 . $state->{'verb'}); + $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'}; + } + elsif ($state->{'remove_texi'}) + { + add_prev($text, $stack, $1); + } + else + { + add_prev($text, $stack, do_text($1, $state)); + } + delete $state->{'verb'}; + next; + } + else + { + add_prev($text, $stack, $_); + last; + } + } + + # a special case for @ followed by an end of line in deff + # FIXME this is similar with makeinfo, but shouldn't that + # be done for @floats and @quotations too? and @item, @center? + # this piece of code is required, to avoid the 'cmd_line' to be + # closed below + if ($state->{'end_of_line_protected'} and $state->{'deff_line'}) + { + print STDERR "Bug: 'end_of_line_protected' with text following: $_\n" + unless /^$/; + return; + } + + # We handle now the end tags + # macro_regexp + if ($state->{'keep_texi'} and s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//) + { + my $end_tag = $2; + add_prev($text, $stack, $1 . "\@end $end_tag"); + next; + } + # macro_regexp + elsif ($state->{'remove_texi'} and s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//) + { + add_prev($text, $stack, $1); + next; + } + # macro_regexp + if (s/^([^{}@,]*)\@end\s+([a-zA-Z][\w-]*)\s//o or s/^([^{}@,]*)\@end\s+([a-zA-Z][\w-]*)$//o) + { + add_prev($text, $stack, do_text($1, $state)); + my $end_tag = $2; + #print STDERR "END_MACRO $end_tag\n"; + #dump_stack ($text, $stack, $state); + + # First we test if the stack is not empty. + # Then we test if the end tag is a format tag. + # We then close paragraphs and preformatted at top of the stack. + # We handle the end tag (even when it was not the tag which appears + # on the top of the stack; in that case we close anything + # until that element) + $state->{'detailmenu'}-- if ($end_tag eq 'detailmenu' and $state->{'detailmenu'}); + # FIXME handle below (look for misc_command) to let the user + # keep that end tag. On the other hand it is only used for + # end detailmenu, so maybe it should just go and detailmenu + # could be handled like a normal format. Last there could be + # something similar than what is done for other misc_commands. + next if (defined($Texi2HTML::Config::misc_command{"end $end_tag"})); + my $top_stack = top_stack($stack); + if (!$top_stack) + { + echo_error ("\@end $end_tag without corresponding opening", $line_nr); + add_prev($text, $stack, "\@end $end_tag"); + next; + } + + if (!$format_type{$end_tag}) + { + echo_warn ("Unknown \@end $end_tag", $line_nr); + #warn "$ERROR Unknown \@end $end_tag\n"; + add_prev($text, $stack, "\@end $end_tag"); + next; + } + unless ($Texi2HTML::Config::format_in_paragraph{$end_tag}) + { # If the $end_tag is wrong we may be keeping paragraph + # for a format with paragraphs on the stack + close_paragraph($text, $stack, $state, $line_nr); + } + + $top_stack = top_stack($stack); + if (!$top_stack or (!defined($top_stack->{'format'}))) + { + echo_error ("\@end $end_tag without corresponding opening element", $line_nr); + add_prev($text, $stack, "\@end $end_tag"); + dump_stack ($text, $stack, $state) if ($T2H_DEBUG); + next; + } + # Warn if the format on top of stack is not compatible with the + # end tag, and find the end tag. + unless ( + ($top_stack->{'format'} eq $end_tag) + or + ( + ($format_type{$end_tag} eq 'menu') and + ( + ($top_stack->{'format'} eq 'menu_preformatted') or + ($top_stack->{'format'} eq 'menu_comment') or + ($top_stack->{'format'} eq 'menu_description') + ) + ) or + ( + ($end_tag eq 'multitable') and + ( + ($top_stack->{'format'} eq 'cell') or + ($top_stack->{'format'} eq 'null') + ) + ) or + ( + ($format_type{$end_tag} eq 'list' ) and + ($top_stack->{'format'} eq 'item') + ) or + ( + ( + ($format_type{$end_tag} eq 'table') and + ($end_tag ne 'multitable') + ) and + ( + ($top_stack->{'format'} eq 'term') or + ($top_stack->{'format'} eq 'line') + ) + ) or + ( + (defined($Texi2HTML::Config::def_map{$end_tag})) and + ($top_stack->{'format'} eq 'deff_item') + ) or + ( + ($end_tag eq 'row') and + ($top_stack->{'format'} eq 'cell') + ) + ) + { + # this is not the right format. We try to close other + # formats to find the format we are searching for. + # First we close paragraphs, as with a wrong $end_format + # they may not be closed properly. + close_paragraph($text, $stack, $state, $line_nr); + $top_stack = top_stack($stack); + if (!$top_stack or (!defined($top_stack->{'format'}))) + { + echo_error ("\@end $end_tag without corresponding opening element", $line_nr); + add_prev($text, $stack, "\@end $end_tag"); + dump_stack ($text, $stack, $state) if ($T2H_DEBUG); + next; + } + my $waited_format = $top_stack->{'format'}; + $waited_format = $fake_format{$top_stack->{'format'}} if ($format_type{$top_stack->{'format'}} eq 'fake'); + echo_error ("waiting for end of $waited_format, found \@end $end_tag", $line_nr); + close_stack($text, $stack, $state, $line_nr, undef, $end_tag); + # an empty preformatted may appear when closing things as + # when closed, formats reopen the preformatted environment + # in case there is some text following, but we know it isn't + # the case here, thus we can close paragraphs. + close_paragraph($text, $stack, $state); + my $new_top_stack = top_stack($stack); + next unless ($new_top_stack and defined($new_top_stack->{'format'}) and (($new_top_stack->{'format'} eq $end_tag) + or (($format_type{$new_top_stack->{'format'}} eq 'fake') and ($fake_format{$new_top_stack->{'format'}} eq $format_type{$end_tag})))); + } + # We should now be able to handle the format + if (defined($format_type{$end_tag}) and $format_type{$end_tag} ne 'fake') + { + end_format($text, $stack, $state, $end_tag, $line_nr); + begin_paragraph_after_command($state,$stack,$end_tag,$_); + } + else + { # this is a fake format, ie a format used internally, inside + # a real format. We do nothing, hoping the real format will + # get closed, closing the fake internal formats + #print STDERR "FAKE \@end $end_tag\n"; + } + next; + } + # This is a macro + #elsif (s/^([^{}@]*)\@([a-zA-Z]\w*|["'~\@\}\{,\.!\?\s\*\-\^`=:\/])//o) + # macro_regexp + elsif (s/^([^{},@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/])//o or s/^([^{}@,]*)\@([a-zA-Z][\w-]*)([\s\{\}\@])/$3/o or s/^([^{},@]*)\@([a-zA-Z][\w-]*)$//o) + { + add_prev($text, $stack, do_text($1, $state)); + my $macro = $2; + #print STDERR "MACRO $macro\n"; + #print STDERR "LINE $_"; + #dump_stack ($text, $stack, $state); + # This is a macro added by close_stack to mark paragraph end + if ($macro eq 'end_paragraph') + { + s/^\{\}//; + my $top_stack = top_stack($stack); + #################################### debug + if (!$top_stack or !$top_stack->{'format'} + or ($top_stack->{'format'} ne 'paragraph')) + { + print STDERR "Bug: end_paragraph but no paragraph to end\n"; + dump_stack ($text, $stack, $state); + next; + } + #################################### end debug + s/^\s//; + my $paragraph = pop @$stack; + add_prev ($text, $stack, do_paragraph($paragraph->{'text'}, $state)); + next; + } + # Handle macro added by close_stack to mark preformatted region end + elsif ($macro eq 'end_preformatted') + { + #print STDERR "END_PREFORMATTED\n"; + s/^\{\}//; + my $top_stack = top_stack($stack); + #################################### debug + if (!$top_stack or !$top_stack->{'format'} + or ($top_stack->{'format'} ne 'preformatted')) + { + print STDERR "Bug: end_preformatted but no preformatted to end\n"; + dump_stack ($text, $stack, $state); + next; + } + #################################### end debug + my $paragraph = pop @$stack; + s/^\s//; + add_prev ($text, $stack, do_preformatted($paragraph->{'text'}, $state)); + next; + } + if (defined($Texi2HTML::Config::misc_command{$macro})) + { + # The strange condition associated with 'keep_texi' is + # there because for an argument appearing on an @itemize + # line (we're in 'check_item'), meant to be prepended to an + # @item we don't want to keep @c or @comment as otherwise it + # eats the @item line. Other commands could do that too but + # then the user deserves what he gets. + if ($state->{'keep_texi'} and + (!$state->{'check_item'} or ($macro ne 'c' and $macro ne 'comment'))) + { + my ($line, $args); + ($_, $line, $args) = preserve_command($_, $macro); + add_prev($text, $stack, "\@$macro". $line); + next; + } + + # Handle the misc command + $_ = misc_command_text($_, $macro, $stack, $state, $text, $line_nr); + return unless (defined($_)); + unless ($Texi2HTML::Config::misc_command{$macro}->{'keep'}) + { + begin_paragraph($stack, $state) if + (!no_paragraph($state,$_)); + next; + } + } + if ($macro eq 'listoffloats') + { + if ($state->{'keep_texi'}) + { + if (s/(.*)//o) + { + add_prev($text, $stack, "\@$macro" . $1); + } + next; + } + return undef if ($state->{'remove_texi'}); + + if (s/^(\s+)(.*)//o) + { + my $arg = $2; + my $style_id = cross_manual_line(normalise_space($arg)); + my $style = substitute_line (&$Texi2HTML::Config::listoffloats_style($arg)); + if (exists ($floats{$style_id})) + { + close_paragraph($text, $stack, $state, $line_nr); + my @listoffloats_entries = (); + foreach my $float (@{$floats{$style_id}->{'floats'}}) + { + my $float_style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($arg, $float)); + my $caption_lines = &$Texi2HTML::Config::listoffloats_caption($float); + # we set 'multiple_pass' such that index entries + # and anchors are not handled one more time; + # the caption has allready been formatted, + # and these have been handled at the right place + my $caption = substitute_text({ 'multiple_pass' => 1 }, @$caption_lines); + push @listoffloats_entries, &$Texi2HTML::Config::listoffloats_entry($arg, $float, $float_style, $caption, href($float, $state->{'element'}->{'file'})); + } + add_prev($text, $stack, &$Texi2HTML::Config::listoffloats($arg, $style, \@listoffloats_entries)); + } + else + { + echo_warn ("Unknown float style $arg", $line_nr); + } + } + else + { + echo_error ("Bad \@$macro line: $_", $line_nr); + } + return undef; + } + # This is a @macroname{...} construct. We add it on top of stack + # It will be handled when we encounter the '}' + # There is a special case for def macros as @deffn{def} is licit + if (!$Texi2HTML::Config::def_map{$macro} and s/^{//) + { + if ($macro eq 'verb') + { + if (/^$/) + { + # Allready warned + #warn "$ERROR verb at end of line"; + } + else + { + s/^(.)//; + $state->{'verb'} = $1; + } + } + elsif ($macro eq 'm_cedilla' and !$state->{'keep_texi'}) + { + $macro = ','; + } + # currently if remove_texi and anchor/ref/footnote + # the text within the command is ignored + # see t2h_remove_command in texi2html.init + push (@$stack, { 'style' => $macro, 'text' => '', 'arg_nr' => 0 }); + $state->{'no_paragraph'}++ if ($no_paragraph_macro{$macro}); + open_arg($macro, 0, $state); + if (defined($style_type{$macro}) and (($style_type{$macro} eq 'style') or ($style_type{$macro} eq 'accent'))) + { + push (@{$state->{'command_stack'}}, $macro); + #print STDERR "# Stacked $macro (@{$state->{'command_stack'}})\n" if ($T2H_DEBUG); + } + next; + } + + # special case if we are checking itemize line. In that case + # we want to make sure that there is no @item on the @itemize + # line, otherwise it will be added on the front of another @item, + # leading to an infinite loop... + + if ($state->{'check_item'} and ($macro =~ /^itemx?$/ or $macro eq 'headitem')) + { + echo_error("\@$macro on \@$state->{'check_item'} line", $line_nr); + next; + } + + # if we're keeping texi unmodified we can do it now + if ($state->{'keep_texi'}) + { + # We treat specially formats accepting {} on command line + if ($macro eq 'multitable' or defined($Texi2HTML::Config::def_map{$macro})) + { + add_prev($text, $stack, "\@$macro" . $_); + $_ = ''; + next; + } + # @ at the end of line may protect the end of line even when + # keeping texi + if ($macro eq "\n") + { + $state->{'end_of_line_protected'} = 1; + #print STDERR "PROTECTING END OF LINE\n"; + } + + add_prev($text, $stack, "\@$macro"); + if ($text_macros{$macro} and $text_macros{$macro} eq 'raw') + { + $state->{'raw'} = $macro; + push (@$stack, {'style' => $macro, 'text' => ''}); + } + next; + } + + # If we are removing texi, the following macros are not removed + # as is but modified. So they are collected first, as if we were + # in normal text + + # a raw macro beginning + if ($text_macros{$macro} and $text_macros{$macro} eq 'raw') + { + if (!$Texi2HTML::Config::format_in_paragraph{$macro}) + { # close paragraph before verbatim (and tex if !L2H) + close_paragraph($text, $stack, $state, $line_nr); + } + $state->{'raw'} = $macro; + push (@$stack, {'style' => $macro, 'text' => ''}); + return if (/^\s*$/); + next; + } + my $simple_macro = 1; + # An accent macro + if (exists($Texi2HTML::Config::accent_map{$macro})) + { + push (@{$state->{'command_stack'}}, $macro); + if (s/^(\S)//o) + { + add_prev($text, $stack, do_simple($macro, $1, $state, [ $1 ], $line_nr)); + } + else + { # The accent is at end of line + add_prev($text, $stack, do_text($macro, $state)); + } + pop @{$state->{'command_stack'}}; + } + # an @-command which should be like @command{}. We handle it... + elsif ($::things_map_ref->{$macro}) + { + echo_warn ("$macro requires {}", $line_nr); + add_prev($text, $stack, do_simple($macro, '', $state)); + } + # an @-command like @command + elsif (defined($::simple_map_ref->{$macro})) + { + add_prev($text, $stack, do_simple($macro, '', $state)); + } + else + { + $simple_macro = 0; + } + if ($simple_macro) + {# if the macro didn't triggered a paragraph start it might now + begin_paragraph($stack, $state) if + ($no_line_macros{$macro} and !no_paragraph($state,$_)); + next; + } + # the following macros are modified or ignored if we are + # removing texi, and they are not handled like macros in text + if ($state->{'remove_texi'}) + { + # handle specially some macros + if ((($macro =~ /^(\w+?)index$/) and ($1 ne 'print')) or + ($macro eq 'itemize') or ($macro =~ /^(|v|f)table$/) + or ($macro eq 'multitable') or ($macro eq 'quotation')) + { + return; + } + elsif ($macro eq 'enumerate') + { + my $spec; + ($_, $spec) = parse_enumerate ($_); + return if (/^\s*$/); + next; + } + elsif (defined($Texi2HTML::Config::def_map{$macro})) + { + my ($style, $category, $name, $type, $class, $arguments); + ($style, $category, $name, $type, $class, $arguments) = parse_def($macro, $_, $line_nr); + # FIXME -- --- ''... lead to simple text in texi2html + # while they are kept as is in html coments by makeinfo + $category = remove_texi($category) if (defined($category)); + $name = remove_texi($name) if (defined($name)); + $type = remove_texi($type) if (defined($type)); + $class = remove_texi($class) if (defined($class)); + $arguments = remove_texi($arguments) if (defined($arguments)); + chomp($arguments); + add_prev($text, $stack, &$Texi2HTML::Config::def_line_no_texi($category, $name, $type, $arguments)); + return; + } + + # ignore other macros + next; + } + + # handle the other macros, in the context of some normal text + if (($macro =~ /^(\w+?)index$/) and ($1 ne 'print')) + { + add_prev($text, $stack, do_index_entry_label($macro,$state,$line_nr)); + return; + } + if ($macro eq 'insertcopying') + { + close_paragraph($text, $stack, $state, $line_nr); + add_prev($text, $stack, do_insertcopying($state)); + # reopen a preformatted format if it was interrupted by the macro + begin_paragraph ($stack, $state) if ($state->{'preformatted'}); + return; + } + if ($macro =~ /^itemx?$/o or ($macro eq 'headitem')) + { + #print STDERR "ITEM: $_"; + #dump_stack($text, $stack, $state); + abort_empty_preformatted($stack, $state); + # FIXME let the user be able not to close the paragraph + close_paragraph($text, $stack, $state, $line_nr); + # these functions return the format if in the right context + my $format; + if ($format = add_item($text, $stack, $state, $line_nr, $_)) + { # handle lists + } + elsif ($format = add_term($text, $stack, $state, $line_nr)) + {# handle table @item line + } + elsif ($format = add_line($text, $stack, $state, $line_nr)) + {# handle table text + } + if ($format) + { + if (defined($format->{'prepended'})) + { + $_ = $format->{'prepended'} . ' ' . $_ if ($format->{'prepended'} ne ''); + } + if (defined($format->{'command'})) + { + open_arg($format->{'command'},0, $state); + } + next; + } + $format = add_row ($text, $stack, $state, $line_nr); # handle multitable + unless ($format) + { + echo_warn ("\@$macro outside of table or list", $line_nr); + next; + } + push @$stack, {'format' => 'row', 'text' => '', 'item_cmd' => $macro }; + if ($format->{'max_columns'}) + { + push @$stack, {'format' => 'cell', 'text' => ''}; + $format->{'cell'} = 1; + + begin_paragraph_after_command($state,$stack,$macro,$_); + } + else + { + echo_warn ("\@$macro in empty multitable", $line_nr); + } + next; + } + if ($macro eq 'tab') + { + abort_empty_preformatted($stack, $state); + # FIXME let the user be able not to close the paragraph + close_paragraph($text, $stack, $state, $line_nr); + my $format = add_cell ($text, $stack, $state); + #print STDERR "tab, $format->{'cell'}, max $format->{'max_columns'}\n"; + if (!$format) + { + echo_warn ("\@$macro outside of multitable", $line_nr); + } + elsif (!$format->{'max_columns'}) + { + echo_warn ("\@$macro in empty multitable", $line_nr); + push @$stack, {'format' => 'null', 'text' => ''}; + next; + } + elsif ($format->{'cell'} > $format->{'max_columns'}) + { + echo_warn ("too much \@$macro (multitable has only $format->{'max_columns'} column(s))", $line_nr); + push @$stack, {'format' => 'null', 'text' => ''}; + next; + } + else + { + push @$stack, {'format' => 'cell', 'text' => ''}; + } + begin_paragraph_after_command($state,$stack,$macro,$_); + next; + } + # Macro opening a format (table, list, deff, example...) + if ($format_type{$macro} and ($format_type{$macro} ne 'fake')) + { + unless ($Texi2HTML::Config::format_in_paragraph{$macro}) + { + close_paragraph($text, $stack, $state, $line_nr); + } + push (@{$state->{'command_stack'}}, $macro); + if ($format_type{$macro} eq 'menu') + { + close_menu($text, $stack, $state, $line_nr); + $state->{'menu'}++; + } + # A deff like macro + if (defined($Texi2HTML::Config::def_map{$macro})) + { + my $top_format = top_format($stack); + if (defined($top_format) and ("$top_format->{'format'}x" eq $macro)) + { + # the @DEFx macro has been put at the top of the + # command_stack, although there is no real format opening + pop @{$state->{'command_stack'}}; + $macro =~ s/x$//o; + if (!$state->{'deff_line'}) + {# DEFx macro within a DEF paragraph + close_stack($text, $stack, $state, $line_nr, undef, 'deff_item'); + my $format_ref = pop @$stack; + add_prev($text, $stack, &$Texi2HTML::Config::def_item($format_ref->{'text'})); + } + #print STDERR "DEFx $macro\n"; + } + else + { + # The previous @def command isn't the same @def + # command. We begin the item for the previous @def + # command and immediately open the new one. + begin_deff_item($stack, $state, 1) if ($state->{'deff_line'}); + $macro =~ s/x$//o; + # we remove what is on the stack and put it back, + # to make sure that it is the form without x. + pop @{$state->{'command_stack'}}; + push @{$state->{'command_stack'}}, $macro; + #print STDERR "DEF begin $macro\n"; + push @$stack, { 'format' => $macro, 'text' => '' }; + } + #print STDERR "BEGIN_DEFF $macro\n"; + #dump_stack ($text, $stack, $state); + $state->{'deff_line'}->{'command'} = $macro; + my ($style, $category, $name, $type, $class, $arguments); + ($style, $category, $name, $type, $class, $_) = parse_def($macro, $_, $line_nr); + #print STDERR "AFTER parse_def $_"; + # duplicate_state? + $state->{'deff_line'}->{'style'} = $style; + $state->{'deff_line'}->{'category'} = substitute_line($category) if (defined($category)); + $state->{'deff_line'}->{'category'} = '' if (!defined($category)); + # FIXME -- --- ''... are transformed to entities by + # makeinfo. It may be wrong. + $state->{'deff_line'}->{'name'} = substitute_line($name) if (defined($name)); + $state->{'deff_line'}->{'name'} = '' if (!defined($name)); + $state->{'deff_line'}->{'type'} = substitute_line($type) if (defined($type)); + $state->{'deff_line'}->{'class'} = substitute_line($class) if (defined($class)); + # the remaining of the line (the argument) + #print STDERR "DEFF: open_cmd_line do_def_line $_"; + open_cmd_line($stack, $state, ['keep'], \&do_def_line); + next; + } + elsif (exists ($Texi2HTML::Config::complex_format_map->{$macro})) + { # handle menu if SIMPLE_MENU. see texi2html.init + $state->{'preformatted'}++; + my $complex_format = $Texi2HTML::Config::complex_format_map->{$macro}; + my $format = { 'format' => $macro, 'text' => '', 'pre_style' => $complex_format->{'pre_style'} }; + my $class = $macro; + $class = $complex_format->{'class'} if (defined($complex_format->{'class'})); + push @{$state->{'preformatted_stack'}}, {'pre_style' =>$complex_format->{'pre_style'}, 'class' => $class }; + push @$stack, $format; + unless ($Texi2HTML::Config::format_in_paragraph{$macro}) + { + begin_paragraph($stack, $state); + } + } + elsif ($Texi2HTML::Config::paragraph_style{$macro}) + { + push (@$stack, { 'format' => $macro, 'text' => '' }); + begin_paragraph_after_command($state,$stack,$macro,$_); + push @{$state->{'paragraph_style'}}, $macro; + if ($macro eq 'center') + { + # @center may be in a weird state with regard with + # nesting, so we put it on the bottom of the stack + pop @{$state->{'command_stack'}}; + unshift @{$state->{'command_stack'}}, $macro; + # for similar reasons, we may have a bad stack nesting + # which results in } after a closing. For example + # @center @samp{something @center end of samp} + # results to samp being kept in the 'command_stack' + + # we keep the end of line for @center, to + # avoid the return in case there is only spaces + # which occurs for all the format commmands followed by + # spaces only + next; + } + } + elsif ($format_type{$macro} eq 'menu') + { + # if $Texi2HTML::Config::SIMPLE_MENU we won't get there + # as the menu is a complex format in that case, so it + # is handled above + push @$stack, { 'format' => $macro, 'text' => '' }; + if ($state->{'preformatted'}) + { + # Start a fake complex format in order to have a given pre style + $state->{'preformatted'}++; + push @$stack, { 'format' => 'menu_preformatted', 'text' => '', 'pre_style' => $Texi2HTML::Config::MENU_PRE_STYLE }; + push @{$state->{'preformatted_stack'}}, {'pre_style' => $Texi2HTML::Config::MENU_PRE_STYLE, 'class' => 'menu-preformatted' }; + } + } + elsif (($format_type{$macro} eq 'list') or ($format_type{$macro} eq 'table')) + { + my $format; + #print STDERR "LIST_TABLE $macro\n"; + #dump_stack($text, $stack, $state); + if (($macro eq 'itemize') or ($macro =~ /^(|v|f)table$/)) + { + my $command; + my $prepended; + ($prepended, $command) = parse_format_command($_,$macro); + $format = { 'format' => $macro, 'text' => '', 'command' => $command, 'prepended' => $prepended, 'term' => 0 }; + $_ = ''; + } + elsif ($macro eq 'enumerate') + { + my $spec; + ($_, $spec) = parse_enumerate ($_); + $spec = 1 if (!defined($spec)); + $format = { 'format' => $macro, 'text' => '', 'spec' => $spec, 'item_nr' => 0 }; + } + elsif ($macro eq 'multitable') + { + my $max_columns = parse_multitable ($_, $line_nr); + if (!$max_columns) + { + echo_warn ("empty multitable", $line_nr); + $max_columns = 0; + } + $format = { 'format' => $macro, 'text' => '', 'max_columns' => $max_columns, 'cell' => 1 }; + } + $format->{'first'} = 1; + $format->{'paragraph_number'} = 0; + push @$stack, $format; + push @{$state->{'table_list_stack'}}, $format; + if ($macro =~ /^(|v|f)table$/) + { + push @$stack, { 'format' => 'line', 'text' => ''}; + } + elsif ($macro eq 'multitable') + { + if ($format->{'max_columns'}) + { + push @$stack, { 'format' => 'row', 'text' => '', 'item_cmd' => $macro }; + push @$stack, { 'format' => 'cell', 'text' => ''}; + } + else + { + # multitable without row... We use the special null + # format which content is ignored + push @$stack, { 'format' => 'null', 'text' => ''}; + push @$stack, { 'format' => 'null', 'text' => ''}; + } + } + if ($format_type{$macro} eq 'list') + { + push @$stack, { 'format' => 'item', 'text' => ''}; + } + begin_paragraph_after_command($state,$stack,$macro,$_) + if ($macro ne 'multitable'); + return if ($format_type{$macro} eq 'table' or $macro eq 'itemize'); + } + elsif ($macro eq 'float' or $macro eq 'quotation') + { + push @$stack, {'format' => $macro, 'text' => '' }; + if ($macro eq 'float') + { + open_cmd_line($stack, $state, ['keep','keep'], \&do_float_line); + } + elsif ($macro eq 'quotation') + { + open_cmd_line($stack, $state, ['keep'], \&do_quotation_line); + } + #dump_stack($text, $stack, $state); + next; + } + # keep this one at the end as there are some other formats + # which are also in format_map + elsif (defined($Texi2HTML::Config::format_map{$macro}) or ($format_type{$macro} eq 'cartouche')) + { + push @$stack, { 'format' => $macro, 'text' => '' }; + begin_paragraph_after_command($state,$stack,$macro,$_); + } + return if (/^\s*$/); + next; + } + $_ = do_unknown ($macro, $_, $text, $stack, $state, $line_nr); + next; + } + elsif(s/^([^{}@,]*)\@([^\s\}\{\@]*)//o) + { # A macro with a character which shouldn't appear in macro name + add_prev($text, $stack, do_text($1, $state)); + $_ = do_unknown ($2, $_, $text, $stack, $state, $line_nr); + next; + } + elsif (s/^([^{},]*)([{}])//o or (@$stack and + defined($stack->[-1]->{'style'}) and + ($stack->[-1]->{'style'} eq 'cmd_line') and /^([^{},]*)$/o)) + { + my $leading_text = $1; + my $brace = $2; + add_prev($text, $stack, do_text($leading_text, $state)); + if (defined($brace) and ($brace eq '{')) + { + add_prev($text, $stack, do_text('{',$state)); + unless ($state->{'keep_texi'} or $state->{'remove_texi'}) + { + echo_error ("'{' without macro. Before: $_", $line_nr); + } + } + elsif (defined($brace) and ($brace eq '}') and + (!@$stack or (!defined($stack->[-1]->{'style'})) + # a non empty stack, but with 'cmd_line' as first item on the stack + # is like an empty stack + or ($stack->[-1]->{'style'} eq 'cmd_line'))) + { + if ($state->{'keep_texi'}) + { + add_prev($text, $stack, '}'); + } + else + { + echo_error("'}' without opening '{' before: $_", $line_nr); + } + } + else + { # A @-command{ ...} is closed + my $style = pop @$stack; + my $command = $style->{'style'}; + my $result; + if (ref($::style_map_ref->{$command}) eq 'HASH') + { + push (@{$style->{'args'}}, $style->{'text'}); + $style->{'fulltext'} .= $style->{'text'}; + #my $number = 0; + #foreach my $arg(@{$style->{'args'}}) + #{ + #print STDERR " $number: $arg\n"; + # $number++; + #} + $style->{'text'} = $style->{'fulltext'}; + $state->{'keep_texi'} = 0 if ( + ($::style_map_ref->{$command}->{'args'}->[$style->{'arg_nr'}] eq 'keep') + and ($state->{'keep_nr'} == 1)); + } + $state->{'no_paragraph'}-- if ($no_paragraph_macro{$command}); + if ($command) + { + $style->{'no_close'} = 1 if ($state->{'no_close'}); + if ($::style_map_ref->{$command} and (defined($style_type{$command})) and ((!$style->{'no_close'} and ($style_type{$command} eq 'style')) or ($style_type{$command} eq 'accent'))) + { + my $style_command = pop @{$state->{'command_stack'}}; + if ($style_command ne $command) + { + print STDERR "Bug: $style_command on 'command_stack', not $command\n"; + push @$stack, $style; + push @{$state->{'command_stack'}}, $style_command; + print STDERR "Stacks before pop top:\n"; + dump_stack($text, $stack, $state); + pop @$stack; + } + } + if ($state->{'keep_texi'}) + { # don't expand @-commands in anchor, refs... + close_arg ($command, $style->{'arg_nr'}, $state); + $result = '@' . $command . '{' . $style->{'text'} . '}'; + } + else + { + $result = do_simple($command, $style->{'text'}, $state, $style->{'args'}, $line_nr, $style->{'no_open'}, $style->{'no_close'}); + if ($state->{'code_style'} < 0) + { + echo_error ("Bug: negative code_style: $state->{'code_style'}, line:$_", $line_nr); + } + } + } + else + { + print STDERR "Bug: empty style in pass_text\n"; + } + add_prev($text, $stack, $result); + if ($command eq 'cmd_line') + { + if ($state->{'deff_line'}) + { +#print STDERR "DO DEFF $state->{'deff_line'}->{'command'} $state->{'deff_line'}->{'arguments'}\n"; + my $command = $state->{'deff_line'}->{'command'}; + my $def_style = $state->{'deff_line'}->{'style'}; + my $category = $state->{'deff_line'}->{'category'}; + my $class = $state->{'deff_line'}->{'class'}; + my $type = $state->{'deff_line'}->{'type'}; + my $name = $state->{'deff_line'}->{'name'}; + #my $arguments = $state->{'deff'}->{'arguments'}; + my $arguments; + $arguments = substitute_line($state->{'deff_line'}->{'arguments'}) if (defined($state->{'deff_line'}->{'arguments'})); + + $category = &$Texi2HTML::Config::definition_category($category, $class, $def_style); + my $index_label = do_index_entry_label($command, $state,$line_nr); + add_prev($text, $stack, &$Texi2HTML::Config::def_line($category, $name, $type, $arguments, $index_label)); + } + elsif ($state->{'preformatted'}) + { # inconditionally begin a preformatted section for + # non @def* commands (currently @float and @quotation) + # for @def* it is done in begin_deff_item + begin_paragraph($stack, $state); + } + $state->{'no_paragraph'}--; + return; + } + } + } + elsif (s/^([^,]*)[,]//o) + { + add_prev($text, $stack, do_text($1, $state)); + if (@$stack and defined($stack->[-1]->{'style'}) + and (ref($::style_map_ref->{$stack->[-1]->{'style'}}) eq 'HASH')) + { + my $macro = $stack->[-1]->{'style'}; + my $style_args = $::style_map_ref->{$macro}->{'args'}; + if (defined($style_args->[$stack->[-1]->{'arg_nr'} + 1])) + { + push (@{$stack->[-1]->{'args'}}, $stack->[-1]->{'text'}); + $stack->[-1]->{'fulltext'} .= $stack->[-1]->{'text'} . do_text(',', $state); + $stack->[-1]->{'text'} = ''; + close_arg ($macro, $stack->[-1]->{'arg_nr'}, $state); + $stack->[-1]->{'arg_nr'}++; + open_arg ($macro, $stack->[-1]->{'arg_nr'}, $state); + next; + } + } + add_prev($text, $stack, do_text(',', $state)); + } + else + { # no macro nor '}', but normal text + add_prev($text, $stack, do_text($_, $state)); + #print STDERR "END LINE:$_!!!\n"; + #dump_stack($text, $stack, $state); + + # @item line is closed by end of line + add_term($text, $stack, $state, $line_nr); + + # @center is closed at the end of line. When a @-command which + # keeps the texi as is happens on the @center line, the @center + # is closed at the end of line appearing after the @-command + # closing (for example @ref, @footnote). + + # when 'closing_center' is true we don't retry to close + # the @center line. + if ($state->{'paragraph_style'}->[-1] eq 'center' + and !$state->{'closing_center'} and !$state->{'keep_texi'}) + { + $state->{'closing_center'} = 1; + unless ($Texi2HTML::Config::format_in_paragraph{'center'}) + { + close_paragraph($text, $stack, $state, $line_nr); + } + close_stack($text, $stack, $state, $line_nr, undef, 'center'); + delete $state->{'closing_center'}; + my $center = pop @$stack; + add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command('center',$center->{'text'})); + my $top_paragraph_style = pop @{$state->{'paragraph_style'}}; + # center is at the bottom of the comand_stack because it + # may be nested in many way + my $bottom_command_stack = shift @{$state->{'command_stack'}}; + print STDERR "Bug: closing center, top_paragraph_style: $top_paragraph_style, bottom_command_stack: $bottom_command_stack.\n" + if ($bottom_command_stack ne 'center' or $top_paragraph_style ne 'center'); + $_ = ''; + next; + } + last; + } + } + return 1; +} + +sub open_arg($$$) +{ + my $macro = shift; + my $arg_nr = shift; + my $state = shift; + if (ref($::style_map_ref->{$macro}) eq 'HASH') + { + my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr]; + if ($arg eq 'code' and !$state->{'keep_texi'}) + { + $state->{'code_style'}++; + } + elsif ($arg eq 'keep') + { + $state->{'keep_nr'}++; + $state->{'keep_texi'} = 1; + } + } + elsif ($code_style_map{$macro} and !$state->{'keep_texi'}) + { + $state->{'code_style'}++; + } +} + +sub close_arg($$$) +{ + my $macro = shift; + my $arg_nr = shift; + my $state = shift; + if (ref($::style_map_ref->{$macro}) eq 'HASH') + { + my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr]; + if ($arg eq 'code' and !$state->{'keep_texi'}) + { + $state->{'code_style'}--; + } + elsif ($arg eq 'keep') + { + $state->{'keep_nr'}--; + $state->{'keep_texi'} = 0 if ($state->{'keep_nr'} == 0); + } +#print STDERR "c $arg_nr $macro $arg $state->{'code_style'}\n"; + } + elsif ($code_style_map{$macro} and !$state->{'keep_texi'}) + { + $state->{'code_style'}--; + } +} + +# add a special style on the top of the stack. This is used for commands +# that extend until the end of the line +sub open_cmd_line($$$$) +{ + my $stack = shift; + my $state = shift; + my $args = shift; + my $function = shift; + push @$stack, {'style' => 'cmd_line', 'text' => '', 'arg_nr' => 0}; + foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi) + { + $hash->{'cmd_line'}->{'args'} = $args; + $hash->{'cmd_line'}->{'function'} = $function; + } + $state->{'no_paragraph'}++; + open_arg ('cmd_line', 0, $state); +} + +# finish @item line in @*table +sub add_term($$$$;$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + my $end = shift; + return unless (exists ($state->{'table_list_stack'})); + my $format = $state->{'table_list_stack'}->[-1]; + return unless (($format_type{$format->{'format'}} eq 'table') and ($format->{'format'} ne 'multitable' ) and $format->{'term'}); + #print STDERR "ADD_TERM\n"; + # we set 'term' = 0 early such that if we encounter an end of line + # during close_stack we don't try to do the term once more + $state->{'table_list_stack'}->[-1]->{'term'} = 0; + # it is the first paragraph for the term. + $format->{'paragraph_number'} = 0; + + #dump_stack($text, $stack, $state); + close_stack($text, $stack, $state, $line_nr, undef, 'term'); + my $term = pop @$stack; + my $command_formatted; + chomp ($term->{'text'}); + if (exists($::style_map_ref->{$format->{'command'}}) and + !exists($Texi2HTML::Config::special_list_commands{$format->{'format'}}->{$format->{'command'}}) and ($style_type{$format->{'command'}} eq 'style')) + { + my $leading_spaces = ''; + my $trailing_spaces = ''; + $term->{'text'} =~ s/^(\s*)//o; + $leading_spaces = $1 if (defined($1)); + $term->{'text'} =~ s/(\s*)$//o; + $trailing_spaces = $1 if (defined($1)); + $term->{'text'} = do_simple($format->{'command'}, $term->{'text'}, $state, [$term->{'text'}]); + $term->{'text'} = $leading_spaces. $term->{'text'} .$trailing_spaces; + } + elsif (exists($::things_map_ref->{$format->{'command'}})) + { + $command_formatted = do_simple($format->{'command'}, '', $state); + } + my $index_label; + if ($format->{'format'} =~ /^(f|v)/o) + { + $index_label = do_index_entry_label($format->{'format'}, $state,$line_nr); + print STDERR "Bug: no index entry for $text" unless defined($index_label); + } + add_prev($text, $stack, &$Texi2HTML::Config::table_item($term->{'text'}, $index_label,$format->{'format'},$format->{'command'}, $command_formatted,$state->{'command_stack'})); + unless ($end) + { + push (@$stack, { 'format' => 'line', 'text' => '' }); + begin_paragraph($stack, $state) if ($state->{'preformatted'}); + } + return $format; +} + +sub add_row($$$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + my $format = $state->{'table_list_stack'}->[-1]; + return unless ($format->{'format'} eq 'multitable'); + if ($format->{'cell'} > $format->{'max_columns'}) + { + close_stack($text, $stack, $state, $line_nr, undef, 'null'); + pop @$stack; + } + unless ($format->{'max_columns'}) + { # empty multitable + pop @$stack; # pop 'row' + return $format; + } + if ($format->{'first'}) + { # first row + $format->{'first'} = 0; + #dump_stack($text, $stack, $state); + #if ($stack->[-1]->{'format'} and ($stack->[-1]->{'format'} eq 'paragraph') and ($stack->[-1]->{'text'} =~ /^\s*$/) and ($format->{'cell'} == 1)) + if ($stack->[-1]->{'format'} and ($stack->[-1]->{'format'} eq 'cell') and ($stack->[-1]->{'text'} =~ /^\s*$/) and ($format->{'cell'} == 1)) + { + pop @$stack; + pop @$stack; + #pop @$stack; + return $format; + } + } + add_cell($text, $stack, $state); + my $row = pop @$stack; + add_prev($text, $stack, &$Texi2HTML::Config::row($row->{'text'}, $row->{'item_cmd'})); + return $format; +} + +sub add_cell($$$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + my $format = $state->{'table_list_stack'}->[-1]; + return unless ($format->{'format'} eq 'multitable'); + if ($format->{'cell'} <= $format->{'max_columns'}) + { + close_stack($text, $stack, $state, $line_nr, undef, 'cell'); + my $cell = pop @$stack; + my $row = top_stack($stack); + print STDERR "Bug: top_stack of cell not a row\n" if (!defined($row) or !defined($row->{'format'}) or ($row->{'format'} ne 'row')); + add_prev($text, $stack, &$Texi2HTML::Config::cell($cell->{'text'}, $row->{'item_cmd'})); + $format->{'cell'}++; + } + return $format; +} + +sub add_line($$$$;$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + my $end = shift; + my $format = $state->{'table_list_stack'}->[-1]; + return unless ($format_type{$format->{'format'}} eq 'table' and ($format->{'format'} ne 'multitable') and ($format->{'term'} == 0)); + #print STDERR "ADD_LINE\n"; + #dump_stack($text, $stack, $state); + # as in pre the end of line are kept, we must explicitely abort empty + # preformatted, close_stack doesn't abort the empty preformatted regions. + abort_empty_preformatted($stack, $state) if ($format->{'first'}); + close_stack($text, $stack, $state, $line_nr, undef, 'line'); + my $line = pop @$stack; + $format->{'paragraph_number'} = 0; + my $first = 0; + $first = 1 if ($format->{'first'}); + if ($first) + { + $format->{'first'} = 0; + # we must have <dd> or <dt> following <dl> thus we do a + # &$Texi2HTML::Config::table_line here too, although it could have + # been a normal paragraph. + add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'})) if ($line->{'text'} =~ /\S/o); + } + else + { + add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'})); + } + unless($end) + { + push (@$stack, { 'format' => 'term', 'text' => '' }); + } + $format->{'term'} = 1; + return $format; +} + +# finish @enumerate or @itemize @item +sub add_item($$$$;$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + my $line = shift; + my $end = shift; + my $format = $state->{'table_list_stack'}->[-1]; + return unless ($format_type{$format->{'format'}} eq 'list'); + #print STDERR "ADD_ITEM: \n"; + # as in pre the end of line are kept, we must explicitely abort empty + # preformatted, close_stack doesn't do that. + abort_empty_preformatted($stack, $state) if ($format->{'first'}); + close_stack($text, $stack, $state, $line_nr, undef, 'item'); + $format->{'paragraph_number'} = 0; + if ($format->{'format'} eq 'enumerate') + { + $format->{'number'} = ''; + my $spec = $format->{'spec'}; + $format->{'item_nr'}++; + if ($spec =~ /^[0-9]$/) + { + $format->{'number'} = $spec + $format->{'item_nr'} - 1; + } + else + { + my $base_letter = ord('a'); + $base_letter = ord('A') if (ucfirst($spec) eq $spec); + + my @letter_ords = decompose(ord($spec) - $base_letter + $format->{'item_nr'} - 1, 26); + foreach my $ord (@letter_ords) + {# WARNING we go directly to 'ba' after 'z', and not 'aa' + #because 'ba' is 1,0 and 'aa' is 0,0. + $format->{'number'} = chr($base_letter + $ord) . $format->{'number'}; + } + } + } + + #dump_stack ($text, $stack, $state); + my $item = pop @$stack; + # the element following ol or ul must be li. Thus even though there + # is no @item we put a normal item. + + # don't do an item if it is the first and it is empty + if (!$format->{'first'} or ($item->{'text'} =~ /\S/o)) + { + my $formatted_command; + if (defined($format->{'command'}) and exists($::things_map_ref->{$format->{'command'}})) + { + $formatted_command = do_simple($format->{'command'}, '', $state); + } + #chomp($item->{'text'}); + add_prev($text, $stack, &$Texi2HTML::Config::list_item($item->{'text'},$format->{'format'},$format->{'command'}, $formatted_command, $format->{'item_nr'}, $format->{'spec'}, $format->{'number'})); + } + if ($format->{'first'}) + { + $format->{'first'} = 0; + } + + # Now prepare the new item + unless($end) + { + push (@$stack, { 'format' => 'item', 'text' => '' }); + begin_paragraph($stack, $state) unless (!$state->{'preformatted'} and no_line($line)); + } + return $format; +} + +# format ``simple'' macros, that is macros without arg or style macros +sub do_simple($$$;$$$$) +{ + my $macro = shift; + my $text = shift; + my $state = shift; + my $args = shift; + my $line_nr = shift; + my $no_open = shift; + my $no_close = shift; + + my $arg_nr = 0; + $arg_nr = @$args - 1 if (defined($args)); + +#print STDERR "DO_SIMPLE $macro $arg_nr $args @$args\n" if (defined($args)); + if (defined($::simple_map_ref->{$macro})) + { + # \n may in certain circumstances, protect end of lines + if ($macro eq "\n") + { + $state->{'end_of_line_protected'} = 1; + #print STDERR "PROTECTING END OF LINE\n"; + } + if ($state->{'keep_texi'}) + { + return "\@$macro"; + } + elsif ($state->{'remove_texi'}) + { +#print STDERR "DO_SIMPLE remove_texi $macro\n"; + return $::simple_map_texi_ref->{$macro}; + } + elsif ($state->{'preformatted'}) + { + return $::simple_map_pre_ref->{$macro}; + } + else + { + return $::simple_map_ref->{$macro}; + } + } + if (defined($::things_map_ref->{$macro})) + { + my $result; + if ($state->{'keep_texi'}) + { + $result = "\@$macro" . '{}'; + } + elsif ($state->{'remove_texi'}) + { + $result = $::texi_map_ref->{$macro}; +#print STDERR "DO_SIMPLE remove_texi texi_map $macro\n"; + } + elsif ($state->{'preformatted'}) + { + $result = $::pre_map_ref->{$macro}; + } + else + { + $result = $::things_map_ref->{$macro}; + } + return $result . $text; + } + elsif (defined($::style_map_ref->{$macro})) + { + if ($state->{'keep_texi'}) + { + return "\@$macro" . '{' . $text . '}'; + } + else + { + my $style; + my $result; + if ($state->{'remove_texi'}) + { +#print STDERR "REMOVE $macro, $style_map_texi_ref->{$macro}, fun $style_map_texi_ref->{$macro}->{'function'} remove cmd " . \&Texi2HTML::Config::t2h_remove_command . " ascii acc " . \&t2h_default_ascii_accent; + $style = $::style_map_texi_ref->{$macro}; + } + elsif ($state->{'preformatted'}) + { + $style = $::style_map_pre_ref->{$macro}; + } + else + { + $style = $::style_map_ref->{$macro}; + } + if (defined($style)) + { # known style + $result = &$Texi2HTML::Config::style($style, $macro, $text, $args, $no_close, $no_open, $line_nr, $state, $state->{'command_stack'}); + } + if (!$no_close) + { + close_arg($macro,$arg_nr, $state); + } + return $result; + } + } + elsif ($macro =~ /^special_(\w+)_(\d+)$/o) + { + my $style = $1; + my $count = $2; + print STDERR "Bug? text in \@$macro not empty.\n" if ($text ne ''); + if ($state->{'keep_texi'}) + {# text should be empty + return "\@$macro" . '{' . $text . '}'; + } + if (defined($Texi2HTML::Config::command_handler{$style}) and + defined($Texi2HTML::Config::command_handler{$style}->{'expand'})) + { + my $struct_count = 1+ $special_commands{$style}->{'max'} - $special_commands{$style}->{'count'}; + if (($count != $struct_count) and $T2H_DEBUG) + { + print STDERR "count $count in \@special $style and structure $struct_count differ\n"; + } + $special_commands{$style}->{'count'}--; + } + my $result = $Texi2HTML::Config::command_handler{$style}->{'expand'} + ($style,$count,$state,$text); + $result = '' if (!defined($result)); + return $result; + } + # Unknown macro + my $result = ''; + my ($done, $result_text, $message) = &$Texi2HTML::Config::unknown_style($macro, $text,$state); + if ($done) + { + echo_warn($message, $line_nr) if (defined($message)); + if (defined($result_text)) + { + $result = $result_text; + } + } + else + { + unless ($no_open) + { # we warn only if no_open is true, i.e. it is the first time we + # close the macro for a multiline macro + echo_warn ("Unknown command with braces `\@$macro'", $line_nr); + $result = do_text("\@$macro") . "{"; + } + $result .= $text; + $result .= '}' unless ($no_close); + } + return $result; +} + +sub do_unknown($$$$$$) +{ + my $macro = shift; + my $line = shift; + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + #print STDERR "do_unknown: $macro ::: $line"; + my ($result_line, $result, $result_text, $message) = &$Texi2HTML::Config::unknown($macro, $line,$stack,$state); + if ($result) + { + add_prev ($text, $stack, $result_text) if (defined($result_text)); + echo_warn($message, $line_nr) if (defined($message)); + return $result_line; + } + else + { + echo_warn ("Unknown command `\@$macro' (left as is)", $line_nr); + add_prev ($text, $stack, do_text("\@$macro")); + return $line; + } +} + +# used only during @macro processing +sub add_text($@) +{ + my $string = shift; + + return if (!defined($string)); + foreach my $scalar_ref (@_) + { + next unless defined($scalar_ref); + if (!defined($$scalar_ref)) + { + $$scalar_ref = $string; + } + else + { + $$scalar_ref .= $string; + } + return; + } +} + +sub add_prev ($$$) +{ + my $text = shift; + my $stack = shift; + my $string = shift; + + unless (defined($text) and ref($text) eq "SCALAR") + { + die "text not a SCALAR ref: " . ref($text) . ""; + } + #if (!defined($stack) or (ref($stack) ne "ARRAY")) + #{ + # $string = $stack; + # $stack = []; + #} + + return if (!defined($string)); + if (@$stack) + { + $stack->[-1]->{'text'} .= $string; + return; + } + + if (!defined($$text)) + { + $$text = $string; + } + else + { + $$text .= $string; + } +} + +sub close_stack_texi_structure($$$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + + return undef unless (@$stack or $state->{'raw'} or $state->{'macro'} or $state->{'macro_name'} or $state->{'ignored'}); + + #print STDERR "close_stack_texi_structure\n"; + #dump_stack ($text, $stack, $state); + my $stack_level = $#$stack + 1; + my $string = ''; + + if ($state->{'ignored'}) + { + $string .= "\@end $state->{'ignored'} "; + echo_warn ("closing $state->{'ignored'}", $line_nr); + } + if ($state->{'texi'}) + { + if ($state->{'macro'}) + { + $string .= "\@end macro "; + echo_warn ("closing macro", $line_nr); + } + elsif ($state->{'macro_name'}) + { + $string .= ('}' x $state->{'macro_depth'}) . " "; + echo_warn ("closing $state->{'macro_name'} ($state->{'macro_depth'} braces missing)", $line_nr); + } + elsif ($state->{'verb'}) + { + echo_warn ("closing \@verb", $line_nr); + $string .= $state->{'verb'} . '}'; + } + elsif ($state->{'raw'}) + { + echo_warn ("closing \@$state->{'raw'} raw format", $line_nr); + $string .= "\@end $state->{'raw'} "; + } + if ($string ne '') + { + #print STDERR "close_stack scan_texi ($string)\n"; + scan_texi ($string, $text, $stack, $state, $line_nr); + $string = ''; + } + } + elsif ($state->{'verb'}) + { + $string .= $state->{'verb'}; + } + + while ($stack_level--) + { + my $stack_text = $stack->[$stack_level]->{'text'}; + $stack_text = '' if (!defined($stack_text)); + if ($stack->[$stack_level]->{'format'}) + { + my $format = $stack->[$stack_level]->{'format'}; + if ($format eq 'index_item') + { + enter_table_index_entry($text, $stack, $state, $line_nr); + next; + } + elsif (!defined($format_type{$format}) or ($format_type{$format} ne 'fake')) + { + $stack_text = "\@$format\n" . $stack_text; + } + } + elsif (defined($stack->[$stack_level]->{'style'})) + { + if ($state->{'structure'}) + { + $stack_text = close_structure_command($stack->[$stack_level], + $state,1,$line_nr) + } + else + { + my $style = $stack->[$stack_level]->{'style'}; + if ($style ne '') + { + $stack_text = "\@$style\{" . $stack_text; + } + else + {# this is a lone opened brace. We readd it there. + $stack_text = "\{" . $stack_text; + } + } + } + pop @$stack; + add_prev($text, $stack, $stack_text); + } + $stack = [ ]; + + $state->{'close_stack'} = 1; + if ($string ne '') + { + if ($state->{'texi'}) + { + #print STDERR "scan_texi in close_stack ($string)\n"; + scan_texi($string, $text, $stack, $state, $line_nr); + } + elsif ($state->{'structure'}) + { + #print STDERR "scan_structure in close_stack ($string)\n"; + scan_structure($string, $text, $stack, $state, $line_nr); + } + } + delete $state->{'close_stack'}; +} + +# close region like @insertcopying, titlepage... +# restore $state->{'after_element'} and delete the structure +sub close_region($) +{ + my $state = shift; + $state->{'after_element'} = 1; + delete $state->{'after_element'} unless + ($state->{'region_lines'}->{'after_element'}); + $state->{'place'} = $state->{'region_lines'}->{'kept_place'}; + delete $state->{'region_lines'}->{'number'}; + delete $state->{'region_lines'}->{'format'}; + delete $state->{'region_lines'}->{'after_element'}; + delete $state->{'region_lines'}->{'kept_place'}; + delete $state->{'region_lines'}; +} + +# close the stack, closing macros and formats left open. +# the precise behavior of the function depends on $close_paragraph: +# undef -> close everything +# defined -> remove empty paragraphs, close until the first format or +# paragraph. don't close styles, duplicate stack of styles not closed + +# if a $format is given the stack is closed according to $close_paragraph but +# if $format is encountered the closing stops + +sub close_stack($$$$;$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + my $close_paragraph = shift; + my $format = shift; + my $new_stack; + + #print STDERR "sub_close_stack\n"; + return $new_stack unless (@$stack); + + my $stack_level = $#$stack + 1; + my $string = ''; + my $verb = ''; + + if ($state->{'verb'}) + { + $string .= $state->{'verb'}; + $verb = $state->{'verb'}; + } + + #debugging + #my $print_format = 'NO FORMAT'; + #$print_format = $format if ($format); + #my $print_close_paragraph = 'close everything'; + #$print_close_paragraph = 'close paragraph without duplicating' if (defined($close_paragraph)); + #$print_close_paragraph = $close_paragraph if ($close_paragraph); + #print STDERR "Close_stack: format $print_format, close_paragraph: $print_close_paragraph\n"; + + while ($stack_level--) + { + if ($stack->[$stack_level]->{'format'}) + { + my $stack_format = $stack->[$stack_level]->{'format'}; + last if (defined($close_paragraph) or (defined($format) and $stack_format eq $format)); + # We silently close paragraphs, preformatted sections and fake formats + if ($stack_format eq 'paragraph') + { + $string .= "\@end_paragraph{}"; + } + elsif ($stack_format eq 'preformatted') + { + $string .= "\@end_preformatted{}"; + } + else + { + if ($fake_format{$stack_format}) + { + warn "# Closing a fake format `$stack_format'\n" if ($T2H_VERBOSE); + } + elsif ($stack_format ne 'center') + { # we don't warn, but add an @end center + echo_warn ("closing `$stack_format'", $line_nr); + #dump_stack ($text, $stack, $state); + } + $string .= "\@end $stack_format "; + } + } + else + { + my $style = $stack->[$stack_level]->{'style'}; + # FIXME images, footnotes, xrefs, anchors with $close_paragraphs? + # seems that it is not possible, as it is triggered by + # close_paragraph which shouldn't be called with keep_texi + # and when the arguments are expanded, there is a + # substitute_line or similar with a new stack. + if ($close_paragraph) + { #duplicate the stack + # the !exists($style_type{$style}) condition catches the unknown + # @-commands: by default they are considered as style commands + if ((exists($style_type{$style}) and ($style_type{$style} eq 'style')) or (!exists($style_type{$style}))) + { + push @$new_stack, { 'style' => $style, 'text' => '', 'no_open' => 1, 'arg_nr' => 0 }; + $string .= '}'; + } + elsif (($style_type{$style} eq 'simple_style') or ($style_type{$style} eq 'accent')) + { + $string .= '}'; + } + else + { + print STDERR "$style while closing paragraph\n"; + } + } + else + { + dump_stack ($text, $stack, $state) if (!defined($style)); # bug + $string .= '}'; + echo_warn ("closing \@-command $style", $line_nr) if ($style); + } + } + } + $state->{'no_close'} = 1 if ($close_paragraph); + $state->{'close_stack'} = 1; + if ($string ne '') + { + #print STDERR "scan_line in CLOSE_STACK ($string)\n"; + #dump_stack ($text, $stack, $state); + scan_line($string, $text, $stack, $state, $line_nr); + } + delete $state->{'no_close'}; + delete $state->{'close_stack'}; + $state->{'verb'} = $verb if (($verb ne '') and $close_paragraph); + # cancel paragraph states and command_stack + # FIXME this seems to be unusefull, see formatting/center.texi + unless (defined($close_paragraph) or defined($format)) + { + $state->{'paragraph_style'} = [ '' ]; + $state->{'command_stack'} = [ '' ]; + } + return $new_stack; +} + +# given a stack and a list of formats, return true if the stack contains +# these formats, first on top +sub stack_order($@) +{ + my $stack = shift; + my $stack_level = $#$stack + 1; + while (@_) + { + my $format = shift; + while ($stack_level--) + { + if ($stack->[$stack_level]->{'format'}) + { + if ($stack->[$stack_level]->{'format'} eq $format) + { + $format = undef; + last; + } + else + { + return 0; + } + } + } + return 0 if ($format); + } + return 1; +} + +sub top_format($) +{ + my $stack = shift; + my $stack_level = $#$stack + 1; + while ($stack_level--) + { + if ($stack->[$stack_level]->{'format'} and !$fake_format{$stack->[$stack_level]->{'format'}}) + { + return $stack->[$stack_level]; + } + } + return undef; +} + +sub close_paragraph($$$;$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + my $line_nr = shift; + #my $macro = shift; + #print STDERR "CLOSE_PARAGRAPH\n"; + #dump_stack($text, $stack, $state); + my $new_stack = close_stack($text, $stack, $state, $line_nr, 1); + my $top_stack = top_stack($stack); + if ($top_stack and !defined($top_stack->{'format'})) + { #debug + print STDERR "Bug: no format on top stack\n"; + dump_stack($text, $stack, $state); + } + if ($top_stack and ($top_stack->{'format'} eq 'paragraph')) + { + my $paragraph = pop @$stack; + add_prev($text, $stack, do_paragraph($paragraph->{'text'}, $state)); + $state->{'paragraph_macros'} = $new_stack; + return 1; + } + elsif ($top_stack and ($top_stack->{'format'} eq 'preformatted')) + { + my $paragraph = pop @$stack; + add_prev($text, $stack, do_preformatted($paragraph->{'text'}, $state)); + $state->{'paragraph_macros'} = $new_stack; + return 1; + } + return; +} + +sub abort_empty_preformatted($$) +{ + my $stack = shift; + my $state = shift; + if (@$stack and $stack->[-1]->{'format'} + and ($stack->[-1]->{'format'} eq 'preformatted') + and ($stack->[-1]->{'text'} !~ /\S/)) + { + pop @$stack; + } +} + +# for debugging +sub dump_stack($$$) +{ + my $text = shift; + my $stack = shift; + my $state = shift; + + if (defined($$text)) + { + print STDERR "text: $$text\n"; + } + else + { + print STDERR "text: UNDEF\n"; + } + my $in_remove = 0; + my $in_simple_format = 0; + my $in_keep = 0; + $in_keep = 1 if ($state->{'keep_texi'}); + if (!$in_keep) + { + $in_simple_format = 1 if ($state->{'simple_format'}); + $in_remove = 1 if ($state->{'remove_texi'} and !$in_simple_format); + } + print STDERR "state(k${in_keep}s${in_simple_format}r${in_remove}): "; + foreach my $key (keys(%$state)) + { + my $value = 'UNDEF'; + $value = $state->{$key} if (defined($state->{$key})); + print STDERR "$key: $value " if (!ref($value)); + } + print STDERR "\n"; + my $stack_level = $#$stack + 1; + while ($stack_level--) + { + print STDERR " $stack_level-> "; + foreach my $key (keys(%{$stack->[$stack_level]})) + { + my $value = 'UNDEF'; + $value = $stack->[$stack_level]->{$key} if + (defined($stack->[$stack_level]->{$key})); + print STDERR "$key: $value "; + } + print STDERR "\n"; + } + if (defined($state->{'table_list_stack'})) + { + print STDERR "table_list_stack: "; + foreach my $format (@{$state->{'table_list_stack'}}) + { + print STDERR "$format->{'format'} "; + } + print STDERR "\n"; + } + if (defined($state->{'command_stack'})) + { + print STDERR "command_stack: "; + foreach my $style (@{$state->{'command_stack'}}) + { + print STDERR "($style) "; + } + print STDERR "\n"; + } + if (defined($state->{'region_lines'})) + { + print STDERR "region_lines($state->{'region_lines'}->{'number'}): $state->{'region_lines'}->{'format'}\n"; + } + if (defined($state->{'text_macro_stack'}) and @{$state->{'text_macro_stack'}}) + { + print STDERR "text_macro_stack: (@{$state->{'text_macro_stack'}})\n"; + } +} + +# for debugging +sub print_elements($) +{ + my $elements = shift; + foreach my $elem(@$elements) + { + if ($elem->{'node'}) + { + print STDERR "node-> $elem "; + } + else + { + print STDERR "chap=> $elem "; + } + foreach my $key (keys(%$elem)) + { + my $value = "UNDEF"; + $value = $elem->{$key} if (defined($elem->{$key})); + print STDERR "$key: $value "; + } + print STDERR "\n"; + } +} + +sub substitute_line($;$) +{ + my $line = shift; + my $state = shift; + $state = {} if (!defined($state)); + $state->{'no_paragraph'} = 1; + # this is usefull when called from &$I + return simple_format($state, $line) if ($state->{'simple_format'}); + return substitute_text($state, $line); +} + +sub substitute_text($@) +{ + my $state = shift; + my @stack = (); + my $text = ''; + my $result = ''; + if ($state->{'structure'}) + { + initialise_state_structure($state); + } + elsif ($state->{'texi'}) + { + initialise_state_texi($state); + } + else + { + initialise_state($state); + } + $state->{'spool'} = []; + #print STDERR "SUBST_TEXT begin\n"; + + while (@_ or @{$state->{'spool'}}) + { + my $line; + if (@{$state->{'spool'}}) + { + $line = shift @{$state->{'spool'}}; + } + else + { + $line = shift @_; + } + next unless (defined($line)); + if ($state->{'structure'}) + { + scan_structure ($line, \$text, \@stack, $state); + } + elsif ($state->{'texi'}) + { + scan_texi ($line, \$text, \@stack, $state); + } + else + { + scan_line($line, \$text, \@stack, $state); + } + next if (@stack); + $result .= $text; + $text = ''; + } + # FIXME could we have the line number ? + # close stack in substitute_text + if ($state->{'texi'} or $state->{'structure'}) + { + close_stack_texi_structure(\$text, \@stack, $state, undef); + } + else + { + close_stack(\$text, \@stack, $state, undef); + } + #print STDERR "SUBST_TEXT end\n"; + return $result . $text; +} + +# this function does the second pass formatting. It is not obvious that +# it is usefull as in that pass the collected things +sub substitute_texi_line($) +{ + my $text = shift; + return $text if $text =~ /^\s*$/; + #print STDERR "substitute_texi_line $text\n"; + my @text = substitute_text({'structure' => 1}, $text); + my @result = (); + while (@text) + { + push @result, split (/\n/, shift (@text)); + } + return '' unless (@result); + my $result = shift @result; + return $result . "\n" unless (@result); + foreach my $line (@result) + { + chomp $line; + $result .= ' ' . $line; + } + return $result . "\n"; +} + +sub print_lines($;$) +{ + my ($fh, $lines) = @_; + $lines = $Texi2HTML::THIS_SECTION unless $lines; + my @cnt; + my $cnt; + for my $line (@$lines) + { + print $fh $line; + if (defined($Texi2HTML::Config::WORDS_IN_PAGE) and ($Texi2HTML::Config::SPLIT eq 'node')) + { + @cnt = split(/\W*\s+\W*/, $line); + $cnt += scalar(@cnt); + } + } + return $cnt; +} + +sub do_index_entry_label($$$) +{ + my $command = shift; + my $state = shift; + my $line_nr = shift; + return '' if ($state->{'multiple_pass'}); + my $entry = shift @index_labels; + if (!defined($entry)) + { + echo_warn ("Not enough index entries !", $line_nr); + return ''; + } + if ($command ne $entry->{'command'}) + { + # happens with bad texinfo with a line like + # @deffn func aaaa args @defvr c--ategory d--efvr_name + echo_warn ("Waiting for index cmd \@$entry->{'command'}, got \@$command", $line_nr); + } + + print STDERR "[(index $command) $entry->{'entry'} $entry->{'label'}]\n" + if ($T2H_DEBUG & $DEBUG_INDEX); + return &$Texi2HTML::Config::index_entry_label ($entry->{'label'}, $state->{'preformatted'}, substitute_line($entry->{'entry'}), + $index_prefix_to_name{$prefix}, + $command); +} + +# decompose a decimal number on a given base. The algorithm looks like +# the division with growing powers (division suivant les puissances +# croissantes) ? +sub decompose($$) +{ + my $number = shift; + my $base = shift; + my @result = (); + + return (0) if ($number == 0); + my $power = 1; + my $remaining = $number; + + while ($remaining) + { + my $factor = $remaining % ($base ** $power); + $remaining -= $factor; + push (@result, $factor / ($base ** ($power - 1))); + $power++; + } + return @result; +} + +# main processing is called here +set_document_language('en') unless ($lang_set); +# APA: There's got to be a better way: +$T2H_USER = &$I('unknown'); + +if ($Texi2HTML::Config::TEST) +{ + # to generate files similar to reference ones to be able to check for + # real changes we use these dummy values if -test is given + $T2H_USER = 'a tester'; + $THISPROG = 'texi2html'; + setlocale( LC_ALL, "C" ); +} +else +{ + # 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; +} + +open_file($docu, $texi_line_number); +#Texi2HTML::LaTeX2HTML::init() if ($Texi2HTML::Config::L2H); +if ($Texi2HTML::Config::L2H) +{ + push @Texi2HTML::Config::command_handler_init, \&Texi2HTML::LaTeX2HTML::init; + push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::latex2html; + push @Texi2HTML::Config::command_handler_finish, \&Texi2HTML::LaTeX2HTML::finish; + $Texi2HTML::Config::command_handler{'math'} = + { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex, + 'expand' => \&Texi2HTML::LaTeX2HTML::do_tex + }; + $Texi2HTML::Config::command_handler{'tex'} = + { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex, + 'expand' => \&Texi2HTML::LaTeX2HTML::do_tex + }; +} +foreach my $handler(@Texi2HTML::Config::command_handler_init) +{ + &$handler; +} + +my @css_import_lines; +my @css_rule_lines; + +# process css files +foreach my $file (@Texi2HTML::Config::CSS_FILES) +{ + my $css_file_fh; + my $css_file; + if ($file eq '-') + { + $css_file_fh = \*STDIN; + $css_file = '-'; + } + else + { + $css_file = locate_init_file ($file); + unless (defined($css_file)) + { + warn "css file $file not found\n"; + next; + } + unless (open (CSSFILE, "$css_file")) + { + warn "Cannot open ${css_file}: $!"; + next; + } + $css_file_fh = \*CSSFILE; + } + my ($import_lines, $rules_lines); + ($import_lines, $rules_lines) = process_css_file ($css_file_fh, $css_file); + push @css_import_lines, @$import_lines; + push @css_rule_lines, @$rules_lines; +} + +$Texi2HTML::THISDOC{'css_import_lines'} = \@css_import_lines; +$Texi2HTML::THISDOC{'css_lines'} = \@css_rule_lines; + +if ($T2H_DEBUG & $DEBUG_USER) +{ + if (@css_import_lines) + { + print STDERR "# css import lines\n"; + foreach my $line (@css_import_lines) + { + print STDERR "$line"; + } + } + if (@css_rule_lines) + { + print STDERR "# css rule lines\n"; + foreach my $line (@css_rule_lines) + { + print STDERR "$line"; + } + } +} + +pass_texi(); +dump_texi(\@lines, 'texi', \@lines_numbers) if ($T2H_DEBUG & $DEBUG_TEXI); +if (defined($Texi2HTML::Config::MACRO_EXPAND)) +{ + my @texi_lines = (@first_lines, @lines); + dump_texi(\@texi_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND); +} +pass_structure(); +if ($T2H_DEBUG & $DEBUG_TEXI) +{ + dump_texi(\@doc_lines, 'first', \@doc_numbers); + if (defined($Texi2HTML::Config::MACRO_EXPAND and $Texi2HTML::Config::DUMP_TEXI)) + { + unshift (@doc_lines, @first_lines); + push (@doc_lines, "\@bye\n"); + dump_texi(\@doc_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND . ".first"); + } +} +exit(0) if ($Texi2HTML::Config::DUMP_TEXI or defined($Texi2HTML::Config::MACRO_EXPAND)); + +foreach my $style (keys(%special_commands)) +{ + $special_commands{$style}->{'max'} = $special_commands{$style}->{'count'}; +} + +rearrange_elements(); +do_names(); + +#Texi2HTML::LaTeX2HTML::latex2html(); +foreach my $handler(@Texi2HTML::Config::command_handler_process) +{ + &$handler; +} + +if (@{$region_lines{'documentdescription'}} and (!defined($Texi2HTML::Config::DOCUMENT_DESCRIPTION))) +{ + my $documentdescription = remove_texi(@{$region_lines{'documentdescription'}}); + my @documentdescription = split (/\n/, $documentdescription); + $Texi2HTML::Config::DOCUMENT_DESCRIPTION = shift @documentdescription; + chomp $Texi2HTML::Config::DOCUMENT_DESCRIPTION; + foreach my $line (@documentdescription) + { + chomp $line; + $Texi2HTML::Config::DOCUMENT_DESCRIPTION .= ' ' . $line; + } +} +# do copyright notice inserted in comment at the beginning of the files +if (@{$region_lines{'copying'}}) +{ + $copying_comment = &$Texi2HTML::Config::copying_comment($region_lines{'copying'}); +} +&$Texi2HTML::Config::toc_body(\@elements_list); +$sec_num = 0; + + +&$Texi2HTML::Config::css_lines(\@css_import_lines, \@css_rule_lines); + +pass_text(); +print STDERR "BUG: " . scalar(@index_labels) . " index entries pending\n" + if (scalar(@index_labels)); +foreach my $special (keys(%special_commands)) +{ + my $count = $special_commands{$special}->{'count'}; + if (($count != 0) and $T2H_VERBOSE) + { + echo_warn ("$count special \@$special were not processed.\n"); + } +} +if ($Texi2HTML::Config::IDX_SUMMARY) +{ + foreach my $entry (keys(%index_names)) + { + do_index_summary_file($entry) unless ($empty_indices{$entry}); + } +} +do_node_files() if ($Texi2HTML::Config::NODE_FILES); +#l2h_FinishFromHtml() if ($Texi2HTML::Config::L2H); +#l2h_Finish() if($Texi2HTML::Config::L2H); +#Texi2HTML::LaTeX2HTML::finish(); +foreach my $handler(@Texi2HTML::Config::command_handler_finish) +{ + &$handler; +} +&$Texi2HTML::Config::finish_out(); +print STDERR "# that's all folks\n" if $T2H_VERBOSE; + +exit(0); + + +############################################################################## + +# 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 ${prefix}/man/man1/texi2html.1 diff --git a/build-aux/texinfo.tex b/build-aux/texinfo.tex new file mode 100644 index 00000000..bac07260 --- /dev/null +++ b/build-aux/texinfo.tex @@ -0,0 +1,8997 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{2008-04-18.10} +% +% Copyright (C) 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, +% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, +% 2007, 2008 Free Software Foundation, Inc. +% +% This texinfo.tex file 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 3 of the +% License, or (at your option) any later version. +% +% This texinfo.tex file 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, see <http://www.gnu.org/licenses/>. +% +% As a special exception, when this file is read by TeX when processing +% a Texinfo source document, you may use the result without +% restriction. (This has been our intent since Texinfo was invented.) +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% http://www.gnu.org/software/texinfo/ (the Texinfo home page), or +% ftp://tug.org/tex/texinfo.tex +% (and all CTAN mirrors, see http://www.ctan.org). +% The texinfo.tex in any given distribution could well be out +% of date, so if that's what you're using, please check. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever; this makes foo.ps. +% The extra TeX runs get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages, to some +% extent. You can get the existing language-specific files from the +% full Texinfo distribution. +% +% The GNU Texinfo home page is http://www.gnu.org/software/texinfo. + + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + + +\chardef\other=12 + +% We never want plain's \outer definition of \+ in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + +% Save some plain tex macros whose names we will redefine. +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexfootnote=\footnote +\let\ptexgtr=> +\let\ptexhat=^ +\let\ptexi=\i +\let\ptexindent=\indent +\let\ptexinsert=\insert +\let\ptexlbrace=\{ +\let\ptexless=< +\let\ptexnewwrite\newwrite +\let\ptexnoindent=\noindent +\let\ptexplus=+ +\let\ptexrbrace=\} +\let\ptexslash=\/ +\let\ptexstar=\* +\let\ptext=\t +\let\ptextop=\top + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Pre-3.0. +\else + \def\linenumber{l.\the\inputlineno:\space} +\fi + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordin\undefined \gdef\putwordin{in}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi + +% Since the category of space is not known, we have to be careful. +\chardef\spacecat = 10 +\def\spaceisspace{\catcode`\ =\spacecat} + +% sometimes characters are active, so we need control sequences. +\chardef\colonChar = `\: +\chardef\commaChar = `\, +\chardef\dashChar = `\- +\chardef\dotChar = `\. +\chardef\exclamChar= `\! +\chardef\lquoteChar= `\` +\chardef\questChar = `\? +\chardef\rquoteChar= `\' +\chardef\semiChar = `\; +\chardef\underChar = `\_ + +% Ignore a token. +% +\def\gobble#1{} + +% The following is used inside several \edef's. +\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} + +% Hyphenation fixes. +\hyphenation{ + Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script + ap-pen-dix bit-map bit-maps + data-base data-bases eshell fall-ing half-way long-est man-u-script + man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm + par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces + spell-ing spell-ings + stand-alone strong-est time-stamp time-stamps which-ever white-space + wide-spread wrap-around +} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen\bindingoffset +\newdimen\normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. We also make +% some effort to order the tracing commands to reduce output in the log +% file; cf. trace.sty in LaTeX. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{% + \tracingstats2 + \tracingpages1 + \tracinglostchars2 % 2 gives us more in etex + \tracingparagraphs1 + \tracingoutput1 + \tracingmacros2 + \tracingrestores1 + \showboxbreadth\maxdimen \showboxdepth\maxdimen + \ifx\eTeXversion\undefined\else % etex gives us more logging + \tracingscantokens1 + \tracingifs1 + \tracinggroups1 + \tracingnesting2 + \tracingassigns1 + \fi + \tracingcommands3 % 3 gives us more in etex + \errorcontextlines16 +}% + +% add check for \lastpenalty to plain's definitions. If the last thing +% we did was a \nobreak, we don't want to insert more space. +% +\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount + \removelastskip\penalty-50\smallskip\fi\fi} +\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount + \removelastskip\penalty-100\medskip\fi\fi} +\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount + \removelastskip\penalty-200\bigskip\fi\fi} + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Output a mark which sets \thischapter, \thissection and \thiscolor. +% We dump everything together because we only have one kind of mark. +% This works because we only use \botmark / \topmark, not \firstmark. +% +% A mark contains a subexpression of the \ifcase ... \fi construct. +% \get*marks macros below extract the needed part using \ifcase. +% +% Another complication is to let the user choose whether \thischapter +% (\thissection) refers to the chapter (section) in effect at the top +% of a page, or that at the bottom of a page. The solution is +% described on page 260 of The TeXbook. It involves outputting two +% marks for the sectioning macros, one before the section break, and +% one after. I won't pretend I can describe this better than DEK... +\def\domark{% + \toks0=\expandafter{\lastchapterdefs}% + \toks2=\expandafter{\lastsectiondefs}% + \toks4=\expandafter{\prevchapterdefs}% + \toks6=\expandafter{\prevsectiondefs}% + \toks8=\expandafter{\lastcolordefs}% + \mark{% + \the\toks0 \the\toks2 + \noexpand\or \the\toks4 \the\toks6 + \noexpand\else \the\toks8 + }% +} +% \topmark doesn't work for the very first chapter (after the title +% page or the contents), so we use \firstmark there -- this gets us +% the mark with the chapter defs, unless the user sneaks in, e.g., +% @setcolor (or @url, or @link, etc.) between @contents and the very +% first @chapter. +\def\gettopheadingmarks{% + \ifcase0\topmark\fi + \ifx\thischapter\empty \ifcase0\firstmark\fi \fi +} +\def\getbottomheadingmarks{\ifcase1\botmark\fi} +\def\getcolormarks{\ifcase2\topmark\fi} + +% Avoid "undefined control sequence" errors. +\def\lastchapterdefs{} +\def\lastsectiondefs{} +\def\prevchapterdefs{} +\def\prevsectiondefs{} +\def\lastcolordefs{} + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + % We don't want .vr (or whatever) entries like this: + % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} + % "\acronym" won't work when it's read back in; + % it needs to be + % {\code {{\tt \backslashcurfont }acronym} + \shipout\vbox{% + % Do this early so pdf references go to the beginning of the page. + \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi + % + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingyyy.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 24pt + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \indexdummies + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1\relax \unvbox#1\relax +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg{\parseargusing{}} +\def\parseargusing#1#2{% + \def\argtorun{#2}% + \begingroup + \obeylines + \spaceisspace + #1% + \parseargline\empty% Insert the \empty token, see \finishparsearg below. +} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + \argremovecomment #1\comment\ArgTerm% + }% +} + +% First remove any @comment, then any @c comment. +\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} +\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} + +% Each occurrence of `\^^M' or `<space>\^^M' is replaced by a single space. +% +% \argremovec might leave us with trailing space, e.g., +% @end itemize @c foo +% This space token undergoes the same procedure and is eventually removed +% by \finishparsearg. +% +\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} +\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} +\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% + \def\temp{#3}% + \ifx\temp\empty + % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: + \let\temp\finishparsearg + \else + \let\temp\argcheckspaces + \fi + % Put the space token in: + \temp#1 #3\ArgTerm +} + +% If a _delimited_ argument is enclosed in braces, they get stripped; so +% to get _exactly_ the rest of the line, we had to prevent such situation. +% We prepended an \empty token at the very beginning and we expand it now, +% just before passing the control to \argtorun. +% (Similarly, we have to think about #3 of \argcheckspacesY above: it is +% either the null string, or it ends with \^^M---thus there is no danger +% that a pair of braces would be stripped. +% +% But first, we have to remove the trailing space token. +% +\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} + +% \parseargdef\foo{...} +% is roughly equivalent to +% \def\foo{\parsearg\Xfoo} +% \def\Xfoo#1{...} +% +% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my +% favourite TeX trick. --kasal, 16nov03 + +\def\parseargdef#1{% + \expandafter \doparseargdef \csname\string#1\endcsname #1% +} +\def\doparseargdef#1#2{% + \def#2{\parsearg#1}% + \def#1##1% +} + +% Several utility definitions with active space: +{ + \obeyspaces + \gdef\obeyedspace{ } + + % Make each space character in the input produce a normal interword + % space in the output. Don't allow a line break at this space, as this + % is used only in environments like @example, where each line of input + % should produce a line of output anyway. + % + \gdef\sepspaces{\obeyspaces\let =\tie} + + % If an index command is used in an @example environment, any spaces + % therein should become regular spaces in the raw index file, not the + % expansion of \tie (\leavevmode \penalty \@M \ ). + \gdef\unsepspaces{\let =\space} +} + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +% Define the framework for environments in texinfo.tex. It's used like this: +% +% \envdef\foo{...} +% \def\Efoo{...} +% +% It's the responsibility of \envdef to insert \begingroup before the +% actual body; @end closes the group after calling \Efoo. \envdef also +% defines \thisenv, so the current environment is known; @end checks +% whether the environment name matches. The \checkenv macro can also be +% used to check whether the current environment is the one expected. +% +% Non-false conditionals (@iftex, @ifset) don't fit into this, so they +% are not treated as environments; they don't open a group. (The +% implementation of @end takes care not to call \endgroup in this +% special case.) + + +% At run-time, environments start with this: +\def\startenvironment#1{\begingroup\def\thisenv{#1}} +% initialize +\let\thisenv\empty + +% ... but they get defined via ``\envdef\foo{...}'': +\long\def\envdef#1#2{\def#1{\startenvironment#1#2}} +\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} + +% Check whether we're in the right environment: +\def\checkenv#1{% + \def\temp{#1}% + \ifx\thisenv\temp + \else + \badenverr + \fi +} + +% Environment mismatch, #1 expected: +\def\badenverr{% + \errhelp = \EMsimple + \errmessage{This command can appear only \inenvironment\temp, + not \inenvironment\thisenv}% +} +\def\inenvironment#1{% + \ifx#1\empty + out of any environment% + \else + in environment \expandafter\string#1% + \fi +} + +% @end foo executes the definition of \Efoo. +% But first, it executes a specialized version of \checkenv +% +\parseargdef\end{% + \if 1\csname iscond.#1\endcsname + \else + % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 + \expandafter\checkenv\csname#1\endcsname + \csname E#1\endcsname + \endgroup + \fi +} + +\newhelp\EMsimple{Press RETURN to continue.} + + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce \{ and \} commands for indices, + % and @{ and @} for the aux/toc files. + \catcode`\{ = \other \catcode`\} = \other + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\! = 0 \catcode`\\ = \other + !gdef!lbracecmd[\{]% + !gdef!rbracecmd[\}]% + !gdef!lbraceatcmd[@{]% + !gdef!rbraceatcmd[@}]% +!endgroup + +% @comma{} to avoid , parsing problems. +\let\comma = , + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown @ordf @ordm +% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} +\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} +\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi + \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% The \TeX{} logo, as in plain, but resetting the spacing so that a +% period following counts as ending a sentence. (Idea found in latex.) +% +\edef\TeX{\TeX \spacefactor=1000 } + +% @LaTeX{} logo. Not quite the same results as the definition in +% latex.ltx, since we use a different font for the raised A; it's most +% convenient for us to use an explicitly smaller font, rather than using +% the \scriptstyle font (since we don't reset \scriptstyle and +% \scriptscriptstyle). +% +\def\LaTeX{% + L\kern-.36em + {\setbox0=\hbox{T}% + \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% + \kern-.15em + \TeX +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @/ allows a line break. +\let\/=\allowbreak + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=\endofsentencespacefactor\space} + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=\endofsentencespacefactor\space} + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=\endofsentencespacefactor\space} + +% @frenchspacing on|off says whether to put extra space after punctuation. +% +\def\onword{on} +\def\offword{off} +% +\parseargdef\frenchspacing{% + \def\temp{#1}% + \ifx\temp\onword \plainfrenchspacing + \else\ifx\temp\offword \plainnonfrenchspacing + \else + \errhelp = \EMsimple + \errmessage{Unknown @frenchspacing option `\temp', must be on/off}% + \fi\fi +} + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +% Another complication is that the group might be very large. This can +% cause the glue on the previous page to be unduly stretched, because it +% does not have much material. In this case, it's better to add an +% explicit \vfill so that the extra space is at the bottom. The +% threshold for doing this is if the group is more than \vfilllimit +% percent of a page (\vfilllimit can be changed inside of @tex). +% +\newbox\groupbox +\def\vfilllimit{0.7} +% +\envdef\group{% + \ifnum\catcode`\^^M=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + \startsavinginserts + % + \setbox\groupbox = \vtop\bgroup + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% The \vtop produces a box with normal height and large depth; thus, TeX puts +% \baselineskip glue before it, and (when the next line of text is done) +% \lineskip glue after it. Thus, space below is not quite equal to space +% above. But it's pretty close. +\def\Egroup{% + % To get correct interline space between the last line of the group + % and the first line afterwards, we have to propagate \prevdepth. + \endgraf % Not \par, as it may have been set to \lisppar. + \global\dimen1 = \prevdepth + \egroup % End the \vtop. + % \dimen0 is the vertical size of the group's box. + \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox + % \dimen2 is how much space is left on the page (more or less). + \dimen2 = \pageheight \advance\dimen2 by -\pagetotal + % if the group doesn't fit on the current page, and it's a big big + % group, force a page break. + \ifdim \dimen0 > \dimen2 + \ifdim \pagetotal < \vfilllimit\pageheight + \page + \fi + \fi + \box\groupbox + \prevdepth = \dimen1 + \checkinserts +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +% Old definition--didn't work. +%\parseargdef\need{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\parseargdef\need{% + % Ensure vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % If the @need value is less than one line space, it's useless. + \dimen0 = #1\mil + \dimen2 = \ht\strutbox + \advance\dimen2 by \dp\strutbox + \ifdim\dimen0 > \dimen2 + % + % Do a \strut just to make the height of this box be normal, so the + % normal leading is inserted relative to the preceding line. + % And a page break here is fine. + \vtop to #1\mil{\strut\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak + \fi +} + +% @br forces paragraph break (and is undocumented). + +\let\br = \par + +% @page forces the start of a new page. +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} + +% This defn is used inside nofill environments such as @example. +\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount + \leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current +% paragraph. For more general purposes, use the \margin insertion +% class. WHICH is `l' or `r'. +% +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} +% +\def\doinmargin#1#2{\strut\vadjust{% + \nobreak + \kern-\strutdepth + \vtop to \strutdepth{% + \baselineskip=\strutdepth + \vss + % if you have multiple lines of stuff to put here, you'll need to + % make the vbox yourself of the appropriate size. + \ifx#1l% + \llap{\ignorespaces #2\hskip\inmarginspacing}% + \else + \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% + \fi + \null + }% +}} +\def\inleftmargin{\doinmargin l} +\def\inrightmargin{\doinmargin r} +% +% @inmargin{TEXT [, RIGHT-TEXT]} +% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; +% else use TEXT for both). +% +\def\inmargin#1{\parseinmargin #1,,\finish} +\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \def\lefttext{#1}% have both texts + \def\righttext{#2}% + \else + \def\lefttext{#1}% have only one text + \def\righttext{#1}% + \fi + % + \ifodd\pageno + \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin + \else + \def\temp{\inleftmargin\lefttext}% + \fi + \temp +} + +% @include FILE -- \input text of FILE. +% +\def\include{\parseargusing\filenamecatcodes\includezzz} +\def\includezzz#1{% + \pushthisfilestack + \def\thisfile{#1}% + {% + \makevalueexpandable % we want to expand any @value in FILE. + \turnoffactive % and allow special characters in the expansion + \edef\temp{\noexpand\input #1 }% + % + % This trickery is to read FILE outside of a group, in case it makes + % definitions, etc. + \expandafter + }\temp + \popthisfilestack +} +\def\filenamecatcodes{% + \catcode`\\=\other + \catcode`~=\other + \catcode`^=\other + \catcode`_=\other + \catcode`|=\other + \catcode`<=\other + \catcode`>=\other + \catcode`+=\other + \catcode`-=\other +} + +\def\pushthisfilestack{% + \expandafter\pushthisfilestackX\popthisfilestack\StackTerm +} +\def\pushthisfilestackX{% + \expandafter\pushthisfilestackY\thisfile\StackTerm +} +\def\pushthisfilestackY #1\StackTerm #2\StackTerm {% + \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% +} + +\def\popthisfilestack{\errthisfilestackempty} +\def\errthisfilestackempty{\errmessage{Internal error: + the stack of filenames is empty.}} + +\def\thisfile{} + +% @center line +% outputs that line, centered. +% +\parseargdef\center{% + \ifhmode + \let\next\centerH + \else + \let\next\centerV + \fi + \next{\hfil \ignorespaces#1\unskip \hfil}% +} +\def\centerH#1{% + {% + \hfil\break + \advance\hsize by -\leftskip + \advance\hsize by -\rightskip + \line{#1}% + \break + }% +} +\def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} + +% @sp n outputs n lines of vertical space + +\parseargdef\sp{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% NCHARS can also be the word `asis' or `none'. +% We cannot feasibly implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\parseargdef\paragraphindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @exampleindent NCHARS +% We'll use ems for NCHARS like @paragraphindent. +% It seems @exampleindent asis isn't necessary, but +% I preserve it to make it similar to @paragraphindent. +\parseargdef\exampleindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \lispnarrowing = 0pt + \else + \lispnarrowing = #1em + \fi + \fi +} + +% @firstparagraphindent WORD +% If WORD is `none', then suppress indentation of the first paragraph +% after a section heading. If WORD is `insert', then do indent at such +% paragraphs. +% +% The paragraph indentation is suppressed or not by calling +% \suppressfirstparagraphindent, which the sectioning commands do. +% We switch the definition of this back and forth according to WORD. +% By default, we suppress indentation. +% +\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} +\def\insertword{insert} +% +\parseargdef\firstparagraphindent{% + \def\temp{#1}% + \ifx\temp\noneword + \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent + \else\ifx\temp\insertword + \let\suppressfirstparagraphindent = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @firstparagraphindent option `\temp'}% + \fi\fi +} + +% Here is how we actually suppress indentation. Redefine \everypar to +% \kern backwards by \parindent, and then reset itself to empty. +% +% We also make \indent itself not actually do anything until the next +% paragraph. +% +\gdef\dosuppressfirstparagraphindent{% + \gdef\indent{% + \restorefirstparagraphindent + \indent + }% + \gdef\noindent{% + \restorefirstparagraphindent + \noindent + }% + \global\everypar = {% + \kern -\parindent + \restorefirstparagraphindent + }% +} + +\gdef\restorefirstparagraphindent{% + \global \let \indent = \ptexindent + \global \let \noindent = \ptexnoindent + \global \everypar = {}% +} + + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math outputs its argument in math mode. +% +% One complication: _ usually means subscripts, but it could also mean +% an actual _ character, as in @math{@var{some_variable} + 1}. So make +% _ active, and distinguish by seeing if the current family is \slfam, +% which is what @var uses. +{ + \catcode`\_ = \active + \gdef\mathunderscore{% + \catcode`\_=\active + \def_{\ifnum\fam=\slfam \_\else\sb\fi}% + } +} +% Another complication: we want \\ (and @\) to output a \ character. +% FYI, plain.tex uses \\ as a temporary control sequence (why?), but +% this is not advertised and we don't care. Texinfo does not +% otherwise define @\. +% +% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. +\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} +% +\def\math{% + \tex + \mathunderscore + \let\\ = \mathbackslash + \mathactive + % make the texinfo accent commands work in math mode + \let\"=\ddot + \let\'=\acute + \let\==\bar + \let\^=\hat + \let\`=\grave + \let\u=\breve + \let\v=\check + \let\~=\tilde + \let\dotaccent=\dot + $\finishmath +} +\def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. + +% Some active characters (such as <) are spaced differently in math. +% We have to reset their definitions in case the @math was an argument +% to a command which sets the catcodes (such as @item or @section). +% +{ + \catcode`^ = \active + \catcode`< = \active + \catcode`> = \active + \catcode`+ = \active + \gdef\mathactive{% + \let^ = \ptexhat + \let< = \ptexless + \let> = \ptexgtr + \let+ = \ptexplus + } +} + +% Some math mode symbols. +\def\bullet{$\ptexbullet$} +\def\geq{\ifmmode \ge\else $\ge$\fi} +\def\leq{\ifmmode \le\else $\le$\fi} +\def\minus{\ifmmode -\else $-$\fi} + +% @dots{} outputs an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in the cm +% typewriter fonts as three actual period characters; on the other hand, +% in other typewriter fonts three periods are wider than 1.5em. So do +% whichever is larger. +% +\def\dots{% + \leavevmode + \setbox0=\hbox{...}% get width of three periods + \ifdim\wd0 > 1.5em + \dimen0 = \wd0 + \else + \dimen0 = 1.5em + \fi + \hbox to \dimen0{% + \hskip 0pt plus.25fil + .\hskip 0pt plus1fil + .\hskip 0pt plus1fil + .\hskip 0pt plus.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \dots + \spacefactor=\endofsentencespacefactor +} + +% @comma{} is so commas can be inserted into text without messing up +% Texinfo's parsing. +% +\let\comma = , + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \iflinks + \tryauxfile + % Open the new aux file. TeX will close it automatically at exit. + \immediate\openout\auxfile=\jobname.aux + \fi % \openindices needs to do some work in any case. + \openindices + \let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + \openin 1 texinfo.cnf + \ifeof 1 \else \input texinfo.cnf \fi + \closein 1 + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{pdf,} +% adobe `portable' document format +\newcount\tempnum +\newcount\lnkcount +\newtoks\filename +\newcount\filenamelength +\newcount\pgn +\newtoks\toksA +\newtoks\toksB +\newtoks\toksC +\newtoks\toksD +\newbox\boxA +\newcount\countA +\newif\ifpdf +\newif\ifpdfmakepagedest + +% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 +% can be set). So we test for \relax and 0 as well as \undefined, +% borrowed from ifpdf.sty. +\ifx\pdfoutput\undefined +\else + \ifx\pdfoutput\relax + \else + \ifcase\pdfoutput + \else + \pdftrue + \fi + \fi +\fi + +% PDF uses PostScript string constants for the names of xref targets, +% for display in the outlines, and in other places. Thus, we have to +% double any backslashes. Otherwise, a name like "\node" will be +% interpreted as a newline (\n), followed by o, d, e. Not good. +% http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html +% (and related messages, the final outcome is that it is up to the TeX +% user to double the backslashes and otherwise make the string valid, so +% that's what we do). + +% double active backslashes. +% +{\catcode`\@=0 \catcode`\\=\active + @gdef@activebackslashdouble{% + @catcode`@\=@active + @let\=@doublebackslash} +} + +% To handle parens, we must adopt a different approach, since parens are +% not active characters. hyperref.dtx (which has the same problem as +% us) handles it with this amazing macro to replace tokens, with minor +% changes for Texinfo. It is included here under the GPL by permission +% from the author, Heiko Oberdiek. +% +% #1 is the tokens to replace. +% #2 is the replacement. +% #3 is the control sequence with the string. +% +\def\HyPsdSubst#1#2#3{% + \def\HyPsdReplace##1#1##2\END{% + ##1% + \ifx\\##2\\% + \else + #2% + \HyReturnAfterFi{% + \HyPsdReplace##2\END + }% + \fi + }% + \xdef#3{\expandafter\HyPsdReplace#3#1\END}% +} +\long\def\HyReturnAfterFi#1\fi{\fi#1} + +% #1 is a control sequence in which to do the replacements. +\def\backslashparens#1{% + \xdef#1{#1}% redefine it as its expansion; the definition is simply + % \lastnode when called from \setref -> \pdfmkdest. + \HyPsdSubst{(}{\realbackslash(}{#1}% + \HyPsdSubst{)}{\realbackslash)}{#1}% +} + +\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images +with PDF output, and none of those formats could be found. (.eps cannot +be supported due to the design of the PDF format; use regular TeX (DVI +output) for that.)} + +\ifpdf + % + % Color manipulation macros based on pdfcolor.tex. + \def\cmykDarkRed{0.28 1 1 0.35} + \def\cmykBlack{0 0 0 1} + % + \def\pdfsetcolor#1{\pdfliteral{#1 k}} + % Set color, and create a mark which defines \thiscolor accordingly, + % so that \makeheadline knows which color to restore. + \def\setcolor#1{% + \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% + \domark + \pdfsetcolor{#1}% + } + % + \def\maincolor{\cmykBlack} + \pdfsetcolor{\maincolor} + \edef\thiscolor{\maincolor} + \def\lastcolordefs{} + % + \def\makefootline{% + \baselineskip24pt + \line{\pdfsetcolor{\maincolor}\the\footline}% + } + % + \def\makeheadline{% + \vbox to 0pt{% + \vskip-22.5pt + \line{% + \vbox to8.5pt{}% + % Extract \thiscolor definition from the marks. + \getcolormarks + % Typeset the headline with \maincolor, then restore the color. + \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% + }% + \vss + }% + \nointerlineskip + } + % + % + \pdfcatalog{/PageMode /UseOutlines} + % + % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). + \def\dopdfimage#1#2#3{% + \def\imagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% + \def\imageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% + % + % pdftex (and the PDF format) support .png, .jpg, .pdf (among + % others). Let's try in that order. + \let\pdfimgext=\empty + \begingroup + \openin 1 #1.png \ifeof 1 + \openin 1 #1.jpg \ifeof 1 + \openin 1 #1.jpeg \ifeof 1 + \openin 1 #1.JPG \ifeof 1 + \openin 1 #1.pdf \ifeof 1 + \openin 1 #1.PDF \ifeof 1 + \errhelp = \nopdfimagehelp + \errmessage{Could not find image file #1 for pdf}% + \else \gdef\pdfimgext{PDF}% + \fi + \else \gdef\pdfimgext{pdf}% + \fi + \else \gdef\pdfimgext{JPG}% + \fi + \else \gdef\pdfimgext{jpeg}% + \fi + \else \gdef\pdfimgext{jpg}% + \fi + \else \gdef\pdfimgext{png}% + \fi + \closein 1 + \endgroup + % + % without \immediate, ancient pdftex seg faults when the same image is + % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) + \ifnum\pdftexversion < 14 + \immediate\pdfimage + \else + \immediate\pdfximage + \fi + \ifdim \wd0 >0pt width \imagewidth \fi + \ifdim \wd2 >0pt height \imageheight \fi + \ifnum\pdftexversion<13 + #1.\pdfimgext + \else + {#1.\pdfimgext}% + \fi + \ifnum\pdftexversion < 14 \else + \pdfrefximage \pdflastximage + \fi} + % + \def\pdfmkdest#1{{% + % We have to set dummies so commands such as @code, and characters + % such as \, aren't expanded when present in a section title. + \indexnofonts + \turnoffactive + \activebackslashdouble + \makevalueexpandable + \def\pdfdestname{#1}% + \backslashparens\pdfdestname + \safewhatsit{\pdfdest name{\pdfdestname} xyz}% + }} + % + % used to mark target names; must be expandable. + \def\pdfmkpgn#1{#1} + % + % by default, use a color that is dark enough to print on paper as + % nearly black, but still distinguishable for online viewing. + \def\urlcolor{\cmykDarkRed} + \def\linkcolor{\cmykDarkRed} + \def\endlink{\setcolor{\maincolor}\pdfendlink} + % + % Adding outlines to PDF; macros for calculating structure of outlines + % come from Petr Olsak + \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} + \def\advancenumber#1{\tempnum=\expnumber{#1}\relax + \advance\tempnum by 1 + \expandafter\xdef\csname#1\endcsname{\the\tempnum}} + % + % #1 is the section text, which is what will be displayed in the + % outline by the pdf viewer. #2 is the pdf expression for the number + % of subentries (or empty, for subsubsections). #3 is the node text, + % which might be empty if this toc entry had no corresponding node. + % #4 is the page number + % + \def\dopdfoutline#1#2#3#4{% + % Generate a link to the node text if that exists; else, use the + % page number. We could generate a destination for the section + % text in the case where a section has no node, but it doesn't + % seem worth the trouble, since most documents are normally structured. + \def\pdfoutlinedest{#3}% + \ifx\pdfoutlinedest\empty + \def\pdfoutlinedest{#4}% + \else + % Doubled backslashes in the name. + {\activebackslashdouble \xdef\pdfoutlinedest{#3}% + \backslashparens\pdfoutlinedest}% + \fi + % + % Also double the backslashes in the display string. + {\activebackslashdouble \xdef\pdfoutlinetext{#1}% + \backslashparens\pdfoutlinetext}% + % + \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% + } + % + \def\pdfmakeoutlines{% + \begingroup + % Thanh's hack / proper braces in bookmarks + \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace + \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace + % + % Read toc silently, to get counts of subentries for \pdfoutline. + \def\numchapentry##1##2##3##4{% + \def\thischapnum{##2}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + }% + \def\numsecentry##1##2##3##4{% + \advancenumber{chap\thischapnum}% + \def\thissecnum{##2}% + \def\thissubsecnum{0}% + }% + \def\numsubsecentry##1##2##3##4{% + \advancenumber{sec\thissecnum}% + \def\thissubsecnum{##2}% + }% + \def\numsubsubsecentry##1##2##3##4{% + \advancenumber{subsec\thissubsecnum}% + }% + \def\thischapnum{0}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + % + % use \def rather than \let here because we redefine \chapentry et + % al. a second time, below. + \def\appentry{\numchapentry}% + \def\appsecentry{\numsecentry}% + \def\appsubsecentry{\numsubsecentry}% + \def\appsubsubsecentry{\numsubsubsecentry}% + \def\unnchapentry{\numchapentry}% + \def\unnsecentry{\numsecentry}% + \def\unnsubsecentry{\numsubsecentry}% + \def\unnsubsubsecentry{\numsubsubsecentry}% + \readdatafile{toc}% + % + % Read toc second time, this time actually producing the outlines. + % The `-' means take the \expnumber as the absolute number of + % subentries, which we calculated on our first read of the .toc above. + % + % We use the node names as the destinations. + \def\numchapentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% + \def\numsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% + \def\numsubsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% + \def\numsubsubsecentry##1##2##3##4{% count is always zero + \dopdfoutline{##1}{}{##3}{##4}}% + % + % PDF outlines are displayed using system fonts, instead of + % document fonts. Therefore we cannot use special characters, + % since the encoding is unknown. For example, the eogonek from + % Latin 2 (0xea) gets translated to a | character. Info from + % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. + % + % xx to do this right, we have to translate 8-bit characters to + % their "best" equivalent, based on the @documentencoding. Right + % now, I guess we'll just let the pdf reader have its way. + \indexnofonts + \setupdatafile + \catcode`\\=\active \otherbackslash + \input \tocreadfilename + \endgroup + } + % + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \ifx\p\space\else\addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \fi + \nextsp} + \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} + \ifnum\pdftexversion < 14 + \let \startlink \pdfannotlink + \else + \let \startlink \pdfstartlink + \fi + % make a live url in pdf output. + \def\pdfurl#1{% + \begingroup + % it seems we really need yet another set of dummies; have not + % tried to figure out what each command should do in the context + % of @url. for now, just make @/ a no-op, that's the only one + % people have actually reported a problem with. + % + \normalturnoffactive + \def\@{@}% + \let\/=\empty + \makevalueexpandable + \leavevmode\setcolor{\urlcolor}% + \startlink attr{/Border [0 0 0]}% + user{/Subtype /Link /A << /S /URI /URI (#1) >>}% + \endgroup} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS|\relax + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} + \setcolor{\linkcolor}#1\endlink} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\else + \let\pdfmkdest = \gobble + \let\pdfurl = \gobble + \let\endlink = \relax + \let\setcolor = \gobble + \let\pdfsetcolor = \gobble + \let\pdfmakeoutlines = \relax +\fi % \ifx\pdfoutput + + +\message{fonts,} + +% Change the current font style to #1, remembering it in \curfontstyle. +% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in +% italics, not bold italics. +% +\def\setfontstyle#1{% + \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. + \csname ten#1\endcsname % change the current font +} + +% Select #1 fonts with the current style. +% +\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} + +\def\rm{\fam=0 \setfontstyle{rm}} +\def\it{\fam=\itfam \setfontstyle{it}} +\def\sl{\fam=\slfam \setfontstyle{sl}} +\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} +\def\tt{\fam=\ttfam \setfontstyle{tt}} + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf. +\newfam\sffam +\def\sf{\fam=\sffam \setfontstyle{sf}} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this font style. +\def\ttsl{\setfontstyle{ttsl}} + + +% Default leading. +\newdimen\textleading \textleading = 13.2pt + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +% can get a sort of poor man's double spacing by redefining this. +\def\baselinefactor{1} +% +\def\setleading#1{% + \dimen0 = #1\relax + \normalbaselineskip = \baselinefactor\dimen0 + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% PDF CMaps. See also LaTeX's t1.cmap. +% +% do nothing with this by default. +\expandafter\let\csname cmapOT1\endcsname\gobble +\expandafter\let\csname cmapOT1IT\endcsname\gobble +\expandafter\let\csname cmapOT1TT\endcsname\gobble + +% if we are producing pdf, and we have \pdffontattr, then define cmaps. +% (\pdffontattr was introduced many years ago, but people still run +% older pdftex's; it's easy to conditionalize, so we do.) +\ifpdf \ifx\pdffontattr\undefined \else + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1-0) +%%Title: (TeX-OT1-0 TeX OT1 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1) +/Supplement 0 +>> def +/CMapName /TeX-OT1-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<23> <26> <0023> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +40 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1IT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1IT-0) +%%Title: (TeX-OT1IT-0 TeX OT1IT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1IT) +/Supplement 0 +>> def +/CMapName /TeX-OT1IT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<25> <26> <0025> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +42 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<23> <0023> +<24> <00A3> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1IT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1TT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1TT-0) +%%Title: (TeX-OT1TT-0 TeX OT1TT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1TT) +/Supplement 0 +>> def +/CMapName /TeX-OT1TT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +5 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<21> <26> <0021> +<28> <5F> <0028> +<61> <7E> <0061> +endbfrange +32 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <2191> +<0C> <2193> +<0D> <0027> +<0E> <00A1> +<0F> <00BF> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<20> <2423> +<27> <2019> +<60> <2018> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1TT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +\fi\fi + + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor, #5 is the CMap +% encoding (currently only OT1, OT1IT and OT1TT are allowed, pass +% empty to omit). +\def\setfont#1#2#3#4#5{% + \font#1=\fontprefix#2#3 scaled #4 + \csname cmap#5\endcsname#1% +} +% This is what gets called when #5 of \setfont is empty. +\let\cmap\gobble +% emacs-page end of cmaps + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +% Definitions for a main text size of 11pt. This is the default in +% Texinfo. +% +\def\definetextfontsizexi{% +% Text fonts (11.2pt, magstep1). +\def\textnominalsize{11pt} +\edef\mainmagstep{\magstephalf} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep +\def\textecsize{1095} + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstep1}{OT1} +\setfont\deftt\ttshape{10}{\magstep1}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 +\def\smallecsize{0900} + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 +\def\smallerecsize{0800} + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} +\def\authortt{\sectt} +\def\titleecsize{2074} + +% Chapter (and unnumbered) fonts (17.28pt). +\def\chapnominalsize{17pt} +\setfont\chaprm\rmbshape{12}{\magstep2}{OT1} +\setfont\chapit\itbshape{10}{\magstep3}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep3}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} +\setfont\chapsf\sfbshape{17}{1000}{OT1} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3}{OT1} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 +\def\chapecsize{1728} + +% Section fonts (14.4pt). +\def\secnominalsize{14pt} +\setfont\secrm\rmbshape{12}{\magstep1}{OT1} +\setfont\secit\itbshape{10}{\magstep2}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep2}{OT1} +\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\secsf\sfbshape{12}{\magstep1}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2}{OT1} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 +\def\sececsize{1440} + +% Subsection fonts (13.15pt). +\def\ssecnominalsize{13pt} +\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} +\setfont\ssecit\itbshape{10}{1315}{OT1IT} +\setfont\ssecsl\slbshape{10}{1315}{OT1} +\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} +\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1315}{OT1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +\def\ssececsize{1200} + +% Reduced fonts for @acro in text (10pt). +\def\reducednominalsize{10pt} +\setfont\reducedrm\rmshape{10}{1000}{OT1} +\setfont\reducedtt\ttshape{10}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{1000}{OT1} +\setfont\reducedit\itshape{10}{1000}{OT1IT} +\setfont\reducedsl\slshape{10}{1000}{OT1} +\setfont\reducedsf\sfshape{10}{1000}{OT1} +\setfont\reducedsc\scshape{10}{1000}{OT1} +\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} +\font\reducedi=cmmi10 +\font\reducedsy=cmsy10 +\def\reducedecsize{1000} + +% reset the current fonts +\textfonts +\rm +} % end of 11pt text font size definitions + + +% Definitions to make the main text be 10pt Computer Modern, with +% section, chapter, etc., sizes following suit. This is for the GNU +% Press printing of the Emacs 22 manual. Maybe other manuals in the +% future. Used with @smallbook, which sets the leading to 12pt. +% +\def\definetextfontsizex{% +% Text fonts (10pt). +\def\textnominalsize{10pt} +\edef\mainmagstep{1000} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep +\def\textecsize{1000} + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstephalf}{OT1} +\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 +\def\smallecsize{0900} + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 +\def\smallerecsize{0800} + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} +\def\authortt{\sectt} +\def\titleecsize{2074} + +% Chapter fonts (14.4pt). +\def\chapnominalsize{14pt} +\setfont\chaprm\rmbshape{12}{\magstep1}{OT1} +\setfont\chapit\itbshape{10}{\magstep2}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep2}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\chapsf\sfbshape{12}{\magstep1}{OT1} +\let\chapbf\chaprm +\setfont\chapsc\scbshape{10}{\magstep2}{OT1} +\font\chapi=cmmi12 scaled \magstep1 +\font\chapsy=cmsy10 scaled \magstep2 +\def\chapecsize{1440} + +% Section fonts (12pt). +\def\secnominalsize{12pt} +\setfont\secrm\rmbshape{12}{1000}{OT1} +\setfont\secit\itbshape{10}{\magstep1}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep1}{OT1} +\setfont\sectt\ttbshape{12}{1000}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} +\setfont\secsf\sfbshape{12}{1000}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep1}{OT1} +\font\seci=cmmi12 +\font\secsy=cmsy10 scaled \magstep1 +\def\sececsize{1200} + +% Subsection fonts (10pt). +\def\ssecnominalsize{10pt} +\setfont\ssecrm\rmbshape{10}{1000}{OT1} +\setfont\ssecit\itbshape{10}{1000}{OT1IT} +\setfont\ssecsl\slbshape{10}{1000}{OT1} +\setfont\ssectt\ttbshape{10}{1000}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} +\setfont\ssecsf\sfbshape{10}{1000}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1000}{OT1} +\font\sseci=cmmi10 +\font\ssecsy=cmsy10 +\def\ssececsize{1000} + +% Reduced fonts for @acro in text (9pt). +\def\reducednominalsize{9pt} +\setfont\reducedrm\rmshape{9}{1000}{OT1} +\setfont\reducedtt\ttshape{9}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{900}{OT1} +\setfont\reducedit\itshape{9}{1000}{OT1IT} +\setfont\reducedsl\slshape{9}{1000}{OT1} +\setfont\reducedsf\sfshape{9}{1000}{OT1} +\setfont\reducedsc\scshape{10}{900}{OT1} +\setfont\reducedttsl\ttslshape{10}{900}{OT1TT} +\font\reducedi=cmmi9 +\font\reducedsy=cmsy9 +\def\reducedecsize{0900} + +% reduce space between paragraphs +\divide\parskip by 2 + +% reset the current fonts +\textfonts +\rm +} % end of 10pt text font size definitions + + +% We provide the user-level command +% @fonttextsize 10 +% (or 11) to redefine the text font size. pt is assumed. +% +\def\xword{10} +\def\xiword{11} +% +\parseargdef\fonttextsize{% + \def\textsizearg{#1}% + \wlog{doing @fonttextsize \textsizearg}% + % + % Set \globaldefs so that documents can use this inside @tex, since + % makeinfo 4.8 does not support it, but we need it nonetheless. + % + \begingroup \globaldefs=1 + \ifx\textsizearg\xword \definetextfontsizex + \else \ifx\textsizearg\xiword \definetextfontsizexi + \else + \errhelp=\EMsimple + \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} + \fi\fi + \endgroup +} + + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts except +% in the main text, we don't bother to reset \scriptfont and +% \scriptscriptfont (which would also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy + \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf + \textfont\ttfam=\tentt \textfont\sffam=\tensf +} + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this because \STYLE needs to also set the +% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire +% \tenSTYLE to set the current font. +% +% Each font-changing command also sets the names \lsize (one size lower) +% and \lllsize (three sizes lower). These relative commands are used in +% the LaTeX logo and acronyms. +% +% This all needs generalizing, badly. +% +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy + \let\tenttsl=\textttsl + \def\curfontsize{text}% + \def\lsize{reduced}\def\lllsize{smaller}% + \resetmathfonts \setleading{\textleading}} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \def\curfontsize{title}% + \def\lsize{chap}\def\lllsize{subsec}% + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \let\tenttsl=\chapttsl + \def\curfontsize{chap}% + \def\lsize{sec}\def\lllsize{text}% + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \let\tenttsl=\secttsl + \def\curfontsize{sec}% + \def\lsize{subsec}\def\lllsize{reduced}% + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \let\tenttsl=\ssecttsl + \def\curfontsize{ssec}% + \def\lsize{text}\def\lllsize{small}% + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts +\def\reducedfonts{% + \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl + \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc + \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy + \let\tenttsl=\reducedttsl + \def\curfontsize{reduced}% + \def\lsize{small}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallfonts{% + \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl + \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc + \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy + \let\tenttsl=\smallttsl + \def\curfontsize{small}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallerfonts{% + \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl + \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc + \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy + \let\tenttsl=\smallerttsl + \def\curfontsize{smaller}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{9.5pt}} + +% Set the fonts to use with the @small... environments. +\let\smallexamplefonts = \smallfonts + +% About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample +% can fit this many characters: +% 8.5x11=86 smallbook=72 a4=90 a5=69 +% If we use \scriptfonts (8pt), then we can fit this many characters: +% 8.5x11=90+ smallbook=80 a4=90+ a5=77 +% For me, subjectively, the few extra characters that fit aren't worth +% the additional smallness of 8pt. So I'm making the default 9pt. +% +% By the way, for comparison, here's what fits with @example (10pt): +% 8.5x11=71 smallbook=60 a4=75 a5=58 +% +% I wish the USA used A4 paper. +% --karl, 24jan03. + + +% Set up the default fonts, so we can use them for creating boxes. +% +\definetextfontsizexi + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000}{OT1} +\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 +\setfont\shortcontsl\slshape{12}{1000}{OT1} +\setfont\shortconttt\ttshape{12}{1000}{OT1TT} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else + \ptexslash\fi\fi\fi} +\def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} + +% like \smartslanted except unconditionally uses \ttsl. +% @var is set to this for defun arguments. +\def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} + +% like \smartslanted except unconditionally use \sl. We never want +% ttsl for book titles, do we? +\def\cite#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\slanted=\smartslanted +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic + +% @b, explicit bold. +\def\b#1{{\bf #1}} +\let\strong=\b + +% @sansserif, explicit sans. +\def\sansserif#1{{\sf #1}} + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +% Set sfcode to normal for the chars that usually have another value. +% Can't use plain's \frenchspacing because it uses the `\x notation, and +% sometimes \x has an active definition that messes things up. +% +\catcode`@=11 + \def\plainfrenchspacing{% + \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m + \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m + \def\endofsentencespacefactor{1000}% for @. and friends + } + \def\plainnonfrenchspacing{% + \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 + \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 + \def\endofsentencespacefactor{3000}% for @. and friends + } +\catcode`@=\other +\def\endofsentencespacefactor{3000}% default + +\def\t#1{% + {\tt \rawbackslash \plainfrenchspacing #1}% + \null +} +\def\samp#1{`\tclose{#1}'\null} +\setfont\keyrm\rmshape{8}{1000}{OT1} +\font\keysy=cmsy9 +\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +\def\key #1{{\nohyphenation \uppercase{#1}}\null} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \plainfrenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in @code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active \catcode`\_=\active + \catcode`\'=\active \catcode`\`=\active + % + \global\def\code{\begingroup + \catcode\rquoteChar=\active \catcode\lquoteChar=\active + \let'\codequoteright \let`\codequoteleft + % + \catcode\dashChar=\active \catcode\underChar=\active + \ifallowcodebreaks + \let-\codedash + \let_\codeunder + \else + \let-\realdash + \let_\realunder + \fi + \codex + } +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{% + % this is all so @math{@code{var_name}+1} can work. In math mode, _ + % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) + % will therefore expand the active definition of _, which is us + % (inside @code that is), therefore an endless loop. + \ifusingtt{\ifmmode + \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. + \else\normalunderscore \fi + \discretionary{}{}{}}% + {\_}% +} +\def\codex #1{\tclose{#1}\endgroup} + +% An additional complication: the above will allow breaks after, e.g., +% each of the four underscores in __typeof__. This is undesirable in +% some manuals, especially if they don't have long identifiers in +% general. @allowcodebreaks provides a way to control this. +% +\newif\ifallowcodebreaks \allowcodebreakstrue + +\def\keywordtrue{true} +\def\keywordfalse{false} + +\parseargdef\allowcodebreaks{% + \def\txiarg{#1}% + \ifx\txiarg\keywordtrue + \allowcodebreakstrue + \else\ifx\txiarg\keywordfalse + \allowcodebreaksfalse + \else + \errhelp = \EMsimple + \errmessage{Unknown @allowcodebreaks option `\txiarg'}% + \fi\fi +} + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\parseargdef\kbdinputstyle{% + \def\txiarg{#1}% + \ifx\txiarg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\txiarg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\txiarg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \else + \errhelp = \EMsimple + \errmessage{Unknown @kbdinputstyle option `\txiarg'}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is `distinct.' +\kbdinputstyle distinct + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @indicateurl, @env, @command quotes seem unnecessary, so use \code. +\let\indicateurl=\code +\let\env=\code +\let\command=\code + +% @clicksequence{File @click{} Open ...} +\def\clicksequence#1{\begingroup #1\endgroup} + +% @clickstyle @arrow (by default) +\parseargdef\clickstyle{\def\click{#1}} +\def\click{\arrow} + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{\begingroup + \unsepspaces + \pdfurl{#1}% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \ifpdf + \unhbox0 % PDF: 2nd arg given, show only it + \else + \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url + \fi + \else + \code{#1}% only url given, so show it + \fi + \fi + \endlink +\endgroup} + +% @url synonym for @uref, since that's how everyone uses it. +% +\let\url=\uref + +% rms does not like angle brackets --karl, 17may97. +% So now @email is just like @uref, unless we are pdf. +% +%\def\email#1{\angleleft{\tt #1}\angleright} +\ifpdf + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{\begingroup + \unsepspaces + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + \endgroup} +\else + \let\email=\uref +\fi + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym for "FBI", "NATO", and the like. +% We print this one point size smaller, since it's intended for +% all-uppercase. +% +\def\acronym#1{\doacronym #1,,\finish} +\def\doacronym#1,#2,#3\finish{% + {\selectfonts\lsize #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + +% @abbr for "Comput. J." and the like. +% No font change, but don't do end-of-sentence spacing. +% +\def\abbr#1{\doabbr #1,,\finish} +\def\doabbr#1,#2,#3\finish{% + {\plainfrenchspacing #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + +% @pounds{} is a sterling sign, which Knuth put in the CM italic font. +% +\def\pounds{{\it\$}} + +% @euro{} comes from a separate font, depending on the current style. +% We use the free feym* fonts from the eurosym package by Henrik +% Theiling, which support regular, slanted, bold and bold slanted (and +% "outlined" (blackboard board, sort of) versions, which we don't need). +% It is available from http://www.ctan.org/tex-archive/fonts/eurosym. +% +% Although only regular is the truly official Euro symbol, we ignore +% that. The Euro is designed to be slightly taller than the regular +% font height. +% +% feymr - regular +% feymo - slanted +% feybr - bold +% feybo - bold slanted +% +% There is no good (free) typewriter version, to my knowledge. +% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. +% Hmm. +% +% Also doesn't work in math. Do we need to do math with euro symbols? +% Hope not. +% +% +\def\euro{{\eurofont e}} +\def\eurofont{% + % We set the font at each command, rather than predefining it in + % \textfonts and the other font-switching commands, so that + % installations which never need the symbol don't have to have the + % font installed. + % + % There is only one designed size (nominal 10pt), so we always scale + % that to the current nominal size. + % + % By the way, simply using "at 1em" works for cmr10 and the like, but + % does not work for cmbx10 and other extended/shrunken fonts. + % + \def\eurosize{\csname\curfontsize nominalsize\endcsname}% + % + \ifx\curfontstyle\bfstylename + % bold: + \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize + \else + % regular: + \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize + \fi + \thiseurofont +} + +% Hacks for glyphs from the EC fonts similar to \euro. We don't +% use \let for the aliases, because sometimes we redefine the original +% macro, and the alias should reflect the redefinition. +\def\guillemetleft{{\ecfont \char"13}} +\def\guillemotleft{\guillemetleft} +\def\guillemetright{{\ecfont \char"14}} +\def\guillemotright{\guillemetright} +\def\guilsinglleft{{\ecfont \char"0E}} +\def\guilsinglright{{\ecfont \char"0F}} +\def\quotedblbase{{\ecfont \char"12}} +\def\quotesinglbase{{\ecfont \char"0D}} +% +\def\ecfont{% + % We can't distinguish serif/sanserif and italic/slanted, but this + % is used for crude hacks anyway (like adding French and German + % quotes to documents typeset with CM, where we lose kerning), so + % hopefully nobody will notice/care. + \edef\ecsize{\csname\curfontsize ecsize\endcsname}% + \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% + \ifx\curfontstyle\bfstylename + % bold: + \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize + \else + % regular: + \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize + \fi + \thisecfont +} + +% @registeredsymbol - R in a circle. The font for the R should really +% be smaller yet, but lllsize is the best we can do for now. +% Adapted from the plain.tex definition of \copyright. +% +\def\registeredsymbol{% + $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% + \hfil\crcr\Orb}}% + }$% +} + +% @textdegree - the normal degrees sign. +% +\def\textdegree{$^\circ$} + +% Laurent Siebenmann reports \Orb undefined with: +% Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 +% so we'll define it if necessary. +% +\ifx\Orb\undefined +\def\Orb{\mathhexbox20D} +\fi + +% Quotes. +\chardef\quotedblleft="5C +\chardef\quotedblright=`\" +\chardef\quoteleft=`\` +\chardef\quoteright=`\' + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\envdef\titlepage{% + % Open one extra group, as we want to close it in the middle of \Etitlepage. + \begingroup + \parindent=0pt \textfonts + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \let\page = \oldpage + \page + \null + }% +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % Need this before the \...aftertitlepage checks so that if they are + % in effect the toc pages will come out with page numbers. + \HEADINGSon + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Macros to be used within @titlepage: + +\let\subtitlerm=\tenrm +\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} + +\def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines + \let\tt=\authortt} + +\parseargdef\title{% + \checkenv\titlepage + \leftline{\titlefonts\rm #1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt +} + +\parseargdef\subtitle{% + \checkenv\titlepage + {\subtitlefont \rightline{#1}}% +} + +% @author should come last, but may come many times. +% It can also be used inside @quotation. +% +\parseargdef\author{% + \def\temp{\quotation}% + \ifx\thisenv\temp + \def\quotationauthor{#1}% printed in \Equotation. + \else + \checkenv\titlepage + \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi + {\authorfont \leftline{#1}}% + \fi +} + + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make TeX use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + + +\def\evenheading{\parsearg\evenheadingxxx} +\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} +\def\evenheadingyyy #1\|#2\|#3\|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddheading{\parsearg\oddheadingxxx} +\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} +\def\oddheadingyyy #1\|#2\|#3\|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} +\def\evenfootingyyy #1\|#2\|#3\|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddfooting{\parsearg\oddfootingxxx} +\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} +\def\oddfootingyyy #1\|#2\|#3\|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -12pt + \global\advance\vsize by -12pt +} + +\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} + +% @evenheadingmarks top \thischapter <- chapter at the top of a page +% @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page +% +% The same set of arguments for: +% +% @oddheadingmarks +% @evenfootingmarks +% @oddfootingmarks +% @everyheadingmarks +% @everyfootingmarks + +\def\evenheadingmarks{\headingmarks{even}{heading}} +\def\oddheadingmarks{\headingmarks{odd}{heading}} +\def\evenfootingmarks{\headingmarks{even}{footing}} +\def\oddfootingmarks{\headingmarks{odd}{footing}} +\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} + \headingmarks{odd}{heading}{#1} } +\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} + \headingmarks{odd}{footing}{#1} } +% #1 = even/odd, #2 = heading/footing, #3 = top/bottom. +\def\headingmarks#1#2#3 {% + \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname + \global\expandafter\let\csname get#1#2marks\endcsname \temp +} + +\everyheadingmarks bottom +\everyfootingmarks bottom + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{% +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% This produces Day Month Year style of output. +% Only define if not already defined, in case a txi-??.tex file has set +% up a different format (e.g., txi-cs.tex does this). +\ifx\today\undefined +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} +\fi + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg{\gdef\thistitle}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @ftable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemindicate{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. However, if + % what follows is an environment such as @example, there will be no + % \parskip glue; then the negative vskip we just inserted would + % cause the example and the item to crash together. So we use this + % bizarre value of 10001 as a signal to \aboveenvbreak to insert + % \parskip glue after all. Section titles are handled this way also. + % + \penalty 10001 + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a list environment}} +\def\itemx{\errmessage{@itemx while not in a list environment}} + +% @table, @ftable, @vtable. +\envdef\table{% + \let\itemindex\gobble + \tablecheck{table}% +} +\envdef\ftable{% + \def\itemindex ##1{\doind {fn}{\code{##1}}}% + \tablecheck{ftable}% +} +\envdef\vtable{% + \def\itemindex ##1{\doind {vr}{\code{##1}}}% + \tablecheck{vtable}% +} +\def\tablecheck#1{% + \ifnum \the\catcode`\^^M=\active + \endgroup + \errmessage{This command won't work in this context; perhaps the problem is + that we are \inenvironment\thisenv}% + \def\next{\doignore{#1}}% + \else + \let\next\tablex + \fi + \next +} +\def\tablex#1{% + \def\itemindicate{#1}% + \parsearg\tabley +} +\def\tabley#1{% + {% + \makevalueexpandable + \edef\temp{\noexpand\tablez #1\space\space\space}% + \expandafter + }\temp \endtablez +} +\def\tablez #1 #2 #3 #4\endtablez{% + \aboveenvbreak + \ifnum 0#1>0 \advance \leftskip by #1\mil \fi + \ifnum 0#2>0 \tableindent=#2\mil \fi + \ifnum 0#3>0 \advance \rightskip by #3\mil \fi + \itemmax=\tableindent + \advance \itemmax by -\itemmargin + \advance \leftskip by \tableindent + \exdentamount=\tableindent + \parindent = 0pt + \parskip = \smallskipamount + \ifdim \parskip=0pt \parskip=2pt \fi + \let\item = \internalBitem + \let\itemx = \internalBitemx +} +\def\Etable{\endgraf\afterenvbreak} +\let\Eftable\Etable +\let\Evtable\Etable +\let\Eitemize\Etable +\let\Eenumerate\Etable + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\envdef\itemize{\parsearg\doitemize} + +\def\doitemize#1{% + \aboveenvbreak + \itemmax=\itemindent + \advance\itemmax by -\itemmargin + \advance\leftskip by \itemindent + \exdentamount=\itemindent + \parindent=0pt + \parskip=\smallskipamount + \ifdim\parskip=0pt \parskip=2pt \fi + \def\itemcontents{#1}% + % @itemize with no arg is equivalent to @itemize @bullet. + \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi + \let\item=\itemizeitem +} + +% Definition of @item while inside @itemize and @enumerate. +% +\def\itemizeitem{% + \advance\itemno by 1 % for enumerations + {\let\par=\endgraf \smallbreak}% reasonable place to break + {% + % If the document has an @itemize directly after a section title, a + % \nobreak will be last on the list, and \sectionheading will have + % done a \vskip-\parskip. In that case, we don't want to zero + % parskip, or the item text will crash with the heading. On the + % other hand, when there is normal text preceding the item (as there + % usually is), we do want to zero parskip, or there would be too much + % space. In that case, we won't have a \nobreak before. At least + % that's the theory. + \ifnum\lastpenalty<10000 \parskip=0in \fi + \noindent + \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% + \vadjust{\penalty 1200}}% not good to break after first line of item. + \flushcr +} + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\envparseargdef\enumerate{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call \doitemize, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \doitemize{#1.}\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab do not need to be on their own lines, but it will not hurt +% if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the @columnfraction, usually a decimal number like .5, but might +% be just 1. We just use it, whatever it is. +% +\def\pickupwholefraction#1 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a + % separator; typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable-only commands. +% +% @headitem starts a heading row, which we typeset in bold. +% Assignments have to be global since we are inside the implicit group +% of an alignment entry. Note that \everycr resets \everytab. +\def\headitem{\checkenv\multitable \crcr \global\everytab={\bf}\the\everytab}% +% +% A \tab used to include \hskip1sp. But then the space in a template +% line is not enough. That is bad. So let's go back to just `&' until +% we encounter the problem it was intended to solve again. +% --karl, nathan@acm.org, 20apr99. +\def\tab{\checkenv\multitable &\the\everytab}% + +% @multitable ... @end multitable definitions: +% +\newtoks\everytab % insert after every tab. +% +\envdef\multitable{% + \vskip\parskip + \startsavinginserts + % + % @item within a multitable starts a normal row. + % We use \def instead of \let so that if one of the multitable entries + % contains an @itemize, we don't choke on the \item (seen as \crcr aka + % \endtemplate) expanding \doitemize. + \def\item{\crcr}% + % + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + % + \everycr = {% + \noalign{% + \global\everytab={}% + \global\colcount=0 % Reset the column counter. + % Check for saved footnotes, etc. + \checkinserts + % Keeps underfull box messages off when table breaks over pages. + %\filbreak + % Maybe so, but it also creates really weird page breaks when the + % table breaks over pages. Wouldn't \vfil be better? Wait until the + % problem manifests itself, so it can be fixed for real --karl. + }% + }% + % + \parsearg\domultitable +} +\def\domultitable#1{% + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup &% + \global\advance\colcount by 1 + \multistrut + \vtop{% + % Use the current \colcount to find the correct column width: + \hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively + % marking characters. + \noindent\ignorespaces##\unskip\multistrut + }\cr +} +\def\Emultitable{% + \crcr + \egroup % end the \halign + \global\setpercentfalse +} + +\def\setmultitablespacing{% + \def\multistrut{\strut}% just use the standard line spacing + % + % Compute \multitablelinespace (if not defined by user) for use in + % \multitableparskip calculation. We used define \multistrut based on + % this, but (ironically) that caused the spacing to be off. + % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. +\ifdim\multitablelinespace=0pt +\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip +\global\advance\multitablelinespace by-\ht0 +\fi +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} + +% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, +% @ifnotxml always succeed. They currently do nothing; we don't +% attempt to check whether the conditionals are properly nested. But we +% have to remember that they are conditionals, so that @end doesn't +% attempt to close an environment group. +% +\def\makecond#1{% + \expandafter\let\csname #1\endcsname = \relax + \expandafter\let\csname iscond.#1\endcsname = 1 +} +\makecond{iftex} +\makecond{ifnotdocbook} +\makecond{ifnothtml} +\makecond{ifnotinfo} +\makecond{ifnotplaintext} +\makecond{ifnotxml} + +% Ignore @ignore, @ifhtml, @ifinfo, and the like. +% +\def\direntry{\doignore{direntry}} +\def\documentdescription{\doignore{documentdescription}} +\def\docbook{\doignore{docbook}} +\def\html{\doignore{html}} +\def\ifdocbook{\doignore{ifdocbook}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifinfo{\doignore{ifinfo}} +\def\ifnottex{\doignore{ifnottex}} +\def\ifplaintext{\doignore{ifplaintext}} +\def\ifxml{\doignore{ifxml}} +\def\ignore{\doignore{ignore}} +\def\menu{\doignore{menu}} +\def\xml{\doignore{xml}} + +% Ignore text until a line `@end #1', keeping track of nested conditionals. +% +% A count to remember the depth of nesting. +\newcount\doignorecount + +\def\doignore#1{\begingroup + % Scan in ``verbatim'' mode: + \obeylines + \catcode`\@ = \other + \catcode`\{ = \other + \catcode`\} = \other + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \spaceisspace + % + % Count number of #1's that we've seen. + \doignorecount = 0 + % + % Swallow text until we reach the matching `@end #1'. + \dodoignore{#1}% +} + +{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. + \obeylines % + % + \gdef\dodoignore#1{% + % #1 contains the command name as a string, e.g., `ifinfo'. + % + % Define a command to find the next `@end #1'. + \long\def\doignoretext##1^^M@end #1{% + \doignoretextyyy##1^^M@#1\_STOP_}% + % + % And this command to find another #1 command, at the beginning of a + % line. (Otherwise, we would consider a line `@c @ifset', for + % example, to count as an @ifset for nesting.) + \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% + % + % And now expand that command. + \doignoretext ^^M% + }% +} + +\def\doignoreyyy#1{% + \def\temp{#1}% + \ifx\temp\empty % Nothing found. + \let\next\doignoretextzzz + \else % Found a nested condition, ... + \advance\doignorecount by 1 + \let\next\doignoretextyyy % ..., look for another. + % If we're here, #1 ends with ^^M\ifinfo (for example). + \fi + \next #1% the token \_STOP_ is present just after this macro. +} + +% We have to swallow the remaining "\_STOP_". +% +\def\doignoretextzzz#1{% + \ifnum\doignorecount = 0 % We have just found the outermost @end. + \let\next\enddoignore + \else % Still inside a nested condition. + \advance\doignorecount by -1 + \let\next\doignoretext % Look for the next @end. + \fi + \next +} + +% Finish off ignored text. +{ \obeylines% + % Ignore anything after the last `@end #1'; this matters in verbatim + % environments, where otherwise the newline after an ignored conditional + % would result in a blank line in the output. + \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% +} + + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% We rely on the fact that \parsearg sets \catcode`\ =10. +% +\parseargdef\set{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + {% + \makevalueexpandable + \def\temp{#2}% + \edef\next{\gdef\makecsname{SET#1}}% + \ifx\temp\empty + \next{}% + \else + \setzzz#2\endsetzzz + \fi + }% +} +% Remove the trailing space \setxxx inserted. +\def\setzzz#1 \endsetzzz{\next{#1}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\parseargdef\clear{% + {% + \makevalueexpandable + \global\expandafter\let\csname SET#1\endcsname=\relax + }% +} + +% @value{foo} gets the text saved in variable foo. +\def\value{\begingroup\makevalueexpandable\valuexxx} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} +{ + \catcode`\- = \active \catcode`\_ = \active + % + \gdef\makevalueexpandable{% + \let\value = \expandablevalue + % We don't want these characters active, ... + \catcode`\-=\other \catcode`\_=\other + % ..., but we might end up with active ones in the argument if + % we're called from @code, as @code{@value{foo-bar_}}, though. + % So \let them to their normal equivalents. + \let-\realdash \let_\normalunderscore + } +} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we call \makevalueexpandable in \indexdummies). +% The command has to be fully expandable (if the variable is set), since +% the result winds up in the index file. This means that if the +% variable's value contains other Texinfo commands, it's almost certain +% it will fail (although perhaps we could fix that with sufficient work +% to do a one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \message{Variable `#1', used in @value, is not set.}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +% To get special treatment of `@end ifset,' call \makeond and the redefine. +% +\makecond{ifset} +\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} +\def\doifset#1#2{% + {% + \makevalueexpandable + \let\next=\empty + \expandafter\ifx\csname SET#2\endcsname\relax + #1% If not set, redefine \next. + \fi + \expandafter + }\next +} +\def\ifsetfail{\doignore{ifset}} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +% The `\else' inside the `\doifset' parameter is a trick to reuse the +% above code: if the variable is not set, do nothing, if it is set, +% then redefine \next to \ifclearfail. +% +\makecond{ifclear} +\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} +\def\ifclearfail{\doignore{ifclear}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory=\comment + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within macros and \if's. +\edef\newwrite{\makecsname{ptexnewwrite}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} +% +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. +% +\def\defcodeindex{\parsearg\newcodeindex} +% +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}}% +} + + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +% +\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} +\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} + +% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), +% #3 the target index (bar). +\def\dosynindex#1#2#3{% + % Only do \closeout if we haven't already done it, else we'll end up + % closing the target index. + \expandafter \ifx\csname donesynindex#2\endcsname \undefined + % The \closeout helps reduce unnecessary open files; the limit on the + % Acorn RISC OS is a mere 16 files. + \expandafter\closeout\csname#2indfile\endcsname + \expandafter\let\csname\donesynindex#2\endcsname = 1 + \fi + % redefine \fooindfile: + \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname + \expandafter\let\csname#2indfile\endcsname=\temp + % redefine \fooindex: + \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +% Take care of Texinfo commands that can appear in an index entry. +% Since there are some commands we want to expand, and others we don't, +% we have to laboriously prevent expansion for those that we don't. +% +\def\indexdummies{% + \escapechar = `\\ % use backslash in output files. + \def\@{@}% change to @@ when we switch to @ as escape char in index files. + \def\ {\realbackslash\space }% + % + % Need these in case \tex is in effect and \{ is a \delimiter again. + % But can't use \lbracecmd and \rbracecmd because texindex assumes + % braces and backslashes are used only as delimiters. + \let\{ = \mylbrace + \let\} = \myrbrace + % + % I don't entirely understand this, but when an index entry is + % generated from a macro call, the \endinput which \scanmacro inserts + % causes processing to be prematurely terminated. This is, + % apparently, because \indexsorttmp is fully expanded, and \endinput + % is an expandable command. The redefinition below makes \endinput + % disappear altogether for that purpose -- although logging shows that + % processing continues to some further point. On the other hand, it + % seems \endinput does not hurt in the printed index arg, since that + % is still getting written without apparent harm. + % + % Sample source (mac-idx3.tex, reported by Graham Percival to + % help-texinfo, 22may06): + % @macro funindex {WORD} + % @findex xyz + % @end macro + % ... + % @funindex commtest + % + % The above is not enough to reproduce the bug, but it gives the flavor. + % + % Sample whatsit resulting: + % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} + % + % So: + \let\endinput = \empty + % + % Do the redefinitions. + \commondummies +} + +% For the aux and toc files, @ is the escape character. So we want to +% redefine everything using @ as the escape character (instead of +% \realbackslash, still used for index files). When everything uses @, +% this will be simpler. +% +\def\atdummies{% + \def\@{@@}% + \def\ {@ }% + \let\{ = \lbraceatcmd + \let\} = \rbraceatcmd + % + % Do the redefinitions. + \commondummies + \otherbackslash +} + +% Called from \indexdummies and \atdummies. +% +\def\commondummies{% + % + % \definedummyword defines \#1 as \string\#1\space, thus effectively + % preventing its expansion. This is used only for control% words, + % not control letters, because the \space would be incorrect for + % control characters, but is needed to separate the control word + % from whatever follows. + % + % For control letters, we have \definedummyletter, which omits the + % space. + % + % These can be used both for control words that take an argument and + % those that do not. If it is followed by {arg} in the input, then + % that will dutifully get written to the index (or wherever). + % + \def\definedummyword ##1{\def##1{\string##1\space}}% + \def\definedummyletter##1{\def##1{\string##1}}% + \let\definedummyaccent\definedummyletter + % + \commondummiesnofonts + % + \definedummyletter\_% + % + % Non-English letters. + \definedummyword\AA + \definedummyword\AE + \definedummyword\L + \definedummyword\OE + \definedummyword\O + \definedummyword\aa + \definedummyword\ae + \definedummyword\l + \definedummyword\oe + \definedummyword\o + \definedummyword\ss + \definedummyword\exclamdown + \definedummyword\questiondown + \definedummyword\ordf + \definedummyword\ordm + % + % Although these internal commands shouldn't show up, sometimes they do. + \definedummyword\bf + \definedummyword\gtr + \definedummyword\hat + \definedummyword\less + \definedummyword\sf + \definedummyword\sl + \definedummyword\tclose + \definedummyword\tt + % + \definedummyword\LaTeX + \definedummyword\TeX + % + % Assorted special characters. + \definedummyword\bullet + \definedummyword\comma + \definedummyword\copyright + \definedummyword\registeredsymbol + \definedummyword\dots + \definedummyword\enddots + \definedummyword\equiv + \definedummyword\error + \definedummyword\euro + \definedummyword\guillemetleft + \definedummyword\guillemetright + \definedummyword\guilsinglleft + \definedummyword\guilsinglright + \definedummyword\expansion + \definedummyword\minus + \definedummyword\pounds + \definedummyword\point + \definedummyword\print + \definedummyword\quotedblbase + \definedummyword\quotedblleft + \definedummyword\quotedblright + \definedummyword\quoteleft + \definedummyword\quoteright + \definedummyword\quotesinglbase + \definedummyword\result + \definedummyword\textdegree + % + % We want to disable all macros so that they are not expanded by \write. + \macrolist + % + \normalturnoffactive + % + % Handle some cases of @value -- where it does not contain any + % (non-fully-expandable) commands. + \makevalueexpandable +} + +% \commondummiesnofonts: common to \commondummies and \indexnofonts. +% +\def\commondummiesnofonts{% + % Control letters and accents. + \definedummyletter\!% + \definedummyaccent\"% + \definedummyaccent\'% + \definedummyletter\*% + \definedummyaccent\,% + \definedummyletter\.% + \definedummyletter\/% + \definedummyletter\:% + \definedummyaccent\=% + \definedummyletter\?% + \definedummyaccent\^% + \definedummyaccent\`% + \definedummyaccent\~% + \definedummyword\u + \definedummyword\v + \definedummyword\H + \definedummyword\dotaccent + \definedummyword\ringaccent + \definedummyword\tieaccent + \definedummyword\ubaraccent + \definedummyword\udotaccent + \definedummyword\dotless + % + % Texinfo font commands. + \definedummyword\b + \definedummyword\i + \definedummyword\r + \definedummyword\sc + \definedummyword\t + % + % Commands that take arguments. + \definedummyword\acronym + \definedummyword\cite + \definedummyword\code + \definedummyword\command + \definedummyword\dfn + \definedummyword\emph + \definedummyword\env + \definedummyword\file + \definedummyword\kbd + \definedummyword\key + \definedummyword\math + \definedummyword\option + \definedummyword\pxref + \definedummyword\ref + \definedummyword\samp + \definedummyword\strong + \definedummyword\tie + \definedummyword\uref + \definedummyword\url + \definedummyword\var + \definedummyword\verb + \definedummyword\w + \definedummyword\xref +} + +% \indexnofonts is used when outputting the strings to sort the index +% by, and when constructing control sequence names. It eliminates all +% control sequences and just writes whatever the best ASCII sort string +% would be for a given command (usually its argument). +% +\def\indexnofonts{% + % Accent commands should become @asis. + \def\definedummyaccent##1{\let##1\asis}% + % We can just ignore other control letters. + \def\definedummyletter##1{\let##1\empty}% + % Hopefully, all control words can become @asis. + \let\definedummyword\definedummyaccent + % + \commondummiesnofonts + % + % Don't no-op \tt, since it isn't a user-level command + % and is used in the definitions of the active chars like <, >, |, etc. + % Likewise with the other plain tex font commands. + %\let\tt=\asis + % + \def\ { }% + \def\@{@}% + % how to handle braces? + \def\_{\normalunderscore}% + % + % Non-English letters. + \def\AA{AA}% + \def\AE{AE}% + \def\L{L}% + \def\OE{OE}% + \def\O{O}% + \def\aa{aa}% + \def\ae{ae}% + \def\l{l}% + \def\oe{oe}% + \def\o{o}% + \def\ss{ss}% + \def\exclamdown{!}% + \def\questiondown{?}% + \def\ordf{a}% + \def\ordm{o}% + % + \def\LaTeX{LaTeX}% + \def\TeX{TeX}% + % + % Assorted special characters. + % (The following {} will end up in the sort string, but that's ok.) + \def\bullet{bullet}% + \def\comma{,}% + \def\copyright{copyright}% + \def\registeredsymbol{R}% + \def\dots{...}% + \def\enddots{...}% + \def\equiv{==}% + \def\error{error}% + \def\euro{euro}% + \def\guillemetleft{<<}% + \def\guillemetright{>>}% + \def\guilsinglleft{<}% + \def\guilsinglright{>}% + \def\expansion{==>}% + \def\minus{-}% + \def\pounds{pounds}% + \def\point{.}% + \def\print{-|}% + \def\quotedblbase{"}% + \def\quotedblleft{"}% + \def\quotedblright{"}% + \def\quoteleft{`}% + \def\quoteright{'}% + \def\quotesinglbase{,}% + \def\result{=>}% + \def\textdegree{degrees}% + % + % We need to get rid of all macros, leaving only the arguments (if present). + % Of course this is not nearly correct, but it is the best we can do for now. + % makeinfo does not expand macros in the argument to @deffn, which ends up + % writing an index entry, and texindex isn't prepared for an index sort entry + % that starts with \. + % + % Since macro invocations are followed by braces, we can just redefine them + % to take a single TeX argument. The case of a macro invocation that + % goes to end-of-line is not handled. + % + \macrolist +} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% Most index entries go through here, but \dosubind is the general case. +% #1 is the index name, #2 is the entry text. +\def\doind#1#2{\dosubind{#1}{#2}{}} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% empty if called from \doind, as we usually are (the main exception +% is with most defuns, which call us directly). +% +\def\dosubind#1#2#3{% + \iflinks + {% + % Store the main index entry text (including the third arg). + \toks0 = {#2}% + % If third arg is present, precede it with a space. + \def\thirdarg{#3}% + \ifx\thirdarg\empty \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + \edef\writeto{\csname#1indfile\endcsname}% + % + \safewhatsit\dosubindwrite + }% + \fi +} + +% Write the entry in \toks0 to the index file: +% +\def\dosubindwrite{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% + \fi + % + % Remember, we are within a group. + \indexdummies % Must do this here, since \bf, etc expand at this stage + \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % Process the index entry with all font commands turned off, to + % get the string to sort by. + {\indexnofonts + \edef\temp{\the\toks0}% need full expansion + \xdef\indexsorttmp{\temp}% + }% + % + % Set up the complete index entry, with both the sort key and + % the original text, including any font commands. We write + % three arguments to \entry to the .?? file (four in the + % subentry case), texindex reduces to two when writing the .??s + % sorted result. + \edef\temp{% + \write\writeto{% + \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% + }% + \temp +} + +% Take care of unwanted page breaks/skips around a whatsit: +% +% If a skip is the last thing on the list now, preserve it +% by backing up by \lastskip, doing the \write, then inserting +% the skip again. Otherwise, the whatsit generated by the +% \write or \pdfdest will make \lastskip zero. The result is that +% sequences like this: +% @end defun +% @tindex whatever +% @defun ... +% will have extra space inserted, because the \medbreak in the +% start of the @defun won't see the skip inserted by the @end of +% the previous defun. +% +% But don't do any of this if we're not in vertical mode. We +% don't want to do a \vskip and prematurely end a paragraph. +% +% Avoid page breaks due to these extra skips, too. +% +% But wait, there is a catch there: +% We'll have to check whether \lastskip is zero skip. \ifdim is not +% sufficient for this purpose, as it ignores stretch and shrink parts +% of the skip. The only way seems to be to check the textual +% representation of the skip. +% +% The following is almost like \def\zeroskipmacro{0.0pt} except that +% the ``p'' and ``t'' characters have catcode \other, not 11 (letter). +% +\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} +% +\newskip\whatsitskip +\newcount\whatsitpenalty +% +% ..., ready, GO: +% +\def\safewhatsit#1{% +\ifhmode + #1% +\else + % \lastskip and \lastpenalty cannot both be nonzero simultaneously. + \whatsitskip = \lastskip + \edef\lastskipmacro{\the\lastskip}% + \whatsitpenalty = \lastpenalty + % + % If \lastskip is nonzero, that means the last item was a + % skip. And since a skip is discardable, that means this + % -\whatsitskip glue we're inserting is preceded by a + % non-discardable item, therefore it is not a potential + % breakpoint, therefore no \nobreak needed. + \ifx\lastskipmacro\zeroskipmacro + \else + \vskip-\whatsitskip + \fi + % + #1% + % + \ifx\lastskipmacro\zeroskipmacro + % If \lastskip was zero, perhaps the last item was a penalty, and + % perhaps it was >=10000, e.g., a \nobreak. In that case, we want + % to re-insert the same penalty (values >10000 are used for various + % signals); since we just inserted a non-discardable item, any + % following glue (such as a \parskip) would be a breakpoint. For example: + % + % @deffn deffn-whatever + % @vindex index-whatever + % Description. + % would allow a break between the index-whatever whatsit + % and the "Description." paragraph. + \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi + \else + % On the other hand, if we had a nonzero \lastskip, + % this make-up glue would be preceded by a non-discardable item + % (the whatsit from the \write), so we must insert a \nobreak. + \nobreak\vskip\whatsitskip + \fi +\fi +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\parseargdef\printindex{\begingroup + \dobreak \chapheadingskip{10000}% + % + \smallfonts \rm + \tolerance = 9500 + \plainfrenchspacing + \everypar = {}% don't want the \kern\-parindent from indentation suppression. + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\backslashcurfont}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \nobreak + \vskip 0pt plus 3\baselineskip + \penalty 0 + \vskip 0pt plus -3\baselineskip + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + % Do our best not to break after the initial. + \nobreak + \vskip .33\baselineskip plus .1\baselineskip +}} + +% \entry typesets a paragraph consisting of the text (#1), dot leaders, and +% then page number (#2) flushed to the right margin. It is used for index +% and table of contents entries. The paragraph is indented by \leftskip. +% +% A straightforward implementation would start like this: +% \def\entry#1#2{... +% But this freezes the catcodes in the argument, and can cause problems to +% @code, which sets - active. This problem was fixed by a kludge--- +% ``-'' was active throughout whole index, but this isn't really right. +% +% The right solution is to prevent \entry from swallowing the whole text. +% --kasal, 21nov03 +\def\entry{% + \begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing + % columns. + \vskip 0pt plus1pt + % + % Swallow the left brace of the text (first parameter): + \afterassignment\doentry + \let\temp = +} +\def\doentry{% + \bgroup % Instead of the swallowed brace. + \noindent + \aftergroup\finishentry + % And now comes the text of the entry. +} +\def\finishentry#1{% + % #1 is the page number. + % + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \setbox\boxA = \hbox{#1}% + \ifdim\wd\boxA = 0pt + \ % + \else + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ifpdf + \pdfgettoks#1.% + \ \the\toksA + \else + \ #1% + \fi + \fi + \par + \endgroup +} + +% Like plain.tex's \dotfill, except uses up at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm +\def\secondary#1#2{{% + \parfillskip=0in + \parskip=0in + \hangindent=1in + \hangafter=1 + \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill + \ifpdf + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \else + #2 + \fi + \par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + \advance\dimen@ by -\ht\partialpage + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +% +% Re-output the contents of the output page -- any previous material, +% followed by the two boxes we just split, in box0 and box2. +\def\pagesofar{% + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +% +% All done with double columns. +\def\enddoublecolumns{% + % The following penalty ensures that the page builder is exercised + % _before_ we change the output routine. This is necessary in the + % following situation: + % + % The last section of the index consists only of a single entry. + % Before this section, \pagetotal is less than \pagegoal, so no + % break occurs before the last section starts. However, the last + % section, consisting of \initial and the single \entry, does not + % fit on the page and has to be broken off. Without the following + % penalty the page builder will not be exercised until \eject + % below, and by that time we'll already have changed the output + % routine to the \balancecolumns version, so the next-to-last + % double-column page will be processed with \balancecolumns, which + % is wrong: The two columns will go to the main vertical list, with + % the broken-off section in the recent contributions. As soon as + % the output routine finishes, TeX starts reconsidering the page + % break. The two columns and the broken-off section both fit on the + % page, because the two columns now take up only half of the page + % goal. When TeX sees \eject from below which follows the final + % section, it invokes the new output routine that we've set after + % \balancecolumns below; \onepageout will try to fit the two columns + % and the final section into the vbox of \pageheight (see + % \pagebody), causing an overfull box. + % + % Note that glue won't work here, because glue does not exercise the + % page builder, unlike penalties (see The TeXbook, pp. 280-281). + \penalty0 + % + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +% +% Called at the end of the double column material. +\def\balancecolumns{% + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Chapters, sections, etc. + +% \unnumberedno is an oxymoron, of course. But we count the unnumbered +% sections so that we can refer to them unambiguously in the pdf +% outlines by their "section number". We avoid collisions with chapter +% numbers by starting them at 10000. (If a document ever has 10000 +% chapters, we're in trouble anyway, I'm sure.) +\newcount\unnumberedno \unnumberedno = 10000 +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +% +% \def\appendixletter{\char\the\appendixno} +% We do the following ugly conditional instead of the above simple +% construct for the sake of pdftex, which needs the actual +% letter in the expansion, not just typeset. +% +\def\appendixletter{% + \ifnum\appendixno=`A A% + \else\ifnum\appendixno=`B B% + \else\ifnum\appendixno=`C C% + \else\ifnum\appendixno=`D D% + \else\ifnum\appendixno=`E E% + \else\ifnum\appendixno=`F F% + \else\ifnum\appendixno=`G G% + \else\ifnum\appendixno=`H H% + \else\ifnum\appendixno=`I I% + \else\ifnum\appendixno=`J J% + \else\ifnum\appendixno=`K K% + \else\ifnum\appendixno=`L L% + \else\ifnum\appendixno=`M M% + \else\ifnum\appendixno=`N N% + \else\ifnum\appendixno=`O O% + \else\ifnum\appendixno=`P P% + \else\ifnum\appendixno=`Q Q% + \else\ifnum\appendixno=`R R% + \else\ifnum\appendixno=`S S% + \else\ifnum\appendixno=`T T% + \else\ifnum\appendixno=`U U% + \else\ifnum\appendixno=`V V% + \else\ifnum\appendixno=`W W% + \else\ifnum\appendixno=`X X% + \else\ifnum\appendixno=`Y Y% + \else\ifnum\appendixno=`Z Z% + % The \the is necessary, despite appearances, because \appendixletter is + % expanded while writing the .toc file. \char\appendixno is not + % expandable, thus it is written literally, thus all appendixes come out + % with the same letter (or @) in the toc without it. + \else\char\the\appendixno + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + +% Each @chapter defines these (using marks) as the number+name, number +% and name of the chapter. Page headings and footings can use +% these. @section does likewise. +\def\thischapter{} +\def\thischapternum{} +\def\thischaptername{} +\def\thissection{} +\def\thissectionnum{} +\def\thissectionname{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% we only have subsub. +\chardef\maxseclevel = 3 +% +% A numbered section within an unnumbered changes to unnumbered too. +% To achive this, remember the "biggest" unnum. sec. we are currently in: +\chardef\unmlevel = \maxseclevel +% +% Trace whether the current chapter is an appendix or not: +% \chapheadtype is "N" or "A", unnumbered chapters are ignored. +\def\chapheadtype{N} + +% Choose a heading macro +% #1 is heading type +% #2 is heading level +% #3 is text for heading +\def\genhead#1#2#3{% + % Compute the abs. sec. level: + \absseclevel=#2 + \advance\absseclevel by \secbase + % Make sure \absseclevel doesn't fall outside the range: + \ifnum \absseclevel < 0 + \absseclevel = 0 + \else + \ifnum \absseclevel > 3 + \absseclevel = 3 + \fi + \fi + % The heading type: + \def\headtype{#1}% + \if \headtype U% + \ifnum \absseclevel < \unmlevel + \chardef\unmlevel = \absseclevel + \fi + \else + % Check for appendix sections: + \ifnum \absseclevel = 0 + \edef\chapheadtype{\headtype}% + \else + \if \headtype A\if \chapheadtype N% + \errmessage{@appendix... within a non-appendix chapter}% + \fi\fi + \fi + % Check for numbered within unnumbered: + \ifnum \absseclevel > \unmlevel + \def\headtype{U}% + \else + \chardef\unmlevel = 3 + \fi + \fi + % Now print the heading: + \if \headtype U% + \ifcase\absseclevel + \unnumberedzzz{#3}% + \or \unnumberedseczzz{#3}% + \or \unnumberedsubseczzz{#3}% + \or \unnumberedsubsubseczzz{#3}% + \fi + \else + \if \headtype A% + \ifcase\absseclevel + \appendixzzz{#3}% + \or \appendixsectionzzz{#3}% + \or \appendixsubseczzz{#3}% + \or \appendixsubsubseczzz{#3}% + \fi + \else + \ifcase\absseclevel + \chapterzzz{#3}% + \or \seczzz{#3}% + \or \numberedsubseczzz{#3}% + \or \numberedsubsubseczzz{#3}% + \fi + \fi + \fi + \suppressfirstparagraphindent +} + +% an interface: +\def\numhead{\genhead N} +\def\apphead{\genhead A} +\def\unnmhead{\genhead U} + +% @chapter, @appendix, @unnumbered. Increment top-level counter, reset +% all lower-level sectioning counters to zero. +% +% Also set \chaplevelprefix, which we prepend to @float sequence numbers +% (e.g., figures), q.v. By default (before any chapter), that is empty. +\let\chaplevelprefix = \empty +% +\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz#1{% + % section resetting is \global in case the chapter is in a group, such + % as an @include file. + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\chapno by 1 + % + % Used for \float. + \gdef\chaplevelprefix{\the\chapno.}% + \resetallfloatnos + % + \message{\putwordChapter\space \the\chapno}% + % + % Write the actual heading. + \chapmacro{#1}{Ynumbered}{\the\chapno}% + % + % So @section and the like are numbered underneath this chapter. + \global\let\section = \numberedsec + \global\let\subsection = \numberedsubsec + \global\let\subsubsection = \numberedsubsubsec +} + +\outer\parseargdef\appendix{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\appendixno by 1 + \gdef\chaplevelprefix{\appendixletter.}% + \resetallfloatnos + % + \def\appendixnum{\putwordAppendix\space \appendixletter}% + \message{\appendixnum}% + % + \chapmacro{#1}{Yappendix}{\appendixletter}% + % + \global\let\section = \appendixsec + \global\let\subsection = \appendixsubsec + \global\let\subsubsection = \appendixsubsubsec +} + +\outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\unnumberedno by 1 + % + % Since an unnumbered has no number, no prefix for figures. + \global\let\chaplevelprefix = \empty + \resetallfloatnos + % + % This used to be simply \message{#1}, but TeX fully expands the + % argument to \message. Therefore, if #1 contained @-commands, TeX + % expanded them. For example, in `@unnumbered The @cite{Book}', TeX + % expanded @cite (which turns out to cause errors because \cite is meant + % to be executed, not expanded). + % + % Anyway, we don't want the fully-expanded definition of @cite to appear + % as a result of the \message, we just want `@cite' itself. We use + % \the<toks register> to achieve this: TeX expands \the<toks> only once, + % simply yielding the contents of <toks register>. (We also do this for + % the toc entries.) + \toks0 = {#1}% + \message{(\the\toks0)}% + % + \chapmacro{#1}{Ynothing}{\the\unnumberedno}% + % + \global\let\section = \unnumberedsec + \global\let\subsection = \unnumberedsubsec + \global\let\subsubsection = \unnumberedsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\parseargdef\centerchap{% + % Well, we could do the following in a group, but that would break + % an assumption that \chapmacro is called at the outermost level. + % Thus we are safer this way: --kasal, 24feb04 + \let\centerparametersmaybe = \centerparameters + \unnmhead0{#1}% + \let\centerparametersmaybe = \relax +} + +% @top is like @unnumbered. +\let\top\unnumbered + +% Sections. +\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz +\def\seczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% +} + +\outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% +} +\let\appendixsec\appendixsection + +\outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% +} + +% Subsections. +\outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno}% +} + +% Subsubsections. +\outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynumbered}% + {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\let\section = \numberedsec +\let\subsection = \numberedsubsec +\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{% + {\advance\chapheadingskip by 10pt \chapbreak }% + \parsearg\chapheadingzzz +} + +\def\chapheading{\chapbreak \parsearg\chapheadingzzz} +\def\chapheadingzzz#1{% + {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% + \bigskip \par\penalty 200\relax + \suppressfirstparagraphindent +} + +% @heading, @subheading, @subsubheading. +\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +% Because \domark is called before \chapoddpage, the filler page will +% get the headings for the next chapter, which is wrong. But we don't +% care -- we just disable all headings on the filler page. +\def\chapoddpage{% + \chappager + \ifodd\pageno \else + \begingroup + \evenheadline={\hfil}\evenfootline={\hfil}% + \oddheadline={\hfil}\oddfootline={\hfil}% + \hbox to 0pt{}% + \chappager + \endgroup + \fi +} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{% +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +% Chapter opening. +% +% #1 is the text, #2 is the section type (Ynumbered, Ynothing, +% Yappendix, Yomitfromtoc), #3 the chapter number. +% +% To test against our argument. +\def\Ynothingkeyword{Ynothing} +\def\Yomitfromtockeyword{Yomitfromtoc} +\def\Yappendixkeyword{Yappendix} +% +\def\chapmacro#1#2#3{% + % Insert the first mark before the heading break (see notes for \domark). + \let\prevchapterdefs=\lastchapterdefs + \let\prevsectiondefs=\lastsectiondefs + \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% + \gdef\thissection{}}% + % + \def\temptype{#2}% + \ifx\temptype\Ynothingkeyword + \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% + \gdef\thischapter{\thischaptername}}% + \else\ifx\temptype\Yomitfromtockeyword + \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% + \gdef\thischapter{}}% + \else\ifx\temptype\Yappendixkeyword + \toks0={#1}% + \xdef\lastchapterdefs{% + \gdef\noexpand\thischaptername{\the\toks0}% + \gdef\noexpand\thischapternum{\appendixletter}% + \gdef\noexpand\thischapter{\putwordAppendix{} \noexpand\thischapternum: + \noexpand\thischaptername}% + }% + \else + \toks0={#1}% + \xdef\lastchapterdefs{% + \gdef\noexpand\thischaptername{\the\toks0}% + \gdef\noexpand\thischapternum{\the\chapno}% + \gdef\noexpand\thischapter{\putwordChapter{} \noexpand\thischapternum: + \noexpand\thischaptername}% + }% + \fi\fi\fi + % + % Output the mark. Pass it through \safewhatsit, to take care of + % the preceding space. + \safewhatsit\domark + % + % Insert the chapter heading break. + \pchapsepmacro + % + % Now the second mark, after the heading break. No break points + % between here and the heading. + \let\prevchapterdefs=\lastchapterdefs + \let\prevsectiondefs=\lastsectiondefs + \domark + % + {% + \chapfonts \rm + % + % Have to define \lastsection before calling \donoderef, because the + % xref code eventually uses it. On the other hand, it has to be called + % after \pchapsepmacro, or the headline will change too soon. + \gdef\lastsection{#1}% + % + % Only insert the separating space if we have a chapter/appendix + % number, and don't print the unnumbered ``number''. + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unnchap}% + \else\ifx\temptype\Yomitfromtockeyword + \setbox0 = \hbox{}% contents like unnumbered, but no toc entry + \def\toctype{omit}% + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% + \def\toctype{app}% + \else + \setbox0 = \hbox{#3\enspace}% + \def\toctype{numchap}% + \fi\fi\fi + % + % Write the toc entry for this chapter. Must come before the + % \donoderef, because we include the current node name in the toc + % entry, and \donoderef resets it to empty. + \writetocentry{\toctype}{#1}{#3}% + % + % For pdftex, we have to write out the node definition (aka, make + % the pdfdest) after any page break, but before the actual text has + % been typeset. If the destination for the pdf outline is after the + % text, then jumping from the outline may wind up with the text not + % being visible, for instance under high magnification. + \donoderef{#2}% + % + % Typeset the actual heading. + \nobreak % Avoid page breaks at the interline glue. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent=\wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerparameters{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt +} + + +% I don't think this chapter style is supported any more, so I'm not +% updating it with the new noderef stuff. We'll see. --karl, 11aug03. +% +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} +% +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} +\def\CHAPFopen{% + \global\let\chapmacro=\chfopen + \global\let\centerchapmacro=\centerchfopen} + + +% Section titles. These macros combine the section number parts and +% call the generic \sectionheading to do the printing. +% +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip{-1000}} + +% Subsection titles. +\newskip\subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} + +% Subsubsection titles. +\def\subsubsecheadingskip{\subsecheadingskip} +\def\subsubsecheadingbreak{\subsecheadingbreak} + + +% Print any size, any type, section title. +% +% #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is +% the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the +% section number. +% +\def\seckeyword{sec} +% +\def\sectionheading#1#2#3#4{% + {% + % Switch to the right set of fonts. + \csname #2fonts\endcsname \rm + % + \def\sectionlevel{#2}% + \def\temptype{#3}% + % + % Insert first mark before the heading break (see notes for \domark). + \let\prevsectiondefs=\lastsectiondefs + \ifx\temptype\Ynothingkeyword + \ifx\sectionlevel\seckeyword + \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% + \gdef\thissection{\thissectionname}}% + \fi + \else\ifx\temptype\Yomitfromtockeyword + % Don't redefine \thissection. + \else\ifx\temptype\Yappendixkeyword + \ifx\sectionlevel\seckeyword + \toks0={#1}% + \xdef\lastsectiondefs{% + \gdef\noexpand\thissectionname{\the\toks0}% + \gdef\noexpand\thissectionnum{#4}% + \gdef\noexpand\thissection{\putwordSection{} \noexpand\thissectionnum: + \noexpand\thissectionname}% + }% + \fi + \else + \ifx\sectionlevel\seckeyword + \toks0={#1}% + \xdef\lastsectiondefs{% + \gdef\noexpand\thissectionname{\the\toks0}% + \gdef\noexpand\thissectionnum{#4}% + \gdef\noexpand\thissection{\putwordSection{} \noexpand\thissectionnum: + \noexpand\thissectionname}% + }% + \fi + \fi\fi\fi + % + % Output the mark. Pass it through \safewhatsit, to take care of + % the preceding space. + \safewhatsit\domark + % + % Insert space above the heading. + \csname #2headingbreak\endcsname + % + % Now the second mark, after the heading break. No break points + % between here and the heading. + \let\prevsectiondefs=\lastsectiondefs + \domark + % + % Only insert the space after the number if we have a section number. + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unn}% + \gdef\lastsection{#1}% + \else\ifx\temptype\Yomitfromtockeyword + % for @headings -- no section number, don't include in toc, + % and don't redefine \lastsection. + \setbox0 = \hbox{}% + \def\toctype{omit}% + \let\sectionlevel=\empty + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{#4\enspace}% + \def\toctype{app}% + \gdef\lastsection{#1}% + \else + \setbox0 = \hbox{#4\enspace}% + \def\toctype{num}% + \gdef\lastsection{#1}% + \fi\fi\fi + % + % Write the toc entry (before \donoderef). See comments in \chapmacro. + \writetocentry{\toctype\sectionlevel}{#1}{#4}% + % + % Write the node reference (= pdf destination for pdftex). + % Again, see comments in \chapmacro. + \donoderef{#3}% + % + % Interline glue will be inserted when the vbox is completed. + % That glue will be a valid breakpoint for the page, since it'll be + % preceded by a whatsit (usually from the \donoderef, or from the + % \writetocentry if there was no node). We don't want to allow that + % break, since then the whatsits could end up on page n while the + % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. + \nobreak + % + % Output the actual section heading. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent=\wd0 % zero if no section number + \unhbox0 #1}% + }% + % Add extra space after the heading -- half of whatever came above it. + % Don't allow stretch, though. + \kern .5 \csname #2headingskip\endcsname + % + % Do not let the kern be a potential breakpoint, as it would be if it + % was followed by glue. + \nobreak + % + % We'll almost certainly start a paragraph next, so don't let that + % glue accumulate. (Not a breakpoint because it's preceded by a + % discardable item.) + \vskip-\parskip + % + % This is purely so the last item on the list is a known \penalty > + % 10000. This is so \startdefun can avoid allowing breakpoints after + % section headings. Otherwise, it would insert a valid breakpoint between: + % + % @section sec-whatever + % @deffn def-whatever + \penalty 10001 +} + + +\message{toc,} +% Table of contents. +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. +% +% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} +% We append the current node name (if any) and page number as additional +% arguments for the \{chap,sec,...}entry macros which will eventually +% read this. The node name is used in the pdf outlines as the +% destination to jump to. +% +% We open the .toc file for writing here instead of at @setfilename (or +% any other fixed time) so that @contents can be anywhere in the document. +% But if #1 is `omit', then we don't do anything. This is used for the +% table of contents chapter openings themselves. +% +\newif\iftocfileopened +\def\omitkeyword{omit}% +% +\def\writetocentry#1#2#3{% + \edef\writetoctype{#1}% + \ifx\writetoctype\omitkeyword \else + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + % + \iflinks + {\atdummies + \edef\temp{% + \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% + \temp + }% + \fi + \fi + % + % Tell \shipout to create a pdf destination on each page, if we're + % writing pdf. These are used in the table of contents. We can't + % just write one on every page because the title pages are numbered + % 1 and 2 (the page numbers aren't printed), and so are the first + % two pages of the document. Thus, we'd have two destinations named + % `1', and two named `2'. + \ifpdf \global\pdfmakepagedesttrue \fi +} + + +% These characters do not print properly in the Computer Modern roman +% fonts, so we must take special care. This is more or less redundant +% with the Texinfo input format setup at the end of this file. +% +\def\activecatcodes{% + \catcode`\"=\active + \catcode`\$=\active + \catcode`\<=\active + \catcode`\>=\active + \catcode`\\=\active + \catcode`\^=\active + \catcode`\_=\active + \catcode`\|=\active + \catcode`\~=\active +} + + +% Read the toc file, which is essentially Texinfo input. +\def\readtocfile{% + \setupdatafile + \activecatcodes + \input \tocreadfilename +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Prepare to read what we've written to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund <tege@matematik.su.se> + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \chapmacro{#1}{Yomitfromtoc}{}% + % + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi +} + +% redefined for the two-volume lispref. We always output on +% \jobname.toc even if this is redefined. +% +\def\tocreadfilename{\jobname.toc} + +% Normal (long) toc. +% +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \tocreadfilename\space + \ifeof 1 \else + \readtocfile + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \ifeof 1 \else + \pdfmakeoutlines + \fi + \closein 1 + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\numchapentry = \shortchapentry + \let\appentry = \shortchapentry + \let\unnchapentry = \shortunnchapentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf + \let\sl=\shortcontsl \let\tt=\shortconttt + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\numsecentry##1##2##3##4{} + \let\appsecentry = \numsecentry + \let\unnsecentry = \numsecentry + \let\numsubsecentry = \numsecentry + \let\appsubsecentry = \numsecentry + \let\unnsubsecentry = \numsecentry + \let\numsubsubsecentry = \numsecentry + \let\appsubsubsecentry = \numsecentry + \let\unnsubsubsecentry = \numsecentry + \openin 1 \tocreadfilename\space + \ifeof 1 \else + \readtocfile + \fi + \closein 1 + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g., `A' for an appendix, or `3' for a chapter. +% +\def\shortchaplabel#1{% + % This space should be enough, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % But use \hss just in case. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + % + % We'd like to right-justify chapter numbers, but that looks strange + % with appendix letters. And right-justifying numbers and + % left-justifying letters looks strange when there is less than 10 + % chapters. Have to read the whole toc once to know how many chapters + % there are before deciding ... + \hbox to 1em{#1\hss}% +} + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapters, in the main contents. +\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} +% +% Chapters, in the short toc. +% See comments in \dochapentry re vbox and related settings. +\def\shortchapentry#1#2#3#4{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% +} + +% Appendices, in the main contents. +% Need the word Appendix, and a fixed-size box. +% +\def\appendixbox#1{% + % We use M since it's probably the widest letter. + \setbox0 = \hbox{\putwordAppendix{} M}% + \hbox to \wd0{\putwordAppendix{} #1\hss}} +% +\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} + +% Unnumbered chapters. +\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} +\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} + +% Sections. +\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} +\let\appsecentry=\numsecentry +\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} + +% Subsections. +\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} +\let\appsubsecentry=\numsubsecentry +\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} + +% And subsubsections. +\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} +\let\appsubsubsecentry=\numsubsubsecentry +\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} + +% This parameter controls the indentation of the various levels. +% Same as \defaultparindent. +\newdimen\tocindent \tocindent = 15pt + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +% We use the same \entry macro as for the index entries. +\let\tocentry = \entry + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\def\subsecentryfonts{\textfonts} +\def\subsubsecentryfonts{\textfonts} + + +\message{environments,} +% @foo ... @end foo. + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +% +% Since these characters are used in examples, they should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% +\def\point{$\star$} +\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} +\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% The @error{} command. +% Adapted from the TeXbook's \boxit. +% +\newbox\errorbox +% +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \reducedsf error\kern-1.5pt} +% +\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{% + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} +% +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\envdef\tex{% + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie + \catcode `\%=14 + \catcode `\+=\other + \catcode `\"=\other + \catcode `\|=\other + \catcode `\<=\other + \catcode `\>=\other + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\/=\ptexslash + \let\*=\ptexstar + \let\t=\ptext + \expandafter \let\csname top\endcsname=\ptextop % outer + \let\frenchspacing=\plainfrenchspacing + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +} +% There is no need to define \Etex. + +% Define @lisp ... @end lisp. +% @lisp environment forms a group so it can rebind things, +% including the definition of @end lisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip. +% +\def\aboveenvbreak{{% + % =10000 instead of <10000 because of a special case in \itemzzz and + % \sectionheading, q.v. + \ifnum \lastpenalty=10000 \else + \advance\envskipamount by \parskip + \endgraf + \ifdim\lastskip<\envskipamount + \removelastskip + % it's not a good place to break if the last penalty was \nobreak + % or better ... + \ifnum\lastpenalty<10000 \penalty-50 \fi + \vskip\envskipamount + \fi + \fi +}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will +% also clear it, so that its embedded environments do the narrowing again. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\envdef\cartouche{% + \ifhmode\par\fi % can't be in the midst of a paragraph. + \startsavinginserts + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt % we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either + % side, and for 6pt waste from + % each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing = t% + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \kern3pt + \hsize=\cartinner + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip + \comment % For explanation, see the end of \def\group. +} +\def\Ecartouche{% + \ifhmode\par\fi + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup + \checkinserts +} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \let\exdent=\nofillexdent +} + +% If you want all examples etc. small: @set dispenvsize small. +% If you want even small examples the full size: @set dispenvsize nosmall. +% This affects the following displayed environments: +% @example, @display, @format, @lisp +% +\def\smallword{small} +\def\nosmallword{nosmall} +\let\SETdispenvsize\relax +\def\setnormaldispenv{% + \ifx\SETdispenvsize\smallword + % end paragraph for sake of leading, in case document has no blank + % line. This is redundant with what happens in \aboveenvbreak, but + % we need to do it before changing the fonts, and it's inconvenient + % to change the fonts afterward. + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} +\def\setsmalldispenv{% + \ifx\SETdispenvsize\nosmallword + \else + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} + +% We often define two environments, @foo and @smallfoo. +% Let's do it by one command: +\def\makedispenv #1#2{ + \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} + \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} + \expandafter\let\csname E#1\endcsname \afterenvbreak + \expandafter\let\csname Esmall#1\endcsname \afterenvbreak +} + +% Define two synonyms: +\def\maketwodispenvs #1#2#3{ + \makedispenv{#1}{#3} + \makedispenv{#2}{#3} +} + +% @lisp: indented, narrowed, typewriter font; @example: same as @lisp. +% +% @smallexample and @smalllisp: use smaller fonts. +% Originally contributed by Pavel@xerox. +% +\maketwodispenvs {lisp}{example}{% + \nonfillstart + \tt\quoteexpand + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} +% @display/@smalldisplay: same as @lisp except keep current font. +% +\makedispenv {display}{% + \nonfillstart + \gobble +} + +% @format/@smallformat: same as @display except don't narrow margins. +% +\makedispenv{format}{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} + +% @flushleft: same as @format, but doesn't obey \SETdispenvsize. +\envdef\flushleft{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} +\let\Eflushleft = \afterenvbreak + +% @flushright. +% +\envdef\flushright{% + \let\nonarrowing = t% + \nonfillstart + \advance\leftskip by 0pt plus 1fill + \gobble +} +\let\Eflushright = \afterenvbreak + + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. We keep \parskip nonzero in general, since +% we're doing normal filling. So, when using \aboveenvbreak and +% \afterenvbreak, temporarily make \parskip 0. +% +\envdef\quotation{% + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \parindent=0pt + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \parsearg\quotationlabel +} + +% We have retained a nonzero parskip for the environment, since we're +% doing normal filling. +% +\def\Equotation{% + \par + \ifx\quotationauthor\undefined\else + % indent a bit. + \leftline{\kern 2\leftskip \sl ---\quotationauthor}% + \fi + {\parskip=0pt \afterenvbreak}% +} + +% If we're given an argument, typeset it in bold with a colon after. +\def\quotationlabel#1{% + \def\temp{#1}% + \ifx\temp\empty \else + {\bf #1: }% + \fi +} + + +% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>} +% If we want to allow any <char> as delimiter, +% we need the curly braces so that makeinfo sees the @verb command, eg: +% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org +% +% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. +% +% [Knuth] p.344; only we need to do the other characters Texinfo sets +% active too. Otherwise, they get lost as the first character on a +% verbatim line. +\def\dospecials{% + \do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% + \do\<\do\>\do\|\do\@\do+\do\"% +} +% +% [Knuth] p. 380 +\def\uncatcodespecials{% + \def\do##1{\catcode`##1=\other}\dospecials} +% +% [Knuth] pp. 380,381,391 +% Disable Spanish ligatures ?` and !` of \tt font +\begingroup + \catcode`\`=\active\gdef`{\relax\lq} +\endgroup +% +% Setup for the @verb command. +% +% Eight spaces for a tab +\begingroup + \catcode`\^^I=\active + \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} +\endgroup +% +\def\setupverb{% + \tt % easiest (and conventionally used) font for verbatim + \def\par{\leavevmode\endgraf}% + \catcode`\`=\active + \tabeightspaces + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces +} + +% Setup for the @verbatim environment +% +% Real tab expansion +\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount +% +\def\starttabbox{\setbox0=\hbox\bgroup} + +% Allow an option to not replace quotes with a regular directed right +% quote/apostrophe (char 0x27), but instead use the undirected quote +% from cmtt (char 0x0d). The undirected quote is ugly, so don't make it +% the default, but it works for pasting with more pdf viewers (at least +% evince), the lilypond developers report. xpdf does work with the +% regular 0x27. +% +\def\codequoteright{% + \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax + \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax + '% + \else \char'15 \fi + \else \char'15 \fi +} +% +% and a similar option for the left quote char vs. a grave accent. +% Modern fonts display ASCII 0x60 as a grave accent, so some people like +% the code environments to do likewise. +% +\def\codequoteleft{% + \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax + \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax + `% + \else \char'22 \fi + \else \char'22 \fi +} +% +\begingroup + \catcode`\^^I=\active + \gdef\tabexpand{% + \catcode`\^^I=\active + \def^^I{\leavevmode\egroup + \dimen0=\wd0 % the width so far, or since the previous tab + \divide\dimen0 by\tabw + \multiply\dimen0 by\tabw % compute previous multiple of \tabw + \advance\dimen0 by\tabw % advance to next multiple of \tabw + \wd0=\dimen0 \box0 \starttabbox + }% + } + \catcode`\'=\active + \gdef\rquoteexpand{\catcode\rquoteChar=\active \def'{\codequoteright}}% + % + \catcode`\`=\active + \gdef\lquoteexpand{\catcode\lquoteChar=\active \def`{\codequoteleft}}% + % + \gdef\quoteexpand{\rquoteexpand \lquoteexpand}% +\endgroup + +% start the verbatim environment. +\def\setupverbatim{% + \let\nonarrowing = t% + \nonfillstart + % Easiest (and conventionally used) font for verbatim + \tt + \def\par{\leavevmode\egroup\box0\endgraf}% + \catcode`\`=\active + \tabexpand + \quoteexpand + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces + \everypar{\starttabbox}% +} + +% Do the @verb magic: verbatim text is quoted by unique +% delimiter characters. Before first delimiter expect a +% right brace, after last delimiter expect closing brace: +% +% \def\doverb'{'<char>#1<char>'}'{#1} +% +% [Knuth] p. 382; only eat outer {} +\begingroup + \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other + \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] +\endgroup +% +\def\verb{\begingroup\setupverb\doverb} +% +% +% Do the @verbatim magic: define the macro \doverbatim so that +% the (first) argument ends when '@end verbatim' is reached, ie: +% +% \def\doverbatim#1@end verbatim{#1} +% +% For Texinfo it's a lot easier than for LaTeX, +% because texinfo's \verbatim doesn't stop at '\end{verbatim}': +% we need not redefine '\', '{' and '}'. +% +% Inspired by LaTeX's verbatim command set [latex.ltx] +% +\begingroup + \catcode`\ =\active + \obeylines % + % ignore everything up to the first ^^M, that's the newline at the end + % of the @verbatim input line itself. Otherwise we get an extra blank + % line in the output. + \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% + % We really want {...\end verbatim} in the body of the macro, but + % without the active space; thus we have to use \xdef and \gobble. +\endgroup +% +\envdef\verbatim{% + \setupverbatim\doverbatim +} +\let\Everbatim = \afterenvbreak + + +% @verbatiminclude FILE - insert text of file in verbatim environment. +% +\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} +% +\def\doverbatiminclude#1{% + {% + \makevalueexpandable + \setupverbatim + \input #1 + \afterenvbreak + }% +} + +% @copying ... @end copying. +% Save the text away for @insertcopying later. +% +% We save the uninterpreted tokens, rather than creating a box. +% Saving the text in a box would be much easier, but then all the +% typesetting commands (@smallbook, font changes, etc.) have to be done +% beforehand -- and a) we want @copying to be done first in the source +% file; b) letting users define the frontmatter in as flexible order as +% possible is very desirable. +% +\def\copying{\checkenv{}\begingroup\scanargctxt\docopying} +\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} +% +\def\insertcopying{% + \begingroup + \parindent = 0pt % paragraph indentation looks wrong on title page + \scanexp\copyingtext + \endgroup +} + + +\message{defuns,} +% @defun etc. + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deflastargmargin \deflastargmargin=18pt +\newcount\defunpenalty + +% Start the processing of @deffn: +\def\startdefun{% + \ifnum\lastpenalty<10000 + \medbreak + \defunpenalty=10003 % Will keep this @deffn together with the + % following @def command, see below. + \else + % If there are two @def commands in a row, we'll have a \nobreak, + % which is there to keep the function description together with its + % header. But if there's nothing but headers, we need to allow a + % break somewhere. Check specifically for penalty 10002, inserted + % by \printdefunline, instead of 10000, since the sectioning + % commands also insert a nobreak penalty, and we don't want to allow + % a break between a section heading and a defun. + % + % As a minor refinement, we avoid "club" headers by signalling + % with penalty of 10003 after the very first @deffn in the + % sequence (see above), and penalty of 10002 after any following + % @def command. + \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi + % + % Similarly, after a section heading, do not allow a break. + % But do insert the glue. + \medskip % preceded by discardable penalty, so not a breakpoint + \fi + % + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent +} + +\def\dodefunx#1{% + % First, check whether we are in the right environment: + \checkenv#1% + % + % As above, allow line break if we have multiple x headers in a row. + % It's not a great place, though. + \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi + % + % And now, it's time to reuse the body of the original defun: + \expandafter\gobbledefun#1% +} +\def\gobbledefun#1\startdefun{} + +% \printdefunline \deffnheader{text} +% +\def\printdefunline#1#2{% + \begingroup + % call \deffnheader: + #1#2 \endheader + % common ending: + \interlinepenalty = 10000 + \advance\rightskip by 0pt plus 1fil + \endgraf + \nobreak\vskip -\parskip + \penalty\defunpenalty % signal to \startdefun and \dodefunx + % Some of the @defun-type tags do not enable magic parentheses, + % rendering the following check redundant. But we don't optimize. + \checkparencounts + \endgroup +} + +\def\Edefun{\endgraf\medbreak} + +% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; +% the only thing remaining is to define \deffnheader. +% +\def\makedefun#1{% + \expandafter\let\csname E#1\endcsname = \Edefun + \edef\temp{\noexpand\domakedefun + \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% + \temp +} + +% \domakedefun \deffn \deffnx \deffnheader +% +% Define \deffn and \deffnx, without parameters. +% \deffnheader has to be defined explicitly. +% +\def\domakedefun#1#2#3{% + \envdef#1{% + \startdefun + \parseargusing\activeparens{\printdefunline#3}% + }% + \def#2{\dodefunx#1}% + \def#3% +} + +%%% Untyped functions: + +% @deffn category name args +\makedefun{deffn}{\deffngeneral{}} + +% @deffn category class name args +\makedefun{defop}#1 {\defopon{#1\ \putwordon}} + +% \defopon {category on}class name args +\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deffngeneral {subind}category name args +% +\def\deffngeneral#1#2 #3 #4\endheader{% + % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. + \dosubind{fn}{\code{#3}}{#1}% + \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% +} + +%%% Typed functions: + +% @deftypefn category type name args +\makedefun{deftypefn}{\deftypefngeneral{}} + +% @deftypeop category class type name args +\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} + +% \deftypeopon {category on}class type name args +\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deftypefngeneral {subind}category type name args +% +\def\deftypefngeneral#1#2 #3 #4 #5\endheader{% + \dosubind{fn}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Typed variables: + +% @deftypevr category type var args +\makedefun{deftypevr}{\deftypecvgeneral{}} + +% @deftypecv category class type var args +\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} + +% \deftypecvof {category of}class type var args +\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } + +% \deftypecvgeneral {subind}category type var args +% +\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% + \dosubind{vr}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Untyped variables: + +% @defvr category var args +\makedefun{defvr}#1 {\deftypevrheader{#1} {} } + +% @defcv category class var args +\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} + +% \defcvof {category of}class var args +\def\defcvof#1#2 {\deftypecvof{#1}#2 {} } + +%%% Type: +% @deftp category name args +\makedefun{deftp}#1 #2 #3\endheader{% + \doind{tp}{\code{#2}}% + \defname{#1}{}{#2}\defunargs{#3\unskip}% +} + +% Remaining @defun-like shortcuts: +\makedefun{defun}{\deffnheader{\putwordDeffunc} } +\makedefun{defmac}{\deffnheader{\putwordDefmac} } +\makedefun{defspec}{\deffnheader{\putwordDefspec} } +\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } +\makedefun{defvar}{\defvrheader{\putwordDefvar} } +\makedefun{defopt}{\defvrheader{\putwordDefopt} } +\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } +\makedefun{defmethod}{\defopon\putwordMethodon} +\makedefun{deftypemethod}{\deftypeopon\putwordMethodon} +\makedefun{defivar}{\defcvof\putwordInstanceVariableof} +\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} + +% \defname, which formats the name of the @def (not the args). +% #1 is the category, such as "Function". +% #2 is the return type, if any. +% #3 is the function name. +% +% We are followed by (but not passed) the arguments, if any. +% +\def\defname#1#2#3{% + % Get the values of \leftskip and \rightskip as they were outside the @def... + \advance\leftskip by -\defbodyindent + % + % How we'll format the type name. Putting it in brackets helps + % distinguish it from the body text that may end up on the next line + % just below it. + \def\temp{#1}% + \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} + % + % Figure out line sizes for the paragraph shape. + % The first line needs space for \box0; but if \rightskip is nonzero, + % we need only space for the part of \box0 which exceeds it: + \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip + % The continuations: + \dimen2=\hsize \advance\dimen2 by -\defargsindent + % (plain.tex says that \dimen1 should be used only as global.) + \parshape 2 0in \dimen0 \defargsindent \dimen2 + % + % Put the type name to the right margin. + \noindent + \hbox to 0pt{% + \hfil\box0 \kern-\hsize + % \hsize has to be shortened this way: + \kern\leftskip + % Intentionally do not respect \rightskip, since we need the space. + }% + % + % Allow all lines to be underfull without complaint: + \tolerance=10000 \hbadness=10000 + \exdentamount=\defbodyindent + {% + % defun fonts. We use typewriter by default (used to be bold) because: + % . we're printing identifiers, they should be in tt in principle. + % . in languages with many accents, such as Czech or French, it's + % common to leave accents off identifiers. The result looks ok in + % tt, but exceedingly strange in rm. + % . we don't want -- and --- to be treated as ligatures. + % . this still does not fix the ?` and !` ligatures, but so far no + % one has made identifiers using them :). + \df \tt + \def\temp{#2}% return value type + \ifx\temp\empty\else \tclose{\temp} \fi + #3% output function name + }% + {\rm\enskip}% hskip 0.5 em of \tenrm + % + \boldbrax + % arguments will be output next, if any. +} + +% Print arguments in slanted roman (not ttsl), inconsistently with using +% tt for the name. This is because literal text is sometimes needed in +% the argument list (groff manual), and ttsl and tt are not very +% distinguishable. Prevent hyphenation at `-' chars. +% +\def\defunargs#1{% + % use sl by default (not ttsl), + % tt for the names. + \df \sl \hyphenchar\font=0 + % + % On the other hand, if an argument has two dashes (for instance), we + % want a way to get ttsl. Let's try @var for that. + \let\var=\ttslanted + #1% + \sl\hyphenchar\font=45 +} + +% We want ()&[] to print specially on the defun line. +% +\def\activeparens{% + \catcode`\(=\active \catcode`\)=\active + \catcode`\[=\active \catcode`\]=\active + \catcode`\&=\active +} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +{ + \activeparens + \global\let(=\lparen \global\let)=\rparen + \global\let[=\lbrack \global\let]=\rbrack + \global\let& = \& + + \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + \gdef\magicamp{\let&=\amprm} +} + +\newcount\parencount + +% If we encounter &foo, then turn on ()-hacking afterwards +\newif\ifampseen +\def\amprm#1 {\ampseentrue{\bf\ }} + +\def\parenfont{% + \ifampseen + % At the first level, print parens in roman, + % otherwise use the default font. + \ifnum \parencount=1 \rm \fi + \else + % The \sf parens (in \boldbrax) actually are a little bolder than + % the contained text. This is especially needed for [ and ] . + \sf + \fi +} +\def\infirstlevel#1{% + \ifampseen + \ifnum\parencount=1 + #1% + \fi + \fi +} +\def\bfafterword#1 {#1 \bf} + +\def\opnr{% + \global\advance\parencount by 1 + {\parenfont(}% + \infirstlevel \bfafterword +} +\def\clnr{% + {\parenfont)}% + \infirstlevel \sl + \global\advance\parencount by -1 +} + +\newcount\brackcount +\def\lbrb{% + \global\advance\brackcount by 1 + {\bf[}% +} +\def\rbrb{% + {\bf]}% + \global\advance\brackcount by -1 +} + +\def\checkparencounts{% + \ifnum\parencount=0 \else \badparencount \fi + \ifnum\brackcount=0 \else \badbrackcount \fi +} +% these should not use \errmessage; the glibc manual, at least, actually +% has such constructs (when documenting function pointers). +\def\badparencount{% + \message{Warning: unbalanced parentheses in @def...}% + \global\parencount=0 +} +\def\badbrackcount{% + \message{Warning: unbalanced square brackets in @def...}% + \global\brackcount=0 +} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scantokens#1{% + \toks0={#1}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \input \jobname.tmp + } +\fi + +\def\scanmacro#1{% + \begingroup + \newlinechar`\^^M + \let\xeatspaces\eatspaces + % Undo catcode changes of \startcontents and \doprintindex + % When called from @insertcopying or (short)caption, we need active + % backslash to get it printed correctly. Previously, we had + % \catcode`\\=\other instead. We'll see whether a problem appears + % with macro expansion. --kasal, 19aug04 + \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ + % ... and \example + \spaceisspace + % + % Append \endinput to make sure that TeX does not see the ending newline. + % I've verified that it is necessary both for e-TeX and for ordinary TeX + % --kasal, 29nov03 + \scantokens{#1\endinput}% + \endgroup +} + +\def\scanexp#1{% + \edef\temp{\noexpand\scanmacro{#1}}% + \temp +} + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? + +% List of all defined macros in the form +% \definedummyword\macro1\definedummyword\macro2... +% Currently is also contains all @aliases; the list can be split +% if there is a need. +\def\macrolist{} + +% Add the macro to \macrolist +\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} +\def\addtomacrolistxxx#1{% + \toks0 = \expandafter{\macrolist\definedummyword#1}% + \xdef\macrolist{\the\toks0}% +} + +% Utility routines. +% This does \let #1 = #2, with \csnames; that is, +% \let \csname#1\endcsname = \csname#2\endcsname +% (except of course we have to play expansion games). +% +\def\cslet#1#2{% + \expandafter\let + \csname#1\expandafter\endcsname + \csname#2\endcsname +} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=\other \catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% Non-ASCII encodings make 8-bit characters active, so un-activate +% them to avoid their expansion. Must do this non-globally, to +% confine the change to the current group. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\scanctxt{% + \catcode`\"=\other + \catcode`\+=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\@=\other + \catcode`\^=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\~=\other + \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi +} + +\def\scanargctxt{% + \scanctxt + \catcode`\\=\other + \catcode`\^^M=\other +} + +\def\macrobodyctxt{% + \scanctxt + \catcode`\{=\other + \catcode`\}=\other + \catcode`\^^M=\other + \usembodybackslash +} + +\def\macroargctxt{% + \scanctxt + \catcode`\\=\other +} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{Macro name \the\macname\space already defined}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + \addtomacrolist{\the\macname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\parseargdef\unmacro{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist: + \begingroup + \expandafter\let\csname#1\endcsname \relax + \let\definedummyword\unmacrodo + \xdef\macrolist{\macrolist}% + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% Called by \do from \dounmacro on each macro. The idea is to omit any +% macro definitions that have been changed to \relax. +% +\def\unmacrodo#1{% + \ifx #1\relax + % remove this + \else + \noexpand\definedummyword \noexpand#1% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% <parameter list> is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \macnamexxx} + + +% @alias. +% We need some trickery to remove the optional spaces around the equal +% sign. Just make them active and then expand them all to nothing. +\def\alias{\parseargusing\obeyspaces\aliasxxx} +\def\aliasxxx #1{\aliasyyy#1\relax} +\def\aliasyyy #1=#2\relax{% + {% + \expandafter\let\obeyedspace=\empty + \addtomacrolist{#1}% + \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% + }% + \next +} + + +\message{cross references,} + +\newwrite\auxfile +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's only job in TeX is to define \lastnode, which is used in +% cross-references. The @node line might or might not have commas, and +% might or might not have spaces before the first comma, like: +% @node foo , bar , ... +% We don't want such trailing spaces in the node name. +% +\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} +% +% also remove a trailing comma, in case of something like this: +% @node Help-Cross, , , Cross-refs +\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} +\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} + +\let\nwnode=\node +\let\lastnode=\empty + +% Write a cross-reference definition for the current node. #1 is the +% type (Ynumbered, Yappendix, Ynothing). +% +\def\donoderef#1{% + \ifx\lastnode\empty\else + \setref{\lastnode}{#1}% + \global\let\lastnode=\empty + \fi +} + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\newcount\savesfregister +% +\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} +\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} +\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} + +% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an +% anchor), which consists of three parts: +% 1) NAME-title - the current sectioning name taken from \lastsection, +% or the anchor name. +% 2) NAME-snt - section number and type, passed as the SNT arg, or +% empty for anchors. +% 3) NAME-pg - the page number. +% +% This is called from \donoderef, \anchor, and \dofloat. In the case of +% floats, there is an additional part, which is not written here: +% 4) NAME-lof - the text as it should appear in a @listoffloats. +% +\def\setref#1#2{% + \pdfmkdest{#1}% + \iflinks + {% + \atdummies % preserve commands, but don't expand them + \edef\writexrdef##1##2{% + \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef + ##1}{##2}}% these are parameters of \writexrdef + }% + \toks0 = \expandafter{\lastsection}% + \immediate \writexrdef{title}{\the\toks0 }% + \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. + \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, during \shipout + }% + \fi +} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \unsepspaces + \def\printedmanual{\ignorespaces #5}% + \def\printedrefname{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual\unskip}% + \setbox0=\hbox{\printedrefname\unskip}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printedrefname{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printedrefname{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printedrefname{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printedrefname{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % Make link in pdf output. + \ifpdf + {\indexnofonts + \turnoffactive + % This expands tokens, so do it after making catcode changes, so _ + % etc. don't get their TeX definitions. + \getfilename{#4}% + % + % See comments at \activebackslashdouble. + {\activebackslashdouble \xdef\pdfxrefdest{#1}% + \backslashparens\pdfxrefdest}% + % + \leavevmode + \startlink attr{/Border [0 0 0]}% + \ifnum\filenamelength>0 + goto file{\the\filename.pdf} name{\pdfxrefdest}% + \else + goto name{\pdfmkpgn{\pdfxrefdest}}% + \fi + }% + \setcolor{\linkcolor}% + \fi + % + % Float references are printed completely differently: "Figure 1.2" + % instead of "[somenode], p.3". We distinguish them by the + % LABEL-title being set to a magic string. + {% + % Have to otherify everything special to allow the \csname to + % include an _ in the xref name, etc. + \indexnofonts + \turnoffactive + \expandafter\global\expandafter\let\expandafter\Xthisreftitle + \csname XR#1-title\endcsname + }% + \iffloat\Xthisreftitle + % If the user specified the print name (third arg) to the ref, + % print it instead of our usual "Figure 1.2". + \ifdim\wd0 = 0pt + \refx{#1-snt}{}% + \else + \printedrefname + \fi + % + % if the user also gave the printed manual name (fifth arg), append + % "in MANUALNAME". + \ifdim \wd1 > 0pt + \space \putwordin{} \cite{\printedmanual}% + \fi + \else + % node/anchor (non-float) references. + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordSection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % output the `[mynode]' via a macro so it can be overridden. + \xrefprintnodename\printedrefname + % + % But we always want a comma and a space: + ,\space + % + % output the `page 3'. + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi + \fi + \endlink +\endgroup} + +% This macro is called from \xrefX for the `[nodename]' part of xref +% output. It's a separate macro only so it can be changed more easily, +% since square brackets don't work well in some documents. Particularly +% one that Bob is working on :). +% +\def\xrefprintnodename#1{[#1]} + +% Things referred to by \setref. +% +\def\Ynothing{} +\def\Yomitfromtoc{} +\def\Ynumbered{% + \ifnum\secno=0 + \putwordChapter@tie \the\chapno + \else \ifnum\subsecno=0 + \putwordSection@tie \the\chapno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno + \else + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} +\def\Yappendix{% + \ifnum\secno=0 + \putwordAppendix@tie @char\the\appendixno{}% + \else \ifnum\subsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno + \else + \putwordSection@tie + @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. +% +\def\refx#1#2{% + {% + \indexnofonts + \otherbackslash + \expandafter\global\expandafter\let\expandafter\thisrefX + \csname XR#1\endcsname + }% + \ifx\thisrefX\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \thisrefX + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. Usually it's +% just a \def (we prepend XR to the control sequence name to avoid +% collisions). But if this is a float type, we have more work to do. +% +\def\xrdef#1#2{% + {% The node name might contain 8-bit characters, which in our current + % implementation are changed to commands like @'e. Don't let these + % mess up the control sequence name. + \indexnofonts + \turnoffactive + \xdef\safexrefname{#1}% + }% + % + \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref + % + % Was that xref control sequence that we just defined for a float? + \expandafter\iffloat\csname XR\safexrefname\endcsname + % it was a float, and we have the (safe) float type in \iffloattype. + \expandafter\let\expandafter\floatlist + \csname floatlist\iffloattype\endcsname + % + % Is this the first time we've seen this float type? + \expandafter\ifx\floatlist\relax + \toks0 = {\do}% yes, so just \do + \else + % had it before, so preserve previous elements in list. + \toks0 = \expandafter{\floatlist\do}% + \fi + % + % Remember this xref in the control sequence \floatlistFLOATTYPE, + % for later use in \listoffloats. + \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 + {\safexrefname}}% + \fi +} + +% Read the last existing aux file, if any. No error if none exists. +% +\def\tryauxfile{% + \openin 1 \jobname.aux + \ifeof 1 \else + \readdatafile{aux}% + \global\havexrefstrue + \fi + \closein 1 +} + +\def\setupdatafile{% + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\^=\other + % + % Special characters. Should be turned off anyway, but... + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`\%=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % + % This is to support \ in node names and titles, since the \ + % characters end up in a \csname. It's easier than + % leaving it active and making its active definition an actual \ + % character. What I don't understand is why it works in the *value* + % of the xrdef. Seems like it should be a catcode12 \, and that + % should not typeset properly. But it works, so I'm moving on for + % now. --karl, 15jan04. + \catcode`\\=\other + % + % Make the characters 128-255 be printing characters. + {% + \count1=128 + \def\loop{% + \catcode\count1=\other + \advance\count1 by 1 + \ifnum \count1<256 \loop \fi + }% + }% + % + % @ is our escape character in .aux files, and we need braces. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\@=0 +} + +\def\readdatafile#1{% +\begingroup + \setupdatafile + \input\jobname.#1 +\endgroup} + + +\message{insertions,} +% including footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \dofootnote +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset (and anything else that uses +% \parseargline) fails inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\gdef\dofootnote{% + \insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \hsize=\pagewidth + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + \smallfonts \rm + % + % Because we use hanging indentation in footnotes, a @noindent appears + % to exdent this text, so make it be a no-op. makeinfo does not use + % hanging indentation so @noindent can still be needed within footnote + % text after an @example or the like (not that this is good style). + \let\noindent = \relax + % + % Hang the footnote text off the number. Use \everypar in case the + % footnote extends for more than one paragraph. + \everypar = {\hang}% + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +}%end \catcode `\@=11 + +% In case a @footnote appears in a vbox, save the footnote text and create +% the real \insert just after the vbox finished. Otherwise, the insertion +% would be lost. +% Similarly, if a @footnote appears inside an alignment, save the footnote +% text to a box and make the \insert when a row of the table is finished. +% And the same can be done for other insert classes. --kasal, 16nov03. + +% Replace the \insert primitive by a cheating macro. +% Deeper inside, just make sure that the saved insertions are not spilled +% out prematurely. +% +\def\startsavinginserts{% + \ifx \insert\ptexinsert + \let\insert\saveinsert + \else + \let\checkinserts\relax + \fi +} + +% This \insert replacement works for both \insert\footins{foo} and +% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. +% +\def\saveinsert#1{% + \edef\next{\noexpand\savetobox \makeSAVEname#1}% + \afterassignment\next + % swallow the left brace + \let\temp = +} +\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} +\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} + +\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} + +\def\placesaveins#1{% + \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname + {\box#1}% +} + +% eat @SAVE -- beware, all of them have catcode \other: +{ + \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) + \gdef\gobblesave @SAVE{} +} + +% initialization: +\def\newsaveins #1{% + \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% + \next +} +\def\newsaveinsX #1{% + \csname newbox\endcsname #1% + \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts + \checksaveins #1}% +} + +% initialize: +\let\checkinserts\empty +\newsaveins\footins +\newsaveins\margin + + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + % Do not bother showing banner with epsf.tex v2.7k (available in + % doc/epsf.tex and on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +\closein 1 +% +% We will only complain once about lack of epsf.tex. +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is (ignored optional) html alt text. +% #5 is (ignored optional) extension. +% #6 is just the usual extra ignored arg for parsing this stuff. +\newif\ifimagevmode +\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup + \catcode`\^^M = 5 % in case we're inside an example + \normalturnoffactive % allow _ et al. in names + % If the image is by itself, center it. + \ifvmode + \imagevmodetrue + \nobreak\medskip + % Usually we'll have text after the image which will insert + % \parskip glue, so insert it here too to equalize the space + % above and below. + \nobreak\vskip\parskip + \nobreak + \fi + % + % Leave vertical mode so that indentation from an enclosing + % environment such as @quotation is respected. On the other hand, if + % it's at the top level, we don't want the normal paragraph indentation. + \noindent + % + % Output the image. + \ifpdf + \dopdfimage{#1}{#2}{#3}% + \else + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \epsfbox{#1.eps}% + \fi + % + \ifimagevmode \medskip \fi % space after the standalone image +\endgroup} + + +% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, +% etc. We don't actually implement floating yet, we always include the +% float "here". But it seemed the best name for the future. +% +\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} + +% There may be a space before second and/or third parameter; delete it. +\def\eatcommaspace#1, {#1,} + +% #1 is the optional FLOATTYPE, the text label for this float, typically +% "Figure", "Table", "Example", etc. Can't contain commas. If omitted, +% this float will not be numbered and cannot be referred to. +% +% #2 is the optional xref label. Also must be present for the float to +% be referable. +% +% #3 is the optional positioning argument; for now, it is ignored. It +% will somehow specify the positions allowed to float to (here, top, bottom). +% +% We keep a separate counter for each FLOATTYPE, which we reset at each +% chapter-level command. +\let\resetallfloatnos=\empty +% +\def\dofloat#1,#2,#3,#4\finish{% + \let\thiscaption=\empty + \let\thisshortcaption=\empty + % + % don't lose footnotes inside @float. + % + % BEWARE: when the floats start float, we have to issue warning whenever an + % insert appears inside a float which could possibly float. --kasal, 26may04 + % + \startsavinginserts + % + % We can't be used inside a paragraph. + \par + % + \vtop\bgroup + \def\floattype{#1}% + \def\floatlabel{#2}% + \def\floatloc{#3}% we do nothing with this yet. + % + \ifx\floattype\empty + \let\safefloattype=\empty + \else + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + \fi + % + % If label is given but no type, we handle that as the empty type. + \ifx\floatlabel\empty \else + % We want each FLOATTYPE to be numbered separately (Figure 1, + % Table 1, Figure 2, ...). (And if no label, no number.) + % + \expandafter\getfloatno\csname\safefloattype floatno\endcsname + \global\advance\floatno by 1 + % + {% + % This magic value for \lastsection is output by \setref as the + % XREFLABEL-title value. \xrefX uses it to distinguish float + % labels (which have a completely different output format) from + % node and anchor labels. And \xrdef uses it to construct the + % lists of floats. + % + \edef\lastsection{\floatmagic=\safefloattype}% + \setref{\floatlabel}{Yfloat}% + }% + \fi + % + % start with \parskip glue, I guess. + \vskip\parskip + % + % Don't suppress indentation if a float happens to start a section. + \restorefirstparagraphindent +} + +% we have these possibilities: +% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap +% @float Foo,lbl & no caption: Foo 1.1 +% @float Foo & @caption{Cap}: Foo: Cap +% @float Foo & no caption: Foo +% @float ,lbl & Caption{Cap}: 1.1: Cap +% @float ,lbl & no caption: 1.1 +% @float & @caption{Cap}: Cap +% @float & no caption: +% +\def\Efloat{% + \let\floatident = \empty + % + % In all cases, if we have a float type, it comes first. + \ifx\floattype\empty \else \def\floatident{\floattype}\fi + % + % If we have an xref label, the number comes next. + \ifx\floatlabel\empty \else + \ifx\floattype\empty \else % if also had float type, need tie first. + \appendtomacro\floatident{\tie}% + \fi + % the number. + \appendtomacro\floatident{\chaplevelprefix\the\floatno}% + \fi + % + % Start the printed caption with what we've constructed in + % \floatident, but keep it separate; we need \floatident again. + \let\captionline = \floatident + % + \ifx\thiscaption\empty \else + \ifx\floatident\empty \else + \appendtomacro\captionline{: }% had ident, so need a colon between + \fi + % + % caption text. + \appendtomacro\captionline{\scanexp\thiscaption}% + \fi + % + % If we have anything to print, print it, with space before. + % Eventually this needs to become an \insert. + \ifx\captionline\empty \else + \vskip.5\parskip + \captionline + % + % Space below caption. + \vskip\parskip + \fi + % + % If have an xref label, write the list of floats info. Do this + % after the caption, to avoid chance of it being a breakpoint. + \ifx\floatlabel\empty \else + % Write the text that goes in the lof to the aux file as + % \floatlabel-lof. Besides \floatident, we include the short + % caption if specified, else the full caption if specified, else nothing. + {% + \atdummies + % + % since we read the caption text in the macro world, where ^^M + % is turned into a normal character, we have to scan it back, so + % we don't write the literal three characters "^^M" into the aux file. + \scanexp{% + \xdef\noexpand\gtemp{% + \ifx\thisshortcaption\empty + \thiscaption + \else + \thisshortcaption + \fi + }% + }% + \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident + \ifx\gtemp\empty \else : \gtemp \fi}}% + }% + \fi + \egroup % end of \vtop + % + % place the captured inserts + % + % BEWARE: when the floats start floating, we have to issue warning + % whenever an insert appears inside a float which could possibly + % float. --kasal, 26may04 + % + \checkinserts +} + +% Append the tokens #2 to the definition of macro #1, not expanding either. +% +\def\appendtomacro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}% +} + +% @caption, @shortcaption +% +\def\caption{\docaption\thiscaption} +\def\shortcaption{\docaption\thisshortcaption} +\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} +\def\defcaption#1#2{\egroup \def#1{#2}} + +% The parameter is the control sequence identifying the counter we are +% going to use. Create it if it doesn't exist and assign it to \floatno. +\def\getfloatno#1{% + \ifx#1\relax + % Haven't seen this figure type before. + \csname newcount\endcsname #1% + % + % Remember to reset this floatno at the next chap. + \expandafter\gdef\expandafter\resetallfloatnos + \expandafter{\resetallfloatnos #1=0 }% + \fi + \let\floatno#1% +} + +% \setref calls this to get the XREFLABEL-snt value. We want an @xref +% to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we +% first read the @float command. +% +\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% + +% Magic string used for the XREFLABEL-title value, so \xrefX can +% distinguish floats from other xref types. +\def\floatmagic{!!float!!} + +% #1 is the control sequence we are passed; we expand into a conditional +% which is true if #1 represents a float ref. That is, the magic +% \lastsection value which we \setref above. +% +\def\iffloat#1{\expandafter\doiffloat#1==\finish} +% +% #1 is (maybe) the \floatmagic string. If so, #2 will be the +% (safe) float type for this float. We set \iffloattype to #2. +% +\def\doiffloat#1=#2=#3\finish{% + \def\temp{#1}% + \def\iffloattype{#2}% + \ifx\temp\floatmagic +} + +% @listoffloats FLOATTYPE - print a list of floats like a table of contents. +% +\parseargdef\listoffloats{% + \def\floattype{#1}% floattype + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + % + % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. + \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax + \ifhavexrefs + % if the user said @listoffloats foo but never @float foo. + \message{\linenumber No `\safefloattype' floats to list.}% + \fi + \else + \begingroup + \leftskip=\tocindent % indent these entries like a toc + \let\do=\listoffloatsdo + \csname floatlist\safefloattype\endcsname + \endgroup + \fi +} + +% This is called on each entry in a list of floats. We're passed the +% xref label, in the form LABEL-title, which is how we save it in the +% aux file. We strip off the -title and look up \XRLABEL-lof, which +% has the text we're supposed to typeset here. +% +% Figures without xref labels will not be included in the list (since +% they won't appear in the aux file). +% +\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} +\def\listoffloatsdoentry#1-title\finish{{% + % Can't fully expand XR#1-lof because it can contain anything. Just + % pass the control sequence. On the other hand, XR#1-pg is just the + % page number, and we want to fully expand that so we can get a link + % in pdf output. + \toksA = \expandafter{\csname XR#1-lof\endcsname}% + % + % use the same \entry macro we use to generate the TOC and index. + \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% + \writeentry +}} + + +\message{localization,} + +% @documentlanguage is usually given very early, just after +% @setfilename. If done too late, it may not override everything +% properly. Single argument is the language (de) or locale (de_DE) +% abbreviation. It would be nice if we could set up a hyphenation file. +% +{ + \catcode`\_ = \active + \globaldefs=1 +\parseargdef\documentlanguage{\begingroup + \let_=\normalunderscore % normal _ character for filenames + \tex % read txi-??.tex file in plain TeX. + % Read the file by the name they passed if it exists. + \openin 1 txi-#1.tex + \ifeof 1 + \documentlanguagetrywithoutunderscore{#1_\finish}% + \else + \input txi-#1.tex + \fi + \closein 1 + \endgroup +\endgroup} +} +% +% If they passed de_DE, and txi-de_DE.tex doesn't exist, +% try txi-de.tex. +% +\def\documentlanguagetrywithoutunderscore#1_#2\finish{% + \openin 1 txi-#1.tex + \ifeof 1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \else + \input txi-#1.tex + \fi + \closein 1 +} +% +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? In the current directory +should work if nowhere else does.} + +% Set the catcode of characters 128 through 255 to the specified number. +% +\def\setnonasciicharscatcode#1{% + \count255=128 + \loop\ifnum\count255<256 + \global\catcode\count255=#1\relax + \advance\count255 by 1 + \repeat +} + +\def\setnonasciicharscatcodenonglobal#1{% + \count255=128 + \loop\ifnum\count255<256 + \catcode\count255=#1\relax + \advance\count255 by 1 + \repeat +} + +% @documentencoding sets the definition of non-ASCII characters +% according to the specified encoding. +% +\parseargdef\documentencoding{% + % Encoding being declared for the document. + \def\declaredencoding{\csname #1.enc\endcsname}% + % + % Supported encodings: names converted to tokens in order to be able + % to compare them with \ifx. + \def\ascii{\csname US-ASCII.enc\endcsname}% + \def\latnine{\csname ISO-8859-15.enc\endcsname}% + \def\latone{\csname ISO-8859-1.enc\endcsname}% + \def\lattwo{\csname ISO-8859-2.enc\endcsname}% + \def\utfeight{\csname UTF-8.enc\endcsname}% + % + \ifx \declaredencoding \ascii + \asciichardefs + % + \else \ifx \declaredencoding \lattwo + \setnonasciicharscatcode\active + \lattwochardefs + % + \else \ifx \declaredencoding \latone + \setnonasciicharscatcode\active + \latonechardefs + % + \else \ifx \declaredencoding \latnine + \setnonasciicharscatcode\active + \latninechardefs + % + \else \ifx \declaredencoding \utfeight + \setnonasciicharscatcode\active + \utfeightchardefs + % + \else + \message{Unknown document encoding #1, ignoring.}% + % + \fi % utfeight + \fi % latnine + \fi % latone + \fi % lattwo + \fi % ascii +} + +% A message to be logged when using a character that isn't available +% the default font encoding (OT1). +% +\def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}} + +% Take account of \c (plain) vs. \, (Texinfo) difference. +\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} + +% First, make active non-ASCII characters in order for them to be +% correctly categorized when TeX reads the replacement text of +% macros containing the character definitions. +\setnonasciicharscatcode\active +% +% Latin1 (ISO-8859-1) character definitions. +\def\latonechardefs{% + \gdef^^a0{~} + \gdef^^a1{\exclamdown} + \gdef^^a2{\missingcharmsg{CENT SIGN}} + \gdef^^a3{{\pounds}} + \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdef^^a5{\missingcharmsg{YEN SIGN}} + \gdef^^a6{\missingcharmsg{BROKEN BAR}} + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\copyright} + \gdef^^aa{\ordf} + \gdef^^ab{\missingcharmsg{LEFT-POINTING DOUBLE ANGLE QUOTATION MARK}} + \gdef^^ac{$\lnot$} + \gdef^^ad{\-} + \gdef^^ae{\registeredsymbol} + \gdef^^af{\={}} + % + \gdef^^b0{\textdegree} + \gdef^^b1{$\pm$} + \gdef^^b2{$^2$} + \gdef^^b3{$^3$} + \gdef^^b4{\'{}} + \gdef^^b5{$\mu$} + \gdef^^b6{\P} + % + \gdef^^b7{$^.$} + \gdef^^b8{\cedilla\ } + \gdef^^b9{$^1$} + \gdef^^ba{\ordm} + % + \gdef^^bb{\missingcharmsg{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK}} + \gdef^^bc{$1\over4$} + \gdef^^bd{$1\over2$} + \gdef^^be{$3\over4$} + \gdef^^bf{\questiondown} + % + \gdef^^c0{\`A} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\~A} + \gdef^^c4{\"A} + \gdef^^c5{\ringaccent A} + \gdef^^c6{\AE} + \gdef^^c7{\cedilla C} + \gdef^^c8{\`E} + \gdef^^c9{\'E} + \gdef^^ca{\^E} + \gdef^^cb{\"E} + \gdef^^cc{\`I} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\"I} + % + \gdef^^d0{\missingcharmsg{LATIN CAPITAL LETTER ETH}} + \gdef^^d1{\~N} + \gdef^^d2{\`O} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\~O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\O} + \gdef^^d9{\`U} + \gdef^^da{\'U} + \gdef^^db{\^U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\missingcharmsg{LATIN CAPITAL LETTER THORN}} + \gdef^^df{\ss} + % + \gdef^^e0{\`a} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\~a} + \gdef^^e4{\"a} + \gdef^^e5{\ringaccent a} + \gdef^^e6{\ae} + \gdef^^e7{\cedilla c} + \gdef^^e8{\`e} + \gdef^^e9{\'e} + \gdef^^ea{\^e} + \gdef^^eb{\"e} + \gdef^^ec{\`{\dotless i}} + \gdef^^ed{\'{\dotless i}} + \gdef^^ee{\^{\dotless i}} + \gdef^^ef{\"{\dotless i}} + % + \gdef^^f0{\missingcharmsg{LATIN SMALL LETTER ETH}} + \gdef^^f1{\~n} + \gdef^^f2{\`o} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\~o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\o} + \gdef^^f9{\`u} + \gdef^^fa{\'u} + \gdef^^fb{\^u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\missingcharmsg{LATIN SMALL LETTER THORN}} + \gdef^^ff{\"y} +} + +% Latin9 (ISO-8859-15) encoding character definitions. +\def\latninechardefs{% + % Encoding is almost identical to Latin1. + \latonechardefs + % + \gdef^^a4{\euro} + \gdef^^a6{\v S} + \gdef^^a8{\v s} + \gdef^^b4{\v Z} + \gdef^^b8{\v z} + \gdef^^bc{\OE} + \gdef^^bd{\oe} + \gdef^^be{\"Y} +} + +% Latin2 (ISO-8859-2) character definitions. +\def\lattwochardefs{% + \gdef^^a0{~} + \gdef^^a1{\missingcharmsg{LATIN CAPITAL LETTER A WITH OGONEK}} + \gdef^^a2{\u{}} + \gdef^^a3{\L} + \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdef^^a5{\v L} + \gdef^^a6{\'S} + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\v S} + \gdef^^aa{\cedilla S} + \gdef^^ab{\v T} + \gdef^^ac{\'Z} + \gdef^^ad{\-} + \gdef^^ae{\v Z} + \gdef^^af{\dotaccent Z} + % + \gdef^^b0{\textdegree} + \gdef^^b1{\missingcharmsg{LATIN SMALL LETTER A WITH OGONEK}} + \gdef^^b2{\missingcharmsg{OGONEK}} + \gdef^^b3{\l} + \gdef^^b4{\'{}} + \gdef^^b5{\v l} + \gdef^^b6{\'s} + \gdef^^b7{\v{}} + \gdef^^b8{\cedilla\ } + \gdef^^b9{\v s} + \gdef^^ba{\cedilla s} + \gdef^^bb{\v t} + \gdef^^bc{\'z} + \gdef^^bd{\H{}} + \gdef^^be{\v z} + \gdef^^bf{\dotaccent z} + % + \gdef^^c0{\'R} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\u A} + \gdef^^c4{\"A} + \gdef^^c5{\'L} + \gdef^^c6{\'C} + \gdef^^c7{\cedilla C} + \gdef^^c8{\v C} + \gdef^^c9{\'E} + \gdef^^ca{\missingcharmsg{LATIN CAPITAL LETTER E WITH OGONEK}} + \gdef^^cb{\"E} + \gdef^^cc{\v E} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\v D} + % + \gdef^^d0{\missingcharmsg{LATIN CAPITAL LETTER D WITH STROKE}} + \gdef^^d1{\'N} + \gdef^^d2{\v N} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\H O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\v R} + \gdef^^d9{\ringaccent U} + \gdef^^da{\'U} + \gdef^^db{\H U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\cedilla T} + \gdef^^df{\ss} + % + \gdef^^e0{\'r} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\u a} + \gdef^^e4{\"a} + \gdef^^e5{\'l} + \gdef^^e6{\'c} + \gdef^^e7{\cedilla c} + \gdef^^e8{\v c} + \gdef^^e9{\'e} + \gdef^^ea{\missingcharmsg{LATIN SMALL LETTER E WITH OGONEK}} + \gdef^^eb{\"e} + \gdef^^ec{\v e} + \gdef^^ed{\'\i} + \gdef^^ee{\^\i} + \gdef^^ef{\v d} + % + \gdef^^f0{\missingcharmsg{LATIN SMALL LETTER D WITH STROKE}} + \gdef^^f1{\'n} + \gdef^^f2{\v n} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\H o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\v r} + \gdef^^f9{\ringaccent u} + \gdef^^fa{\'u} + \gdef^^fb{\H u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\cedilla t} + \gdef^^ff{\dotaccent{}} +} + +% UTF-8 character definitions. +% +% This code to support UTF-8 is based on LaTeX's utf8.def, with some +% changes for Texinfo conventions. It is included here under the GPL by +% permission from Frank Mittelbach and the LaTeX team. +% +\newcount\countUTFx +\newcount\countUTFy +\newcount\countUTFz + +\gdef\UTFviiiTwoOctets#1#2{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\endcsname} +% +\gdef\UTFviiiThreeOctets#1#2#3{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} +% +\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} + +\gdef\UTFviiiDefined#1{% + \ifx #1\relax + \message{\linenumber Unicode char \string #1 not defined for Texinfo}% + \else + \expandafter #1% + \fi +} + +\begingroup + \catcode`\~13 + \catcode`\"12 + + \def\UTFviiiLoop{% + \global\catcode\countUTFx\active + \uccode`\~\countUTFx + \uppercase\expandafter{\UTFviiiTmp}% + \advance\countUTFx by 1 + \ifnum\countUTFx < \countUTFy + \expandafter\UTFviiiLoop + \fi} + + \countUTFx = "C2 + \countUTFy = "E0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiTwoOctets\string~}} + \UTFviiiLoop + + \countUTFx = "E0 + \countUTFy = "F0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiThreeOctets\string~}} + \UTFviiiLoop + + \countUTFx = "F0 + \countUTFy = "F4 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiFourOctets\string~}} + \UTFviiiLoop +\endgroup + +\begingroup + \catcode`\"=12 + \catcode`\<=12 + \catcode`\.=12 + \catcode`\,=12 + \catcode`\;=12 + \catcode`\!=12 + \catcode`\~=13 + + \gdef\DeclareUnicodeCharacter#1#2{% + \countUTFz = "#1\relax + \wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% + \begingroup + \parseXMLCharref + \def\UTFviiiTwoOctets##1##2{% + \csname u8:##1\string ##2\endcsname}% + \def\UTFviiiThreeOctets##1##2##3{% + \csname u8:##1\string ##2\string ##3\endcsname}% + \def\UTFviiiFourOctets##1##2##3##4{% + \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \gdef\UTFviiiTmp{#2}% + \endgroup} + + \gdef\parseXMLCharref{% + \ifnum\countUTFz < "A0\relax + \errhelp = \EMsimple + \errmessage{Cannot define Unicode char value < 00A0}% + \else\ifnum\countUTFz < "800\relax + \parseUTFviiiA,% + \parseUTFviiiB C\UTFviiiTwoOctets.,% + \else\ifnum\countUTFz < "10000\relax + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% + \else + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiA!% + \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% + \fi\fi\fi + } + + \gdef\parseUTFviiiA#1{% + \countUTFx = \countUTFz + \divide\countUTFz by 64 + \countUTFy = \countUTFz + \multiply\countUTFz by 64 + \advance\countUTFx by -\countUTFz + \advance\countUTFx by 128 + \uccode `#1\countUTFx + \countUTFz = \countUTFy} + + \gdef\parseUTFviiiB#1#2#3#4{% + \advance\countUTFz by "#10\relax + \uccode `#3\countUTFz + \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} +\endgroup + +\def\utfeightchardefs{% + \DeclareUnicodeCharacter{00A0}{\tie} + \DeclareUnicodeCharacter{00A1}{\exclamdown} + \DeclareUnicodeCharacter{00A3}{\pounds} + \DeclareUnicodeCharacter{00A8}{\"{ }} + \DeclareUnicodeCharacter{00A9}{\copyright} + \DeclareUnicodeCharacter{00AA}{\ordf} + \DeclareUnicodeCharacter{00AB}{\guillemetleft} + \DeclareUnicodeCharacter{00AD}{\-} + \DeclareUnicodeCharacter{00AE}{\registeredsymbol} + \DeclareUnicodeCharacter{00AF}{\={ }} + + \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} + \DeclareUnicodeCharacter{00B4}{\'{ }} + \DeclareUnicodeCharacter{00B8}{\cedilla{ }} + \DeclareUnicodeCharacter{00BA}{\ordm} + \DeclareUnicodeCharacter{00BB}{\guillemetright} + \DeclareUnicodeCharacter{00BF}{\questiondown} + + \DeclareUnicodeCharacter{00C0}{\`A} + \DeclareUnicodeCharacter{00C1}{\'A} + \DeclareUnicodeCharacter{00C2}{\^A} + \DeclareUnicodeCharacter{00C3}{\~A} + \DeclareUnicodeCharacter{00C4}{\"A} + \DeclareUnicodeCharacter{00C5}{\AA} + \DeclareUnicodeCharacter{00C6}{\AE} + \DeclareUnicodeCharacter{00C7}{\cedilla{C}} + \DeclareUnicodeCharacter{00C8}{\`E} + \DeclareUnicodeCharacter{00C9}{\'E} + \DeclareUnicodeCharacter{00CA}{\^E} + \DeclareUnicodeCharacter{00CB}{\"E} + \DeclareUnicodeCharacter{00CC}{\`I} + \DeclareUnicodeCharacter{00CD}{\'I} + \DeclareUnicodeCharacter{00CE}{\^I} + \DeclareUnicodeCharacter{00CF}{\"I} + + \DeclareUnicodeCharacter{00D1}{\~N} + \DeclareUnicodeCharacter{00D2}{\`O} + \DeclareUnicodeCharacter{00D3}{\'O} + \DeclareUnicodeCharacter{00D4}{\^O} + \DeclareUnicodeCharacter{00D5}{\~O} + \DeclareUnicodeCharacter{00D6}{\"O} + \DeclareUnicodeCharacter{00D8}{\O} + \DeclareUnicodeCharacter{00D9}{\`U} + \DeclareUnicodeCharacter{00DA}{\'U} + \DeclareUnicodeCharacter{00DB}{\^U} + \DeclareUnicodeCharacter{00DC}{\"U} + \DeclareUnicodeCharacter{00DD}{\'Y} + \DeclareUnicodeCharacter{00DF}{\ss} + + \DeclareUnicodeCharacter{00E0}{\`a} + \DeclareUnicodeCharacter{00E1}{\'a} + \DeclareUnicodeCharacter{00E2}{\^a} + \DeclareUnicodeCharacter{00E3}{\~a} + \DeclareUnicodeCharacter{00E4}{\"a} + \DeclareUnicodeCharacter{00E5}{\aa} + \DeclareUnicodeCharacter{00E6}{\ae} + \DeclareUnicodeCharacter{00E7}{\cedilla{c}} + \DeclareUnicodeCharacter{00E8}{\`e} + \DeclareUnicodeCharacter{00E9}{\'e} + \DeclareUnicodeCharacter{00EA}{\^e} + \DeclareUnicodeCharacter{00EB}{\"e} + \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} + \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} + \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} + \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} + + \DeclareUnicodeCharacter{00F1}{\~n} + \DeclareUnicodeCharacter{00F2}{\`o} + \DeclareUnicodeCharacter{00F3}{\'o} + \DeclareUnicodeCharacter{00F4}{\^o} + \DeclareUnicodeCharacter{00F5}{\~o} + \DeclareUnicodeCharacter{00F6}{\"o} + \DeclareUnicodeCharacter{00F8}{\o} + \DeclareUnicodeCharacter{00F9}{\`u} + \DeclareUnicodeCharacter{00FA}{\'u} + \DeclareUnicodeCharacter{00FB}{\^u} + \DeclareUnicodeCharacter{00FC}{\"u} + \DeclareUnicodeCharacter{00FD}{\'y} + \DeclareUnicodeCharacter{00FF}{\"y} + + \DeclareUnicodeCharacter{0100}{\=A} + \DeclareUnicodeCharacter{0101}{\=a} + \DeclareUnicodeCharacter{0102}{\u{A}} + \DeclareUnicodeCharacter{0103}{\u{a}} + \DeclareUnicodeCharacter{0106}{\'C} + \DeclareUnicodeCharacter{0107}{\'c} + \DeclareUnicodeCharacter{0108}{\^C} + \DeclareUnicodeCharacter{0109}{\^c} + \DeclareUnicodeCharacter{010A}{\dotaccent{C}} + \DeclareUnicodeCharacter{010B}{\dotaccent{c}} + \DeclareUnicodeCharacter{010C}{\v{C}} + \DeclareUnicodeCharacter{010D}{\v{c}} + \DeclareUnicodeCharacter{010E}{\v{D}} + + \DeclareUnicodeCharacter{0112}{\=E} + \DeclareUnicodeCharacter{0113}{\=e} + \DeclareUnicodeCharacter{0114}{\u{E}} + \DeclareUnicodeCharacter{0115}{\u{e}} + \DeclareUnicodeCharacter{0116}{\dotaccent{E}} + \DeclareUnicodeCharacter{0117}{\dotaccent{e}} + \DeclareUnicodeCharacter{011A}{\v{E}} + \DeclareUnicodeCharacter{011B}{\v{e}} + \DeclareUnicodeCharacter{011C}{\^G} + \DeclareUnicodeCharacter{011D}{\^g} + \DeclareUnicodeCharacter{011E}{\u{G}} + \DeclareUnicodeCharacter{011F}{\u{g}} + + \DeclareUnicodeCharacter{0120}{\dotaccent{G}} + \DeclareUnicodeCharacter{0121}{\dotaccent{g}} + \DeclareUnicodeCharacter{0124}{\^H} + \DeclareUnicodeCharacter{0125}{\^h} + \DeclareUnicodeCharacter{0128}{\~I} + \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} + \DeclareUnicodeCharacter{012A}{\=I} + \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} + \DeclareUnicodeCharacter{012C}{\u{I}} + \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} + + \DeclareUnicodeCharacter{0130}{\dotaccent{I}} + \DeclareUnicodeCharacter{0131}{\dotless{i}} + \DeclareUnicodeCharacter{0132}{IJ} + \DeclareUnicodeCharacter{0133}{ij} + \DeclareUnicodeCharacter{0134}{\^J} + \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} + \DeclareUnicodeCharacter{0139}{\'L} + \DeclareUnicodeCharacter{013A}{\'l} + + \DeclareUnicodeCharacter{0141}{\L} + \DeclareUnicodeCharacter{0142}{\l} + \DeclareUnicodeCharacter{0143}{\'N} + \DeclareUnicodeCharacter{0144}{\'n} + \DeclareUnicodeCharacter{0147}{\v{N}} + \DeclareUnicodeCharacter{0148}{\v{n}} + \DeclareUnicodeCharacter{014C}{\=O} + \DeclareUnicodeCharacter{014D}{\=o} + \DeclareUnicodeCharacter{014E}{\u{O}} + \DeclareUnicodeCharacter{014F}{\u{o}} + + \DeclareUnicodeCharacter{0150}{\H{O}} + \DeclareUnicodeCharacter{0151}{\H{o}} + \DeclareUnicodeCharacter{0152}{\OE} + \DeclareUnicodeCharacter{0153}{\oe} + \DeclareUnicodeCharacter{0154}{\'R} + \DeclareUnicodeCharacter{0155}{\'r} + \DeclareUnicodeCharacter{0158}{\v{R}} + \DeclareUnicodeCharacter{0159}{\v{r}} + \DeclareUnicodeCharacter{015A}{\'S} + \DeclareUnicodeCharacter{015B}{\'s} + \DeclareUnicodeCharacter{015C}{\^S} + \DeclareUnicodeCharacter{015D}{\^s} + \DeclareUnicodeCharacter{015E}{\cedilla{S}} + \DeclareUnicodeCharacter{015F}{\cedilla{s}} + + \DeclareUnicodeCharacter{0160}{\v{S}} + \DeclareUnicodeCharacter{0161}{\v{s}} + \DeclareUnicodeCharacter{0162}{\cedilla{t}} + \DeclareUnicodeCharacter{0163}{\cedilla{T}} + \DeclareUnicodeCharacter{0164}{\v{T}} + + \DeclareUnicodeCharacter{0168}{\~U} + \DeclareUnicodeCharacter{0169}{\~u} + \DeclareUnicodeCharacter{016A}{\=U} + \DeclareUnicodeCharacter{016B}{\=u} + \DeclareUnicodeCharacter{016C}{\u{U}} + \DeclareUnicodeCharacter{016D}{\u{u}} + \DeclareUnicodeCharacter{016E}{\ringaccent{U}} + \DeclareUnicodeCharacter{016F}{\ringaccent{u}} + + \DeclareUnicodeCharacter{0170}{\H{U}} + \DeclareUnicodeCharacter{0171}{\H{u}} + \DeclareUnicodeCharacter{0174}{\^W} + \DeclareUnicodeCharacter{0175}{\^w} + \DeclareUnicodeCharacter{0176}{\^Y} + \DeclareUnicodeCharacter{0177}{\^y} + \DeclareUnicodeCharacter{0178}{\"Y} + \DeclareUnicodeCharacter{0179}{\'Z} + \DeclareUnicodeCharacter{017A}{\'z} + \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} + \DeclareUnicodeCharacter{017C}{\dotaccent{z}} + \DeclareUnicodeCharacter{017D}{\v{Z}} + \DeclareUnicodeCharacter{017E}{\v{z}} + + \DeclareUnicodeCharacter{01C4}{D\v{Z}} + \DeclareUnicodeCharacter{01C5}{D\v{z}} + \DeclareUnicodeCharacter{01C6}{d\v{z}} + \DeclareUnicodeCharacter{01C7}{LJ} + \DeclareUnicodeCharacter{01C8}{Lj} + \DeclareUnicodeCharacter{01C9}{lj} + \DeclareUnicodeCharacter{01CA}{NJ} + \DeclareUnicodeCharacter{01CB}{Nj} + \DeclareUnicodeCharacter{01CC}{nj} + \DeclareUnicodeCharacter{01CD}{\v{A}} + \DeclareUnicodeCharacter{01CE}{\v{a}} + \DeclareUnicodeCharacter{01CF}{\v{I}} + + \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} + \DeclareUnicodeCharacter{01D1}{\v{O}} + \DeclareUnicodeCharacter{01D2}{\v{o}} + \DeclareUnicodeCharacter{01D3}{\v{U}} + \DeclareUnicodeCharacter{01D4}{\v{u}} + + \DeclareUnicodeCharacter{01E2}{\={\AE}} + \DeclareUnicodeCharacter{01E3}{\={\ae}} + \DeclareUnicodeCharacter{01E6}{\v{G}} + \DeclareUnicodeCharacter{01E7}{\v{g}} + \DeclareUnicodeCharacter{01E8}{\v{K}} + \DeclareUnicodeCharacter{01E9}{\v{k}} + + \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} + \DeclareUnicodeCharacter{01F1}{DZ} + \DeclareUnicodeCharacter{01F2}{Dz} + \DeclareUnicodeCharacter{01F3}{dz} + \DeclareUnicodeCharacter{01F4}{\'G} + \DeclareUnicodeCharacter{01F5}{\'g} + \DeclareUnicodeCharacter{01F8}{\`N} + \DeclareUnicodeCharacter{01F9}{\`n} + \DeclareUnicodeCharacter{01FC}{\'{\AE}} + \DeclareUnicodeCharacter{01FD}{\'{\ae}} + \DeclareUnicodeCharacter{01FE}{\'{\O}} + \DeclareUnicodeCharacter{01FF}{\'{\o}} + + \DeclareUnicodeCharacter{021E}{\v{H}} + \DeclareUnicodeCharacter{021F}{\v{h}} + + \DeclareUnicodeCharacter{0226}{\dotaccent{A}} + \DeclareUnicodeCharacter{0227}{\dotaccent{a}} + \DeclareUnicodeCharacter{0228}{\cedilla{E}} + \DeclareUnicodeCharacter{0229}{\cedilla{e}} + \DeclareUnicodeCharacter{022E}{\dotaccent{O}} + \DeclareUnicodeCharacter{022F}{\dotaccent{o}} + + \DeclareUnicodeCharacter{0232}{\=Y} + \DeclareUnicodeCharacter{0233}{\=y} + \DeclareUnicodeCharacter{0237}{\dotless{j}} + + \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} + \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} + \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} + \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} + \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} + \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} + \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} + \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} + \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} + \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} + \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} + \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} + + \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} + \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} + + \DeclareUnicodeCharacter{1E20}{\=G} + \DeclareUnicodeCharacter{1E21}{\=g} + \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} + \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} + \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} + \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} + \DeclareUnicodeCharacter{1E26}{\"H} + \DeclareUnicodeCharacter{1E27}{\"h} + + \DeclareUnicodeCharacter{1E30}{\'K} + \DeclareUnicodeCharacter{1E31}{\'k} + \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} + \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} + \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} + \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} + \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} + \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} + \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} + \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} + \DeclareUnicodeCharacter{1E3E}{\'M} + \DeclareUnicodeCharacter{1E3F}{\'m} + + \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} + \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} + \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} + \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} + \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} + \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} + \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} + \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} + \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} + \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} + + \DeclareUnicodeCharacter{1E54}{\'P} + \DeclareUnicodeCharacter{1E55}{\'p} + \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} + \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} + \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} + \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} + \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} + \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} + \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} + \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} + + \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} + \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} + \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} + \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} + \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} + \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} + \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} + \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} + \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} + \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} + + \DeclareUnicodeCharacter{1E7C}{\~V} + \DeclareUnicodeCharacter{1E7D}{\~v} + \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} + \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} + + \DeclareUnicodeCharacter{1E80}{\`W} + \DeclareUnicodeCharacter{1E81}{\`w} + \DeclareUnicodeCharacter{1E82}{\'W} + \DeclareUnicodeCharacter{1E83}{\'w} + \DeclareUnicodeCharacter{1E84}{\"W} + \DeclareUnicodeCharacter{1E85}{\"w} + \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} + \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} + \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} + \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} + \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} + \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} + \DeclareUnicodeCharacter{1E8C}{\"X} + \DeclareUnicodeCharacter{1E8D}{\"x} + \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} + \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} + + \DeclareUnicodeCharacter{1E90}{\^Z} + \DeclareUnicodeCharacter{1E91}{\^z} + \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} + \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} + \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} + \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} + \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} + \DeclareUnicodeCharacter{1E97}{\"t} + \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} + \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} + + \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} + \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} + + \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} + \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} + \DeclareUnicodeCharacter{1EBC}{\~E} + \DeclareUnicodeCharacter{1EBD}{\~e} + + \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} + \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} + \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} + \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} + + \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} + \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} + + \DeclareUnicodeCharacter{1EF2}{\`Y} + \DeclareUnicodeCharacter{1EF3}{\`y} + \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} + + \DeclareUnicodeCharacter{1EF8}{\~Y} + \DeclareUnicodeCharacter{1EF9}{\~y} + + \DeclareUnicodeCharacter{2013}{--} + \DeclareUnicodeCharacter{2014}{---} + \DeclareUnicodeCharacter{2018}{\quoteleft} + \DeclareUnicodeCharacter{2019}{\quoteright} + \DeclareUnicodeCharacter{201A}{\quotesinglbase} + \DeclareUnicodeCharacter{201C}{\quotedblleft} + \DeclareUnicodeCharacter{201D}{\quotedblright} + \DeclareUnicodeCharacter{201E}{\quotedblbase} + \DeclareUnicodeCharacter{2022}{\bullet} + \DeclareUnicodeCharacter{2026}{\dots} + \DeclareUnicodeCharacter{2039}{\guilsinglleft} + \DeclareUnicodeCharacter{203A}{\guilsinglright} + \DeclareUnicodeCharacter{20AC}{\euro} + + \DeclareUnicodeCharacter{2192}{\expansion} + \DeclareUnicodeCharacter{21D2}{\result} + + \DeclareUnicodeCharacter{2212}{\minus} + \DeclareUnicodeCharacter{2217}{\point} + \DeclareUnicodeCharacter{2261}{\equiv} +}% end of \utfeightchardefs + + +% US-ASCII character definitions. +\def\asciichardefs{% nothing need be done + \relax +} + +% Make non-ASCII characters printable again for compatibility with +% existing Texinfo documents that may use them, even without declaring a +% document encoding. +% +\setnonasciicharscatcode \other + + +\message{formatting,} + +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = .15\hsize + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; +% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; +% 7) physical page height; 8) physical page width. +% +% We also call \setleading{\textleading}, so the caller should define +% \textleading. The caller should also set \parskip. +% +\def\internalpagesizes#1#2#3#4#5#6#7#8{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \ifpdf + \pdfpageheight #7\relax + \pdfpagewidth #8\relax + % if we don't reset these, they will remain at "1 true in" of + % whatever layout pdftex was dumped with. + \pdfhorigin = 1 true in + \pdfvorigin = 1 true in + \fi + % + \setleading{\textleading} + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % If page is nothing but text, make it come out even. + \internalpagesizes{607.2pt}{6in}% that's 46 lines + {\voffset}{.25in}% + {\bindingoffset}{36pt}% + {11in}{8.5in}% +}} + +% Use @smallbook to reset parameters for 7x9.25 trim size. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.5in}{5in}% + {-.2in}{0in}% + {\bindingoffset}{16pt}% + {9.25in}{7in}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .5cm +}} + +% Use @smallerbook to reset parameters for 6x9 trim size. +% (Just testing, parameters still in flux.) +\def\smallerbook{{\globaldefs = 1 + \parskip = 1.5pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.4in}{4.8in}% + {-.2in}{-.4in}% + {0pt}{14pt}% + {9in}{6in}% + % + \lispnarrowing = 0.25in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .4cm +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % Double-side printing via postscript on Laserjet 4050 + % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. + % To change the settings for a different printer or situation, adjust + % \normaloffset until the front-side and back-side texts align. Then + % do the same for \bindingoffset. You can set these for testing in + % your texinfo source file like this: + % @tex + % \global\normaloffset = -6mm + % \global\bindingoffset = 10mm + % @end tex + \internalpagesizes{673.2pt}{160mm}% that's 51 lines + {\voffset}{\hoffset}% + {\bindingoffset}{44pt}% + {297mm}{210mm}% + % + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = 5mm +}} + +% Use @afivepaper to print on European A5 paper. +% From romildo@urano.iceb.ufop.br, 2 July 2000. +% He also recommends making @example and @lisp be small. +\def\afivepaper{{\globaldefs = 1 + \parskip = 2pt plus 1pt minus 0.1pt + \textleading = 12.5pt + % + \internalpagesizes{160mm}{120mm}% + {\voffset}{\hoffset}% + {\bindingoffset}{8pt}% + {210mm}{148mm}% + % + \lispnarrowing = 0.2in + \tolerance = 800 + \hfuzz = 1.2pt + \contentsrightmargin = 0pt + \defbodyindent = 2mm + \tableindent = 12mm +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. +\def\afourlatex{{\globaldefs = 1 + \afourpaper + \internalpagesizes{237mm}{150mm}% + {\voffset}{4.6mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + % + % Must explicitly reset to 0 because we call \afourpaper. + \globaldefs = 0 +}} + +% Use @afourwide to print on A4 paper in landscape format. +\def\afourwide{{\globaldefs = 1 + \afourpaper + \internalpagesizes{241mm}{165mm}% + {\voffset}{-2.95mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + \globaldefs = 0 +}} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\parseargdef\pagesizes{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{\textleading}% + % + \dimen0 = #1\relax + \advance\dimen0 by \voffset + % + \dimen2 = \hsize + \advance\dimen2 by \normaloffset + % + \internalpagesizes{#1}{\hsize}% + {\voffset}{\normaloffset}% + {\bindingoffset}{44pt}% + {\dimen0}{\dimen2}% +}} + +% Set default to letter. +% +\letterpaper + + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\catcode`\$=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} +\def\normaldollar{$}%$ font-lock fix + +% This macro is used to make a character print one way in \tt +% (where it can probably be output as-is), and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} + +% Same as above, but check for italic font. Actually this also catches +% non-italic slanted fonts since it is impossible to distinguish them from +% italic fonts. But since this is only used by $ and it uses \sl anyway +% this is not a problem. +\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +\let\realunder=_ +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +\catcode`\$=\active +\def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +% Used sometimes to turn off (effectively) the active characters even after +% parsing them. +\def\turnoffactive{% + \normalturnoffactive + \otherbackslash +} + +\catcode`\@=0 + +% \backslashcurfont outputs one backslash character in current font, +% as in \char`\\. +\global\chardef\backslashcurfont=`\\ +\global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work + +% \realbackslash is an actual character `\' with catcode other, and +% \doublebackslash is two of them (for the pdf outlines). +{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} + +% In texinfo, backslash is an active character; it prints the backslash +% in fixed width font. +\catcode`\\=\active +@def@normalbackslash{{@tt@backslashcurfont}} +% On startup, @fixbackslash assigns: +% @let \ = @normalbackslash + +% \rawbackslash defines an active \ to do \backslashcurfont. +% \otherbackslash defines an active \ to be a literal `\' character with +% catcode other. +@gdef@rawbackslash{@let\=@backslashcurfont} +@gdef@otherbackslash{@let\=@realbackslash} + +% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of +% the literal character `\'. +% +@def@normalturnoffactive{% + @let\=@normalbackslash + @let"=@normaldoublequote + @let~=@normaltilde + @let^=@normalcaret + @let_=@normalunderscore + @let|=@normalverticalbar + @let<=@normalless + @let>=@normalgreater + @let+=@normalplus + @let$=@normaldollar %$ font-lock fix + @unsepspaces +} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\' in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also turn back on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{% + @ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active + @catcode`@_=@active +} + +% Say @foo, not \foo, in error messages. +@escapechar = `@@ + +% These look ok in all fonts, so just make them not special. +@catcode`@& = @other +@catcode`@# = @other +@catcode`@% = @other + + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%02H" +@c time-stamp-end: "}" +@c End: + +@c vim:sw=2: + +@ignore + arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 +@end ignore diff --git a/build-aux/windres-options b/build-aux/windres-options new file mode 100755 index 00000000..779fddec --- /dev/null +++ b/build-aux/windres-options @@ -0,0 +1,45 @@ +#!/bin/sh +# Usage: windres-options [--escape] PACKAGE_VERSION +# Outputs a set of command-line options for 'windres', containing definitions +# for the preprocessor variables +# PACKAGE_VERSION_STRING +# PACKAGE_VERSION_MAJOR +# PACKAGE_VERSION_MINOR +# PACKAGE_VERSION_SUBMINOR + +escape= +if test "$1" = "--escape"; then + escape=yes + shift +fi +version="$1" # something like 2.0 or 2.17 or 2.17.3 or 2.17.3-pre3 + +sed_extract_major='/^[0-9]/{s/^\([0-9]*\).*/\1/p;q;} +i\ +0 +q +' +sed_extract_minor='/^[0-9][0-9]*[.][0-9]/{s/^[0-9]*[.]\([0-9]*\).*/\1/p;q;} +i\ +0 +q +' +sed_extract_subminor='/^[0-9][0-9]*[.][0-9][0-9]*[.][0-9]/{s/^[0-9]*[.][0-9]*[.]\([0-9]*\).*/\1/p;q;} +i\ +0 +q +' + +{ + echo "-DPACKAGE_VERSION_STRING=\"${version}\"" + echo "-DPACKAGE_VERSION_MAJOR="`echo "${version}" | sed -n -e "$sed_extract_major"` + echo "-DPACKAGE_VERSION_MINOR="`echo "${version}" | sed -n -e "$sed_extract_minor"` + echo "-DPACKAGE_VERSION_SUBMINOR="`echo "${version}" | sed -n -e "$sed_extract_subminor"` +} | +{ + if test -n "$escape"; then + sed -e 's,\(["\\]\),\\\1,g' + else + cat + fi +} |