aboutsummaryrefslogtreecommitdiff
path: root/contrib/texinfo/util
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/texinfo/util')
-rw-r--r--contrib/texinfo/util/Makefile.in101
-rw-r--r--contrib/texinfo/util/deref.c238
-rwxr-xr-xcontrib/texinfo/util/fixfonts84
-rwxr-xr-xcontrib/texinfo/util/gen-dir-node176
-rw-r--r--contrib/texinfo/util/install-info.c1141
-rwxr-xr-xcontrib/texinfo/util/mkinstalldirs40
-rwxr-xr-xcontrib/texinfo/util/tex3patch71
-rwxr-xr-xcontrib/texinfo/util/texi2dvi364
-rw-r--r--contrib/texinfo/util/texindex.c1793
9 files changed, 0 insertions, 4008 deletions
diff --git a/contrib/texinfo/util/Makefile.in b/contrib/texinfo/util/Makefile.in
deleted file mode 100644
index aa3b85a8bd68..000000000000
--- a/contrib/texinfo/util/Makefile.in
+++ /dev/null
@@ -1,101 +0,0 @@
-# Makefile for GNU Texindex and other utilities.
-# $Id: Makefile.in,v 1.5 1996/09/29 20:07:06 karl Exp $
-#
-# Copyright (C) 1990, 91, 92, 96 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#### Start of system configuration section. ####
-
-srcdir = @srcdir@
-VPATH = $(srcdir):$(common)
-
-common = $(srcdir)/../libtxi
-
-CC = @CC@
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_DATA = @INSTALL_DATA@
-
-LN = ln
-RM = rm -f
-MKDIR = mkdir
-
-DEFS = @DEFS@
-LIBS = -L../libtxi -ltxi @LIBS@
-LOADLIBES = $(LIBS)
-
-SHELL = /bin/sh
-
-CFLAGS = @CFLAGS@
-LDFLAGS = @LDFLAGS@
-
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-bindir = $(exec_prefix)/bin
-# Prefix for each installed program, normally empty or `g'.
-binprefix =
-# Prefix for each installed man page, normally empty or `g'.
-manprefix =
-mandir = $(prefix)/man/man1
-manext = 1
-infodir = $(prefix)/info
-
-#### End of system configuration section. ####
-
-all: texindex install-info
-sub-all: all
-
-.c.o:
- $(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) -I$(common) $(CFLAGS) $<
-
-
-install: all
- $(INSTALL_PROGRAM) texindex $(bindir)/texindex
- $(INSTALL_PROGRAM) $(srcdir)/texi2dvi $(bindir)/texi2dvi
- $(INSTALL_PROGRAM) install-info $(bindir)/install-info
-
-uninstall:
- rm -f $(bindir)/texindex $(bindir)/texi2dvi $(bindir)/install-info
-
-Makefile: Makefile.in ../config.status
- cd ..; sh config.status
-
-TAGS:
- etags *.c *.h $(common)/getopt*.c $(common)/getopt.h
-
-clean:
- rm -f *.o a.out core core.* texindex install-info
-
-mostlyclean: clean
-
-distclean: clean
- rm -f Makefile config.status
-
-realclean: distclean
- rm -f TAGS
-
-texindex: texindex.o ../libtxi/libtxi.a
- $(CC) $(LDFLAGS) -o texindex texindex.o $(LOADLIBES)
-
-texindex.o: texindex.c $(common)/getopt.h
-
-install-info: install-info.o
- $(CC) $(LDFLAGS) -o install-info install-info.o $(LOADLIBES)
-
-install-info.o: install-info.c $(common)/getopt.h
-
-# Prevent GNU make v3 from overflowing arg limit on SysV.
-.NOEXPORT:
diff --git a/contrib/texinfo/util/deref.c b/contrib/texinfo/util/deref.c
deleted file mode 100644
index c15bc1abcf15..000000000000
--- a/contrib/texinfo/util/deref.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * deref.c
-
- * compile command: gcc -g -o deref deref.c
-
- * execute command: deref filename.texi > newfile.texi
-
- * To: bob@gnu.ai.mit.edu
- * Subject: another tool
- * Date: 18 Dec 91 16:03:13 EST (Wed)
- * From: gatech!skeeve!arnold@eddie.mit.edu (Arnold D. Robbins)
- *
- * Here is deref.c. It turns texinfo cross references back into the
- * one argument form. It has the same limitations as fixref; one xref per
- * line and can't cross lines. You can use it to find references that do
- * cross a line boundary this way:
- *
- * deref < manual > /dev/null 2>errs
- *
- * (This assumes bash or /bin/sh.) The file errs will have list of lines
- * where deref could not find matching braces.
- *
- * A gawk manual processed by deref goes through makeinfo without complaint.
- * Compile with gcc and you should be set.
- *
- * Enjoy,
- *
- * Arnold
- * -----------
- */
-
-/*
- * deref.c
- *
- * Make all texinfo references into the one argument form.
- *
- * Arnold Robbins
- * arnold@skeeve.atl.ga.us
- * December, 1991
- *
- * Copyright, 1991, Arnold Robbins
- */
-
-/*
- * LIMITATIONS:
- * One texinfo cross reference per line.
- * Cross references may not cross newlines.
- * Use of fgets for input (to be fixed).
- */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-
-/* for gcc on the 3B1, delete if this gives you grief */
-extern int fclose (FILE * fp);
-extern int fprintf (FILE * fp, const char *str,...);
-
-extern char *strerror (int errno);
-extern char *strchr (char *cp, int ch);
-extern int strncmp (const char *s1, const char *s2, int count);
-
-extern int errno;
-
-void process (FILE * fp);
-void repair (char *line, char *ref, int toffset);
-
-int Errs = 0;
-char *Name = "stdin";
-int Line = 0;
-char *Me;
-
-/* main --- handle arguments, global vars for errors */
-
-int
-main (int argc, char **argv)
-{
- FILE *fp;
-
- Me = argv[0];
-
- if (argc == 1)
- process (stdin);
- else
- for (argc--, argv++; *argv != NULL; argc--, argv++)
- {
- if (argv[0][0] == '-' && argv[0][1] == '\0')
- {
- Name = "stdin";
- Line = 0;
- process (stdin);
- }
- else if ((fp = fopen (*argv, "r")) != NULL)
- {
- Name = *argv;
- Line = 0;
- process (fp);
- fclose (fp);
- }
- else
- {
- fprintf (stderr, "%s: can not open: %s\n",
- *argv, strerror (errno));
- Errs++;
- }
- }
- return Errs != 0;
-}
-
-/* isref --- decide if we've seen a texinfo cross reference */
-
-int
-isref (char *cp)
-{
- if (strncmp (cp, "@ref{", 5) == 0)
- return 5;
- if (strncmp (cp, "@xref{", 6) == 0)
- return 6;
- if (strncmp (cp, "@pxref{", 7) == 0)
- return 7;
- return 0;
-}
-
-/* process --- read files, look for references, fix them up */
-
-void
-process (FILE * fp)
-{
- char buf[BUFSIZ];
- char *cp;
- int count;
-
- while (fgets (buf, sizeof buf, fp) != NULL)
- {
- Line++;
- cp = strchr (buf, '@');
- if (cp == NULL)
- {
- fputs (buf, stdout);
- continue;
- }
- do
- {
- count = isref (cp);
- if (count == 0)
- {
- cp++;
- cp = strchr (cp, '@');
- if (cp == NULL)
- {
- fputs (buf, stdout);
- goto next;
- }
- continue;
- }
- /* got one */
- repair (buf, cp, count);
- break;
- }
- while (cp != NULL);
- next:;
- }
-}
-
-/* repair --- turn all texinfo cross references into the one argument form */
-
-void
-repair (char *line, char *ref, int toffset)
-{
- int braces = 1; /* have seen first left brace */
- char *cp;
-
- ref += toffset;
-
- /* output line up to and including left brace in reference */
- for (cp = line; cp <= ref; cp++)
- putchar (*cp);
-
- /* output node name */
- for (; *cp && *cp != '}' && *cp != ',' && *cp != '\n'; cp++)
- putchar (*cp);
-
- if (*cp != '}')
- { /* could have been one arg xref */
- /* skip to matching right brace */
- for (; braces > 0; cp++)
- {
- switch (*cp)
- {
- case '@':
- cp++; /* blindly skip next character */
- break;
- case '{':
- braces++;
- break;
- case '}':
- braces--;
- break;
- case '\n':
- case '\0':
- Errs++;
- fprintf (stderr,
- "%s: %s: %d: mismatched braces\n",
- Me, Name, Line);
- goto out;
- default:
- break;
- }
- }
- out:
- ;
- }
-
- putchar ('}');
- if (*cp == '}')
- cp++;
-
- /* now the rest of the line */
- for (; *cp; cp++)
- putchar (*cp);
- return;
-}
-
-/* strerror --- return error string, delete if in your library */
-
-char *
-strerror (int errno)
-{
- static char buf[100];
- extern int sys_nerr;
- extern char *sys_errlist[];
-
- if (errno < sys_nerr && errno >= 0)
- return sys_errlist[errno];
-
- sprintf (buf, "unknown error %d", errno);
- return buf;
-}
diff --git a/contrib/texinfo/util/fixfonts b/contrib/texinfo/util/fixfonts
deleted file mode 100755
index ee2ea7192198..000000000000
--- a/contrib/texinfo/util/fixfonts
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/sh
-# Make links named `lcircle10' for all TFM and GF/PK files, if no
-# lcircle10 files already exist.
-
-# Don't override definition of prefix and/or libdir if they are
-# already defined in the environment.
-if test "z${prefix}" = "z" ; then
- prefix=/usr/local
-else
- # prefix may contain references to other variables, thanks to make.
- eval prefix=\""${prefix}"\"
-fi
-
-if test "z${libdir}" = "z" ; then
- libdir="${prefix}/lib/tex"
-else
- # libdir may contain references to other variables, thanks to make.
- eval libdir=\""${libdir}"\"
-fi
-
-texlibdir="${libdir}"
-texfontdir="${texlibdir}/fonts"
-
-# Directories for the different font formats, in case they're not all
-# stored in one place.
-textfmdir="${textfmdir-${texfontdir}}"
-texpkdir="${texpkdir-${texfontdir}}"
-texgfdir="${texgfdir-${texfontdir}}"
-
-test "z${TMPDIR}" = "z" && TMPDIR="/tmp"
-
-tempfile="${TMPDIR}/circ$$"
-tempfile2="${TMPDIR}/circ2$$"
-
-# EXIT SIGHUP SIGINT SIGQUIT SIGTERM
-#trap 'rm -f "${tempfile}" "${tempfile2}"' 0 1 2 3 15
-
-# Find all the fonts with names that include `circle'.
-(cd "${texfontdir}"; find . -name '*circle*' -print > "${tempfile}")
-
-# If they have lcircle10.tfm, assume everything is there, and quit.
-if grep 'lcircle10\.tfm' "${tempfile}" > /dev/null 2>&1 ; then
- echo "Found lcircle10.tfm."
- exit 0
-fi
-
-# No TFM file for lcircle. Make a link to circle10.tfm if it exists,
-# and then make a link to the bitmap files.
-grep 'circle10\.tfm' "${tempfile}" > "${tempfile2}" \
- || {
- echo "I can't find any circle fonts in ${texfontdir}.
-If it isn't installed somewhere else, you need to get the Metafont sources
-from somewhere, e.g., labrea.stanford.edu:pub/tex/latex/circle10.mf, and
-run Metafont on them."
- exit 1
- }
-
-# We have circle10.tfm. (If we have it more than once, take the first
-# one.) Make the link.
-tempfile2_line1="`sed -ne '1p;q' \"${tempfile2}\"`"
-ln "${tempfile2_line1}" "${textfmdir}/lcircle10.tfm"
-echo "Linked to ${tempfile2_line1}."
-
-# Now make a link for the PK files, if any.
-(cd "${texpkdir}"
- for f in `grep 'circle10.*pk' "${tempfile}"` ; do
- set - `echo "$f" \
- | sed -ne '/\//!s/^/.\//;s/\(.*\)\/\([^\/][^\/]*\)$/\1 \2/;p'`
- ln "$f" "${1}/l${2}"
- echo "Linked to $f."
- done
-)
-
-# And finally for the GF files.
-(cd "${texgfdir}"
- for f in `grep 'circle10.*gf' "${tempfile}"` ; do
- set - `echo "$f" \
- | sed -ne '/\//!s/^/.\//;s/\(.*\)\/\([^\/][^\/]*\)$/\1 \2/;p'`
- ln "$f" "${1}/l${2}"
- echo "Linked to $f."
- done
-)
-
-# eof
diff --git a/contrib/texinfo/util/gen-dir-node b/contrib/texinfo/util/gen-dir-node
deleted file mode 100755
index 8f13088f920d..000000000000
--- a/contrib/texinfo/util/gen-dir-node
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/bin/sh
-# $Id: gen-dir-node,v 1.2 1996/10/03 18:49:48 karl Exp $
-# Generate the top-level Info node, given a directory of Info files
-# and (optionally) a skeleton file. The output will be suitable for a
-# top-level dir file. The skeleton file contains info topic names in the
-# order they should appear in the output. There are three special
-# lines that alter the behavior: a line consisting of just "--" causes
-# the next line to be echoed verbatim to the output. A line
-# containing just "%%" causes all the remaining filenames (wildcards
-# allowed) in the rest of the file to be ignored. A line containing
-# just "!!" exits the script when reached (unless preceded by a line
-# containing just "--"). Once the script reaches the end of the
-# skeleton file, it goes through the remaining files in the directory
-# in order, putting their entries at the end. The script will use the
-# ENTRY information in each info file if it exists. Otherwise it will
-# make a minimal entry.
-
-# sent by Jeffrey Osier <jeffrey@cygnus.com>, who thinks it came from
-# zoo@winternet.com (david d `zoo' zuhn)
-
-# modified 7 April 1995 by Joe Harrington <jh@tecate.gsfc.nasa.gov> to
-# take special flags
-
-INFODIR=$1
-if [ $# = 2 ] ; then
- SKELETON=$2
-else
- SKELETON=/dev/null
-fi
-
-skip=
-
-if [ $# -gt 2 ] ; then
- echo usage: $0 info-directory [ skeleton-file ] 1>&2
- exit 1
-else
- true
-fi
-
-if [ ! -d ${INFODIR} ] ; then
- echo "$0: first argument must specify a directory"
- exit 1
-fi
-
-### output the dir header
-echo "-*- Text -*-"
-echo "This file was generated automatically by $0."
-echo "This version was generated on `date`"
-echo "by `whoami`@`hostname` for `(cd ${INFODIR}; pwd)`"
-
-cat << moobler
-
-This is the file .../info/dir, which contains the topmost node of the
-Info hierarchy. The first time you invoke Info you start off
-looking at that node, which is (dir)Top.
-
-File: dir Node: Top This is the top of the INFO tree
- This (the Directory node) gives a menu of major topics.
- Typing "d" returns here, "q" exits, "?" lists all INFO commands, "h"
- gives a primer for first-timers, "mTexinfo<Return>" visits Texinfo topic,
- etc.
- Or click mouse button 2 on a menu item or cross reference to select it.
- --- PLEASE ADD DOCUMENTATION TO THIS TREE. (See INFO topic first.) ---
-
-* Menu: The list of major topics begins on the next line.
-
-moobler
-
-### go through the list of files in the skeleton. If an info file
-### exists, grab the ENTRY information from it. If an entry exists
-### use it, otherwise create a minimal dir entry.
-###
-### Then remove that file from the list of existing files. If any
-### additional files remain (ones that don't have a skeleton entry),
-### then generate entries for those in the same way, putting the info for
-### those at the end....
-
-infofiles=`(cd ${INFODIR}; ls | egrep -v '\-|^dir$|^dir\.info$|^dir\.orig$')`
-
-# echoing gets clobbered by backquotes; we do it the hard way...
-lines=`wc $SKELETON | awk '{print $1}'`
-line=1
-while [ $lines -ge $line ] ; do
- # Read one line from the file. This is so that we can echo lines with
- # whitespace and quoted characters in them.
- fileline=`awk NR==$line $SKELETON`
-
- # flag fancy features
- if [ ! -z "$echoline" ] ; then # echo line
- echo "$fileline"
- fileline=
- echoline=
- elif [ "${fileline}" = "--" ] ; then # should we echo the next line?
- echoline=1
- elif [ "${fileline}" = "%%" ] ; then # eliminate remaining files from dir?
- skip=1
- elif [ "${fileline}" = "!!" ] ; then # quit now
- exit 0
- fi
-
- # handle files if they exist
- for file in $fileline"" ; do # expand wildcards ("" handles blank lines)
-
- fname=
-
- if [ -z "$echoline" -a ! -z "$file" ] ; then
-
- # Find the file to operate upon. Check both possible names.
- infoname=`echo $file | sed 's/\.info$//'`
- noext=
- ext=
- if [ -f ${INFODIR}/$infoname ] ; then
- noext=$infoname
- fi
- if [ -f ${INFODIR}/${infoname}.info ] ; then
- ext=${infoname}.info
- fi
-
- # If it exists with both names take what was said in the file.
- if [ ! -z "$ext" -a ! -z "$noext" ]; then
- fname=$file
- warn="### Warning: $ext and $noext both exist! Using ${file}. ###"
- elif [ ! \( -z "$ext" -a -z "$noext" \) ]; then
- # just take the name if it exists only once
- fname=${noext}${ext}
- fi
-
- # if we found something and aren't skipping, do the entry
- if [ ! -z "$fname" ] ; then
- if [ -z "$skip" ] ; then
-
- if [ ! -z "$warn" ] ; then # issue any warning
- echo $warn
- warn=
- fi
-
- entry=`sed -e '1,/START-INFO-DIR-ENTRY/d' \
- -e '/END-INFO-DIR-ENTRY/,$d' ${INFODIR}/$fname`
- if [ ! -z "${entry}" ] ; then
- echo "${entry}"
- else
- echo "* ${infoname}: (${fname})."
- fi
- fi
-
- # remove the name from the directory listing
- infofiles=`echo ${infofiles} | sed -e "s/ ${fname} / /" \
- -e "s/^${fname} //" \
- -e "s/ ${fname}$//"`
-
- fi
-
- fi
-
- done
-
- line=`expr $line + 1`
-done
-
-if [ -z "${infofiles}" ] ; then
- exit 0
-else
- echo
-fi
-
-for file in ${infofiles}; do
- infoname=`echo $file | sed 's/\.info$//'`
- entry=`sed -e '1,/START-INFO-DIR-ENTRY/d' \
- -e '/END-INFO-DIR-ENTRY/,$d' ${INFODIR}/${file}`
-
- if [ ! -z "${entry}" ] ; then
- echo "${entry}"
- else
- echo "* ${infoname}: (${file})."
- fi
-done
diff --git a/contrib/texinfo/util/install-info.c b/contrib/texinfo/util/install-info.c
deleted file mode 100644
index e5850f37a541..000000000000
--- a/contrib/texinfo/util/install-info.c
+++ /dev/null
@@ -1,1141 +0,0 @@
-/* install-info -- create Info directory entry(ies) for an Info file.
- Copyright (C) 1996 Free Software Foundation, Inc.
-
-$Id$
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#define INSTALL_INFO_VERSION_STRING "GNU install-info (Texinfo 3.9) 1.2"
-
-#include <stdio.h>
-#include <errno.h>
-#include <getopt.h>
-#include <sys/types.h>
-
-/* Get O_RDONLY. */
-#ifdef HAVE_SYS_FCNTL_H
-#include <sys/fcntl.h>
-#else
-#include <fcntl.h>
-#endif /* !HAVE_SYS_FCNTL_H */
-#ifdef HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-
-/* Name this program was invoked with. */
-char *progname;
-
-char *readfile ();
-struct line_data *findlines ();
-void fatal ();
-void insert_entry_here ();
-int compare_section_names ();
-
-struct spec_entry;
-
-/* Data structures. */
-
-/* Record info about a single line from a file
- as read into core. */
-
-struct line_data
-{
- /* The start of the line. */
- char *start;
- /* The number of characters in the line,
- excluding the terminating newline. */
- int size;
- /* Vector containing pointers to the entries to add before this line.
- The vector is null-terminated. */
- struct spec_entry **add_entries_before;
- /* 1 means output any needed new sections before this line. */
- int add_sections_before;
- /* 1 means don't output this line. */
- int delete;
-};
-
-/* This is used for a list of the specified menu section names
- in which entries should be added. */
-
-struct spec_section
-{
- struct spec_section *next;
- char *name;
- /* 1 means we have not yet found an existing section with this name
- in the dir file--so we will need to add a new section. */
- int missing;
-};
-
-/* This is used for a list of the entries specified to be added. */
-
-struct spec_entry
-{
- struct spec_entry *next;
- char *text;
-};
-
-/* This is used for a list of nodes found by parsing the dir file. */
-
-struct node
-{
- struct node *next;
- /* The node name. */
- char *name;
- /* The line number of the line where the node starts.
- This is the line that contains control-underscore. */
- int start_line;
- /* The line number of the line where the node ends,
- which is the end of the file or where the next line starts. */
- int end_line;
- /* Start of first line in this node's menu
- (the line after the * Menu: line). */
- char *menu_start;
- /* The start of the chain of sections in this node's menu. */
- struct menu_section *sections;
- /* The last menu section in the chain. */
- struct menu_section *last_section;
-};
-
-/* This is used for a list of sections found in a node's menu.
- Each struct node has such a list in the sections field. */
-
-struct menu_section
-{
- struct menu_section *next;
- char *name;
- /* Line number of start of section. */
- int start_line;
- /* Line number of end of section. */
- int end_line;
-};
-
-/* Memory allocation and string operations. */
-
-/* Like malloc but get fatal error if memory is exhausted. */
-
-void *
-xmalloc (size)
- unsigned int size;
-{
- extern void *malloc ();
- void *result = malloc (size);
- if (result == NULL)
- fatal ("virtual memory exhausted", 0);
- return result;
-}
-
-/* Like malloc but get fatal error if memory is exhausted. */
-
-void *
-xrealloc (obj, size)
- void *obj;
- unsigned int size;
-{
- extern void *realloc ();
- void *result = realloc (obj, size);
- if (result == NULL)
- fatal ("virtual memory exhausted", 0);
- return result;
-}
-
-/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
-
-char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
-
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
-}
-
-/* Return a string containing SIZE characters
- copied from starting at STRING. */
-
-char *
-copy_string (string, size)
- char *string;
- int size;
-{
- int i;
- char *copy = (char *) xmalloc (size + 1);
- for (i = 0; i < size; i++)
- copy[i] = string[i];
- copy[size] = 0;
- return copy;
-}
-
-/* Error message functions. */
-
-/* Print error message. `s1' is printf control string, `s2' is arg for it. */
-
-/* VARARGS1 */
-void
-error (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- fprintf (stderr, "%s: ", progname);
- fprintf (stderr, s1, s2, s3);
- fprintf (stderr, "\n");
-}
-
-/* VARARGS1 */
-void
-warning (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- fprintf (stderr, "%s: Warning: ", progname);
- fprintf (stderr, s1, s2, s3);
- fprintf (stderr, "\n");
-}
-
-/* Print error message and exit. */
-
-void
-fatal (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- error (s1, s2, s3);
- exit (1);
-}
-
-/* Print fatal error message based on errno, with file name NAME. */
-
-void
-pfatal_with_name (name)
- char *name;
-{
- char *s = concat ("", strerror (errno), " for %s");
- fatal (s, name);
-}
-
-/* Given the full text of a menu entry, null terminated,
- return just the menu item name (copied). */
-
-char *
-extract_menu_item_name (item_text)
- char *item_text;
-{
- char *p;
-
- if (*item_text == '*')
- item_text++;
- while (*item_text == ' ')
- item_text++;
-
- p = item_text;
- while (*p && *p != ':') p++;
- return copy_string (item_text, p - item_text);
-}
-
-/* Given the full text of a menu entry, terminated by null or newline,
- return just the menu item file (copied). */
-
-char *
-extract_menu_file_name (item_text)
- char *item_text;
-{
- char *p = item_text;
-
- /* If we have text that looks like * ITEM: (FILE)NODE...,
- extract just FILE. Otherwise return "(none)". */
-
- if (*p == '*')
- p++;
- while (*p == ' ')
- p++;
-
- /* Skip to and past the colon. */
- while (*p && *p != '\n' && *p != ':') p++;
- if (*p == ':') p++;
-
- /* Skip past the open-paren. */
- while (1)
- {
- if (*p == '(')
- break;
- else if (*p == ' ' || *p == '\t')
- p++;
- else
- return "(none)";
- }
- p++;
-
- item_text = p;
-
- /* File name ends just before the close-paren. */
- while (*p && *p != '\n' && *p != ')') p++;
- if (*p != ')')
- return "(none)";
-
- return copy_string (item_text, p - item_text);
-}
-
-void
-suggest_asking_for_help ()
-{
- fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
- progname);
- exit (1);
-}
-
-void
-print_help ()
-{
- printf ("%s [OPTION]... [INFO-FILE [DIR-FILE]]\n\
- Install INFO-FILE in the Info directory file DIR-FILE.\n\
-\n\
-Options:\n\
---delete Delete existing entries in INFO-FILE;\n\
- don't insert any new entries.\n\
---defentry=TEXT Like --entry, but only use TEXT if an entry\n\
- is not present in INFO-FILE.\n\
---defsection=TEXT Like --section, but only use TEXT if a section\n\
- is not present in INFO-FILE.\n\
---dir-file=NAME Specify file name of Info directory file.\n\
- This is equivalent to using the DIR-FILE argument.\n\
---entry=TEXT Insert TEXT as an Info directory entry.\n\
- TEXT should have the form of an Info menu item line\n\
- plus zero or more extra lines starting with whitespace.\n\
- If you specify more than one entry, they are all added.\n\
- If you don't specify any entries, they are determined\n\
- from information in the Info file itself.\n\
---forceentry=TEXT Like --entry, but ignore any entry in INFO-FILE.\n\
---help Display this help and exit.\n\
---info-file=FILE Specify Info file to install in the directory.\n\
- This is equivalent to using the INFO-FILE argument.\n\
---info-dir=DIR Same as --dir-file=DIR/dir.\n\
---item=TEXT Same as --entry TEXT.\n\
- An Info directory entry is actually a menu item.\n\
---quiet Suppress warnings.\n\
---remove Same as --delete.\n\
---section=SEC Put this file's entries in section SEC of the directory.\n\
- If you specify more than one section, all the entries\n\
- are added in each of the sections.\n\
- If you don't specify any sections, they are determined\n\
- from information in the Info file itself.\n\
---version Display version information and exit.\n\
-\n\
-Email bug reports to bug-texinfo@prep.ai.mit.edu.\n\
-", progname);
-}
-
-
-/* This table defines all the long-named options, says whether they
- use an argument, and maps them into equivalent single-letter options. */
-
-struct option longopts[] =
-{
- { "delete", no_argument, NULL, 'r' },
- { "defentry", required_argument, NULL, 'E' },
- { "defsection", required_argument, NULL, 'S' },
- { "dir-file", required_argument, NULL, 'd' },
- { "entry", required_argument, NULL, 'e' },
- { "forceentry", required_argument, NULL, 'f' },
- { "help", no_argument, NULL, 'h' },
- { "info-dir", required_argument, NULL, 'D' },
- { "info-file", required_argument, NULL, 'i' },
- { "item", required_argument, NULL, 'e' },
- { "quiet", no_argument, NULL, 'q' },
- { "remove", no_argument, NULL, 'r' },
- { "section", required_argument, NULL, 's' },
- { "version", no_argument, NULL, 'V' },
- { 0 }
-};
-
-main (argc, argv)
- int argc;
- char **argv;
-{
- char *infile = 0, *dirfile = 0;
- char *infile_sans_info;
- unsigned infilelen_sans_info;
- FILE *output;
-
- /* Record the text of the Info file, as a sequence of characters
- and as a sequence of lines. */
- char *input_data;
- int input_size;
- struct line_data *input_lines;
- int input_nlines;
-
- /* Record here the specified section names and directory entries. */
- struct spec_section *input_sections = NULL;
- struct spec_entry *entries_to_add = NULL;
- int n_entries_to_add = 0;
-
- /* Record the old text of the dir file, as plain characters,
- as lines, and as nodes. */
- char *dir_data;
- int dir_size;
- int dir_nlines;
- struct line_data *dir_lines;
- struct node *dir_nodes;
-
- /* Nonzero means --delete was specified (just delete existing entries). */
- int delete_flag = 0;
- int something_deleted = 0;
- /* Nonzero means -q was specified. */
- int quiet_flag = 0;
-
- int node_header_flag;
- int prefix_length;
- int i;
-
- /* Nonzero means only use if not present in info file. */
- int entry_default = 0;
- int entry_force = 0;
- int section_default = 0;
-
- progname = argv[0];
-
- while (1)
- {
- int opt = getopt_long (argc, argv, "i:d:e:s:hHr", longopts, 0);
-
- if (opt == EOF)
- break;
-
- switch (opt)
- {
- case 0:
- /* If getopt returns 0, then it has already processed a
- long-named option. We should do nothing. */
- break;
-
- case 1:
- abort ();
-
- case 'd':
- if (dirfile)
- {
- fprintf (stderr, "%s: Specify the Info directory only once.\n",
- progname);
- suggest_asking_for_help ();
- }
- dirfile = optarg;
- break;
-
- case 'D':
- if (dirfile)
- {
- fprintf (stderr, "%s: Specify the Info directory only once.\n",
- progname);
- suggest_asking_for_help ();
- }
- dirfile = concat (optarg, "", "/dir");
- break;
-
- case 'f':
- entry_force = 1;
- if (!optarg[0])
- {
- fprintf (stderr, "%s: Must provide entry name.\n", progname);
- suggest_asking_for_help ();
- }
- case 'E':
- entry_default = 1;
- if (!optarg[0])
- break;
- case 'e':
- {
- struct spec_entry *next
- = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
- if (! (*optarg != 0 && optarg[strlen (optarg) - 1] == '\n'))
- optarg = concat (optarg, "\n", "");
- next->text = optarg;
- next->next = entries_to_add;
- entries_to_add = next;
- n_entries_to_add++;
- }
- break;
-
- case 'h':
- case 'H':
- print_help ();
- exit (0);
-
- case 'i':
- if (infile)
- {
- fprintf (stderr, "%s: Specify the Info file only once.\n",
- progname);
- suggest_asking_for_help ();
- }
- infile = optarg;
- break;
-
- case 'q':
- quiet_flag = 1;
- break;
-
- case 'r':
- delete_flag = 1;
- break;
-
- case 'S':
- section_default = 1;
- if (!optarg[0])
- break;
- case 's':
- {
- struct spec_section *next
- = (struct spec_section *) xmalloc (sizeof (struct spec_section));
- next->name = optarg;
- next->next = input_sections;
- next->missing = 1;
- input_sections = next;
- }
- break;
-
- case 'V':
- puts (INSTALL_INFO_VERSION_STRING);
-puts ("Copyright (C) 1996 Free Software Foundation, Inc.\n\
-There is NO warranty. You may redistribute this software\n\
-under the terms of the GNU General Public License.\n\
-For more information about these matters, see the files named COPYING.");
- exit (0);
-
- default:
- suggest_asking_for_help ();
- }
- }
-
- if (entry_force)
- entry_default = 0;
-
- /* Interpret the non-option arguments as file names. */
- for (; optind < argc; ++optind)
- {
- if (infile == 0)
- infile = argv[optind];
- else if (dirfile == 0)
- dirfile = argv[optind];
- else
- error ("excess command line argument `%s'", argv[optind]);
- }
-
- if (!infile)
- fatal ("No input file specified");
- if (!dirfile)
- fatal ("No dir file specified");
-
- /* Read the Info file and parse it into lines. */
-
- input_data = readfile (infile, &input_size);
- input_lines = findlines (input_data, input_size, &input_nlines);
-
- /* Parse the input file to find the section names it specifies. */
-
- if (input_sections == 0 || section_default)
- {
- prefix_length = strlen ("INFO-DIR-SECTION ");
- for (i = 0; i < input_nlines; i++)
- {
- if (!strncmp ("INFO-DIR-SECTION ", input_lines[i].start,
- prefix_length))
- {
- struct spec_section *next
- = (struct spec_section *) xmalloc (sizeof (struct spec_section));
-
- if (section_default)
- {
- input_sections = NULL; /* This leaks. */
- section_default = 0;
- }
-
- next->name = copy_string (input_lines[i].start + prefix_length,
- input_lines[i].size - prefix_length);
- next->next = input_sections;
- next->missing = 1;
- input_sections = next;
- }
- }
- }
-
- /* Default to section "Miscellaneous" if no sections specified. */
- if (input_sections == 0)
- {
- input_sections
- = (struct spec_section *) xmalloc (sizeof (struct spec_section));
- input_sections->name = "Miscellaneous";
- input_sections->next = 0;
- input_sections->missing = 1;
- }
-
- /* Now find the directory entries specified in the file
- and put them on entries_to_add. But not if entries
- were specified explicitly with command options. */
-
- if ( !entry_force && (entries_to_add == 0 || entry_default) )
- {
- char *start_of_this_entry = 0;
- for (i = 0; i < input_nlines; i++)
- {
- if (!strncmp ("START-INFO-DIR-ENTRY", input_lines[i].start,
- input_lines[i].size)
- && sizeof ("START-INFO-DIR-ENTRY") - 1 == input_lines[i].size)
- {
- if (start_of_this_entry != 0)
- fatal ("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY");
- start_of_this_entry = input_lines[i + 1].start;
- }
- if (!strncmp ("END-INFO-DIR-ENTRY", input_lines[i].start,
- input_lines[i].size)
- && sizeof ("END-INFO-DIR-ENTRY") - 1 == input_lines[i].size)
- {
- if (start_of_this_entry != 0)
- {
- struct spec_entry *next
- = (struct spec_entry *) xmalloc (sizeof (struct spec_entry));
-
- if (entry_default)
- {
- entries_to_add = NULL;
- entry_default = 0;
- }
-
- next->text = copy_string (start_of_this_entry,
- input_lines[i].start - start_of_this_entry);
- next->next = entries_to_add;
- entries_to_add = next;
- n_entries_to_add++;
- start_of_this_entry = 0;
- }
- else
- fatal ("END-INFO-DIR-ENTRY without matching START-INFO-DIR-ENTRY");
- }
- }
- if (start_of_this_entry != 0)
- fatal ("START-INFO-DIR-ENTRY without matching END-INFO-DIR-ENTRY");
- }
-
- if (!delete_flag)
- if (entries_to_add == 0)
- fatal ("no info dir entry in `%s'", infile);
-
- /* Now read in the Info dir file. */
- dir_data = readfile (dirfile, &dir_size);
- dir_lines = findlines (dir_data, dir_size, &dir_nlines);
-
- /* We will be comparing the entries in the dir file against the
- current filename, so need to strip off any directory prefix and any
- .info suffix. */
- {
- unsigned basename_len;
- extern char *strrchr ();
- char *infile_basename = strrchr (infile, '/');
- if (infile_basename)
- infile_basename++;
- else
- infile_basename = infile;
-
- basename_len = strlen (infile_basename);
- infile_sans_info
- = (strlen (infile_basename) > 5
- && strcmp (infile_basename + basename_len - 5, ".info") == 0)
- ? copy_string (infile_basename, basename_len - 5)
- : infile_basename;
-
- infilelen_sans_info = strlen (infile_sans_info);
- }
-
- /* Parse the dir file. Find all the nodes, and their menus,
- and the sections of their menus. */
-
- dir_nodes = 0;
- node_header_flag = 0;
- for (i = 0; i < dir_nlines; i++)
- {
- /* Parse node header lines. */
- if (node_header_flag)
- {
- int j, end;
- for (j = 0; j < dir_lines[i].size; j++)
- /* Find the node name and store it in the `struct node'. */
- if (!strncmp ("Node:", dir_lines[i].start + j, 5))
- {
- char *line = dir_lines[i].start;
- /* Find the start of the node name. */
- j += 5;
- while (line[j] == ' ' || line[j] == '\t')
- j++;
- /* Find the end of the node name. */
- end = j;
- while (line[end] != 0 && line[end] != ',' && line[end] != '\n'
- && line[end] != '\t')
- end++;
- dir_nodes->name = copy_string (line + j, end - j);
- }
- node_header_flag = 0;
- }
-
- /* Notice the start of a node. */
- if (*dir_lines[i].start == 037)
- {
- struct node *next
- = (struct node *) xmalloc (sizeof (struct node));
- next->next = dir_nodes;
- next->name = NULL;
- next->start_line = i;
- next->end_line = 0;
- next->menu_start = NULL;
- next->sections = NULL;
- next->last_section = NULL;
-
- if (dir_nodes != 0)
- dir_nodes->end_line = i;
- /* Fill in the end of the last menu section
- of the previous node. */
- if (dir_nodes != 0 && dir_nodes->last_section != 0)
- dir_nodes->last_section->end_line = i;
-
- dir_nodes = next;
-
- /* The following line is the header of this node;
- parse it. */
- node_header_flag = 1;
- }
-
- /* Notice the lines that start menus. */
- if (dir_nodes != 0
- && !strncmp ("* Menu:", dir_lines[i].start, 7))
- dir_nodes->menu_start = dir_lines[i + 1].start;
-
- /* Notice sections in menus. */
- if (dir_nodes != 0
- && dir_nodes->menu_start != 0
- && *dir_lines[i].start != '\n'
- && *dir_lines[i].start != '*'
- && *dir_lines[i].start != ' '
- && *dir_lines[i].start != '\t')
- {
- /* Add this menu section to the node's list.
- This list grows in forward order. */
- struct menu_section *next
- = (struct menu_section *) xmalloc (sizeof (struct menu_section));
- next->start_line = i + 1;
- next->next = 0;
- next->end_line = 0;
- next->name = copy_string (dir_lines[i].start, dir_lines[i].size);
- if (dir_nodes->sections)
- {
- dir_nodes->last_section->next = next;
- dir_nodes->last_section->end_line = i;
- }
- else
- dir_nodes->sections = next;
- dir_nodes->last_section = next;
- }
-
- /* Check for an existing entry that should be deleted.
- Delete all entries which specify this file name. */
- if (*dir_lines[i].start == '*')
- {
- char *p = dir_lines[i].start;
-
- while (*p != 0 && *p != ':')
- p++;
- p++;
- while (*p == ' ') p++;
- if (*p == '(')
- {
- p++;
- if ((dir_lines[i].size
- > (p - dir_lines[i].start + infilelen_sans_info))
- && !strncmp(p, infile_sans_info, infilelen_sans_info)
- && ( p[infilelen_sans_info] == ')' ||
- strncmp (p + infilelen_sans_info, ".info)", 6) == 0))
- dir_lines[i].delete = 1;
- }
- }
- /* Treat lines that start with whitespace
- as continuations; if we are deleting an entry,
- delete all its continuations as well. */
- else if (i > 0
- && (*dir_lines[i].start == ' '
- || *dir_lines[i].start == '\t'))
- {
- dir_lines[i].delete = dir_lines[i - 1].delete;
- something_deleted = 1;
- }
- }
-
- /* Finish the info about the end of the last node. */
- if (dir_nodes != 0)
- {
- dir_nodes->end_line = dir_nlines;
- if (dir_nodes->last_section != 0)
- dir_nodes->last_section->end_line = dir_nlines;
- }
-
- /* Decide where to add the new entries (unless --delete was used).
- Find the menu sections to add them in.
- In each section, find the proper alphabetical place to add
- each of the entries. */
-
- if (!delete_flag)
- {
- struct node *node;
- struct menu_section *section;
- struct spec_section *spec;
-
- for (node = dir_nodes; node; node = node->next)
- for (section = node->sections; section; section = section->next)
- {
- for (i = section->end_line; i > section->start_line; i--)
- if (dir_lines[i - 1].size != 0)
- break;
- section->end_line = i;
-
- for (spec = input_sections; spec; spec = spec->next)
- if (!strcmp (spec->name, section->name))
- break;
- if (spec)
- {
- int add_at_line = section->end_line;
- struct spec_entry *entry;
- /* Say we have found at least one section with this name,
- so we need not add such a section. */
- spec->missing = 0;
- /* For each entry, find the right place in this section
- to add it. */
- for (entry = entries_to_add; entry; entry = entry->next)
- {
- int textlen = strlen (entry->text);
- /* Subtract one because dir_lines is zero-based,
- but the `end_line' and `start_line' members are
- one-based. */
- for (i = section->end_line - 1;
- i >= section->start_line - 1; i--)
- {
- /* If an entry exists with the same name,
- and was not marked for deletion
- (which means it is for some other file),
- we are in trouble. */
- if (dir_lines[i].start[0] == '*'
- && menu_line_equal (entry->text, textlen,
- dir_lines[i].start,
- dir_lines[i].size)
- && !dir_lines[i].delete)
- fatal ("menu item `%s' already exists, for file `%s'",
- extract_menu_item_name (entry->text),
- extract_menu_file_name (dir_lines[i].start));
- if (dir_lines[i].start[0] == '*'
- && menu_line_lessp (entry->text, textlen,
- dir_lines[i].start,
- dir_lines[i].size))
- add_at_line = i;
- }
- insert_entry_here (entry, add_at_line,
- dir_lines, n_entries_to_add);
- }
- }
- }
-
- /* Mark the end of the Top node as the place to add any
- new sections that are needed. */
- for (node = dir_nodes; node; node = node->next)
- if (node->name && strcmp (node->name, "Top") == 0)
- dir_lines[node->end_line].add_sections_before = 1;
- }
-
- if (delete_flag && !something_deleted && !quiet_flag)
- warning ("no entries found for `%s'; nothing deleted", infile);
-
- /* Output the old dir file, interpolating the new sections
- and/or new entries where appropriate. */
-
- output = fopen (dirfile, "w");
- if (!output)
- {
- perror (dirfile);
- exit (1);
- }
-
- for (i = 0; i <= dir_nlines; i++)
- {
- int j;
-
- /* If we decided to output some new entries before this line,
- output them now. */
- if (dir_lines[i].add_entries_before)
- for (j = 0; j < n_entries_to_add; j++)
- {
- struct spec_entry *this = dir_lines[i].add_entries_before[j];
- if (this == 0)
- break;
- fputs (this->text, output);
- }
- /* If we decided to add some sections here
- because there are no such sections in the file,
- output them now. */
- if (dir_lines[i].add_sections_before)
- {
- struct spec_section *spec;
- struct spec_section **sections;
- int n_sections = 0;
-
- /* Count the sections and allocate a vector for all of them. */
- for (spec = input_sections; spec; spec = spec->next)
- n_sections++;
- sections = ((struct spec_section **)
- xmalloc (n_sections * sizeof (struct spec_section *)));
-
- /* Fill the vector SECTIONS with pointers to all the sections,
- and sort them. */
- j = 0;
- for (spec = input_sections; spec; spec = spec->next)
- sections[j++] = spec;
- qsort (sections, n_sections, sizeof (struct spec_section *),
- compare_section_names);
-
- /* Generate the new sections in alphabetical order.
- In each new section, output all of our entries. */
- for (j = 0; j < n_sections; j++)
- {
- spec = sections[j];
- if (spec->missing)
- {
- struct spec_entry *entry;
-
- putc ('\n', output);
- fputs (spec->name, output);
- putc ('\n', output);
- for (entry = entries_to_add; entry; entry = entry->next)
- fputs (entry->text, output);
- }
- }
-
- free (sections);
- }
-
- /* Output the original dir lines unless marked for deletion. */
- if (i < dir_nlines && !dir_lines[i].delete)
- {
- fwrite (dir_lines[i].start, 1, dir_lines[i].size, output);
- putc ('\n', output);
- }
- }
-
- fclose (output);
-
- exit (0);
-}
-
-/* Read all of file FILNAME into memory
- and return the address of the data.
- Store the size into SIZEP.
- If there is trouble, do a fatal error. */
-
-char *
-readfile (filename, sizep)
- char *filename;
- int *sizep;
-{
- int data_size = 1024;
- char *data = (char *) xmalloc (data_size);
- int filled = 0;
- int nread = 0;
-
- int desc = open (filename, O_RDONLY);
-
- if (desc < 0)
- pfatal_with_name (filename);
-
- while (1)
- {
- nread = read (desc, data + filled, data_size - filled);
- if (nread < 0)
- pfatal_with_name (filename);
- if (nread == 0)
- break;
-
- filled += nread;
- if (filled == data_size)
- {
- data_size *= 2;
- data = (char *) xrealloc (data, data_size);
- }
- }
-
- *sizep = filled;
- return data;
-}
-
-/* Divide the text at DATA (of SIZE bytes) into lines.
- Return a vector of struct line_data describing the lines.
- Store the length of that vector into *NLINESP. */
-
-struct line_data *
-findlines (data, size, nlinesp)
- char *data;
- int size;
- int *nlinesp;
-{
- struct line_data *lines;
- int lines_allocated = 512;
- int filled = 0;
- int i = 0;
- int lineflag;
-
- lines = (struct line_data *) xmalloc (lines_allocated * sizeof (struct line_data));
-
- lineflag = 1;
- for (i = 0; i < size; i++)
- {
- if (lineflag)
- {
- if (filled == lines_allocated)
- {
- lines_allocated *= 2;
- lines = (struct line_data *) xrealloc (lines, lines_allocated * sizeof (struct line_data));
- }
- lines[filled].start = &data[i];
- lines[filled].add_entries_before = 0;
- lines[filled].add_sections_before = 0;
- lines[filled].delete = 0;
- if (filled > 0)
- lines[filled - 1].size
- = lines[filled].start - lines[filled - 1].start - 1;
- filled++;
- }
- lineflag = (data[i] == '\n');
- }
- if (filled > 0)
- lines[filled - 1].size = &data[i] - lines[filled - 1].start - lineflag;
-
- /* Do not leave garbage in the last element. */
- lines[filled].start = NULL;
- lines[filled].add_entries_before = NULL;
- lines[filled].add_sections_before = 0;
- lines[filled].delete = 0;
- lines[filled].size = 0;
-
- *nlinesp = filled;
- return lines;
-}
-
-/* Compare the menu item names in LINE1 (line length LEN1)
- and LINE2 (line length LEN2). Return 1 if the item name
- in LINE1 is less, 0 otherwise. */
-
-int
-menu_line_lessp (line1, len1, line2, len2)
- char *line1;
- int len1;
- char *line2;
- int len2;
-{
- int minlen = (len1 < len2 ? len1 : len2);
- int i;
-
- for (i = 0; i < minlen; i++)
- {
- /* If one item name is a prefix of the other,
- the former one is less. */
- if (line1[i] == ':' && line2[i] != ':')
- return 1;
- if (line2[i] == ':' && line1[i] != ':')
- return 0;
- /* If they both continue and differ, one is less. */
- if (line1[i] < line2[i])
- return 1;
- if (line1[i] > line2[i])
- return 0;
- }
- /* With a properly formatted dir file,
- we can only get here if the item names are equal. */
- return 0;
-}
-
-/* Compare the menu item names in LINE1 (line length LEN1)
- and LINE2 (line length LEN2). Return 1 if the item names are equal,
- 0 otherwise. */
-
-int
-menu_line_equal (line1, len1, line2, len2)
- char *line1;
- int len1;
- char *line2;
- int len2;
-{
- int minlen = (len1 < len2 ? len1 : len2);
- int i;
-
- for (i = 0; i < minlen; i++)
- {
- /* If both item names end here, they are equal. */
- if (line1[i] == ':' && line2[i] == ':')
- return 1;
- /* If they both continue and differ, one is less. */
- if (line1[i] != line2[i])
- return 0;
- }
- /* With a properly formatted dir file,
- we can only get here if the item names are equal. */
- return 1;
-}
-
-/* This is the comparison function for qsort
- for a vector of pointers to struct spec_section.
- Compare the section names. */
-
-int
-compare_section_names (sec1, sec2)
- struct spec_section **sec1, **sec2;
-{
- char *name1 = (*sec1)->name;
- char *name2 = (*sec2)->name;
- return strcmp (name1, name2);
-}
-
-/* Insert ENTRY into the add_entries_before vector
- for line number LINE_NUMBER of the dir file.
- DIR_LINES and N_ENTRIES carry information from like-named variables
- in main. */
-
-void
-insert_entry_here (entry, line_number, dir_lines, n_entries)
- struct spec_entry *entry;
- int line_number;
- struct line_data *dir_lines;
- int n_entries;
-{
- int i;
-
- if (dir_lines[line_number].add_entries_before == 0)
- {
- dir_lines[line_number].add_entries_before
- = (struct spec_entry **) xmalloc (n_entries * sizeof (struct spec_entry *));
- for (i = 0; i < n_entries; i++)
- dir_lines[line_number].add_entries_before[i] = 0;
- }
-
- for (i = 0; i < n_entries; i++)
- if (dir_lines[line_number].add_entries_before[i] == 0)
- break;
-
- if (i == n_entries)
- abort ();
-
- dir_lines[line_number].add_entries_before[i] = entry;
-}
diff --git a/contrib/texinfo/util/mkinstalldirs b/contrib/texinfo/util/mkinstalldirs
deleted file mode 100755
index a01481be4367..000000000000
--- a/contrib/texinfo/util/mkinstalldirs
+++ /dev/null
@@ -1,40 +0,0 @@
-#! /bin/sh
-# mkinstalldirs --- make directory hierarchy
-# Author: Noah Friedman <friedman@prep.ai.mit.edu>
-# Created: 1993-05-16
-# Public domain
-
-# $Id: mkinstalldirs,v 1.10 1996/05/03 07:37:52 friedman Exp $
-
-errstatus=0
-
-for file
-do
- set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
- shift
-
- pathcomp=
- for d
- do
- pathcomp="$pathcomp$d"
- case "$pathcomp" in
- -* ) pathcomp=./$pathcomp ;;
- esac
-
- if test ! -d "$pathcomp"; then
- echo "mkdir $pathcomp" 1>&2
-
- mkdir "$pathcomp" || lasterr=$?
-
- if test ! -d "$pathcomp"; then
- errstatus=$lasterr
- fi
- fi
-
- pathcomp="$pathcomp/"
- done
-done
-
-exit $errstatus
-
-# mkinstalldirs ends here
diff --git a/contrib/texinfo/util/tex3patch b/contrib/texinfo/util/tex3patch
deleted file mode 100755
index 1708c7588bbb..000000000000
--- a/contrib/texinfo/util/tex3patch
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/sh
-# Auxiliary script to work around TeX 3.0 bug. ---- tex3patch ----
-# patches texinfo.tex in current directory, or in directory given as arg.
-
-ANYVERSION=no
-
-for arg in $1 $2
-do
- case $arg in
- --dammit | -d ) ANYVERSION=yes ;;
-
- * ) dir=$arg
- esac
-done
-
-if [ -z "$dir" ]; then
- dir='.'
-fi
-
-if [ \( 2 -lt $# \) -o \
- \( ! -f $dir/texinfo.tex \) ]; then
- echo "To patch texinfo.tex for peaceful coexistence with Unix TeX 3.0,"
- echo "run $0"
- echo "with no arguments in the same directory as texinfo.tex; or run"
- echo " $0 DIRECTORY"
- echo "(where DIRECTORY is a path leading to texinfo.tex)."
- exit
-fi
-
-if [ -z "$TMPDIR" ]; then
- TMPDIR=/tmp
-fi
-
-echo "Checking for \`dummy.tfm'"
-
-( cd $TMPDIR; tex '\relax \batchmode \font\foo=dummy \bye' )
-
-grep -s '3.0' $TMPDIR/texput.log
-if [ 1 = "$?" -a "$ANYVERSION" != "yes" ]; then
- echo "You probably do not need this patch,"
- echo "since your TeX does not seem to be version 3.0."
- echo "If you insist on applying the patch, run $0"
- echo "again with the option \`--dammit'"
- exit
-fi
-
-grep -s 'file not found' $TMPDIR/texput.log
-if [ 0 = $? ]; then
- echo "This patch requires the dummy font metric file \`dummy.tfm',"
- echo "which does not seem to be part of your TeX installation."
- echo "Please get your TeX maintainer to install \`dummy.tfm',"
- echo "then run this script again."
- exit
-fi
-rm $TMPDIR/texput.log
-
-echo "Patching $dir/texinfo.tex"
-
-sed -e 's/%%*\\font\\nullfont/\\font\\nullfont/' \
- $dir/texinfo.tex >$TMPDIR/texinfo.tex
-mv $dir/texinfo.tex $dir/texinfo.tex-distrib; mv $TMPDIR/texinfo.tex $dir
-
-if [ 0 = $? ]; then
- echo "Patched $dir/texinfo.tex to avoid TeX 3.0 bug."
- echo "The original version is saved as $dir/texinfo.tex-distrib."
-else
- echo "Patch failed. Sorry."
-fi
-----------------------------------------tex3patch ends
-
-
diff --git a/contrib/texinfo/util/texi2dvi b/contrib/texinfo/util/texi2dvi
deleted file mode 100755
index 9b2e48eefcc4..000000000000
--- a/contrib/texinfo/util/texi2dvi
+++ /dev/null
@@ -1,364 +0,0 @@
-#! /bin/sh
-# texi2dvi --- smartly produce DVI files from texinfo sources
-
-# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
-
-# $Id: texi2dvi,v 1.10 1996/10/04 18:21:55 karl Exp $
-
-# 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, you can either send email to this
-# program's maintainer or write to: The Free Software Foundation,
-# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
-
-# Commentary:
-
-# Author: Noah Friedman <friedman@prep.ai.mit.edu>
-
-# Please send bug reports, etc. to bug-texinfo@prep.ai.mit.edu
-# If possible, please send a copy of the output of the script called with
-# the `--debug' option when making a bug report.
-
-# In the interest of general portability, some common bourne shell
-# constructs were avoided because they weren't guaranteed to be available
-# in some earlier implementations. I've tried to make this program as
-# portable as possible. Welcome to unix, where the lowest common
-# denominator is rapidly diminishing.
-#
-# Among the more interesting lossages I noticed with some bourne shells
-# are:
-# * No shell functions.
-# * No `unset' builtin.
-# * `shift' cannot take a numeric argument, and signals an error if
-# there are no arguments to shift.
-
-# Code:
-
-# Name by which this script was invoked.
-progname=`echo "$0" | sed -e 's/[^\/]*\///g'`
-
-# This string is expanded by rcs automatically when this file is checked out.
-rcs_revision='$Revision: 1.10 $'
-version=`set - $rcs_revision; echo $2`
-
-# To prevent hairy quoting and escaping later.
-bq='`'
-eq="'"
-
-usage="Usage: $0 [OPTION]... FILE...
-Run a Texinfo document through TeX.
-
-Options:
--D, --debug Turn on shell debugging ($bq${bq}set -x$eq$eq).
--t, --texinfo CMD Insert CMD after @setfilename before running TeX.
---verbose Report on what is done.
--h, --help Display this help and exit.
--v, --version Display version information and exit.
-
-The values of the TEX, TEXINDEX, and MAKEINFO environment variables are
-used to run those commands, if they are set.
-
-Email bug reports to bug-texinfo@prep.ai.mit.edu.
-"
-
-# Initialize variables.
-# Don't use `unset' since old bourne shells don't have this command.
-# Instead, assign them an empty value.
-# Some of these, like TEX and TEXINDEX, may be inherited from the environment.
-backup_extension=.bak # these files get deleted if all goes well.
-debug=
-orig_pwd="`pwd`"
-textra=
-verbose=false
-makeinfo="${MAKEINFO-makeinfo}"
-texindex="${TEXINDEX-texindex}"
-tex="${TEX-tex}"
-
-# Save this so we can construct a new TEXINPUTS path for each file.
-TEXINPUTS_orig="$TEXINPUTS"
-export TEXINPUTS
-
-# Parse command line arguments.
-# Make sure that all wildcarded options are long enough to be unambiguous.
-# It's a good idea to document the full long option name in each case.
-# Long options which take arguments will need a `*' appended to the
-# canonical name to match the value appended after the `=' character.
-while : ; do
- case $# in 0) break ;; esac
- case "$1" in
- -D | --debug | --d* ) debug=t; shift ;;
- -h | --help | --h* ) echo "$usage"; exit 0 ;;
- # OK, we should do real option parsing here, but be lazy for now.
- -t | --texinfo | --t*) shift; textra="$textra $1"; shift ;;
- -v | --vers* )
- echo "$progname (Texinfo 3.9) $version"
- echo "Copyright (C) 1996 Free Software Foundation, Inc.
-There is NO warranty. You may redistribute this software
-under the terms of the GNU General Public License.
-For more information about these matters, see the files named COPYING."
- exit 0 ;;
- --verb* ) verbose=echo; shift ;;
- -- ) # Stop option processing
- shift
- break
- ;;
- -* )
- case "$1" in
- --*=* ) arg=`echo "$1" | sed -e 's/=.*//'` ;;
- * ) arg="$1" ;;
- esac
- exec 1>&2
- echo "$progname: Unknown or ambiguous option $bq$arg$eq."
- echo "$progname: Try $bq--help$eq for more information."
- exit 1
- ;;
- * )
- break
- ;;
- esac
-done
-
-# See if there are any command line args left (which will be interpreted as
-# filename arguments).
-if test $# -eq 0; then
- exec 1>&2
- echo "$progname: At least one file name is required as an argument."
- echo "$progname: Try $bq--help$eq for more information."
- exit 2
-fi
-
-test "$debug" = t && set -x
-
-# Texify files
-for command_line_filename in ${1+"$@"} ; do
- $verbose "Processing $command_line_filename ..."
-
- # See if file exists. If it doesn't we're in trouble since, even
- # though the user may be able to reenter a valid filename at the tex
- # prompt (assuming they're attending the terminal), this script won't
- # be able to find the right index files and so forth.
- if test ! -r "${command_line_filename}" ; then
- echo "$0: Could not read ${command_line_filename}." >&2
- continue
- fi
-
- # Roughly equivalent to `dirname ...`, but more portable
- directory="`echo ${command_line_filename} | sed 's/\/[^\/]*$//'`"
- filename_texi="`basename ${command_line_filename}`"
- # Strip off the last extension part (probably .texinfo or .texi)
- filename_noext="`echo ${filename_texi} | sed 's/\.[^.]*$//'`"
-
- # Use same basename since we want to generate aux files with the same
- # basename as the manual. Use extension .texi for the temp file so
- # that TeX will ignore it. Thus, we must use a subdirectory.
- #
- # Output the macro-expanded file to here.
- tmp_dir=${TMPDIR-/tmp}/$$
- filename_tmp=$tmp_dir/$filename_noext.texi
- # Output the file with the user's extra commands to here.
- filename_tmp2=$tmp_dir.2/$filename_noext.texi
- mkdir $tmp_dir $tmp_dir.2
-
- # If directory and file are the same, then it's probably because there's
- # no pathname component. Set dirname to `.', the current directory.
- if test "z${directory}" = "z${command_line_filename}" ; then
- directory=.
- fi
-
- # Source file might @include additional texinfo sources. Put `.' and
- # directory where source file(s) reside in TEXINPUTS before anything
- # else. `.' goes first to ensure that any old .aux, .cps, etc. files in
- # ${directory} don't get used in preference to fresher files in `.'.
- TEXINPUTS=".:${directory}:${TEXINPUTS_orig}"
-
- # Expand macro commands in the original source file using Makeinfo;
- # the macro syntax bfox implemented is impossible to implement in TeX.
- # Always use `end' footnote style, since the `separate' style
- # generates different output (arguably this is a bug in -E).
- # Discard main info output, the user asked to run TeX, not makeinfo.
- # Redirect output to /dev/null to throw away `Making info file...' msg.
- $verbose "Macro-expanding $command_line_filename to $filename_tmp ..."
- $makeinfo --footnote-style=end -E $filename_tmp -o /dev/null \
- $command_line_filename >/dev/null
-
- # But if there were no macros, or makeinfo failed for some reason,
- # just use the original file. (It shouldn't make any difference, but
- # let's be safe.)
- if test $? -ne 0 || cmp -s $filename_tmp $command_line_filename; then
- $verbose "Reverting to $command_line_filename ..."
- filename_input=$command_line_filename
- else
- filename_input=$filename_tmp
- fi
-
- # Used most commonly for @finalout, @smallbook, etc.
- if test -n "$textra"; then
- $verbose "Inserting extra commands: $textra."
- sed '/^@setfilename/a\
-'"$textra" $filename_input >$filename_tmp2
- filename_input=$filename_tmp2
- fi
-
- while true; do # will break out of loop below
- # "Unset" variables that might have values from previous iterations and
- # which won't be completely reset later.
- definite_index_files=
-
- # Find all files having root filename with a two-letter extension,
- # determine whether they're really index files, and save them. Foo.aux
- # is actually the cross-references file, but we need to keep track of
- # that too.
- possible_index_files="`eval echo ${filename_noext}.?? ${filename_noext}.aux`"
- for this_file in ${possible_index_files} ; do
- # If file is empty, forget it.
- test -s "${this_file}" || continue
-
- # Examine first character of file. If it's not suitable to be an
- # index or xref file, don't process it.
- first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`"
- if test "x${first_character}" = "x\\" \
- || test "x${first_character}" = "x'"; then
- definite_index_files="${definite_index_files} ${this_file}"
- fi
- done
- orig_index_files="${definite_index_files}"
- orig_index_files_sans_aux="`echo ${definite_index_files} \
- | sed 's/'${filename_noext}'\.aux//;
- s/^[ ]*//;s/[ ]*$//;'`"
-
- # Now save copies of original index files so we have some means of
- # comparison later.
- $verbose "Backing up current index files: $orig_index_files ..."
- for index_file_to_save in ${orig_index_files} ; do
- cp "${index_file_to_save}" "${index_file_to_save}${backup_extension}"
- done
-
- # Run texindex on current index files. If they already exist, and
- # after running TeX a first time the index files don't change, then
- # there's no reason to run TeX again. But we won't know that if the
- # index files are out of date or nonexistent.
- if test -n "${orig_index_files_sans_aux}" ; then
- $verbose "Running $texindex $orig_index_files_sans_aux ..."
- ${texindex} ${orig_index_files_sans_aux}
- fi
-
- # Finally, run TeX.
- $verbose "Running $tex $filename_input ..."
- ${tex} "$filename_input"
-
- # Check if index files changed.
- #
- definite_index_files=
- # Get list of new index files.
- possible_index_files="`eval echo ${filename_noext}.?? ${filename_noext}.aux`"
- for this_file in ${possible_index_files} ; do
- # If file is empty, forget it.
- test -s "${this_file}" || continue
-
- # Examine first character of file. If it's not a backslash or
- # single quote, then it's definitely not an index or xref file.
- # (Will have to check for @ when we switch to Texinfo syntax in
- # all these files...)
- first_character="`sed -n '1s/^\(.\).*$/\1/p;q' ${this_file}`"
- if test "x${first_character}" = "x\\" \
- || test "x${first_character}" = "x'"; then
- definite_index_files="${definite_index_files} ${this_file}"
- fi
- done
- new_index_files="${definite_index_files}"
- new_index_files_sans_aux="`echo ${definite_index_files} \
- | sed 's/'${filename_noext}'\.aux//;
- s/^[ ]*//;s/[ ]*$//;'`"
-
- # If old and new list don't at least have the same file list, then one
- # file or another has definitely changed.
- $verbose "Original index files =$orig_index_files"
- $verbose "New index files =$new_index_files"
- if test "z${orig_index_files}" != "z${new_index_files}" ; then
- index_files_changed_p=t
- else
- # File list is the same. We must compare each file until we find a
- # difference.
- index_files_changed_p=
- for this_file in ${new_index_files} ; do
- $verbose "Comparing index file $this_file ..."
- # cmp -s will return nonzero exit status if files differ.
- cmp -s "${this_file}" "${this_file}${backup_extension}"
- if test $? -ne 0 ; then
- # We only need to keep comparing until we find *one* that
- # differs, because we'll have to run texindex & tex no
- # matter what.
- index_files_changed_p=t
- $verbose "Index file $this_file differed:"
- test $verbose = echo \
- && diff -c "${this_file}${backup_extension}" "${this_file}"
- break
- fi
- done
- fi
-
- # If index files have changed since TeX has been run, or if the aux
- # file wasn't present originally, run texindex and TeX again.
- if test "${index_files_changed_p}" ; then :; else
- # Nothing changed. We're done with TeX.
- break
- fi
- done
-
- # Generate list of files to delete, then call rm once with the entire
- # list. This is significantly faster than multiple executions of rm.
- file_list=
- for file in ${orig_index_files} ; do
- file_list="${file_list} ${file}${backup_extension}"
- done
- if test -n "${file_list}" ; then
- $verbose "Removing $file_list $tmp_dir $tmp_dir.2 ..."
- rm -f ${file_list}
- rm -rf $tmp_dir $tmp_dir.2
- fi
-done
-
-$verbose "$0 done."
-true # exit successfully.
-
-# texi2dvi ends here
-# $Log: texi2dvi,v $
-# Revision 1.10 1996/10/04 18:21:55 karl
-# Include only the current year in the copyright message.
-#
-# Revision 1.9 1996/10/04 11:49:48 karl
-# Exit successfully. From arnold.
-#
-# Revision 1.8 1996/10/03 23:14:26 karl
-# Only show diff if verbose.
-# Update version number.
-#
-# Revision 1.7 1996/09/29 22:56:08 karl
-# Use $progname instead of $0 for --version.
-#
-# Revision 1.6 1996/09/28 21:01:23 karl
-# Recompute original index files each time through loop.
-# Make indentation uniform.
-# Use same basename for the temp input files.
-# Standardize --version output.
-#
-# Revision 1.5 1996/09/26 14:46:34 karl
-# (texi2dvi): Run TeX until the aux/index files stabilize, instead of just
-# twice. From: David Shaw <daves@gsms01.alcatel.com.au>.
-#
-# Revision 1.4 1996/08/27 18:59:26 karl
-# Include bug reporting address.
-#
-# Revision 1.3 1996/07/26 18:20:56 karl
-# Do macro expansion with makeinfo before running TeX.
-# Various expansion safety measures added for test; avoid use of -o.
-#
diff --git a/contrib/texinfo/util/texindex.c b/contrib/texinfo/util/texindex.c
deleted file mode 100644
index 47a56791611f..000000000000
--- a/contrib/texinfo/util/texindex.c
+++ /dev/null
@@ -1,1793 +0,0 @@
-/* Prepare TeX index dribble output into an actual index.
- $Id: texindex.c,v 1.6 1996/10/04 18:21:30 karl Exp $
-
- Copyright (C) 1987, 91, 92, 96 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307. */
-
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-#include "getopt.h"
-
-#define TEXINDEX_VERSION_STRING "GNU Texindex (Texinfo 3.9) 2.1"
-
-#if defined (emacs)
-# include "../src/config.h"
-/* Some s/os.h files redefine these. */
-# undef read
-# undef close
-# undef write
-# undef open
-#endif
-
-#if defined (HAVE_STRING_H)
-# include <string.h>
-#endif /* HAVE_STRING_H */
-
-#if !defined (HAVE_STRCHR)
-char *strrchr ();
-#endif /* !HAVE_STRCHR */
-
-#if defined (STDC_HEADERS)
-# include <stdlib.h>
-#else /* !STDC_HEADERS */
-char *getenv (), *malloc (), *realloc ();
-#endif /* !STDC_HEADERS */
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#else /* !HAVE_UNISTD_H */
-off_t lseek ();
-#endif /* !HAVE_UNISTD_H */
-
-#if !defined (HAVE_MEMSET)
-#undef memset
-#define memset(ptr, ignore, count) bzero (ptr, count)
-#endif
-
-
-char *mktemp ();
-
-#if defined (VMS)
-# include <file.h>
-# define TI_NO_ERROR ((1 << 28) | 1)
-# define TI_FATAL_ERROR ((1 << 28) | 4)
-# define unlink delete
-#else /* !VMS */
-# if defined (HAVE_SYS_FCNTL_H)
-# include <sys/types.h>
-# include <sys/fcntl.h>
-# endif /* HAVE_SYS_FCNTL_H */
-
-# if defined (_AIX) || !defined (_POSIX_VERSION)
-# include <sys/file.h>
-# else /* !AIX && _POSIX_VERSION */
-# if !defined (HAVE_SYS_FCNTL_H)
-# include <fcntl.h>
-# endif /* !HAVE_FCNTL_H */
-# endif /* !_AIX && _POSIX_VERSION */
-# define TI_NO_ERROR 0
-# define TI_FATAL_ERROR 1
-#endif /* !VMS */
-
-#if !defined (SEEK_SET)
-# define SEEK_SET 0
-# define SEEK_CUR 1
-# define SEEK_END 2
-#endif /* !SEEK_SET */
-
-#ifndef errno
-extern int errno;
-#endif
-#ifndef strerror
-extern char *strerror ();
-#endif
-
-/* When sorting in core, this structure describes one line
- and the position and length of its first keyfield. */
-struct lineinfo
-{
- char *text; /* The actual text of the line. */
- union {
- char *text; /* The start of the key (for textual comparison). */
- long number; /* The numeric value (for numeric comparison). */
- } key;
- long keylen; /* Length of KEY field. */
-};
-
-/* This structure describes a field to use as a sort key. */
-struct keyfield
-{
- int startwords; /* Number of words to skip. */
- int startchars; /* Number of additional chars to skip. */
- int endwords; /* Number of words to ignore at end. */
- int endchars; /* Ditto for characters of last word. */
- char ignore_blanks; /* Non-zero means ignore spaces and tabs. */
- char fold_case; /* Non-zero means case doesn't matter. */
- char reverse; /* Non-zero means compare in reverse order. */
- char numeric; /* Non-zeros means field is ASCII numeric. */
- char positional; /* Sort according to file position. */
- char braced; /* Count balanced-braced groupings as fields. */
-};
-
-/* Vector of keyfields to use. */
-struct keyfield keyfields[3];
-
-/* Number of keyfields stored in that vector. */
-int num_keyfields = 3;
-
-/* Vector of input file names, terminated with a null pointer. */
-char **infiles;
-
-/* Vector of corresponding output file names, or NULL, meaning default it
- (add an `s' to the end). */
-char **outfiles;
-
-/* Length of `infiles'. */
-int num_infiles;
-
-/* Pointer to the array of pointers to lines being sorted. */
-char **linearray;
-
-/* The allocated length of `linearray'. */
-long nlines;
-
-/* Directory to use for temporary files. On Unix, it ends with a slash. */
-char *tempdir;
-
-/* Start of filename to use for temporary files. */
-char *tempbase;
-
-/* Number of last temporary file. */
-int tempcount;
-
-/* Number of last temporary file already deleted.
- Temporary files are deleted by `flush_tempfiles' in order of creation. */
-int last_deleted_tempcount;
-
-/* During in-core sort, this points to the base of the data block
- which contains all the lines of data. */
-char *text_base;
-
-/* Additional command switches .*/
-
-/* Nonzero means do not delete tempfiles -- for debugging. */
-int keep_tempfiles;
-
-/* The name this program was run with. */
-char *program_name;
-
-/* Forward declarations of functions in this file. */
-
-void decode_command ();
-void sort_in_core ();
-void sort_offline ();
-char **parsefile ();
-char *find_field ();
-char *find_pos ();
-long find_value ();
-char *find_braced_pos ();
-char *find_braced_end ();
-void writelines ();
-int compare_field ();
-int compare_full ();
-long readline ();
-int merge_files ();
-int merge_direct ();
-void pfatal_with_name ();
-void fatal ();
-void error ();
-void *xmalloc (), *xrealloc ();
-char *concat ();
-char *maketempname ();
-void flush_tempfiles ();
-char *tempcopy ();
-
-#define MAX_IN_CORE_SORT 500000
-
-void
-main (argc, argv)
- int argc;
- char **argv;
-{
- int i;
-
- tempcount = 0;
- last_deleted_tempcount = 0;
-
- program_name = strrchr (argv[0], '/');
- if (program_name != (char *)NULL)
- program_name++;
- else
- program_name = argv[0];
-
- /* Describe the kind of sorting to do. */
- /* The first keyfield uses the first braced field and folds case. */
- keyfields[0].braced = 1;
- keyfields[0].fold_case = 1;
- keyfields[0].endwords = -1;
- keyfields[0].endchars = -1;
-
- /* The second keyfield uses the second braced field, numerically. */
- keyfields[1].braced = 1;
- keyfields[1].numeric = 1;
- keyfields[1].startwords = 1;
- keyfields[1].endwords = -1;
- keyfields[1].endchars = -1;
-
- /* The third keyfield (which is ignored while discarding duplicates)
- compares the whole line. */
- keyfields[2].endwords = -1;
- keyfields[2].endchars = -1;
-
- decode_command (argc, argv);
-
- tempbase = mktemp (concat ("txiXXXXXX", "", ""));
-
- /* Process input files completely, one by one. */
-
- for (i = 0; i < num_infiles; i++)
- {
- int desc;
- long ptr;
- char *outfile;
-
- desc = open (infiles[i], O_RDONLY, 0);
- if (desc < 0)
- pfatal_with_name (infiles[i]);
- lseek (desc, (off_t) 0, SEEK_END);
- ptr = (long) lseek (desc, (off_t) 0, SEEK_CUR);
-
- close (desc);
-
- outfile = outfiles[i];
- if (!outfile)
- {
- outfile = concat (infiles[i], "s", "");
- }
-
- if (ptr < MAX_IN_CORE_SORT)
- /* Sort a small amount of data. */
- sort_in_core (infiles[i], ptr, outfile);
- else
- sort_offline (infiles[i], ptr, outfile);
- }
-
- flush_tempfiles (tempcount);
- exit (TI_NO_ERROR);
-}
-
-typedef struct
-{
- char *long_name;
- char *short_name;
- int *variable_ref;
- int variable_value;
- char *arg_name;
- char *doc_string;
-} TEXINDEX_OPTION;
-
-TEXINDEX_OPTION texindex_options[] = {
- { "--keep", "-k", &keep_tempfiles, 1, (char *)NULL,
- "keep temporary files around after processing" },
- { "--no-keep", 0, &keep_tempfiles, 0, (char *)NULL,
- "do not keep temporary files around after processing (default)" },
- { "--output", "-o", (int *)NULL, 0, "FILE",
- "send output to FILE" },
- { "--version", (char *)NULL, (int *)NULL, 0, (char *)NULL,
- "display version information and exit" },
- { "--help", "-h", (int *)NULL, 0, (char *)NULL,
- "display this help and exit" },
- { (char *)NULL, (char *)NULL, (int *)NULL, 0, (char *)NULL }
-};
-
-void
-usage (result_value)
- int result_value;
-{
- register int i;
- FILE *f = result_value ? stderr : stdout;
-
- fprintf (f, "Usage: %s [OPTION]... FILE...\n", program_name);
- fprintf (f, "Generate a sorted index for each TeX output FILE.\n");
- /* Avoid trigraph nonsense. */
- fprintf (f, "Usually FILE... is `foo.??\' for a document `foo.texi'.\n");
- fprintf (f, "\nOptions:\n");
-
- for (i = 0; texindex_options[i].long_name; i++)
- {
- if (texindex_options[i].short_name)
- fprintf (f, "%s, ", texindex_options[i].short_name);
-
- fprintf (f, "%s %s",
- texindex_options[i].long_name,
- texindex_options[i].arg_name
- ? texindex_options[i].arg_name : "");
-
- fprintf (f, "\t%s\n", texindex_options[i].doc_string);
- }
- puts ("\nEmail bug reports to bug-texinfo@prep.ai.mit.edu.");
-
- exit (result_value);
-}
-
-/* Decode the command line arguments to set the parameter variables
- and set up the vector of keyfields and the vector of input files. */
-
-void
-decode_command (argc, argv)
- int argc;
- char **argv;
-{
- int arg_index = 1;
- int optc;
- char **ip;
- char **op;
-
- /* Store default values into parameter variables. */
-
- tempdir = getenv ("TMPDIR");
-#ifdef VMS
- if (tempdir == NULL)
- tempdir = "sys$scratch:";
-#else
- if (tempdir == NULL)
- tempdir = "/tmp/";
- else
- tempdir = concat (tempdir, "/", "");
-#endif
-
- keep_tempfiles = 0;
-
- /* Allocate ARGC input files, which must be enough. */
-
- infiles = (char **) xmalloc (argc * sizeof (char *));
- outfiles = (char **) xmalloc (argc * sizeof (char *));
- ip = infiles;
- op = outfiles;
-
- while (arg_index < argc)
- {
- char *arg = argv[arg_index++];
-
- if (*arg == '-')
- {
- if (strcmp (arg, "--version") == 0)
- {
- puts (TEXINDEX_VERSION_STRING);
-puts ("Copyright (C) 1996 Free Software Foundation, Inc.\n\
-There is NO warranty. You may redistribute this software\n\
-under the terms of the GNU General Public License.\n\
-For more information about these matters, see the files named COPYING.");
- exit (0);
- }
- else if ((strcmp (arg, "--keep") == 0) ||
- (strcmp (arg, "-k") == 0))
- {
- keep_tempfiles = 1;
- }
- else if ((strcmp (arg, "--help") == 0) ||
- (strcmp (arg, "-h") == 0))
- {
- usage (0);
- }
- else if ((strcmp (arg, "--output") == 0) ||
- (strcmp (arg, "-o") == 0))
- {
- if (argv[arg_index] != (char *)NULL)
- {
- arg_index++;
- if (op > outfiles)
- *(op - 1) = argv[arg_index];
- }
- else
- usage (1);
- }
- else
- usage (1);
- }
- else
- {
- *ip++ = arg;
- *op++ = (char *)NULL;
- }
- }
-
- /* Record number of keyfields and terminate list of filenames. */
- num_infiles = ip - infiles;
- *ip = (char *)NULL;
- if (num_infiles == 0)
- usage (1);
-}
-
-/* Return a name for a temporary file. */
-
-char *
-maketempname (count)
- int count;
-{
- char tempsuffix[10];
- sprintf (tempsuffix, "%d", count);
- return concat (tempdir, tempbase, tempsuffix);
-}
-
-/* Delete all temporary files up to TO_COUNT. */
-
-void
-flush_tempfiles (to_count)
- int to_count;
-{
- if (keep_tempfiles)
- return;
- while (last_deleted_tempcount < to_count)
- unlink (maketempname (++last_deleted_tempcount));
-}
-
-/* Copy the input file open on IDESC into a temporary file
- and return the temporary file name. */
-
-#define BUFSIZE 1024
-
-char *
-tempcopy (idesc)
- int idesc;
-{
- char *outfile = maketempname (++tempcount);
- int odesc;
- char buffer[BUFSIZE];
-
- odesc = open (outfile, O_WRONLY | O_CREAT, 0666);
-
- if (odesc < 0)
- pfatal_with_name (outfile);
-
- while (1)
- {
- int nread = read (idesc, buffer, BUFSIZE);
- write (odesc, buffer, nread);
- if (!nread)
- break;
- }
-
- close (odesc);
-
- return outfile;
-}
-
-/* Compare LINE1 and LINE2 according to the specified set of keyfields. */
-
-int
-compare_full (line1, line2)
- char **line1, **line2;
-{
- int i;
-
- /* Compare using the first keyfield;
- if that does not distinguish the lines, try the second keyfield;
- and so on. */
-
- for (i = 0; i < num_keyfields; i++)
- {
- long length1, length2;
- char *start1 = find_field (&keyfields[i], *line1, &length1);
- char *start2 = find_field (&keyfields[i], *line2, &length2);
- int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base,
- start2, length2, *line2 - text_base);
- if (tem)
- {
- if (keyfields[i].reverse)
- return -tem;
- return tem;
- }
- }
-
- return 0; /* Lines match exactly. */
-}
-
-/* Compare LINE1 and LINE2, described by structures
- in which the first keyfield is identified in advance.
- For positional sorting, assumes that the order of the lines in core
- reflects their nominal order. */
-
-int
-compare_prepared (line1, line2)
- struct lineinfo *line1, *line2;
-{
- int i;
- int tem;
- char *text1, *text2;
-
- /* Compare using the first keyfield, which has been found for us already. */
- if (keyfields->positional)
- {
- if (line1->text - text_base > line2->text - text_base)
- tem = 1;
- else
- tem = -1;
- }
- else if (keyfields->numeric)
- tem = line1->key.number - line2->key.number;
- else
- tem = compare_field (keyfields, line1->key.text, line1->keylen, 0,
- line2->key.text, line2->keylen, 0);
- if (tem)
- {
- if (keyfields->reverse)
- return -tem;
- return tem;
- }
-
- text1 = line1->text;
- text2 = line2->text;
-
- /* Compare using the second keyfield;
- if that does not distinguish the lines, try the third keyfield;
- and so on. */
-
- for (i = 1; i < num_keyfields; i++)
- {
- long length1, length2;
- char *start1 = find_field (&keyfields[i], text1, &length1);
- char *start2 = find_field (&keyfields[i], text2, &length2);
- int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base,
- start2, length2, text2 - text_base);
- if (tem)
- {
- if (keyfields[i].reverse)
- return -tem;
- return tem;
- }
- }
-
- return 0; /* Lines match exactly. */
-}
-
-/* Like compare_full but more general.
- You can pass any strings, and you can say how many keyfields to use.
- POS1 and POS2 should indicate the nominal positional ordering of
- the two lines in the input. */
-
-int
-compare_general (str1, str2, pos1, pos2, use_keyfields)
- char *str1, *str2;
- long pos1, pos2;
- int use_keyfields;
-{
- int i;
-
- /* Compare using the first keyfield;
- if that does not distinguish the lines, try the second keyfield;
- and so on. */
-
- for (i = 0; i < use_keyfields; i++)
- {
- long length1, length2;
- char *start1 = find_field (&keyfields[i], str1, &length1);
- char *start2 = find_field (&keyfields[i], str2, &length2);
- int tem = compare_field (&keyfields[i], start1, length1, pos1,
- start2, length2, pos2);
- if (tem)
- {
- if (keyfields[i].reverse)
- return -tem;
- return tem;
- }
- }
-
- return 0; /* Lines match exactly. */
-}
-
-/* Find the start and length of a field in STR according to KEYFIELD.
- A pointer to the starting character is returned, and the length
- is stored into the int that LENGTHPTR points to. */
-
-char *
-find_field (keyfield, str, lengthptr)
- struct keyfield *keyfield;
- char *str;
- long *lengthptr;
-{
- char *start;
- char *end;
- char *(*fun) ();
-
- if (keyfield->braced)
- fun = find_braced_pos;
- else
- fun = find_pos;
-
- start = (*fun) (str, keyfield->startwords, keyfield->startchars,
- keyfield->ignore_blanks);
- if (keyfield->endwords < 0)
- {
- if (keyfield->braced)
- end = find_braced_end (start);
- else
- {
- end = start;
- while (*end && *end != '\n')
- end++;
- }
- }
- else
- {
- end = (*fun) (str, keyfield->endwords, keyfield->endchars, 0);
- if (end - str < start - str)
- end = start;
- }
- *lengthptr = end - start;
- return start;
-}
-
-/* Return a pointer to a specified place within STR,
- skipping (from the beginning) WORDS words and then CHARS chars.
- If IGNORE_BLANKS is nonzero, we skip all blanks
- after finding the specified word. */
-
-char *
-find_pos (str, words, chars, ignore_blanks)
- char *str;
- int words, chars;
- int ignore_blanks;
-{
- int i;
- char *p = str;
-
- for (i = 0; i < words; i++)
- {
- char c;
- /* Find next bunch of nonblanks and skip them. */
- while ((c = *p) == ' ' || c == '\t')
- p++;
- while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t'))
- p++;
- if (!*p || *p == '\n')
- return p;
- }
-
- while (*p == ' ' || *p == '\t')
- p++;
-
- for (i = 0; i < chars; i++)
- {
- if (!*p || *p == '\n')
- break;
- p++;
- }
- return p;
-}
-
-/* Like find_pos but assumes that each field is surrounded by braces
- and that braces within fields are balanced. */
-
-char *
-find_braced_pos (str, words, chars, ignore_blanks)
- char *str;
- int words, chars;
- int ignore_blanks;
-{
- int i;
- int bracelevel;
- char *p = str;
- char c;
-
- for (i = 0; i < words; i++)
- {
- bracelevel = 1;
- while ((c = *p++) != '{' && c != '\n' && c)
- /* Do nothing. */ ;
- if (c != '{')
- return p - 1;
- while (bracelevel)
- {
- c = *p++;
- if (c == '{')
- bracelevel++;
- if (c == '}')
- bracelevel--;
- if (c == 0 || c == '\n')
- return p - 1;
- }
- }
-
- while ((c = *p++) != '{' && c != '\n' && c)
- /* Do nothing. */ ;
-
- if (c != '{')
- return p - 1;
-
- if (ignore_blanks)
- while ((c = *p) == ' ' || c == '\t')
- p++;
-
- for (i = 0; i < chars; i++)
- {
- if (!*p || *p == '\n')
- break;
- p++;
- }
- return p;
-}
-
-/* Find the end of the balanced-brace field which starts at STR.
- The position returned is just before the closing brace. */
-
-char *
-find_braced_end (str)
- char *str;
-{
- int bracelevel;
- char *p = str;
- char c;
-
- bracelevel = 1;
- while (bracelevel)
- {
- c = *p++;
- if (c == '{')
- bracelevel++;
- if (c == '}')
- bracelevel--;
- if (c == 0 || c == '\n')
- return p - 1;
- }
- return p - 1;
-}
-
-long
-find_value (start, length)
- char *start;
- long length;
-{
- while (length != 0L)
- {
- if (isdigit (*start))
- return atol (start);
- length--;
- start++;
- }
- return 0l;
-}
-
-/* Vector used to translate characters for comparison.
- This is how we make all alphanumerics follow all else,
- and ignore case in the first sorting. */
-int char_order[256];
-
-void
-init_char_order ()
-{
- int i;
- for (i = 1; i < 256; i++)
- char_order[i] = i;
-
- for (i = '0'; i <= '9'; i++)
- char_order[i] += 512;
-
- for (i = 'a'; i <= 'z'; i++)
- {
- char_order[i] = 512 + i;
- char_order[i + 'A' - 'a'] = 512 + i;
- }
-}
-
-/* Compare two fields (each specified as a start pointer and a character count)
- according to KEYFIELD.
- The sign of the value reports the relation between the fields. */
-
-int
-compare_field (keyfield, start1, length1, pos1, start2, length2, pos2)
- struct keyfield *keyfield;
- char *start1;
- long length1;
- long pos1;
- char *start2;
- long length2;
- long pos2;
-{
- if (keyfields->positional)
- {
- if (pos1 > pos2)
- return 1;
- else
- return -1;
- }
- if (keyfield->numeric)
- {
- long value = find_value (start1, length1) - find_value (start2, length2);
- if (value > 0)
- return 1;
- if (value < 0)
- return -1;
- return 0;
- }
- else
- {
- char *p1 = start1;
- char *p2 = start2;
- char *e1 = start1 + length1;
- char *e2 = start2 + length2;
-
- while (1)
- {
- int c1, c2;
-
- if (p1 == e1)
- c1 = 0;
- else
- c1 = *p1++;
- if (p2 == e2)
- c2 = 0;
- else
- c2 = *p2++;
-
- if (char_order[c1] != char_order[c2])
- return char_order[c1] - char_order[c2];
- if (!c1)
- break;
- }
-
- /* Strings are equal except possibly for case. */
- p1 = start1;
- p2 = start2;
- while (1)
- {
- int c1, c2;
-
- if (p1 == e1)
- c1 = 0;
- else
- c1 = *p1++;
- if (p2 == e2)
- c2 = 0;
- else
- c2 = *p2++;
-
- if (c1 != c2)
- /* Reverse sign here so upper case comes out last. */
- return c2 - c1;
- if (!c1)
- break;
- }
-
- return 0;
- }
-}
-
-/* A `struct linebuffer' is a structure which holds a line of text.
- `readline' reads a line from a stream into a linebuffer
- and works regardless of the length of the line. */
-
-struct linebuffer
-{
- long size;
- char *buffer;
-};
-
-/* Initialize LINEBUFFER for use. */
-
-void
-initbuffer (linebuffer)
- struct linebuffer *linebuffer;
-{
- linebuffer->size = 200;
- linebuffer->buffer = (char *) xmalloc (200);
-}
-
-/* Read a line of text from STREAM into LINEBUFFER.
- Return the length of the line. */
-
-long
-readline (linebuffer, stream)
- struct linebuffer *linebuffer;
- FILE *stream;
-{
- char *buffer = linebuffer->buffer;
- char *p = linebuffer->buffer;
- char *end = p + linebuffer->size;
-
- while (1)
- {
- int c = getc (stream);
- if (p == end)
- {
- buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
- p += buffer - linebuffer->buffer;
- end += buffer - linebuffer->buffer;
- linebuffer->buffer = buffer;
- }
- if (c < 0 || c == '\n')
- {
- *p = 0;
- break;
- }
- *p++ = c;
- }
-
- return p - buffer;
-}
-
-/* Sort an input file too big to sort in core. */
-
-void
-sort_offline (infile, nfiles, total, outfile)
- char *infile;
- int nfiles;
- long total;
- char *outfile;
-{
- /* More than enough. */
- int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT;
- char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
- FILE *istream = fopen (infile, "r");
- int i;
- struct linebuffer lb;
- long linelength;
- int failure = 0;
-
- initbuffer (&lb);
-
- /* Read in one line of input data. */
-
- linelength = readline (&lb, istream);
-
- if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
- {
- error ("%s: not a texinfo index file", infile);
- return;
- }
-
- /* Split up the input into `ntemps' temporary files, or maybe fewer,
- and put the new files' names into `tempfiles' */
-
- for (i = 0; i < ntemps; i++)
- {
- char *outname = maketempname (++tempcount);
- FILE *ostream = fopen (outname, "w");
- long tempsize = 0;
-
- if (!ostream)
- pfatal_with_name (outname);
- tempfiles[i] = outname;
-
- /* Copy lines into this temp file as long as it does not make file
- "too big" or until there are no more lines. */
-
- while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)
- {
- tempsize += linelength + 1;
- fputs (lb.buffer, ostream);
- putc ('\n', ostream);
-
- /* Read another line of input data. */
-
- linelength = readline (&lb, istream);
- if (!linelength && feof (istream))
- break;
-
- if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
- {
- error ("%s: not a texinfo index file", infile);
- failure = 1;
- goto fail;
- }
- }
- fclose (ostream);
- if (feof (istream))
- break;
- }
-
- free (lb.buffer);
-
-fail:
- /* Record number of temp files we actually needed. */
-
- ntemps = i;
-
- /* Sort each tempfile into another tempfile.
- Delete the first set of tempfiles and put the names of the second
- into `tempfiles'. */
-
- for (i = 0; i < ntemps; i++)
- {
- char *newtemp = maketempname (++tempcount);
- sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp);
- if (!keep_tempfiles)
- unlink (tempfiles[i]);
- tempfiles[i] = newtemp;
- }
-
- if (failure)
- return;
-
- /* Merge the tempfiles together and indexify. */
-
- merge_files (tempfiles, ntemps, outfile);
-}
-
-/* Sort INFILE, whose size is TOTAL,
- assuming that is small enough to be done in-core,
- then indexify it and send the output to OUTFILE (or to stdout). */
-
-void
-sort_in_core (infile, total, outfile)
- char *infile;
- long total;
- char *outfile;
-{
- char **nextline;
- char *data = (char *) xmalloc (total + 1);
- char *file_data;
- long file_size;
- int i;
- FILE *ostream = stdout;
- struct lineinfo *lineinfo;
-
- /* Read the contents of the file into the moby array `data'. */
-
- int desc = open (infile, O_RDONLY, 0);
-
- if (desc < 0)
- fatal ("failure reopening %s", infile);
- for (file_size = 0;;)
- {
- i = read (desc, data + file_size, total - file_size);
- if (i <= 0)
- break;
- file_size += i;
- }
- file_data = data;
- data[file_size] = 0;
-
- close (desc);
-
- if (file_size > 0 && data[0] != '\\' && data[0] != '@')
- {
- error ("%s: not a texinfo index file", infile);
- return;
- }
-
- init_char_order ();
-
- /* Sort routines want to know this address. */
-
- text_base = data;
-
- /* Create the array of pointers to lines, with a default size
- frequently enough. */
-
- nlines = total / 50;
- if (!nlines)
- nlines = 2;
- linearray = (char **) xmalloc (nlines * sizeof (char *));
-
- /* `nextline' points to the next free slot in this array.
- `nlines' is the allocated size. */
-
- nextline = linearray;
-
- /* Parse the input file's data, and make entries for the lines. */
-
- nextline = parsefile (infile, nextline, file_data, file_size);
- if (nextline == 0)
- {
- error ("%s: not a texinfo index file", infile);
- return;
- }
-
- /* Sort the lines. */
-
- /* If we have enough space, find the first keyfield of each line in advance.
- Make a `struct lineinfo' for each line, which records the keyfield
- as well as the line, and sort them. */
-
- lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo));
-
- if (lineinfo)
- {
- struct lineinfo *lp;
- char **p;
-
- for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
- {
- lp->text = *p;
- lp->key.text = find_field (keyfields, *p, &lp->keylen);
- if (keyfields->numeric)
- lp->key.number = find_value (lp->key.text, lp->keylen);
- }
-
- qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo),
- compare_prepared);
-
- for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
- *p = lp->text;
-
- free (lineinfo);
- }
- else
- qsort (linearray, nextline - linearray, sizeof (char *), compare_full);
-
- /* Open the output file. */
-
- if (outfile)
- {
- ostream = fopen (outfile, "w");
- if (!ostream)
- pfatal_with_name (outfile);
- }
-
- writelines (linearray, nextline - linearray, ostream);
- if (outfile)
- fclose (ostream);
-
- free (linearray);
- free (data);
-}
-
-/* Parse an input string in core into lines.
- DATA is the input string, and SIZE is its length.
- Data goes in LINEARRAY starting at NEXTLINE.
- The value returned is the first entry in LINEARRAY still unused.
- Value 0 means input file contents are invalid. */
-
-char **
-parsefile (filename, nextline, data, size)
- char *filename;
- char **nextline;
- char *data;
- long size;
-{
- char *p, *end;
- char **line = nextline;
-
- p = data;
- end = p + size;
- *end = 0;
-
- while (p != end)
- {
- if (p[0] != '\\' && p[0] != '@')
- return 0;
-
- *line = p;
- while (*p && *p != '\n')
- p++;
- if (p != end)
- p++;
-
- line++;
- if (line == linearray + nlines)
- {
- char **old = linearray;
- linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4));
- line += linearray - old;
- }
- }
-
- return line;
-}
-
-/* Indexification is a filter applied to the sorted lines
- as they are being written to the output file.
- Multiple entries for the same name, with different page numbers,
- get combined into a single entry with multiple page numbers.
- The first braced field, which is used for sorting, is discarded.
- However, its first character is examined, folded to lower case,
- and if it is different from that in the previous line fed to us
- a \initial line is written with one argument, the new initial.
-
- If an entry has four braced fields, then the second and third
- constitute primary and secondary names.
- In this case, each change of primary name
- generates a \primary line which contains only the primary name,
- and in between these are \secondary lines which contain
- just a secondary name and page numbers. */
-
-/* The last primary name we wrote a \primary entry for.
- If only one level of indexing is being done, this is the last name seen. */
-char *lastprimary;
-/* Length of storage allocated for lastprimary. */
-int lastprimarylength;
-
-/* Similar, for the secondary name. */
-char *lastsecondary;
-int lastsecondarylength;
-
-/* Zero if we are not in the middle of writing an entry.
- One if we have written the beginning of an entry but have not
- yet written any page numbers into it.
- Greater than one if we have written the beginning of an entry
- plus at least one page number. */
-int pending;
-
-/* The initial (for sorting purposes) of the last primary entry written.
- When this changes, a \initial {c} line is written */
-
-char *lastinitial;
-
-int lastinitiallength;
-
-/* When we need a string of length 1 for the value of lastinitial,
- store it here. */
-
-char lastinitial1[2];
-
-/* Initialize static storage for writing an index. */
-
-void
-init_index ()
-{
- pending = 0;
- lastinitial = lastinitial1;
- lastinitial1[0] = 0;
- lastinitial1[1] = 0;
- lastinitiallength = 0;
- lastprimarylength = 100;
- lastprimary = (char *) xmalloc (lastprimarylength + 1);
- memset (lastprimary, '\0', lastprimarylength + 1);
- lastsecondarylength = 100;
- lastsecondary = (char *) xmalloc (lastsecondarylength + 1);
- memset (lastsecondary, '\0', lastsecondarylength + 1);
-}
-
-/* Indexify. Merge entries for the same name,
- insert headers for each initial character, etc. */
-
-void
-indexify (line, ostream)
- char *line;
- FILE *ostream;
-{
- char *primary, *secondary, *pagenumber;
- int primarylength, secondarylength = 0, pagelength;
- int nosecondary;
- int initiallength;
- char *initial;
- char initial1[2];
- register char *p;
-
- /* First, analyze the parts of the entry fed to us this time. */
-
- p = find_braced_pos (line, 0, 0, 0);
- if (*p == '{')
- {
- initial = p;
- /* Get length of inner pair of braces starting at `p',
- including that inner pair of braces. */
- initiallength = find_braced_end (p + 1) + 1 - p;
- }
- else
- {
- initial = initial1;
- initial1[0] = *p;
- initial1[1] = 0;
- initiallength = 1;
-
- if (initial1[0] >= 'a' && initial1[0] <= 'z')
- initial1[0] -= 040;
- }
-
- pagenumber = find_braced_pos (line, 1, 0, 0);
- pagelength = find_braced_end (pagenumber) - pagenumber;
- if (pagelength == 0)
- abort ();
-
- primary = find_braced_pos (line, 2, 0, 0);
- primarylength = find_braced_end (primary) - primary;
-
- secondary = find_braced_pos (line, 3, 0, 0);
- nosecondary = !*secondary;
- if (!nosecondary)
- secondarylength = find_braced_end (secondary) - secondary;
-
- /* If the primary is different from before, make a new primary entry. */
- if (strncmp (primary, lastprimary, primarylength))
- {
- /* Close off current secondary entry first, if one is open. */
- if (pending)
- {
- fputs ("}\n", ostream);
- pending = 0;
- }
-
- /* If this primary has a different initial, include an entry for
- the initial. */
- if (initiallength != lastinitiallength ||
- strncmp (initial, lastinitial, initiallength))
- {
- fprintf (ostream, "\\initial {");
- fwrite (initial, 1, initiallength, ostream);
- fprintf (ostream, "}\n", initial);
- if (initial == initial1)
- {
- lastinitial = lastinitial1;
- *lastinitial1 = *initial1;
- }
- else
- {
- lastinitial = initial;
- }
- lastinitiallength = initiallength;
- }
-
- /* Make the entry for the primary. */
- if (nosecondary)
- fputs ("\\entry {", ostream);
- else
- fputs ("\\primary {", ostream);
- fwrite (primary, primarylength, 1, ostream);
- if (nosecondary)
- {
- fputs ("}{", ostream);
- pending = 1;
- }
- else
- fputs ("}\n", ostream);
-
- /* Record name of most recent primary. */
- if (lastprimarylength < primarylength)
- {
- lastprimarylength = primarylength + 100;
- lastprimary = (char *) xrealloc (lastprimary,
- 1 + lastprimarylength);
- }
- strncpy (lastprimary, primary, primarylength);
- lastprimary[primarylength] = 0;
-
- /* There is no current secondary within this primary, now. */
- lastsecondary[0] = 0;
- }
-
- /* Should not have an entry with no subtopic following one with a subtopic. */
-
- if (nosecondary && *lastsecondary)
- error ("entry %s follows an entry with a secondary name", line);
-
- /* Start a new secondary entry if necessary. */
- if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength))
- {
- if (pending)
- {
- fputs ("}\n", ostream);
- pending = 0;
- }
-
- /* Write the entry for the secondary. */
- fputs ("\\secondary {", ostream);
- fwrite (secondary, secondarylength, 1, ostream);
- fputs ("}{", ostream);
- pending = 1;
-
- /* Record name of most recent secondary. */
- if (lastsecondarylength < secondarylength)
- {
- lastsecondarylength = secondarylength + 100;
- lastsecondary = (char *) xrealloc (lastsecondary,
- 1 + lastsecondarylength);
- }
- strncpy (lastsecondary, secondary, secondarylength);
- lastsecondary[secondarylength] = 0;
- }
-
- /* Here to add one more page number to the current entry. */
- if (pending++ != 1)
- fputs (", ", ostream); /* Punctuate first, if this is not the first. */
- fwrite (pagenumber, pagelength, 1, ostream);
-}
-
-/* Close out any unfinished output entry. */
-
-void
-finish_index (ostream)
- FILE *ostream;
-{
- if (pending)
- fputs ("}\n", ostream);
- free (lastprimary);
- free (lastsecondary);
-}
-
-/* Copy the lines in the sorted order.
- Each line is copied out of the input file it was found in. */
-
-void
-writelines (linearray, nlines, ostream)
- char **linearray;
- int nlines;
- FILE *ostream;
-{
- char **stop_line = linearray + nlines;
- char **next_line;
-
- init_index ();
-
- /* Output the text of the lines, and free the buffer space. */
-
- for (next_line = linearray; next_line != stop_line; next_line++)
- {
- /* If -u was specified, output the line only if distinct from previous one. */
- if (next_line == linearray
- /* Compare previous line with this one, using only the
- explicitly specd keyfields. */
- || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1))
- {
- char *p = *next_line;
- char c;
-
- while ((c = *p++) && c != '\n')
- /* Do nothing. */ ;
- *(p - 1) = 0;
- indexify (*next_line, ostream);
- }
- }
-
- finish_index (ostream);
-}
-
-/* Assume (and optionally verify) that each input file is sorted;
- merge them and output the result.
- Returns nonzero if any input file fails to be sorted.
-
- This is the high-level interface that can handle an unlimited
- number of files. */
-
-#define MAX_DIRECT_MERGE 10
-
-int
-merge_files (infiles, nfiles, outfile)
- char **infiles;
- int nfiles;
- char *outfile;
-{
- char **tempfiles;
- int ntemps;
- int i;
- int value = 0;
- int start_tempcount = tempcount;
-
- if (nfiles <= MAX_DIRECT_MERGE)
- return merge_direct (infiles, nfiles, outfile);
-
- /* Merge groups of MAX_DIRECT_MERGE input files at a time,
- making a temporary file to hold each group's result. */
-
- ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE;
- tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
- for (i = 0; i < ntemps; i++)
- {
- int nf = MAX_DIRECT_MERGE;
- if (i + 1 == ntemps)
- nf = nfiles - i * MAX_DIRECT_MERGE;
- tempfiles[i] = maketempname (++tempcount);
- value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]);
- }
-
- /* All temporary files that existed before are no longer needed
- since their contents have been merged into our new tempfiles.
- So delete them. */
- flush_tempfiles (start_tempcount);
-
- /* Now merge the temporary files we created. */
-
- merge_files (tempfiles, ntemps, outfile);
-
- free (tempfiles);
-
- return value;
-}
-
-/* Assume (and optionally verify) that each input file is sorted;
- merge them and output the result.
- Returns nonzero if any input file fails to be sorted.
-
- This version of merging will not work if the number of
- input files gets too high. Higher level functions
- use it only with a bounded number of input files. */
-
-int
-merge_direct (infiles, nfiles, outfile)
- char **infiles;
- int nfiles;
- char *outfile;
-{
- struct linebuffer *lb1, *lb2;
- struct linebuffer **thisline, **prevline;
- FILE **streams;
- int i;
- int nleft;
- int lossage = 0;
- int *file_lossage;
- struct linebuffer *prev_out = 0;
- FILE *ostream = stdout;
-
- if (outfile)
- {
- ostream = fopen (outfile, "w");
- }
- if (!ostream)
- pfatal_with_name (outfile);
-
- init_index ();
-
- if (nfiles == 0)
- {
- if (outfile)
- fclose (ostream);
- return 0;
- }
-
- /* For each file, make two line buffers.
- Also, for each file, there is an element of `thisline'
- which points at any time to one of the file's two buffers,
- and an element of `prevline' which points to the other buffer.
- `thisline' is supposed to point to the next available line from the file,
- while `prevline' holds the last file line used,
- which is remembered so that we can verify that the file is properly sorted. */
-
- /* lb1 and lb2 contain one buffer each per file. */
- lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
- lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
-
- /* thisline[i] points to the linebuffer holding the next available line in file i,
- or is zero if there are no lines left in that file. */
- thisline = (struct linebuffer **)
- xmalloc (nfiles * sizeof (struct linebuffer *));
- /* prevline[i] points to the linebuffer holding the last used line
- from file i. This is just for verifying that file i is properly
- sorted. */
- prevline = (struct linebuffer **)
- xmalloc (nfiles * sizeof (struct linebuffer *));
- /* streams[i] holds the input stream for file i. */
- streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));
- /* file_lossage[i] is nonzero if we already know file i is not
- properly sorted. */
- file_lossage = (int *) xmalloc (nfiles * sizeof (int));
-
- /* Allocate and initialize all that storage. */
-
- for (i = 0; i < nfiles; i++)
- {
- initbuffer (&lb1[i]);
- initbuffer (&lb2[i]);
- thisline[i] = &lb1[i];
- prevline[i] = &lb2[i];
- file_lossage[i] = 0;
- streams[i] = fopen (infiles[i], "r");
- if (!streams[i])
- pfatal_with_name (infiles[i]);
-
- readline (thisline[i], streams[i]);
- }
-
- /* Keep count of number of files not at eof. */
- nleft = nfiles;
-
- while (nleft)
- {
- struct linebuffer *best = 0;
- struct linebuffer *exch;
- int bestfile = -1;
- int i;
-
- /* Look at the next avail line of each file; choose the least one. */
-
- for (i = 0; i < nfiles; i++)
- {
- if (thisline[i] &&
- (!best ||
- 0 < compare_general (best->buffer, thisline[i]->buffer,
- (long) bestfile, (long) i, num_keyfields)))
- {
- best = thisline[i];
- bestfile = i;
- }
- }
-
- /* Output that line, unless it matches the previous one and we
- don't want duplicates. */
-
- if (!(prev_out &&
- !compare_general (prev_out->buffer,
- best->buffer, 0L, 1L, num_keyfields - 1)))
- indexify (best->buffer, ostream);
- prev_out = best;
-
- /* Now make the line the previous of its file, and fetch a new
- line from that file. */
-
- exch = prevline[bestfile];
- prevline[bestfile] = thisline[bestfile];
- thisline[bestfile] = exch;
-
- while (1)
- {
- /* If the file has no more, mark it empty. */
-
- if (feof (streams[bestfile]))
- {
- thisline[bestfile] = 0;
- /* Update the number of files still not empty. */
- nleft--;
- break;
- }
- readline (thisline[bestfile], streams[bestfile]);
- if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile]))
- break;
- }
- }
-
- finish_index (ostream);
-
- /* Free all storage and close all input streams. */
-
- for (i = 0; i < nfiles; i++)
- {
- fclose (streams[i]);
- free (lb1[i].buffer);
- free (lb2[i].buffer);
- }
- free (file_lossage);
- free (lb1);
- free (lb2);
- free (thisline);
- free (prevline);
- free (streams);
-
- if (outfile)
- fclose (ostream);
-
- return lossage;
-}
-
-/* Print error message and exit. */
-
-void
-fatal (format, arg)
- char *format, *arg;
-{
- error (format, arg);
- exit (TI_FATAL_ERROR);
-}
-
-/* Print error message. FORMAT is printf control string, ARG is arg for it. */
-void
-error (format, arg)
- char *format, *arg;
-{
- printf ("%s: ", program_name);
- printf (format, arg);
- if (format[strlen (format) -1] != '\n')
- printf ("\n");
-}
-
-void
-perror_with_name (name)
- char *name;
-{
- char *s;
-
- s = strerror (errno);
- printf ("%s: ", program_name);
- printf ("%s; for file `%s'.\n", s, name);
-}
-
-void
-pfatal_with_name (name)
- char *name;
-{
- char *s;
-
- s = strerror (errno);
- printf ("%s: ", program_name);
- printf ("%s; for file `%s'.\n", s, name);
- exit (TI_FATAL_ERROR);
-}
-
-/* Return a newly-allocated string whose contents concatenate those of
- S1, S2, S3. */
-
-char *
-concat (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
- char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
-
- strcpy (result, s1);
- strcpy (result + len1, s2);
- strcpy (result + len1 + len2, s3);
- *(result + len1 + len2 + len3) = 0;
-
- return result;
-}
-
-#if !defined (HAVE_STRERROR)
-extern char *sys_errlist[];
-extern int sys_nerr;
-
-char *
-strerror (num)
- int num;
-{
- if (num >= sys_nerr)
- return ("");
- else
- return (sys_errlist[num]);
-}
-#endif /* !HAVE_STRERROR */
-
-#if !defined (HAVE_STRCHR)
-char *
-strrchr (string, character)
- char *string;
- int character;
-{
- register int i;
-
- for (i = strlen (string) - 1; i > -1; i--)
- if (string[i] == character)
- return (string + i);
-
- return ((char *)NULL);
-}
-#endif /* HAVE_STRCHR */
-
-/* Just like malloc, but kills the program in case of fatal error. */
-void *
-xmalloc (nbytes)
- int nbytes;
-{
- void *temp = (void *) malloc (nbytes);
-
- if (nbytes && temp == (void *)NULL)
- memory_error ("xmalloc", nbytes);
-
- return (temp);
-}
-
-/* Like realloc (), but barfs if there isn't enough memory. */
-void *
-xrealloc (pointer, nbytes)
- void *pointer;
- int nbytes;
-{
- void *temp;
-
- if (!pointer)
- temp = (void *)xmalloc (nbytes);
- else
- temp = (void *)realloc (pointer, nbytes);
-
- if (nbytes && !temp)
- memory_error ("xrealloc", nbytes);
-
- return (temp);
-}
-
-memory_error (callers_name, bytes_wanted)
- char *callers_name;
- int bytes_wanted;
-{
- char printable_string[80];
-
- sprintf (printable_string,
- "Virtual memory exhausted in %s ()! Needed %d bytes.",
- callers_name, bytes_wanted);
-
- error (printable_string);
- abort ();
-}
-