#include "system.h"
#include <getopt.h>
#if defined (emacs)
# include "../src/config.h"
# undef read
# undef close
# undef write
# undef open
#endif
#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
# define TI_NO_ERROR 0
# define TI_FATAL_ERROR 1
#endif
#if !defined (SEEK_SET)
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
#endif
struct lineinfo
{
char *text;
union {
char *text;
long number;
} key;
long keylen;
};
struct keyfield
{
int startwords;
int startchars;
int endwords;
int endchars;
char ignore_blanks;
char fold_case;
char reverse;
char numeric;
char positional;
char braced;
};
struct keyfield keyfields[3];
int num_keyfields = 3;
char **infiles;
char **outfiles;
int num_infiles;
char **linearray;
long nlines;
char *tempdir;
char *tempbase;
int tempcount;
int last_deleted_tempcount;
char *text_base;
int keep_tempfiles;
char *program_name;
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
int
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];
#ifdef HAVE_SETLOCALE
setlocale (LC_ALL, "");
#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
keyfields[0].braced = 1;
keyfields[0].fold_case = 1;
keyfields[0].endwords = -1;
keyfields[0].endchars = -1;
keyfields[1].braced = 1;
keyfields[1].numeric = 1;
keyfields[1].startwords = 1;
keyfields[1].endwords = -1;
keyfields[1].endchars = -1;
keyfields[2].endwords = -1;
keyfields[2].endchars = -1;
decode_command (argc, argv);
tempbase = mktemp (concat ("txiXXXXXX", "", ""));
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_in_core (infiles[i], ptr, outfile);
else
sort_offline (infiles[i], ptr, outfile);
}
flush_tempfiles (tempcount);
exit (TI_NO_ERROR);
return 0;
}
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 }
};
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"));
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);
}
void
decode_command (argc, argv)
int argc;
char **argv;
{
int arg_index = 1;
char **ip;
char **op;
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;
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;
}
}
num_infiles = ip - infiles;
*ip = (char *)NULL;
if (num_infiles == 0)
usage (1);
}
char *
maketempname (count)
int count;
{
char tempsuffix[10];
sprintf (tempsuffix, "%d", count);
return concat (tempdir, tempbase, tempsuffix);
}
void
flush_tempfiles (to_count)
int to_count;
{
if (keep_tempfiles)
return;
while (last_deleted_tempcount < to_count)
unlink (maketempname (++last_deleted_tempcount));
}
#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;
}
int
compare_full (line1, line2)
char **line1, **line2;
{
int i;
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;
}
int
compare_prepared (line1, line2)
struct lineinfo *line1, *line2;
{
int i;
int tem;
char *text1, *text2;
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;
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;
}
int
compare_general (str1, str2, pos1, pos2, use_keyfields)
char *str1, *str2;
long pos1, pos2;
int use_keyfields;
{
int i;
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;
}
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;
}
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;
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;
}
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)
;
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)
;
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;
}
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;
}
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;
}
}
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;
}
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)
return c2 - c1;
if (!c1)
break;
}
return 0;
}
}
struct linebuffer
{
long size;
char *buffer;
};
void
initbuffer (linebuffer)
struct linebuffer *linebuffer;
{
linebuffer->size = 200;
linebuffer->buffer = (char *) xmalloc (200);
}
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;
}
void
sort_offline (infile, nfiles, total, outfile)
char *infile;
int nfiles;
long total;
char *outfile;
{
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);
linelength = readline (&lb, istream);
if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
{
error (_("%s: not a texinfo index file"), infile);
return;
}
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;
while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)
{
tempsize += linelength + 1;
fputs (lb.buffer, ostream);
putc ('\n', ostream);
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:
ntemps = i;
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_files (tempfiles, ntemps, outfile);
}
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;
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 ();
text_base = data;
nlines = total / 50;
if (!nlines)
nlines = 2;
linearray = (char **) xmalloc (nlines * sizeof (char *));
nextline = linearray;
nextline = parsefile (infile, nextline, file_data, file_size);
if (nextline == 0)
{
error (_("%s: not a texinfo index file"), infile);
return;
}
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);
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);
}
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;
}
char *lastprimary;
int lastprimarylength;
char *lastsecondary;
int lastsecondarylength;
int pending;
char *lastinitial;
int lastinitiallength;
char lastinitial1[2];
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);
}
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;
p = find_braced_pos (line, 0, 0, 0);
if (*p == '{')
{
initial = p;
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 (strncmp (primary, lastprimary, primarylength))
{
if (pending)
{
fputs ("}\n", ostream);
pending = 0;
}
if (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;
}
if (nosecondary)
fputs ("\\entry {", ostream);
else
fputs ("\\primary {", ostream);
fwrite (primary, primarylength, 1, ostream);
if (nosecondary)
{
fputs ("}{", ostream);
pending = 1;
}
else
fputs ("}\n", ostream);
if (lastprimarylength < primarylength)
{
lastprimarylength = primarylength + 100;
lastprimary = (char *) xrealloc (lastprimary,
1 + lastprimarylength);
}
strncpy (lastprimary, primary, primarylength);
lastprimary[primarylength] = 0;
lastsecondary[0] = 0;
}
if (nosecondary && *lastsecondary)
error (_("entry %s follows an entry with a secondary name"), line);
if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength))
{
if (pending)
{
fputs ("}\n", ostream);
pending = 0;
}
fputs ("\\secondary {", ostream);
fwrite (secondary, secondarylength, 1, ostream);
fputs ("}{", ostream);
pending = 1;
if (lastsecondarylength < secondarylength)
{
lastsecondarylength = secondarylength + 100;
lastsecondary = (char *) xrealloc (lastsecondary,
1 + lastsecondarylength);
}
strncpy (lastsecondary, secondary, secondarylength);
lastsecondary[secondarylength] = 0;
}
if (pending++ != 1)
fputs (", ", ostream);
fwrite (pagenumber, pagelength, 1, ostream);
}
void
finish_index (ostream)
FILE *ostream;
{
if (pending)
fputs ("}\n", ostream);
free (lastprimary);
free (lastsecondary);
}
void
writelines (linearray, nlines, ostream)
char **linearray;
int nlines;
FILE *ostream;
{
char **stop_line = linearray + nlines;
char **next_line;
init_index ();
for (next_line = linearray; next_line != stop_line; next_line++)
{
if (next_line == linearray
|| compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1))
{
char *p = *next_line;
char c;
while ((c = *p++) && c != '\n')
;
*(p - 1) = 0;
indexify (*next_line, ostream);
}
}
finish_index (ostream);
}
#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);
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]);
}
flush_tempfiles (start_tempcount);
merge_files (tempfiles, ntemps, outfile);
free (tempfiles);
return value;
}
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;
}
lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
thisline = (struct linebuffer **)
xmalloc (nfiles * sizeof (struct linebuffer *));
prevline = (struct linebuffer **)
xmalloc (nfiles * sizeof (struct linebuffer *));
streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));
file_lossage = (int *) xmalloc (nfiles * sizeof (int));
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]);
}
nleft = nfiles;
while (nleft)
{
struct linebuffer *best = 0;
struct linebuffer *exch;
int bestfile = -1;
int i;
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;
}
}
if (!(prev_out &&
!compare_general (prev_out->buffer,
best->buffer, 0L, 1L, num_keyfields - 1)))
indexify (best->buffer, ostream);
prev_out = best;
exch = prevline[bestfile];
prevline[bestfile] = thisline[bestfile];
thisline[bestfile] = exch;
while (1)
{
if (feof (streams[bestfile]))
{
thisline[bestfile] = 0;
nleft--;
break;
}
readline (thisline[bestfile], streams[bestfile]);
if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile]))
break;
}
}
finish_index (ostream);
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;
}
void
fatal (format, arg)
char *format, *arg;
{
error (format, arg);
exit (TI_FATAL_ERROR);
}
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);
}
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
#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
void
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 ();
}
void *
xmalloc (nbytes)
int nbytes;
{
void *temp = (void *) malloc (nbytes);
if (nbytes && temp == (void *)NULL)
memory_error ("xmalloc", nbytes);
return (temp);
}
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);
}