📄 texindex.c
字号:
/* Prepare TeX index dribble output into an actual index. $Id: texindex.c,v 1.1.1.3 1998/03/24 18:20:31 law Exp $ Copyright (C) 1987, 91, 92, 96, 97, 98 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 "system.h"#include <getopt.h>#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_MEMSET)#undef memset#define memset(ptr, ignore, count) bzero (ptr, count)#endifchar *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 */# 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 *//* 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 500000intmain (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];#ifdef HAVE_SETLOCALE /* Set locale via LC_ALL. */ setlocale (LC_ALL, "");#endif /* Set the text message domain. */ bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); /* 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); return 0; /* Avoid bogus warnings. */}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, N_("keep temporary files around after processing") }, { "--no-keep", 0, &keep_tempfiles, 0, (char *)NULL, N_("do not keep temporary files around after processing (default)") }, { "--output", "-o", (int *)NULL, 0, "FILE", N_("send output to FILE") }, { "--version", (char *)NULL, (int *)NULL, 0, (char *)NULL, N_("display version information and exit") }, { "--help", "-h", (int *)NULL, 0, (char *)NULL, N_("display this help and exit") }, { (char *)NULL, (char *)NULL, (int *)NULL, 0, (char *)NULL }};voidusage (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@gnu.org.")); 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. */voiddecode_command (argc, argv) int argc; char **argv;{ int arg_index = 1; 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) { printf ("texindex (GNU %s) %s\n", PACKAGE, VERSION); printf (_("Copyright (C) %s 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.\n"), "1998"); 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. */voidflush_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 1024char *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. */intcompare_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. */intcompare_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. */intcompare_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -