root/trunk/texinfo/texinfo-4.9-nokeep-1.patch
| Revision 1861, 18.6 kB (checked in by robert, 1 year ago) |
|---|
-
texinfo-4.9/util/texindex.c
old new 1 1 /* texindex -- sort TeX index dribble output into an actual index. 2 $Id: texindex.c,v 1. 11.2.2 2007/06/27 17:11:08karl Exp $2 $Id: texindex.c,v 1.22 2007/07/01 21:20:34 karl Exp $ 3 3 4 4 Copyright (C) 1987, 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2001, 5 2002, 2003, 2004, 200 7 Free Software Foundation, Inc.5 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 6 6 7 This program is free software ;you can redistribute it and/or modify7 This program is free software: you can redistribute it and/or modify 8 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation ; either version 3, or (at your option)10 any later version.9 the Free Software Foundation, either version 3 of the License, or 10 (at your option) any later version. 11 11 12 12 This program is distributed in the hope that it will be useful, 13 13 but WITHOUT ANY WARRANTY; without even the implied warranty of … … 15 15 GNU General Public License for more details. 16 16 17 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307. */ 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 19 21 20 #include "system.h" 22 21 #include <getopt.h> 23 22 24 staticchar *program_name = "texindex";23 char *program_name = "texindex"; 25 24 26 25 #if defined (emacs) 27 26 # include "../src/config.h" … … 37 36 #define memset(ptr, ignore, count) bzero (ptr, count) 38 37 #endif 39 38 40 char *mktemp (char *);41 42 39 #if !defined (SEEK_SET) 43 40 # define SEEK_SET 0 44 41 # define SEEK_CUR 1 45 42 # define SEEK_END 2 46 43 #endif /* !SEEK_SET */ 47 44 48 struct linebuffer;49 50 45 /* When sorting in core, this structure describes one line 51 46 and the position and length of its first keyfield. */ 52 47 struct lineinfo … … 96 91 /* The allocated length of `linearray'. */ 97 92 long nlines; 98 93 99 /* Directory to use for temporary files. On Unix, it ends with a slash. */100 char *tempdir;101 102 /* Number of last temporary file. */103 int tempcount;104 105 /* Number of last temporary file already deleted.106 Temporary files are deleted by `flush_tempfiles' in order of creation. */107 int last_deleted_tempcount;108 109 94 /* During in-core sort, this points to the base of the data block 110 95 which contains all the lines of data. */ 111 96 char *text_base; … … 117 102 determine whether we need initials in the sorted form. */ 118 103 char first_initial; 119 104 120 /* Additional command switches .*/121 122 /* Nonzero means do not delete tempfiles -- for debugging. */123 int keep_tempfiles;124 125 105 /* Forward declarations of functions in this file. */ 126 106 void decode_command (int argc, char **argv); 127 107 void sort_in_core (char *infile, int total, char *outfile); 128 void sort_offline (char *infile, off_t total, char *outfile);129 108 char **parsefile (char *filename, char **nextline, char *data, long int size); 130 109 char *find_field (struct keyfield *keyfield, char *str, long int *lengthptr); 131 110 char *find_pos (char *str, int words, int chars, int ignore_blanks); … … 137 116 long int length1, long int pos1, char *start2, 138 117 long int length2, long int pos2); 139 118 int compare_full (const void *, const void *); 140 long readline (struct linebuffer *linebuffer, FILE *stream);141 int merge_files (char **infiles, int nfiles, char *outfile);142 int merge_direct (char **infiles, int nfiles, char *outfile);143 119 void pfatal_with_name (const char *name); 144 120 void fatal (const char *format, const char *arg); 145 121 void error (const char *format, const char *arg); 146 122 void *xmalloc (), *xrealloc (); 147 char *concat (char *s1, char *s2); 148 void flush_tempfiles (int to_count); 123 static char *concat3 (const char *, const char *, const char *); 149 124 150 #define MAX_IN_CORE_SORT 500000151 152 125 int 153 126 main (int argc, char **argv) 154 127 { 155 128 int i; 156 129 157 tempcount = 0;158 last_deleted_tempcount = 0;159 160 130 #ifdef HAVE_SETLOCALE 161 131 /* Set locale via LC_ALL. */ 162 132 setlocale (LC_ALL, ""); … … 220 190 221 191 outfile = outfiles[i]; 222 192 if (!outfile) 223 outfile = concat (infiles[i], "s");193 outfile = concat3 (infiles[i], "s", ""); 224 194 225 195 need_initials = 0; 226 196 first_initial = '\0'; 227 197 228 if (ptr < MAX_IN_CORE_SORT) 229 /* Sort a small amount of data. */ 230 sort_in_core (infiles[i], (int)ptr, outfile); 231 else 232 sort_offline (infiles[i], ptr, outfile); 198 if (ptr != (int)ptr) 199 { 200 fprintf (stderr, "%s: %s: file too large\n", program_name, 201 infiles[i]); 202 xexit (1); 203 } 204 sort_in_core (infiles[i], (int)ptr, outfile); 233 205 } 234 206 235 flush_tempfiles (tempcount);236 207 xexit (0); 237 208 return 0; /* Avoid bogus warnings. */ 238 209 } … … 250 221 TEXINDEX_OPTION texindex_options[] = { 251 222 { "--help", "-h", (int *)NULL, 0, (char *)NULL, 252 223 N_("display this help and exit") }, 253 { "--keep", "-k", &keep_tempfiles, 1, (char *)NULL,254 N_("keep temporary files around after processing") },255 { "--no-keep", 0, &keep_tempfiles, 0, (char *)NULL,256 N_("do not keep temporary files around after processing (default)") },257 224 { "--output", "-o", (int *)NULL, 0, "FILE", 258 225 N_("send output to FILE") }, 259 226 { "--version", (char *)NULL, (int *)NULL, 0, (char *)NULL, … … 308 275 char **ip; 309 276 char **op; 310 277 311 /* Store default values into parameter variables. */312 313 tempdir = getenv ("TMPDIR");314 if (tempdir == NULL)315 tempdir = getenv ("TEMP");316 if (tempdir == NULL)317 tempdir = getenv ("TMP");318 if (tempdir == NULL)319 tempdir = DEFAULT_TMPDIR;320 else321 tempdir = concat (tempdir, "/");322 323 keep_tempfiles = 0;324 325 278 /* Allocate ARGC input files, which must be enough. */ 326 279 327 280 infiles = (char **) xmalloc (argc * sizeof (char *)); … … 349 302 else if ((strcmp (arg, "--keep") == 0) || 350 303 (strcmp (arg, "-k") == 0)) 351 304 { 352 keep_tempfiles = 1; 305 /* Ignore, for backward compatibility */ 353 306 } 354 307 else if ((strcmp (arg, "--help") == 0) || 355 308 (strcmp (arg, "-h") == 0)) … … 385 338 usage (1); 386 339 } 387 340 388 /* Return a name for temporary file COUNT. */389 390 static char *391 maketempname (int count)392 {393 static char *tempbase = NULL;394 char tempsuffix[10];395 396 if (!tempbase)397 {398 int fd;399 tempbase = concat (tempdir, "txidxXXXXXX");400 401 fd = mkstemp (tempbase);402 if (fd == -1)403 pfatal_with_name (tempbase);404 }405 406 sprintf (tempsuffix, ".%d", count);407 return concat (tempbase, tempsuffix);408 }409 410 411 /* Delete all temporary files up to TO_COUNT. */412 413 void414 flush_tempfiles (int to_count)415 {416 if (keep_tempfiles)417 return;418 while (last_deleted_tempcount < to_count)419 unlink (maketempname (++last_deleted_tempcount));420 }421 422 423 341 /* Compare LINE1 and LINE2 according to the specified set of keyfields. */ 424 342 425 343 int … … 802 720 } 803 721 } 804 722 805 /* A `struct linebuffer' is a structure which holds a line of text.806 `readline' reads a line from a stream into a linebuffer807 and works regardless of the length of the line. */808 809 struct linebuffer810 {811 long size;812 char *buffer;813 };814 815 /* Initialize LINEBUFFER for use. */816 817 void818 initbuffer (struct linebuffer *linebuffer)819 {820 linebuffer->size = 200;821 linebuffer->buffer = (char *) xmalloc (200);822 }823 824 /* Read a line of text from STREAM into LINEBUFFER.825 Return the length of the line. */826 827 long828 readline (struct linebuffer *linebuffer, FILE *stream)829 {830 char *buffer = linebuffer->buffer;831 char *p = linebuffer->buffer;832 char *end = p + linebuffer->size;833 834 while (1)835 {836 int c = getc (stream);837 if (p == end)838 {839 buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);840 p += buffer - linebuffer->buffer;841 end += buffer - linebuffer->buffer;842 linebuffer->buffer = buffer;843 }844 if (c < 0 || c == '\n')845 {846 *p = 0;847 break;848 }849 *p++ = c;850 }851 852 return p - buffer;853 }854 855 /* Sort an input file too big to sort in core. */856 857 void858 sort_offline (char *infile, off_t total, char *outfile)859 {860 /* More than enough. */861 int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT;862 char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *));863 FILE *istream = fopen (infile, "r");864 int i;865 struct linebuffer lb;866 long linelength;867 int failure = 0;868 869 initbuffer (&lb);870 871 /* Read in one line of input data. */872 873 linelength = readline (&lb, istream);874 875 if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')876 {877 error (_("%s: not a texinfo index file"), infile);878 return;879 }880 881 /* Split up the input into `ntemps' temporary files, or maybe fewer,882 and put the new files' names into `tempfiles' */883 884 for (i = 0; i < ntemps; i++)885 {886 char *outname = maketempname (++tempcount);887 FILE *ostream = fopen (outname, "w");888 long tempsize = 0;889 890 if (!ostream)891 pfatal_with_name (outname);892 tempfiles[i] = outname;893 894 /* Copy lines into this temp file as long as it does not make file895 "too big" or until there are no more lines. */896 897 while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)898 {899 tempsize += linelength + 1;900 fputs (lb.buffer, ostream);901 putc ('\n', ostream);902 903 /* Read another line of input data. */904 905 linelength = readline (&lb, istream);906 if (!linelength && feof (istream))907 break;908 909 if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')910 {911 error (_("%s: not a texinfo index file"), infile);912 failure = 1;913 goto fail;914 }915 }916 fclose (ostream);917 if (feof (istream))918 break;919 }920 921 free (lb.buffer);922 923 fail:924 /* Record number of temp files we actually needed. */925 926 ntemps = i;927 928 /* Sort each tempfile into another tempfile.929 Delete the first set of tempfiles and put the names of the second930 into `tempfiles'. */931 932 for (i = 0; i < ntemps; i++)933 {934 char *newtemp = maketempname (++tempcount);935 sort_in_core (tempfiles[i], MAX_IN_CORE_SORT, newtemp);936 if (!keep_tempfiles)937 unlink (tempfiles[i]);938 tempfiles[i] = newtemp;939 }940 941 if (failure)942 return;943 944 /* Merge the tempfiles together and indexify. */945 946 merge_files (tempfiles, ntemps, outfile);947 }948 949 723 /* Sort INFILE, whose size is TOTAL, 950 724 assuming that is small enough to be done in-core, 951 725 then indexify it and send the output to OUTFILE (or to stdout). */ … … 1349 1123 1350 1124 for (next_line = linearray; next_line != stop_line; next_line++) 1351 1125 { 1352 /* If -u was specified, output the line only if distinct from 1353 previous one. */ 1126 /* Output the line only if distinct from previous one. */ 1354 1127 if (next_line == linearray 1355 1128 /* Compare previous line with this one, using only the 1356 1129 explicitly specd keyfields. */ … … 1370 1143 finish_index (ostream); 1371 1144 } 1372 1145 1373 /* Assume (and optionally verify) that each input file is sorted;1374 merge them and output the result.1375 Returns nonzero if any input file fails to be sorted.1376 1377 This is the high-level interface that can handle an unlimited1378 number of files. */1379 1380 #define MAX_DIRECT_MERGE 101381 1382 int1383 merge_files (char **infiles, int nfiles, char *outfile)1384 {1385 char **tempfiles;1386 int ntemps;1387 int i;1388 int value = 0;1389 int start_tempcount = tempcount;1390 1391 if (nfiles <= MAX_DIRECT_MERGE)1392 return merge_direct (infiles, nfiles, outfile);1393 1394 /* Merge groups of MAX_DIRECT_MERGE input files at a time,1395 making a temporary file to hold each group's result. */1396 1397 ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE;1398 tempfiles = (char **) xmalloc (ntemps * sizeof (char *));1399 for (i = 0; i < ntemps; i++)1400 {1401 int nf = MAX_DIRECT_MERGE;1402 if (i + 1 == ntemps)1403 nf = nfiles - i * MAX_DIRECT_MERGE;1404 tempfiles[i] = maketempname (++tempcount);1405 value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]);1406 }1407 1408 /* All temporary files that existed before are no longer needed1409 since their contents have been merged into our new tempfiles.1410 So delete them. */1411 flush_tempfiles (start_tempcount);1412 1413 /* Now merge the temporary files we created. */1414 1415 merge_files (tempfiles, ntemps, outfile);1416 1417 free (tempfiles);1418 1419 return value;1420 }1421 1422 /* Assume (and optionally verify) that each input file is sorted;1423 merge them and output the result.1424 Returns nonzero if any input file fails to be sorted.1425 1426 This version of merging will not work if the number of1427 input files gets too high. Higher level functions1428 use it only with a bounded number of input files. */1429 1430 int1431 merge_direct (char **infiles, int nfiles, char *outfile)1432 {1433 struct linebuffer *lb1, *lb2;1434 struct linebuffer **thisline, **prevline;1435 FILE **streams;1436 int i;1437 int nleft;1438 int lossage = 0;1439 int *file_lossage;1440 struct linebuffer *prev_out = 0;1441 FILE *ostream = stdout;1442 1443 if (outfile)1444 {1445 ostream = fopen (outfile, "w");1446 }1447 if (!ostream)1448 pfatal_with_name (outfile);1449 1450 init_index ();1451 1452 if (nfiles == 0)1453 {1454 if (outfile)1455 fclose (ostream);1456 return 0;1457 }1458 1459 /* For each file, make two line buffers. Also, for each file, there1460 is an element of `thisline' which points at any time to one of the1461 file's two buffers, and an element of `prevline' which points to1462 the other buffer. `thisline' is supposed to point to the next1463 available line from the file, while `prevline' holds the last file1464 line used, which is remembered so that we can verify that the file1465 is properly sorted. */1466 1467 /* lb1 and lb2 contain one buffer each per file. */1468 lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));1469 lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));1470 1471 /* thisline[i] points to the linebuffer holding the next available1472 line in file i, or is zero if there are no lines left in that file. */1473 thisline = (struct linebuffer **)1474 xmalloc (nfiles * sizeof (struct linebuffer *));1475 /* prevline[i] points to the linebuffer holding the last used line1476 from file i. This is just for verifying that file i is properly1477 sorted. */1478 prevline = (struct linebuffer **)1479 xmalloc (nfiles * sizeof (struct linebuffer *));1480 /* streams[i] holds the input stream for file i. */1481 streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));1482 /* file_lossage[i] is nonzero if we already know file i is not1483 properly sorted. */1484 file_lossage = (int *) xmalloc (nfiles * sizeof (int));1485 1486 /* Allocate and initialize all that storage. */1487 1488 for (i = 0; i < nfiles; i++)1489 {1490 initbuffer (&lb1[i]);1491 initbuffer (&lb2[i]);1492 thisline[i] = &lb1[i];1493 prevline[i] = &lb2[i];1494 file_lossage[i] = 0;1495 streams[i] = fopen (infiles[i], "r");1496 if (!streams[i])1497 pfatal_with_name (infiles[i]);1498 1499 readline (thisline[i], streams[i]);1500 }1501 1502 /* Keep count of number of files not at eof. */1503 nleft = nfiles;1504 1505 while (nleft)1506 {1507 struct linebuffer *best = 0;1508 struct linebuffer *exch;1509 int bestfile = -1;1510 int i;1511 1512 /* Look at the next avail line of each file; choose the least one. */1513 1514 for (i = 0; i < nfiles; i++)1515 {1516 if (thisline[i] &&1517 (!best ||1518 0 < compare_general (best->buffer, thisline[i]->buffer,1519 (long) bestfile, (long) i, num_keyfields)))1520 {1521 best = thisline[i];1522 bestfile = i;1523 }1524 }1525 1526 /* Output that line, unless it matches the previous one and we1527 don't want duplicates. */1528 1529 if (!(prev_out &&1530 !compare_general (prev_out->buffer,1531 best->buffer, 0L, 1L, num_keyfields - 1)))1532 indexify (best->buffer, ostream);1533 prev_out = best;1534 1535 /* Now make the line the previous of its file, and fetch a new1536 line from that file. */1537 1538 exch = prevline[bestfile];1539 prevline[bestfile] = thisline[bestfile];1540 thisline[bestfile] = exch;1541 1542 while (1)1543 {1544 /* If the file has no more, mark it empty. */1545 1546 if (feof (streams[bestfile]))1547 {1548 thisline[bestfile] = 0;1549 /* Update the number of files still not empty. */1550 nleft--;1551 break;1552 }1553 readline (thisline[bestfile], streams[bestfile]);1554 if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile]))1555 break;1556 }1557 }1558 1559 finish_index (ostream);1560 1561 /* Free all storage and close all input streams. */1562 1563 for (i = 0; i < nfiles; i++)1564 {1565 fclose (streams[i]);1566 free (lb1[i].buffer);1567 free (lb2[i].buffer);1568 }1569 free (file_lossage);1570 free (lb1);1571 free (lb2);1572 free (thisline);1573 free (prevline);1574 free (streams);1575 1576 if (outfile)1577 fclose (ostream);1578 1579 return lossage;1580 }1581 1582 1146 /* Print error message and exit. */ 1583 1147 1584 1148 void … … 1613 1177 } 1614 1178 1615 1179 1616 /* Return a newly-allocated string concatenating S1 and S2. */1180 /* Return a newly-allocated string concatenating S1, S2, and S3. */ 1617 1181 1618 char *1619 concat (char *s1, char *s2)1182 static char * 1183 concat3 (const char *s1, const char *s2, const char *s3) 1620 1184 { 1621 int len1 = strlen (s1), len2 = strlen (s2) ;1622 char *result = (char *) xmalloc (len1 + len2 + 1);1185 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); 1186 char *result = (char *) xmalloc (len1 + len2 + len3 + 1); 1623 1187 1624 1188 strcpy (result, s1); 1625 1189 strcpy (result + len1, s2); 1626 *(result + len1 + len2) = 0; 1190 strcpy (result + len1 + len2, s3); 1191 *(result + len1 + len2 + len3) = 0; 1627 1192 1628 1193 return result; 1629 1194 }
Note: See TracBrowser for help on using the browser.
