diff options
Diffstat (limited to 'contrib/texinfo/util')
-rw-r--r-- | contrib/texinfo/util/Makefile.in | 101 | ||||
-rw-r--r-- | contrib/texinfo/util/deref.c | 238 | ||||
-rwxr-xr-x | contrib/texinfo/util/fixfonts | 84 | ||||
-rwxr-xr-x | contrib/texinfo/util/gen-dir-node | 176 | ||||
-rw-r--r-- | contrib/texinfo/util/install-info.c | 1141 | ||||
-rwxr-xr-x | contrib/texinfo/util/mkinstalldirs | 40 | ||||
-rwxr-xr-x | contrib/texinfo/util/tex3patch | 71 | ||||
-rwxr-xr-x | contrib/texinfo/util/texi2dvi | 364 | ||||
-rw-r--r-- | contrib/texinfo/util/texindex.c | 1793 |
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 (); -} - |