Back to index

tetex-bin  3.0
Classes | Defines | Functions | Variables
texindex.c File Reference
#include "system.h"
#include <getopt.h>

Go to the source code of this file.

Classes

struct  lineinfo
struct  keyfield
struct  TEXINDEX_OPTION
struct  linebuffer
union  lineinfo.key

Defines

#define memset(ptr, ignore, count)   bzero (ptr, count)
#define SEEK_SET   0
#define SEEK_CUR   1
#define SEEK_END   2
#define MAX_IN_CORE_SORT   500000
#define MAX_DIRECT_MERGE   10

Functions

char * mktemp (char *)
void decode_command (int argc, char **argv)
void sort_in_core (char *infile, int total, char *outfile)
void sort_offline (char *infile, off_t total, char *outfile)
char ** parsefile (char *filename, char **nextline, char *data, long int size)
char * find_field (struct keyfield *keyfield, char *str, long int *lengthptr)
char * find_pos (char *str, int words, int chars, int ignore_blanks)
long find_value (char *start, long int length)
char * find_braced_pos (char *str, int words, int chars, int ignore_blanks)
char * find_braced_end (char *str)
void writelines (char **linearray, int nlines, FILE *ostream)
int compare_field (struct keyfield *keyfield, char *start1, long int length1, long int pos1, char *start2, long int length2, long int pos2)
int compare_full (const void *, const void *)
long readline (struct linebuffer *linebuffer, FILE *stream)
int merge_files (char **infiles, int nfiles, char *outfile)
int merge_direct (char **infiles, int nfiles, char *outfile)
void pfatal_with_name (const char *name)
void fatal (const char *format, const char *arg)
void error (const char *format, const char *arg)
voidxmalloc ()
voidxrealloc ()
char * concat (char *s1, char *s2)
void flush_tempfiles (int to_count)
int main (int argc, char **argv)
void usage (int result_value)
static char * maketempname (int count)
int compare_prepared (const void *p1, const void *p2)
int compare_general (char *str1, char *str2, long int pos1, long int pos2, int use_keyfields)
void init_char_order (void)
void initbuffer (struct linebuffer *linebuffer)
void init_index (void)
void indexify (char *line, FILE *ostream)
void finish_index (FILE *ostream)
void perror_with_name (const char *name)

Variables

static char * program_name = "texindex"
int num_keyfields = 3
char ** infiles
char ** outfiles
int num_infiles
char ** linearray
long nlines
char * tempdir
int tempcount
int last_deleted_tempcount
char * text_base
int need_initials
char first_initial
int keep_tempfiles
TEXINDEX_OPTION texindex_options []
int char_order [256]
char * lastprimary
int lastprimarylength
char * lastsecondary
int lastsecondarylength
int pending
char * lastinitial
int lastinitiallength
char lastinitial1 [2]

Class Documentation

struct lineinfo

Definition at line 52 of file texindex.c.

Class Members
union lineinfo key
long keylen
char * text
struct keyfield

Definition at line 63 of file texindex.c.

Class Members
char braced
int endchars
int endwords
char fold_case
char ignore_blanks
char numeric
char positional
char reverse
int startchars
int startwords
struct TEXINDEX_OPTION

Definition at line 240 of file texindex.c.

Class Members
char * arg_name
char * doc_string
char * long_name
char * short_name
int * variable_ref
int variable_value
struct linebuffer

Definition at line 808 of file texindex.c.

Class Members
char * buffer
long size
union lineinfo.key

Definition at line 55 of file texindex.c.

Class Members
long number
char * text

Define Documentation

#define MAX_DIRECT_MERGE   10

Definition at line 1379 of file texindex.c.

#define MAX_IN_CORE_SORT   500000

Definition at line 150 of file texindex.c.

#define memset (   ptr,
  ignore,
  count 
)    bzero (ptr, count)

Definition at line 37 of file texindex.c.

#define SEEK_CUR   1

Definition at line 44 of file texindex.c.

#define SEEK_END   2

Definition at line 45 of file texindex.c.

#define SEEK_SET   0

Definition at line 43 of file texindex.c.


Function Documentation

int compare_field ( struct keyfield keyfield,
char *  start1,
long int  length1,
long int  pos1,
char *  start2,
long int  length2,
long int  pos2 
)

Definition at line 732 of file texindex.c.

{
  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;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int compare_full ( const void p1,
const void p2 
)

Definition at line 425 of file texindex.c.

{
  char **line1 = (char **) p1;
  char **line2 = (char **) p2;
  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. */
}

Here is the call graph for this function:

Here is the caller graph for this function:

int compare_general ( char *  str1,
char *  str2,
long int  pos1,
long int  pos2,
int  use_keyfields 
)

Definition at line 519 of file texindex.c.

{
  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. */
}

Here is the call graph for this function:

Here is the caller graph for this function:

int compare_prepared ( const void p1,
const void p2 
)

Definition at line 459 of file texindex.c.

{
  struct lineinfo *line1 = (struct lineinfo *) p1;
  struct lineinfo *line2 = (struct lineinfo *) p2;
  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. */
}

Here is the call graph for this function:

Here is the caller graph for this function:

char * concat ( char *  s1,
char *  s2 
)

Definition at line 1618 of file texindex.c.

{
  int len1 = strlen (s1), len2 = strlen (s2);
  char *result = (char *) xmalloc (len1 + len2 + 1);

  strcpy (result, s1);
  strcpy (result + len1, s2);
  *(result + len1 + len2) = 0;

  return result;
}

Here is the call graph for this function:

void decode_command ( int  argc,
char **  argv 
)

Definition at line 305 of file texindex.c.

{
  int arg_index = 1;
  char **ip;
  char **op;

  /* Store default values into parameter variables. */

  tempdir = getenv ("TMPDIR");
  if (tempdir == NULL)
    tempdir = getenv ("TEMP");
  if (tempdir == NULL)
    tempdir = getenv ("TMP");
  if (tempdir == NULL)
    tempdir = DEFAULT_TMPDIR;
  else
    tempdir = concat (tempdir, "/");

  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);
              puts ("");
              puts ("Copyright (C) 2004 Free Software Foundation, Inc.");
              printf (_("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"));
              xexit (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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void error ( const char *  format,
const char *  arg 
)

Definition at line 1592 of file texindex.c.

{
  printf ("%s: ", program_name);
  printf (format, arg);
  if (format[strlen (format) -1] != '\n')
    printf ("\n");
}

Here is the call graph for this function:

void fatal ( const char *  format,
const char *  arg 
)

Definition at line 1584 of file texindex.c.

{
  error (format, arg);
  xexit (1);
}

Here is the call graph for this function:

char * find_braced_end ( char *  str)

Definition at line 672 of file texindex.c.

{
  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;
}

Here is the caller graph for this function:

char * find_braced_pos ( char *  str,
int  words,
int  chars,
int  ignore_blanks 
)

Definition at line 623 of file texindex.c.

{
  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;
}

Here is the caller graph for this function:

char * find_field ( struct keyfield keyfield,
char *  str,
long int lengthptr 
)

Definition at line 550 of file texindex.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char * find_pos ( char *  str,
int  words,
int  chars,
int  ignore_blanks 
)

Definition at line 590 of file texindex.c.

{
  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;
}

Here is the caller graph for this function:

long find_value ( char *  start,
long int  length 
)

Definition at line 693 of file texindex.c.

{
  while (length != 0L)
    {
      if (isdigit (*start))
        return atol (start);
      length--;
      start++;
    }
  return 0l;
}

Here is the caller graph for this function:

void finish_index ( FILE ostream)

Definition at line 1328 of file texindex.c.

{
  if (pending)
    fputs ("}\n", ostream);
  free (lastprimary);
  free (lastsecondary);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void flush_tempfiles ( int  to_count)

Definition at line 413 of file texindex.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void indexify ( char *  line,
FILE ostream 
)

Definition at line 1187 of file texindex.c.

{
  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] = toupper (*p);
      initial1[1] = 0;
      initiallength = 1;
    }

  pagenumber = find_braced_pos (line, 1, 0, 0);
  pagelength = find_braced_end (pagenumber) - pagenumber;
  if (pagelength == 0)
    fatal (_("No page number in %s"), line);

  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 (need_initials &&
          (initiallength != lastinitiallength ||
           strncmp (initial, lastinitial, initiallength)))
        {
          fprintf (ostream, "\\initial {");
          fwrite (initial, 1, initiallength, ostream);
          fputs ("}\n", ostream);
          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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 711 of file texindex.c.

{
  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;
    }
}

Here is the caller graph for this function:

Definition at line 1168 of file texindex.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void initbuffer ( struct linebuffer linebuffer)

Definition at line 817 of file texindex.c.

{
  linebuffer->size = 200;
  linebuffer->buffer = (char *) xmalloc (200);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 153 of file texindex.c.

{
  int i;

  tempcount = 0;
  last_deleted_tempcount = 0;

#ifdef HAVE_SETLOCALE
  /* Set locale via LC_ALL.  */
  setlocale (LC_ALL, "");
#endif

  /* Set the text message domain.  */
  bindtextdomain (PACKAGE, LOCALEDIR);
  textdomain (PACKAGE);

  /* In case we write to a redirected stdout that fails.  */
  /* not ready atexit (close_stdout); */

  /* 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);

  /* Process input files completely, one by one.  */

  for (i = 0; i < num_infiles; i++)
    {
      int desc;
      off_t ptr;
      char *outfile;
      struct stat instat;

      desc = open (infiles[i], O_RDONLY, 0);
      if (desc < 0)
        pfatal_with_name (infiles[i]);

      if (stat (infiles[i], &instat))
        pfatal_with_name (infiles[i]);
      if (S_ISDIR (instat.st_mode))
        {
#ifdef EISDIR
          errno = EISDIR;
#endif
          pfatal_with_name (infiles[i]);
        }

      lseek (desc, (off_t) 0, SEEK_END);
      ptr = (off_t) lseek (desc, (off_t) 0, SEEK_CUR);

      close (desc);

      outfile = outfiles[i];
      if (!outfile)
        outfile = concat (infiles[i], "s");

      need_initials = 0;
      first_initial = '\0';

      if (ptr < MAX_IN_CORE_SORT)
        /* Sort a small amount of data. */
        sort_in_core (infiles[i], (int)ptr, outfile);
      else
        sort_offline (infiles[i], ptr, outfile);
    }

  flush_tempfiles (tempcount);
  xexit (0);
  return 0; /* Avoid bogus warnings.  */
}

Here is the call graph for this function:

static char* maketempname ( int  count) [static]

Definition at line 390 of file texindex.c.

{
  static char *tempbase = NULL;
  char tempsuffix[10];

  if (!tempbase)
    {
      int fd;
      tempbase = concat (tempdir, "txidxXXXXXX");

      fd = mkstemp (tempbase);
      if (fd == -1)
        pfatal_with_name (tempbase);
    }

  sprintf (tempsuffix, ".%d", count);
  return concat (tempbase, tempsuffix);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int merge_direct ( char **  infiles,
int  nfiles,
char *  outfile 
)

Definition at line 1430 of file texindex.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int merge_files ( char **  infiles,
int  nfiles,
char *  outfile 
)

Definition at line 1382 of file texindex.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* mktemp ( char *  )

Here is the caller graph for this function:

char ** parsefile ( char *  filename,
char **  nextline,
char *  data,
long int  size 
)

Definition at line 1071 of file texindex.c.

{
  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;

      /* Find the first letter of the first field of this line.  If it
         is different from the first letter of the first field of the
         first line, we need initial headers in the output index.  */
      while (*p && *p != '{')
        p++;
      if (p == end)
        return 0;
      p++;
      if (first_initial)
        {
          if (first_initial != toupper (*p))
            need_initials = 1;
        }
      else
        first_initial = toupper (*p);

      while (*p && *p != '\n')
        p++;
      if (p != end)
        p++;

      line++;
      if (line == linearray + nlines)
        {
          char **old = linearray;
          linearray = xrealloc (linearray, sizeof (char *) * (nlines *= 4));
          line += linearray - old;
        }
    }

  return line;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void perror_with_name ( const char *  name)

Definition at line 1601 of file texindex.c.

{
  fprintf (stderr, "%s: ", program_name);
  perror (name);
}

Here is the call graph for this function:

void pfatal_with_name ( const char *  name)
long readline ( struct linebuffer linebuffer,
FILE stream 
)

Definition at line 827 of file texindex.c.

{
  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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void sort_in_core ( char *  infile,
int  total,
char *  outfile 
)

Definition at line 953 of file texindex.c.

{
  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 = 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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void sort_offline ( char *  infile,
off_t  total,
char *  outfile 
)

Definition at line 857 of file texindex.c.

{
  /* 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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void usage ( int  result_value)

Definition at line 265 of file texindex.c.

{
  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 specified as `foo.%c%c\' for a document `foo.texi'.\n"),
           '?', '?'); /* avoid trigraph in cat-id-tbl.c */
  fprintf (f, _("\nOptions:\n"));

  for (i = 0; texindex_options[i].long_name; i++)
    {
      putc (' ', f);

      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));
    }
  fputs (_("\n\
Email bug reports to bug-texinfo@gnu.org,\n\
general questions and discussion to help-texinfo@gnu.org.\n\
Texinfo home page: http://www.gnu.org/software/texinfo/"), f);
  fputs ("\n", f);

  xexit (result_value);
}

Here is the call graph for this function:

void writelines ( char **  linearray,
int  nlines,
FILE ostream 
)

Definition at line 1340 of file texindex.c.

{
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* xmalloc ( )
void * xrealloc ( )

Variable Documentation

Definition at line 708 of file texindex.c.

Definition at line 118 of file texindex.c.

char** infiles

Definition at line 84 of file texindex.c.

Definition at line 123 of file texindex.c.

Definition at line 107 of file texindex.c.

char* lastinitial

Definition at line 1156 of file texindex.c.

char lastinitial1[2]

Definition at line 1163 of file texindex.c.

Definition at line 1158 of file texindex.c.

char* lastprimary

Definition at line 1138 of file texindex.c.

Definition at line 1140 of file texindex.c.

Definition at line 1143 of file texindex.c.

Definition at line 1144 of file texindex.c.

char** linearray

Definition at line 94 of file texindex.c.

Definition at line 114 of file texindex.c.

long nlines

Definition at line 97 of file texindex.c.

Definition at line 91 of file texindex.c.

Definition at line 81 of file texindex.c.

char** outfiles

Definition at line 88 of file texindex.c.

Definition at line 1151 of file texindex.c.

char* program_name = "texindex" [static]

Definition at line 24 of file texindex.c.

Definition at line 103 of file texindex.c.

char* tempdir

Definition at line 100 of file texindex.c.

Initial value:
 {
  { "--help", "-h", (int *)NULL, 0, (char *)NULL,
      N_("display this help and exit") },
  { "--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") },
  { (char *)NULL, (char *)NULL, (int *)NULL, 0, (char *)NULL }
}

Definition at line 250 of file texindex.c.

char* text_base

Definition at line 111 of file texindex.c.